Further refine r352393, only call vnode_pager_setsize() outside the
node lock when shrinking. This is similar to r252528, applied to the above commit. Apparently there is a race which makes necessary at least to keep the n_size and pager size consistent when extending. Current suspect is that iod threads perform vnode_pager_setsize() without taking the vnode lock, which corrupts the file content. Reported and tested by: Masachika ISHIZUKA <ish@amail.plala.or.jp> Discussed with: rmacklem (related issues) Sponsored by: The FreeBSD Foundation MFC after: 1 week
This commit is contained in:
parent
53e898f9eb
commit
82f8cfda99
@ -414,12 +414,12 @@ nfscl_loadattrcache(struct vnode **vpp, struct nfsvattr *nap, void *nvaper,
|
|||||||
struct nfsnode *np;
|
struct nfsnode *np;
|
||||||
struct nfsmount *nmp;
|
struct nfsmount *nmp;
|
||||||
struct timespec mtime_save;
|
struct timespec mtime_save;
|
||||||
|
vm_object_t object;
|
||||||
u_quad_t nsize;
|
u_quad_t nsize;
|
||||||
int setnsize, error, force_fid_err;
|
int error, force_fid_err;
|
||||||
|
bool setnsize;
|
||||||
|
|
||||||
error = 0;
|
error = 0;
|
||||||
setnsize = 0;
|
|
||||||
nsize = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If v_type == VNON it is a new node, so fill in the v_type,
|
* If v_type == VNON it is a new node, so fill in the v_type,
|
||||||
@ -511,8 +511,7 @@ nfscl_loadattrcache(struct vnode **vpp, struct nfsvattr *nap, void *nvaper,
|
|||||||
* zero np->n_attrstamp to indicate that
|
* zero np->n_attrstamp to indicate that
|
||||||
* the attributes are stale.
|
* the attributes are stale.
|
||||||
*/
|
*/
|
||||||
nsize = vap->va_size = np->n_size;
|
vap->va_size = np->n_size;
|
||||||
setnsize = 1;
|
|
||||||
np->n_attrstamp = 0;
|
np->n_attrstamp = 0;
|
||||||
KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
|
KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
|
||||||
} else if (np->n_flag & NMODIFIED) {
|
} else if (np->n_flag & NMODIFIED) {
|
||||||
@ -526,22 +525,9 @@ nfscl_loadattrcache(struct vnode **vpp, struct nfsvattr *nap, void *nvaper,
|
|||||||
np->n_size = vap->va_size;
|
np->n_size = vap->va_size;
|
||||||
np->n_flag |= NSIZECHANGED;
|
np->n_flag |= NSIZECHANGED;
|
||||||
}
|
}
|
||||||
nsize = np->n_size;
|
|
||||||
setnsize = 1;
|
|
||||||
} else if (vap->va_size < np->n_size) {
|
|
||||||
/*
|
|
||||||
* When shrinking the size, the call to
|
|
||||||
* vnode_pager_setsize() cannot be done
|
|
||||||
* with the mutex held, so delay it until
|
|
||||||
* after the mtx_unlock call.
|
|
||||||
*/
|
|
||||||
nsize = np->n_size = vap->va_size;
|
|
||||||
np->n_flag |= NSIZECHANGED;
|
|
||||||
setnsize = 1;
|
|
||||||
} else {
|
} else {
|
||||||
nsize = np->n_size = vap->va_size;
|
np->n_size = vap->va_size;
|
||||||
np->n_flag |= NSIZECHANGED;
|
np->n_flag |= NSIZECHANGED;
|
||||||
setnsize = 1;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
np->n_size = vap->va_size;
|
np->n_size = vap->va_size;
|
||||||
@ -579,6 +565,23 @@ nfscl_loadattrcache(struct vnode **vpp, struct nfsvattr *nap, void *nvaper,
|
|||||||
if (np->n_attrstamp != 0)
|
if (np->n_attrstamp != 0)
|
||||||
KDTRACE_NFS_ATTRCACHE_LOAD_DONE(vp, vap, error);
|
KDTRACE_NFS_ATTRCACHE_LOAD_DONE(vp, vap, error);
|
||||||
#endif
|
#endif
|
||||||
|
nsize = vap->va_size;
|
||||||
|
object = vp->v_object;
|
||||||
|
setnsize = false;
|
||||||
|
if (object != NULL) {
|
||||||
|
if (OFF_TO_IDX(nsize + PAGE_MASK) < object->size) {
|
||||||
|
/*
|
||||||
|
* When shrinking the size, the call to
|
||||||
|
* vnode_pager_setsize() cannot be done with
|
||||||
|
* the mutex held, because we might need to
|
||||||
|
* wait for a busy page. Delay it until after
|
||||||
|
* the node is unlocked.
|
||||||
|
*/
|
||||||
|
setnsize = true;
|
||||||
|
} else {
|
||||||
|
vnode_pager_setsize(vp, nsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
NFSUNLOCKNODE(np);
|
NFSUNLOCKNODE(np);
|
||||||
if (setnsize)
|
if (setnsize)
|
||||||
vnode_pager_setsize(vp, nsize);
|
vnode_pager_setsize(vp, nsize);
|
||||||
|
Loading…
Reference in New Issue
Block a user