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:
parent
7ab18d4990
commit
a08e5f97bc
@ -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]);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user