Subject: Re: uvm_fault kernel: page fault trap while un-tar-ing a large file
To: Edgar =?iso-8859-1?B?RnXf?= <ef@math.uni-bonn.de>
From: Juergen Hannken-Illjes <hannken@eis.cs.tu-bs.de>
List: tech-kern
Date: 06/23/2007 12:30:14
On Fri, Jun 22, 2007 at 10:39:11PM +0200, Edgar Fuß wrote:
> >Just built GENERIC.MP from my NetBSD4 tree and it looks like Line 729
> >is right and the error comes from TAILQ_REMOVE when it assigns
> >*(elm)->field.tqe_prev = (elm)->field.tqe_next.
> OK, looks that you're right and I inspected the wrong netbsd.gdb.
> 
> I added a test just before the TAILQ_REMOVE that would panic
> if dq->dq_freelist.tqe_prev was NULL and give me the value of dq.
> After a few tries, I managed to hit the panic. I dumped and gdb'ing
> the dump revealed that the code was trying to remove an entry from the
> free list that wasn't on it in the first place.
> 
> Everything else with that entry looks reasonable:
> $20 = {dq_hash = {le_next = 0x0, le_prev = 0xffff800008fb9bf0},  
> dq_freelist = {
>     tqe_next = 0x0, tqe_prev = 0x0}, dq_flags = 12, dq_cnt = 0,  
> dq_spare = 0,
>   dq_type = 0, dq_id = 10060, dq_ump = 0xffff800009584a00, dq_dqb = {
>     dqb_bhardlimit = 0, dqb_bsoftlimit = 0, dqb_curblocks = 11101240,
>     dqb_ihardlimit = 0, dqb_isoftlimit = 0, dqb_curinodes = 65536,
>     dqb_btime = 1183141531, dqb_itime = 1183141531}}
> 
> The id is correct, the mount pointer is correct.
> The reference count is zero, so it should be on the free list.
> I think the value of curinodes looks suspicious.
> 
> I can give more information from the dump if needed.

Ok.  As soon as we allocate 65536 vnodes per uid on a quota-enabled
file system the refcount will overflow.  You were untarring a big
archive, yes?

The appended diff (based on -current) should fix the problem.  If it works
for you I will commit and request the necessary pullups.

-- 
Juergen Hannken-Illjes - hannken@eis.cs.tu-bs.de - TU Braunschweig (Germany)

Index: sys/ufs/ufs/quota.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/quota.h,v
retrieving revision 1.23
diff -p -u -4 -r1.23 quota.h
--- sys/ufs/ufs/quota.h	4 Mar 2007 06:03:46 -0000	1.23
+++ sys/ufs/ufs/quota.h	23 Jun 2007 09:49:55 -0000
@@ -117,11 +117,10 @@ struct dqblk {
 struct dquot {
 	LIST_ENTRY(dquot) dq_hash;	/* hash list */
 	TAILQ_ENTRY(dquot) dq_freelist;	/* free list */
 	u_int16_t dq_flags;		/* flags, see below */
-	u_int16_t dq_cnt;		/* count of active references */
-	u_int16_t dq_spare;		/* unused spare padding */
 	u_int16_t dq_type;		/* quota type of this dquot */
+	u_int32_t dq_cnt;		/* count of active references */
 	u_int32_t dq_id;		/* identifier this applies to */
 	struct	ufsmount *dq_ump;	/* filesystem that this is taken from */
 	struct	dqblk dq_dqb;		/* actual usage & quotas */
 };
Index: sys/ufs/ufs/ufs_quota.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/ufs_quota.c,v
retrieving revision 1.45
diff -p -u -4 -r1.45 ufs_quota.c
--- sys/ufs/ufs/ufs_quota.c	7 Apr 2007 14:21:52 -0000	1.45
+++ sys/ufs/ufs/ufs_quota.c	23 Jun 2007 09:49:55 -0000
@@ -815,8 +815,9 @@ void
 dqref(struct dquot *dq)
 {
 
 	dq->dq_cnt++;
+	KASSERT(dq->dq_cnt > 0);
 }
 
 /*
  * Release a reference to a dquot.