summaryrefslogtreecommitdiffstats
path: root/sys/fs/nfsclient/nfs_clstate.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/nfsclient/nfs_clstate.c')
-rw-r--r--sys/fs/nfsclient/nfs_clstate.c181
1 files changed, 97 insertions, 84 deletions
diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c
index aa81437..7ce2b8e 100644
--- a/sys/fs/nfsclient/nfs_clstate.c
+++ b/sys/fs/nfsclient/nfs_clstate.c
@@ -95,7 +95,7 @@ int nfscl_deleghighwater = NFSCLDELEGHIGHWATER;
static int nfscl_delegcnt = 0;
static int nfscl_getopen(struct nfsclownerhead *, u_int8_t *, int, u_int8_t *,
- NFSPROC_T *, u_int32_t, struct nfsclowner **, struct nfsclopen **);
+ u_int8_t *, u_int32_t, struct nfscllockowner **, struct nfsclopen **);
static void nfscl_clrelease(struct nfsclclient *);
static void nfscl_cleanclient(struct nfsclclient *);
static void nfscl_expireclient(struct nfsclclient *, struct nfsmount *,
@@ -114,7 +114,6 @@ static struct nfscldeleg *nfscl_finddeleg(struct nfsclclient *, u_int8_t *,
int);
static int nfscl_checkconflict(struct nfscllockownerhead *, struct nfscllock *,
u_int8_t *, struct nfscllock **);
-static void nfscl_freelockowner(struct nfscllockowner *, int);
static void nfscl_freealllocks(struct nfscllockownerhead *, int);
static int nfscl_localconflict(struct nfsclclient *, u_int8_t *, int,
struct nfscllock *, u_int8_t *, struct nfscldeleg *, struct nfscllock **);
@@ -522,25 +521,20 @@ nfscl_getstateid(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t mode,
* for a matching OpenOwner and use that.
*/
nfscl_filllockowner(p->td_proc, own, F_POSIX);
- error = nfscl_getopen(&clp->nfsc_owner, nfhp, fhlen, NULL, p,
- mode, NULL, &op);
- if (error == 0) {
- /* now look for a lockowner */
- LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
- if (!NFSBCMP(lp->nfsl_owner, own,
- NFSV4CL_LOCKNAMELEN)) {
- stateidp->seqid =
- lp->nfsl_stateid.seqid;
- stateidp->other[0] =
- lp->nfsl_stateid.other[0];
- stateidp->other[1] =
- lp->nfsl_stateid.other[1];
- stateidp->other[2] =
- lp->nfsl_stateid.other[2];
- NFSUNLOCKCLSTATE();
- return (0);
- }
- }
+ lp = NULL;
+ error = nfscl_getopen(&clp->nfsc_owner, nfhp, fhlen, own, own,
+ mode, &lp, &op);
+ if (error == 0 && lp != NULL) {
+ stateidp->seqid =
+ lp->nfsl_stateid.seqid;
+ stateidp->other[0] =
+ lp->nfsl_stateid.other[0];
+ stateidp->other[1] =
+ lp->nfsl_stateid.other[1];
+ stateidp->other[2] =
+ lp->nfsl_stateid.other[2];
+ NFSUNLOCKCLSTATE();
+ return (0);
}
}
if (op == NULL) {
@@ -579,55 +573,74 @@ nfscl_getstateid(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t mode,
}
/*
- * Get an existing open. Search up the parentage tree for a match and
- * return with the first one found.
+ * Search for a matching file, mode and, optionally, lockowner.
*/
static int
nfscl_getopen(struct nfsclownerhead *ohp, u_int8_t *nfhp, int fhlen,
- u_int8_t *rown, NFSPROC_T *p, u_int32_t mode, struct nfsclowner **owpp,
- struct nfsclopen **opp)
+ u_int8_t *openown, u_int8_t *lockown, u_int32_t mode,
+ struct nfscllockowner **lpp, struct nfsclopen **opp)
{
- struct nfsclowner *owp = NULL;
- struct nfsclopen *op;
- NFSPROC_T *nproc;
- u_int8_t own[NFSV4CL_LOCKNAMELEN], *ownp;
+ struct nfsclowner *owp;
+ struct nfsclopen *op, *rop, *rop2;
+ struct nfscllockowner *lp;
+ int keep_looping;
- nproc = p;
- op = NULL;
- while (op == NULL && (nproc != NULL || rown != NULL)) {
- if (nproc != NULL) {
- nfscl_filllockowner(nproc->td_proc, own, F_POSIX);
- ownp = own;
- } else {
- ownp = rown;
- }
- /* Search the client list */
- LIST_FOREACH(owp, ohp, nfsow_list) {
- if (!NFSBCMP(owp->nfsow_owner, ownp,
- NFSV4CL_LOCKNAMELEN))
- break;
- }
- if (owp != NULL) {
- /* and look for the correct open */
- LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
- if (op->nfso_fhlen == fhlen &&
- !NFSBCMP(op->nfso_fh, nfhp, fhlen)
- && (op->nfso_mode & mode) == mode) {
- break;
+ if (lpp != NULL)
+ *lpp = NULL;
+ /*
+ * rop will be set to the open to be returned. There are three
+ * variants of this, all for an open of the correct file:
+ * 1 - A match of lockown.
+ * 2 - A match of the openown, when no lockown match exists.
+ * 3 - A match for any open, if no openown or lockown match exists.
+ * Looking for #2 over #3 probably isn't necessary, but since
+ * RFC3530 is vague w.r.t. the relationship between openowners and
+ * lockowners, I think this is the safer way to go.
+ */
+ rop = NULL;
+ rop2 = NULL;
+ keep_looping = 1;
+ /* Search the client list */
+ owp = LIST_FIRST(ohp);
+ while (owp != NULL && keep_looping != 0) {
+ /* and look for the correct open */
+ op = LIST_FIRST(&owp->nfsow_open);
+ while (op != NULL && keep_looping != 0) {
+ if (op->nfso_fhlen == fhlen &&
+ !NFSBCMP(op->nfso_fh, nfhp, fhlen)
+ && (op->nfso_mode & mode) == mode) {
+ if (lpp != NULL) {
+ /* Now look for a matching lockowner. */
+ LIST_FOREACH(lp, &op->nfso_lock,
+ nfsl_list) {
+ if (!NFSBCMP(lp->nfsl_owner,
+ lockown,
+ NFSV4CL_LOCKNAMELEN)) {
+ *lpp = lp;
+ rop = op;
+ keep_looping = 0;
+ break;
+ }
+ }
+ }
+ if (rop == NULL && !NFSBCMP(owp->nfsow_owner,
+ openown, NFSV4CL_LOCKNAMELEN)) {
+ rop = op;
+ if (lpp == NULL)
+ keep_looping = 0;
}
+ if (rop2 == NULL)
+ rop2 = op;
}
+ op = LIST_NEXT(op, nfso_list);
}
- if (rown != NULL)
- break;
- if (op == NULL)
- nproc = nfscl_getparent(nproc);
+ owp = LIST_NEXT(owp, nfsow_list);
}
- if (op == NULL) {
+ if (rop == NULL)
+ rop = rop2;
+ if (rop == NULL)
return (EBADF);
- }
- if (owpp)
- *owpp = owp;
- *opp = op;
+ *opp = rop;
return (0);
}
@@ -748,7 +761,8 @@ nfscl_getcl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
FREE((caddr_t)newclp, M_NFSCLCLIENT);
}
NFSLOCKCLSTATE();
- while ((clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID) == 0 && !igotlock)
+ while ((clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID) == 0 && !igotlock &&
+ (mp->mnt_kern_flag & MNTK_UNMOUNTF) == 0)
igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL,
NFSCLSTATEMUTEXPTR, mp);
if (!igotlock)
@@ -892,16 +906,16 @@ nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
struct nfscldeleg *dp = NULL, *ldp = NULL;
struct nfscllockownerhead *lhp = NULL;
struct nfsnode *np;
- u_int8_t own[NFSV4CL_LOCKNAMELEN], *ownp;
+ u_int8_t own[NFSV4CL_LOCKNAMELEN], *ownp, openown[NFSV4CL_LOCKNAMELEN];
+ u_int8_t *openownp;
int error = 0, ret, donelocally = 0;
u_int32_t mode;
- if (type == F_WRLCK)
- mode = NFSV4OPEN_ACCESSWRITE;
- else
- mode = NFSV4OPEN_ACCESSREAD;
+ /* For Lock Ops, the open mode doesn't matter, so use 0 to match any. */
+ mode = 0;
np = VTONFS(vp);
*lpp = NULL;
+ lp = NULL;
*newonep = 0;
*donelocallyp = 0;
@@ -941,9 +955,12 @@ nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
op = NULL;
if (recovery) {
ownp = rownp;
+ openownp = ropenownp;
} else {
nfscl_filllockowner(id, own, flags);
ownp = own;
+ nfscl_filllockowner(p->td_proc, openown, F_POSIX);
+ openownp = openown;
}
if (!recovery) {
NFSLOCKCLSTATE();
@@ -962,13 +979,13 @@ nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
dp = NULL;
}
if (dp != NULL) {
- /* Now, find the associated open to get the correct openowner */
+ /* Now, find an open and maybe a lockowner. */
ret = nfscl_getopen(&dp->nfsdl_owner, np->n_fhp->nfh_fh,
- np->n_fhp->nfh_len, NULL, p, mode, NULL, &op);
+ np->n_fhp->nfh_len, openownp, ownp, mode, NULL, &op);
if (ret)
ret = nfscl_getopen(&clp->nfsc_owner,
- np->n_fhp->nfh_fh, np->n_fhp->nfh_len, NULL, p,
- mode, NULL, &op);
+ np->n_fhp->nfh_fh, np->n_fhp->nfh_len, openownp,
+ ownp, mode, NULL, &op);
if (!ret) {
lhp = &dp->nfsdl_lock;
TAILQ_REMOVE(&clp->nfsc_deleg, dp, nfsdl_list);
@@ -981,16 +998,11 @@ nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
}
if (!donelocally) {
/*
- * Get the related Open.
+ * Get the related Open and maybe lockowner.
*/
- if (recovery)
- error = nfscl_getopen(&clp->nfsc_owner,
- np->n_fhp->nfh_fh, np->n_fhp->nfh_len, ropenownp,
- NULL, mode, NULL, &op);
- else
- error = nfscl_getopen(&clp->nfsc_owner,
- np->n_fhp->nfh_fh, np->n_fhp->nfh_len, NULL, p,
- mode, NULL, &op);
+ error = nfscl_getopen(&clp->nfsc_owner,
+ np->n_fhp->nfh_fh, np->n_fhp->nfh_len, openownp,
+ ownp, mode, &lp, &op);
if (!error)
lhp = &op->nfso_lock;
}
@@ -1011,10 +1023,11 @@ nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
/*
* Ok, see if a lockowner exists and create one, as required.
*/
- LIST_FOREACH(lp, lhp, nfsl_list) {
- if (!NFSBCMP(lp->nfsl_owner, ownp, NFSV4CL_LOCKNAMELEN))
- break;
- }
+ if (lp == NULL)
+ LIST_FOREACH(lp, lhp, nfsl_list) {
+ if (!NFSBCMP(lp->nfsl_owner, ownp, NFSV4CL_LOCKNAMELEN))
+ break;
+ }
if (lp == NULL) {
NFSBCOPY(ownp, nlp->nfsl_owner, NFSV4CL_LOCKNAMELEN);
if (recovery)
@@ -1450,7 +1463,7 @@ nfscl_freeopenowner(struct nfsclowner *owp, int local)
/*
* Free up a byte range lock owner structure.
*/
-static void
+APPLESTATIC void
nfscl_freelockowner(struct nfscllockowner *lp, int local)
{
struct nfscllock *lop, *nlop;
OpenPOWER on IntegriCloud