Changeset View
Standalone View
sys/fs/nfsclient/nfs_clvnops.c
Show First 20 Lines • Show All 136 Lines • ▼ Show 20 Lines | static int nfs_sillyrename(struct vnode *, struct vnode *, | ||||
struct componentname *); | struct componentname *); | ||||
static vop_access_t nfsspec_access; | static vop_access_t nfsspec_access; | ||||
static vop_readlink_t nfs_readlink; | static vop_readlink_t nfs_readlink; | ||||
static vop_print_t nfs_print; | static vop_print_t nfs_print; | ||||
static vop_advlock_t nfs_advlock; | static vop_advlock_t nfs_advlock; | ||||
static vop_advlockasync_t nfs_advlockasync; | static vop_advlockasync_t nfs_advlockasync; | ||||
static vop_getacl_t nfs_getacl; | static vop_getacl_t nfs_getacl; | ||||
static vop_setacl_t nfs_setacl; | static vop_setacl_t nfs_setacl; | ||||
static vop_lock1_t nfs_lock; | |||||
/* | /* | ||||
* Global vfs data structures for nfs | * Global vfs data structures for nfs | ||||
*/ | */ | ||||
static struct vop_vector newnfs_vnodeops_nosig = { | static struct vop_vector newnfs_vnodeops_nosig = { | ||||
.vop_default = &default_vnodeops, | .vop_default = &default_vnodeops, | ||||
.vop_access = nfs_access, | .vop_access = nfs_access, | ||||
.vop_advlock = nfs_advlock, | .vop_advlock = nfs_advlock, | ||||
.vop_advlockasync = nfs_advlockasync, | .vop_advlockasync = nfs_advlockasync, | ||||
.vop_close = nfs_close, | .vop_close = nfs_close, | ||||
.vop_create = nfs_create, | .vop_create = nfs_create, | ||||
.vop_fsync = nfs_fsync, | .vop_fsync = nfs_fsync, | ||||
.vop_getattr = nfs_getattr, | .vop_getattr = nfs_getattr, | ||||
.vop_getpages = ncl_getpages, | .vop_getpages = ncl_getpages, | ||||
.vop_putpages = ncl_putpages, | .vop_putpages = ncl_putpages, | ||||
.vop_inactive = ncl_inactive, | .vop_inactive = ncl_inactive, | ||||
.vop_link = nfs_link, | .vop_link = nfs_link, | ||||
.vop_lock1 = nfs_lock, | |||||
.vop_lookup = nfs_lookup, | .vop_lookup = nfs_lookup, | ||||
.vop_mkdir = nfs_mkdir, | .vop_mkdir = nfs_mkdir, | ||||
.vop_mknod = nfs_mknod, | .vop_mknod = nfs_mknod, | ||||
.vop_open = nfs_open, | .vop_open = nfs_open, | ||||
.vop_pathconf = nfs_pathconf, | .vop_pathconf = nfs_pathconf, | ||||
.vop_print = nfs_print, | .vop_print = nfs_print, | ||||
.vop_read = nfs_read, | .vop_read = nfs_read, | ||||
.vop_readdir = nfs_readdir, | .vop_readdir = nfs_readdir, | ||||
▲ Show 20 Lines • Show All 118 Lines • ▼ Show 20 Lines | |||||
* nmp->nm_mtx : Protects the fields in the nfsmount. | * nmp->nm_mtx : Protects the fields in the nfsmount. | ||||
rep->r_mtx | rep->r_mtx | ||||
* ncl_iod_mutex : Global lock, protects shared nfsiod state. | * ncl_iod_mutex : Global lock, protects shared nfsiod state. | ||||
* nfs_reqq_mtx : Global lock, protects the nfs_reqq list. | * nfs_reqq_mtx : Global lock, protects the nfs_reqq list. | ||||
nmp->nm_mtx | nmp->nm_mtx | ||||
rep->r_mtx | rep->r_mtx | ||||
* rep->r_mtx : Protects the fields in an nfsreq. | * rep->r_mtx : Protects the fields in an nfsreq. | ||||
*/ | */ | ||||
static int | |||||
nfs_lock(struct vop_lock1_args *ap) | |||||
{ | |||||
struct vnode *vp; | |||||
struct nfsnode *np; | |||||
u_quad_t nsize; | |||||
int error, lktype; | |||||
bool onfault; | |||||
vp = ap->a_vp; | |||||
lktype = ap->a_flags & LK_TYPE_MASK; | |||||
error = VOP_LOCK1_APV(&default_vnodeops, ap); | |||||
if (error != 0 || vp->v_op != &newnfs_vnodeops) | |||||
return (error); | |||||
np = VTONFS(vp); | |||||
NFSLOCKNODE(np); | |||||
if ((np->n_flag & NVNSETSZSKIP) == 0 || (lktype != LK_SHARED && | |||||
lktype != LK_EXCLUSIVE && lktype != LK_UPGRADE && | |||||
lktype != LK_TRYUPGRADE)) { | |||||
NFSUNLOCKNODE(np); | |||||
rmacklem: lktype != LK_UPGRADE is checked twice. Did you mean one of them to be
lktype != LK_DOWNGRADE?
| |||||
Done Inline ActionsIt should have been LK_TRYUPGRADE. I am checking for the ops that cause exclusive locked vnode on success. Hmm, I might handle LK_DOWNGRADE as well, in fact. But this is all theoretical right now, because I think upgrade/downgrade are not issued for NFS vnodes. kib: It should have been LK_TRYUPGRADE. I am checking for the ops that cause exclusive locked vnode… | |||||
Not Done Inline ActionsThere is one case of LK_UPGRADE and no LK_DOWNGRADEs (except the one your I now realize that the LK_DOWNGRADE case would imply that there is already rmacklem: There is one case of LK_UPGRADE and no LK_DOWNGRADEs (except the one your
nfs_lock code adds)… | |||||
Done Inline ActionsLK_UPGRADE/DOWNGRADE come mostly from namei(9) when handling the last path element and locking request from the caller. LK_DOWNGRADE means that the current lock is exclusive indeed, but NVNSETSZSKIP is not synchronized by the vnode lock, so it could be set precisely because other thread did not locked the vnode. And since we own the lock exclusive, it might be good to call vnode_pager_setsize(). But in fact, the only critical moment where we must not miss the call is when vget() is called from vm_fault(), see onfault detection below. It is that de-synchronization which caused the reported SIGSEGV, I believe. kib: LK_UPGRADE/DOWNGRADE come mostly from namei(9) when handling the last path element and locking… | |||||
return (0); | |||||
} | |||||
onfault = (ap->a_flags & LK_EATTR_MASK) == LK_NOWAIT && | |||||
(ap->a_flags & LK_INIT_MASK) == LK_CANRECURSE && | |||||
(lktype == LK_SHARED || lktype == LK_EXCLUSIVE); | |||||
if (onfault && vp->v_vnlock->lk_recurse == 0) { | |||||
/* | |||||
* Force retry in vm_fault(), to make the lock request | |||||
* sleepable, which allows us to piggy-back the | |||||
* sleepable call to vnode_pager_setsize(). | |||||
*/ | |||||
NFSUNLOCKNODE(np); | |||||
VOP_UNLOCK(vp, 0); | |||||
return (EBUSY); | |||||
} | |||||
if ((ap->a_flags & LK_NOWAIT) != 0 || | |||||
(lktype == LK_SHARED && vp->v_vnlock->lk_recurse > 0)) { | |||||
NFSUNLOCKNODE(np); | |||||
return (0); | |||||
} | |||||
if (lktype == LK_SHARED) { | |||||
NFSUNLOCKNODE(np); | |||||
VOP_UNLOCK(vp, 0); | |||||
ap->a_flags &= ~(LK_TYPE_MASK | LK_INTERLOCK); | |||||
ap->a_flags |= LK_EXCLUSIVE; | |||||
error = VOP_LOCK1_APV(&default_vnodeops, ap); | |||||
if (error != 0 || vp->v_op != &newnfs_vnodeops) | |||||
return (error); | |||||
NFSLOCKNODE(np); | |||||
if ((np->n_flag & NVNSETSZSKIP) == 0) { | |||||
NFSUNLOCKNODE(np); | |||||
goto downgrade; | |||||
} | |||||
} | |||||
np->n_flag &= ~NVNSETSZSKIP; | |||||
nsize = np->n_size; | |||||
NFSUNLOCKNODE(np); | |||||
vnode_pager_setsize(vp, nsize); | |||||
downgrade: | |||||
if (lktype == LK_SHARED) { | |||||
ap->a_flags &= ~(LK_TYPE_MASK | LK_INTERLOCK); | |||||
ap->a_flags |= LK_DOWNGRADE; | |||||
(void)VOP_LOCK1_APV(&default_vnodeops, ap); | |||||
} | |||||
return (0); | |||||
} | |||||
static int | static int | ||||
nfs34_access_otw(struct vnode *vp, int wmode, struct thread *td, | nfs34_access_otw(struct vnode *vp, int wmode, struct thread *td, | ||||
struct ucred *cred, u_int32_t *retmode) | struct ucred *cred, u_int32_t *retmode) | ||||
{ | { | ||||
int error = 0, attrflag, i, lrupos; | int error = 0, attrflag, i, lrupos; | ||||
u_int32_t rmode; | u_int32_t rmode; | ||||
struct nfsnode *np = VTONFS(vp); | struct nfsnode *np = VTONFS(vp); | ||||
▲ Show 20 Lines • Show All 3,244 Lines • Show Last 20 Lines |
lktype != LK_UPGRADE is checked twice. Did you mean one of them to be
lktype != LK_DOWNGRADE?