Changeset View
Changeset View
Standalone View
Standalone View
fs/nfsclient/nfs_clport.c
Show First 20 Lines • Show All 227 Lines • ▼ Show 20 Lines | nfscl_nget(struct mount *mntp, struct vnode *dvp, struct nfsfh *nfhp, | ||||
np->n_vnode = vp; | np->n_vnode = vp; | ||||
/* | /* | ||||
* Initialize the mutex even if the vnode is going to be a loser. | * Initialize the mutex even if the vnode is going to be a loser. | ||||
* This simplifies the logic in reclaim, which can then unconditionally | * This simplifies the logic in reclaim, which can then unconditionally | ||||
* destroy the mutex (in the case of the loser, or if hash_insert | * destroy the mutex (in the case of the loser, or if hash_insert | ||||
* happened to return an error no special casing is needed). | * happened to return an error no special casing is needed). | ||||
*/ | */ | ||||
mtx_init(&np->n_mtx, "NEWNFSnode lock", NULL, MTX_DEF | MTX_DUPOK); | mtx_init(&np->n_mtx, "NEWNFSnode lock", NULL, MTX_DEF | MTX_DUPOK); | ||||
sx_init(&np->n_slock, "NEWNFSnode slock"); | |||||
lockinit(&np->n_excl, PVFS, "nfsupg", VLKTIMEOUT, LK_NOSHARE | | lockinit(&np->n_excl, PVFS, "nfsupg", VLKTIMEOUT, LK_NOSHARE | | ||||
LK_CANRECURSE); | LK_CANRECURSE); | ||||
/* | /* | ||||
* Are we getting the root? If so, make sure the vnode flags | * Are we getting the root? If so, make sure the vnode flags | ||||
* are correct | * are correct | ||||
*/ | */ | ||||
if ((nfhp->nfh_len == nmp->nm_fhsize) && | if ((nfhp->nfh_len == nmp->nm_fhsize) && | ||||
Show All 27 Lines | nfscl_nget(struct mount *mntp, struct vnode *dvp, struct nfsfh *nfhp, | ||||
*/ | */ | ||||
lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL); | lockmgr(vp->v_vnlock, LK_EXCLUSIVE | LK_NOWITNESS, NULL); | ||||
VN_LOCK_AREC(vp); | VN_LOCK_AREC(vp); | ||||
VN_LOCK_ASHARE(vp); | VN_LOCK_ASHARE(vp); | ||||
error = insmntque(vp, mntp); | error = insmntque(vp, mntp); | ||||
if (error != 0) { | if (error != 0) { | ||||
*npp = NULL; | *npp = NULL; | ||||
mtx_destroy(&np->n_mtx); | mtx_destroy(&np->n_mtx); | ||||
sx_destroy(&np->n_slock); | |||||
lockdestroy(&np->n_excl); | lockdestroy(&np->n_excl); | ||||
free(nfhp, M_NFSFH); | free(nfhp, M_NFSFH); | ||||
if (np->n_v4 != NULL) | if (np->n_v4 != NULL) | ||||
free(np->n_v4, M_NFSV4NODE); | free(np->n_v4, M_NFSV4NODE); | ||||
uma_zfree(newnfsnode_zone, np); | uma_zfree(newnfsnode_zone, np); | ||||
return (error); | return (error); | ||||
} | } | ||||
error = vfs_hash_insert(vp, hash, lkflags, | error = vfs_hash_insert(vp, hash, lkflags, | ||||
▲ Show 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | |||||
nfscl_loadattrcache(struct vnode **vpp, struct nfsvattr *nap, void *nvaper, | nfscl_loadattrcache(struct vnode **vpp, struct nfsvattr *nap, void *nvaper, | ||||
void *stuff, int writeattr, int dontshrink) | void *stuff, int writeattr, int dontshrink) | ||||
{ | { | ||||
struct vnode *vp = *vpp; | struct vnode *vp = *vpp; | ||||
struct vattr *vap, *nvap = &nap->na_vattr, *vaper = nvaper; | struct vattr *vap, *nvap = &nap->na_vattr, *vaper = 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; | |||||
int error, force_fid_err; | int error, force_fid_err; | ||||
bool setnsize; | bool unlocked; | ||||
error = 0; | error = 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, | ||||
* n_mtime fields. Check to see if it represents a special | * n_mtime fields. Check to see if it represents a special | ||||
* device, and if so, check for a possible alias. Once the | * device, and if so, check for a possible alias. Once the | ||||
* correct vnode has been obtained, fill in the rest of the | * correct vnode has been obtained, fill in the rest of the | ||||
* information. | * information. | ||||
*/ | */ | ||||
np = VTONFS(vp); | np = VTONFS(vp); | ||||
NFSLOCKNODE(np); | sx_xlock(&np->n_slock); | ||||
mtx_lock(&np->n_mtx); | |||||
if (vp->v_type != nvap->va_type) { | if (vp->v_type != nvap->va_type) { | ||||
vp->v_type = nvap->va_type; | vp->v_type = nvap->va_type; | ||||
if (vp->v_type == VFIFO) | if (vp->v_type == VFIFO) | ||||
vp->v_op = &newnfs_fifoops; | vp->v_op = &newnfs_fifoops; | ||||
np->n_mtime = nvap->va_mtime; | np->n_mtime = nvap->va_mtime; | ||||
} | } | ||||
nmp = VFSTONFS(vp->v_mount); | nmp = VFSTONFS(vp->v_mount); | ||||
vap = &np->n_vattr.na_vattr; | vap = &np->n_vattr.na_vattr; | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | if (NFSHASNFSV4(nmp) && NFSHASHASSETFSID(nmp) && | ||||
*/ | */ | ||||
vn_fsid(vp, vap); | vn_fsid(vp, vap); | ||||
if ((uint32_t)vap->va_fsid == np->n_vattr.na_filesid[0]) | if ((uint32_t)vap->va_fsid == np->n_vattr.na_filesid[0]) | ||||
vap->va_fsid = hash32_buf( | vap->va_fsid = hash32_buf( | ||||
np->n_vattr.na_filesid, 2 * sizeof(uint64_t), 0); | np->n_vattr.na_filesid, 2 * sizeof(uint64_t), 0); | ||||
} else | } else | ||||
vn_fsid(vp, vap); | vn_fsid(vp, vap); | ||||
np->n_attrstamp = time_second; | np->n_attrstamp = time_second; | ||||
unlocked = false; | |||||
if (vap->va_size != np->n_size) { | if (vap->va_size != np->n_size) { | ||||
if (vap->va_type == VREG) { | if (vap->va_type == VREG) { | ||||
if (dontshrink && vap->va_size < np->n_size) { | if (dontshrink && vap->va_size < np->n_size) { | ||||
/* | /* | ||||
* We've been told not to shrink the file; | * We've been told not to shrink the file; | ||||
* zero np->n_attrstamp to indicate that | * zero np->n_attrstamp to indicate that | ||||
* the attributes are stale. | * the attributes are stale. | ||||
*/ | */ | ||||
vap->va_size = np->n_size; | vap->va_size = np->n_size; | ||||
np->n_attrstamp = 0; | np->n_attrstamp = 0; | ||||
unlocked = true; | |||||
mtx_unlock(&np->n_mtx); | |||||
KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); | KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp); | ||||
vnode_pager_setsize(vp, np->n_size); | |||||
} else if (np->n_flag & NMODIFIED) { | } else if (np->n_flag & NMODIFIED) { | ||||
/* | /* | ||||
* We've modified the file: Use the larger | * We've modified the file: Use the larger | ||||
* of our size, and the server's size. | * of our size, and the server's size. | ||||
*/ | */ | ||||
if (vap->va_size < np->n_size) { | if (vap->va_size < np->n_size) { | ||||
vap->va_size = np->n_size; | vap->va_size = np->n_size; | ||||
} else { | } else { | ||||
np->n_size = vap->va_size; | np->n_size = vap->va_size; | ||||
np->n_flag |= NSIZECHANGED; | np->n_flag |= NSIZECHANGED; | ||||
} | } | ||||
unlocked = true; | |||||
mtx_unlock(&np->n_mtx); | |||||
vnode_pager_setsize(vp, np->n_size); | |||||
} else { | } else { | ||||
np->n_size = vap->va_size; | np->n_size = vap->va_size; | ||||
np->n_flag |= NSIZECHANGED; | np->n_flag |= NSIZECHANGED; | ||||
unlocked = true; | |||||
mtx_unlock(&np->n_mtx); | |||||
vnode_pager_setsize(vp, np->n_size); | |||||
} | } | ||||
} else { | } else { | ||||
np->n_size = vap->va_size; | np->n_size = vap->va_size; | ||||
} | } | ||||
} | } | ||||
if (unlocked) | |||||
mtx_lock(&np->n_mtx); | |||||
/* | /* | ||||
* The following checks are added to prevent a race between (say) | * The following checks are added to prevent a race between (say) | ||||
* a READDIR+ and a WRITE. | * a READDIR+ and a WRITE. | ||||
* READDIR+, WRITE requests sent out. | * READDIR+, WRITE requests sent out. | ||||
* READDIR+ resp, WRITE resp received on client. | * READDIR+ resp, WRITE resp received on client. | ||||
* However, the WRITE resp was handled before the READDIR+ resp | * However, the WRITE resp was handled before the READDIR+ resp | ||||
* causing the post op attrs from the write to be loaded first | * causing the post op attrs from the write to be loaded first | ||||
* and the attrs from the READDIR+ to be loaded later. If this | * and the attrs from the READDIR+ to be loaded later. If this | ||||
Show All 15 Lines | if (np->n_flag & NCHG) { | ||||
vaper->va_mtime = np->n_mtim; | vaper->va_mtime = np->n_mtim; | ||||
} | } | ||||
} | } | ||||
out: | out: | ||||
#ifdef KDTRACE_HOOKS | #ifdef KDTRACE_HOOKS | ||||
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; | mtx_unlock(&np->n_mtx); | ||||
kib: You do not need to check this, vnode_pager_setsize() already does the check.
IMO it could be… | |||||
object = vp->v_object; | sx_xunlock(&np->n_slock); | ||||
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); | |||||
if (setnsize) | |||||
vnode_pager_setsize(vp, nsize); | |||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Fill in the client id name. For these bytes: | * Fill in the client id name. For these bytes: | ||||
* 1 - they must be unique | * 1 - they must be unique | ||||
* 2 - they should be persistent across client reboots | * 2 - they should be persistent across client reboots | ||||
* 1 is more critical than 2 | * 1 is more critical than 2 | ||||
▲ Show 20 Lines • Show All 795 Lines • Show Last 20 Lines |
You do not need to check this, vnode_pager_setsize() already does the check.
IMO it could be more useful to check the sizes as I did at line 572 and avoid calling vnode_pager_setsize() at all, this avoids locking the object. But it is fine to call it unconditionally too.