The vm_pageout_flush() functions sbusies pages in the passed pages

run.  After that, the pager put method is called, usually translated
to VOP_WRITE().  For the filesystems which use buffer cache,
bufwrite() sbusies the buffer pages again, waiting for the xbusy state
to drain.  The later is done in vfs_drain_busy_pages(), which is
called with the buffer pages already sbusied (by vm_pageout_flush()).

Since vfs_drain_busy_pages() can only wait for one page at the time,
and during the wait, the object lock is dropped, previous pages in the
buffer must be protected from other threads busying them.  Up to the
moment, it was done by xbusying the pages, that is incompatible with
the sbusy state in the new implementation of busy.  Switch to sbusy.

Reported and tested by:	pho
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Konstantin Belousov 2013-09-05 12:56:08 +00:00
parent 7a4b2bc56c
commit a677b31425

View File

@ -3994,7 +3994,7 @@ vfs_drain_busy_pages(struct buf *bp)
m = bp->b_pages[i];
if (vm_page_xbusied(m)) {
for (; last_busied < i; last_busied++)
vm_page_xbusy(bp->b_pages[last_busied]);
vm_page_sbusy(bp->b_pages[last_busied]);
while (vm_page_xbusied(m)) {
vm_page_lock(m);
VM_OBJECT_WUNLOCK(bp->b_bufobj->bo_object);
@ -4004,7 +4004,7 @@ vfs_drain_busy_pages(struct buf *bp)
}
}
for (i = 0; i < last_busied; i++)
vm_page_xunbusy(bp->b_pages[i]);
vm_page_sunbusy(bp->b_pages[i]);
}
/*