A problem with the old NFS client where large writes to large files
would sometimes result in a corrupted file was reported via email. This problem appears to have been caused by r251719 (reverting r251719 fixed the problem). Although I have not been able to reproduce this problem, I suspect it is caused by another thread increasing np->n_size after the mtx_unlock(&np->n_mtx) but before the vnode_pager_setsize() call. Since the np->n_mtx mutex serializes updates to np->n_size, doing the vnode_pager_setsize() with the mutex locked appears to avoid the problem. Unfortunately, vnode_pager_setsize() where the new size is smaller, cannot be called with a mutex held. This patch returns the semantics to be close to pre-r251719 such that the call to the vnode_pager_setsize() is only delayed until after the mutex is unlocked when np->n_size is shrinking. Since the file is growing when being written, I believe this will fix the corruption. Reported by: David G. Lawrence (dg@dglawrence.com) Tested by: David G. Lawrence (pending, to happen soon) Reviewed by: kib MFC after: 1 week
This commit is contained in:
parent
4a1b5780c0
commit
13e7ae9b12
@ -581,6 +581,7 @@ nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp,
|
||||
vap->va_size = np->n_size;
|
||||
np->n_attrstamp = 0;
|
||||
KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
|
||||
vnode_pager_setsize(vp, np->n_size);
|
||||
} else if (np->n_flag & NMODIFIED) {
|
||||
/*
|
||||
* We've modified the file: Use the larger
|
||||
@ -592,12 +593,22 @@ nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp,
|
||||
np->n_size = vap->va_size;
|
||||
np->n_flag |= NSIZECHANGED;
|
||||
}
|
||||
vnode_pager_setsize(vp, np->n_size);
|
||||
} 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 {
|
||||
np->n_size = vap->va_size;
|
||||
np->n_flag |= NSIZECHANGED;
|
||||
vnode_pager_setsize(vp, np->n_size);
|
||||
}
|
||||
setnsize = 1;
|
||||
nsize = vap->va_size;
|
||||
} else {
|
||||
np->n_size = vap->va_size;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user