Fix rounding in vop_stdadvise() for POSIX_FADV_NOREUSE (really

POSIX_FADV_DONTNEED).  The most broken case was for applications that
advise for the whole file and then do block-aligned i/o's 1 block at
a time.  Then advice is sent to VOP_ADVISE() 1 block at a time, but
in vop_stdadvise() the 1-block advice was turned into 0-block advice
for the buffer cache part.

The bugs were caused partly by callers representing the region as
(a_start, a_end), where a_end is actually the maximum, and everything
else representing the region as (start, end) where 'end' is actually
the end (1 after the maximum).  The maximum a_end must be rounded up,
but was rounded down.  Also, rounding to page boundaries was inconsistent.

The bugs and fixes have no effect for zfs and other file systems that
don't use the buffer cache or the page cache.  Most or all file systems
currently use the default VOP_FADVISE(), but it finds a null buffer cache
and a null page cache for file systems that don't use normal methods.

Reviewed by:	kib
This commit is contained in:
bde 2018-12-21 04:57:59 +00:00
parent b9ea8013d1
commit 97d496ecdd

View File

@ -1063,7 +1063,7 @@ vop_stdadvise(struct vop_advise_args *ap)
struct vnode *vp;
struct bufobj *bo;
daddr_t startn, endn;
off_t start, end;
off_t bstart, bend, start, end;
int bsize, error;
vp = ap->a_vp;
@ -1084,6 +1084,19 @@ vop_stdadvise(struct vop_advise_args *ap)
break;
}
/*
* Round to block boundaries (and later possibly further to
* page boundaries). Applications cannot reasonably be aware
* of the boundaries, and the rounding must be to expand at
* both extremities to cover enough. It still doesn't cover
* read-ahead. For partial blocks, this gives unnecessary
* discarding of buffers but is efficient enough since the
* pages usually remain in VMIO for some time.
*/
bsize = vp->v_bufobj.bo_bsize;
bstart = roundup(ap->a_start, bsize);
bend = roundup(ap->a_end, bsize);
/*
* Deactivate pages in the specified range from the backing VM
* object. Pages that are resident in the buffer cache will
@ -1091,8 +1104,8 @@ vop_stdadvise(struct vop_advise_args *ap)
* below.
*/
if (vp->v_object != NULL) {
start = trunc_page(ap->a_start);
end = round_page(ap->a_end);
start = trunc_page(bstart);
end = round_page(bend);
VM_OBJECT_RLOCK(vp->v_object);
vm_object_page_noreuse(vp->v_object, OFF_TO_IDX(start),
OFF_TO_IDX(end));
@ -1101,9 +1114,8 @@ vop_stdadvise(struct vop_advise_args *ap)
bo = &vp->v_bufobj;
BO_RLOCK(bo);
bsize = vp->v_bufobj.bo_bsize;
startn = ap->a_start / bsize;
endn = ap->a_end / bsize;
startn = bstart / bsize;
endn = bend / bsize;
error = bnoreuselist(&bo->bo_clean, bo, startn, endn);
if (error == 0)
error = bnoreuselist(&bo->bo_dirty, bo, startn, endn);