Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 14 Aug 1998 04:47:10 -0700
From:      David Greenman <dg@root.com>
To:        Terry Lambert <tlambert@primenet.com>
Cc:        mike@smith.net.au, peter@sirius.com, mrcpu@internetcds.com, hackers@FreeBSD.ORG, stable@FreeBSD.ORG
Subject:   Re: vmopar state in 2.2.7? 
Message-ID:  <199808141147.EAA23436@implode.root.com>
In-Reply-To: Your message of "Fri, 14 Aug 1998 02:27:05 -0000." <199808140227.TAA25476@usr02.primenet.com> 

next in thread | previous in thread | raw e-mail | index | archive | help
>In the second case, 1261, the consequences could be bad.  In fact,
>the consequences of sleeping at all could be bad.  The reason it
>seems to work around the problem for you is that the page causing
>the problem is not the first page on the list and start has been
>incremented.  Because start is not decremented before the "goto again",
>the calculation on line 1207:
>
>	again:                  
>		size = end - start;
>		if (size > 4 || size >= object->size / 4) {
>
>Bogusly omits the page which was just obtained.  This means that
>
>	vm_page_protect(p, VM_PROT_NONE);
>	PAGE_WAKEUP(p);
>	vm_page_free(p);
>
>is never called.
>
>The net result is that pages are left hanging out in space, but the system
>thinks they have been reclaimed.

   Err, it doesn't "omit the page which was just obtained". First off, pages
aren't obtained; all that happens is a pointer to them is gotten - they are
still on the object page list.
   For optimal performance, there are two ways that the code will traverse
the resident pages in the object. The first is the case where the object
either contains a small number of pages or if all the pages should be removed.
In this case, it just accesses the unsorted object resident page list. Since
this list contains all of the pages in a resident object, the code must
check the offset of the pages to ensure that they are within the proper
range that is being removed. Pages that are wired or dirty are skipped. If
while doing this a busy page is encountered, then the system must wait for
the page to become not busy. While sleeping, the order of pages might have
changed in the list, however, so it is necessary to start over again from
the beginning of the object page list. "start" isn't and can't be updated
since the order of pages that are removed is random.
   The second method is to look up the page on the object page hash list.
This has somewhat higher overhead, but is more efficient when dealing with
a small number of pages in an object that has a large number of resident
pages. Since in this case we process the pages sequentially in the start to
end range, we can increment start as each page is removed (or skipped as
the case may be). If the page is busy, then start isn't incremented and thus
the 'goto again' will begin with the page which was just slept on.
   Once again, the bug isn't in the code there. The effects that have been
described suggest a missing wakeup. I believe the attached patches should
fix the problem.

-DG

David Greenman
Co-founder/Principal Architect, The FreeBSD Project

Index: nfs/nfs_bio.c
===================================================================
RCS file: /home/ncvs/src/sys/nfs/nfs_bio.c,v
retrieving revision 1.28.2.7
diff -c -r1.28.2.7 nfs_bio.c
*** nfs_bio.c	1998/01/28 00:26:54	1.28.2.7
--- nfs_bio.c	1998/08/14 11:42:02
***************
*** 131,136 ****
--- 131,140 ----
  
  	m->flags |= PG_BUSY;
  	m->busy--;
+ 	if (m->busy == 0 && (m->flags & PG_WANTED)) {
+ 		m->flags &= ~PG_WANTED;
+ 		wakeup(m);
+ 	}
  
  	if (error && (auio.uio_resid == MAXBSIZE))
  		return VM_PAGER_ERROR;
Index: vm/vnode_pager.c
===================================================================
RCS file: /home/ncvs/src/sys/vm/vnode_pager.c,v
retrieving revision 1.65.2.2
diff -c -r1.65.2.2 vnode_pager.c
*** vnode_pager.c	1997/05/28 18:26:46	1.65.2.2
--- vnode_pager.c	1998/08/14 11:43:06
***************
*** 963,970 ****
  		if (i < ncount) {
  			rtvals[i] = VM_PAGER_OK;
  		}
! 		if ((m[i]->busy == 0) && (m[i]->flags & PG_WANTED))
  			wakeup(m[i]);
  	}
  	return rtvals[0];
  }
--- 963,972 ----
  		if (i < ncount) {
  			rtvals[i] = VM_PAGER_OK;
  		}
! 		if ((m[i]->busy == 0) && (m[i]->flags & PG_WANTED)) {
! 			m[i]->flags &= ~PG_WANTED;
  			wakeup(m[i]);
+ 		}
  	}
  	return rtvals[0];
  }

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-stable" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199808141147.EAA23436>