Add a null_remove() function to nullfs, so that the v_usecount

of the lower level vnode is incremented to greater than 1 when
the upper level vnode's v_usecount is greater than one. This
is necessary for the NFS clients, so that they will do a silly
rename of the file instead of actually removing it when the
file is still in use. It is "racy", since the v_usecount is
incremented in many places in the kernel with
minimal synchronization, but an extraneous silly rename is
preferred to not doing a silly rename when it is required.
The only other file systems that currently check the value
of v_usecount in their VOP_REMOVE() functions are nwfs and
smbfs. These file systems choose to fail a remove when the
v_usecount is greater than 1 and I believe will function
more correctly with this patch, as well.

Tested by:	to.my.trociny at gmail.com
Submitted by:	to.my.trociny at gmail.com (earlier version)
Reviewed by:	kib
MFC after:	2 weeks
This commit is contained in:
Rick Macklem 2010-08-31 01:16:45 +00:00
parent 5bdff860e7
commit 2d0c83b139

View File

@ -498,6 +498,32 @@ null_accessx(struct vop_accessx_args *ap)
return (null_bypass((struct vop_generic_args *)ap));
}
/*
* Increasing refcount of lower vnode is needed at least for the case
* when lower FS is NFS to do sillyrename if the file is in use.
* Unfortunately v_usecount is incremented in many places in
* the kernel and, as such, there may be races that result in
* the NFS client doing an extraneous silly rename, but that seems
* preferable to not doing a silly rename when it is needed.
*/
static int
null_remove(struct vop_remove_args *ap)
{
int retval, vreleit;
struct vnode *lvp;
if (vrefcnt(ap->a_vp) > 1) {
lvp = NULLVPTOLOWERVP(ap->a_vp);
VREF(lvp);
vreleit = 1;
} else
vreleit = 0;
retval = null_bypass(&ap->a_gen);
if (vreleit != 0)
vrele(lvp);
return (retval);
}
/*
* We handle this to eliminate null FS to lower FS
* file moving. Don't know why we don't allow this,
@ -809,6 +835,7 @@ struct vop_vector null_vnodeops = {
.vop_open = null_open,
.vop_print = null_print,
.vop_reclaim = null_reclaim,
.vop_remove = null_remove,
.vop_rename = null_rename,
.vop_setattr = null_setattr,
.vop_strategy = VOP_EOPNOTSUPP,