Both cluster_rbuild() and cluster_wbuild() sometimes set the pages
shared busy without first draining the hard busy state. Previously it went unnoticed since VPO_BUSY and m->busy fields were distinct, and vm_page_io_start() did not verified that the passed page has VPO_BUSY flag cleared, but such page state is wrong. New implementation is more strict and catched this case. Drain the busy state as needed, before calling vm_page_sbusy(). Tested by: pho, jkim Sponsored by: The FreeBSD Foundation
This commit is contained in:
parent
e68c64f0ba
commit
4f8cf6e59b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=254668
@ -108,7 +108,6 @@ static void vm_hold_load_pages(struct buf *bp, vm_offset_t from,
|
||||
static void vfs_page_set_valid(struct buf *bp, vm_ooffset_t off, vm_page_t m);
|
||||
static void vfs_page_set_validclean(struct buf *bp, vm_ooffset_t off,
|
||||
vm_page_t m);
|
||||
static void vfs_drain_busy_pages(struct buf *bp);
|
||||
static void vfs_clean_pages_dirty_buf(struct buf *bp);
|
||||
static void vfs_setdirty_locked_object(struct buf *bp);
|
||||
static void vfs_vmio_release(struct buf *bp);
|
||||
@ -3983,7 +3982,7 @@ vfs_page_set_validclean(struct buf *bp, vm_ooffset_t off, vm_page_t m)
|
||||
* Ensure that all buffer pages are not exclusive busied. If any page is
|
||||
* exclusive busy, drain it.
|
||||
*/
|
||||
static void
|
||||
void
|
||||
vfs_drain_busy_pages(struct buf *bp)
|
||||
{
|
||||
vm_page_t m;
|
||||
|
@ -315,7 +315,7 @@ cluster_rbuild(struct vnode *vp, u_quad_t filesize, daddr_t lbn,
|
||||
daddr_t bn;
|
||||
off_t off;
|
||||
long tinc, tsize;
|
||||
int i, inc, j, toff;
|
||||
int i, inc, j, k, toff;
|
||||
|
||||
KASSERT(size == vp->v_mount->mnt_stat.f_iosize,
|
||||
("cluster_rbuild: size %ld != f_iosize %jd\n",
|
||||
@ -378,7 +378,15 @@ cluster_rbuild(struct vnode *vp, u_quad_t filesize, daddr_t lbn,
|
||||
inc = btodb(size);
|
||||
bo = &vp->v_bufobj;
|
||||
for (bn = blkno, i = 0; i < run; ++i, bn += inc) {
|
||||
if (i != 0) {
|
||||
if (i == 0) {
|
||||
VM_OBJECT_WLOCK(tbp->b_bufobj->bo_object);
|
||||
vfs_drain_busy_pages(tbp);
|
||||
vm_object_pip_add(tbp->b_bufobj->bo_object,
|
||||
tbp->b_npages);
|
||||
for (k = 0; k < tbp->b_npages; k++)
|
||||
vm_page_sbusy(tbp->b_pages[k]);
|
||||
VM_OBJECT_WUNLOCK(tbp->b_bufobj->bo_object);
|
||||
} else {
|
||||
if ((bp->b_npages * PAGE_SIZE) +
|
||||
round_page(size) > vp->v_mount->mnt_iosize_max) {
|
||||
break;
|
||||
@ -424,14 +432,23 @@ cluster_rbuild(struct vnode *vp, u_quad_t filesize, daddr_t lbn,
|
||||
if ((tbp->b_pages[j]->valid &
|
||||
vm_page_bits(toff, tinc)) != 0)
|
||||
break;
|
||||
if (vm_page_xbusied(tbp->b_pages[j]))
|
||||
break;
|
||||
vm_object_pip_add(tbp->b_bufobj->bo_object, 1);
|
||||
vm_page_sbusy(tbp->b_pages[j]);
|
||||
off += tinc;
|
||||
tsize -= tinc;
|
||||
}
|
||||
VM_OBJECT_WUNLOCK(tbp->b_bufobj->bo_object);
|
||||
if (tsize > 0) {
|
||||
clean_sbusy:
|
||||
vm_object_pip_add(tbp->b_bufobj->bo_object, -j);
|
||||
for (k = 0; k < j; k++)
|
||||
vm_page_sunbusy(tbp->b_pages[k]);
|
||||
VM_OBJECT_WUNLOCK(tbp->b_bufobj->bo_object);
|
||||
bqrelse(tbp);
|
||||
break;
|
||||
}
|
||||
VM_OBJECT_WUNLOCK(tbp->b_bufobj->bo_object);
|
||||
|
||||
/*
|
||||
* Set a read-ahead mark as appropriate
|
||||
@ -451,8 +468,8 @@ cluster_rbuild(struct vnode *vp, u_quad_t filesize, daddr_t lbn,
|
||||
if (tbp->b_blkno == tbp->b_lblkno) {
|
||||
tbp->b_blkno = bn;
|
||||
} else if (tbp->b_blkno != bn) {
|
||||
brelse(tbp);
|
||||
break;
|
||||
VM_OBJECT_WLOCK(tbp->b_bufobj->bo_object);
|
||||
goto clean_sbusy;
|
||||
}
|
||||
}
|
||||
/*
|
||||
@ -466,10 +483,8 @@ cluster_rbuild(struct vnode *vp, u_quad_t filesize, daddr_t lbn,
|
||||
for (j = 0; j < tbp->b_npages; j += 1) {
|
||||
vm_page_t m;
|
||||
m = tbp->b_pages[j];
|
||||
vm_page_sbusy(m);
|
||||
vm_object_pip_add(m->object, 1);
|
||||
if ((bp->b_npages == 0) ||
|
||||
(bp->b_pages[bp->b_npages-1] != m)) {
|
||||
(bp->b_pages[bp->b_npages-1] != m)) {
|
||||
bp->b_pages[bp->b_npages] = m;
|
||||
bp->b_npages++;
|
||||
}
|
||||
@ -944,7 +959,9 @@ cluster_wbuild(struct vnode *vp, long size, daddr_t start_lbn, int len,
|
||||
vm_page_t m;
|
||||
|
||||
VM_OBJECT_WLOCK(tbp->b_bufobj->bo_object);
|
||||
if (i != 0) { /* if not first buffer */
|
||||
if (i == 0) {
|
||||
vfs_drain_busy_pages(tbp);
|
||||
} else { /* if not first buffer */
|
||||
for (j = 0; j < tbp->b_npages; j += 1) {
|
||||
m = tbp->b_pages[j];
|
||||
if (vm_page_xbusied(m)) {
|
||||
|
@ -501,6 +501,7 @@ void bufstrategy(struct bufobj *, struct buf *);
|
||||
void brelse(struct buf *);
|
||||
void bqrelse(struct buf *);
|
||||
int vfs_bio_awrite(struct buf *);
|
||||
void vfs_drain_busy_pages(struct buf *bp);
|
||||
struct buf * getpbuf(int *);
|
||||
struct buf *incore(struct bufobj *, daddr_t);
|
||||
struct buf *gbincore(struct bufobj *, daddr_t);
|
||||
|
Loading…
Reference in New Issue
Block a user