diff options
author | Rajesh Amaravathi <rajesh@redhat.com> | 2012-04-12 14:49:44 +0530 |
---|---|---|
committer | Vijay Bellur <vijay@gluster.com> | 2012-05-17 02:12:49 -0700 |
commit | cbcf82aa58058fe05dbd9a8d8879ca0364e5df95 (patch) | |
tree | 83c7dc8da592fb0442d5626eac6779c813d61655 | |
parent | d8ede99e6f429d3a63b794c495f99fc8f76e9651 (diff) |
nfs/nlm: procedures for PC clients
* This change introduces four NLMv4 procedures:
NM_LOCK, SHARE, UNSHARE and FREE_ALL.
These are used by PC clients (windows/dos) to control access
to files.
1. NM_LOCK: this lock is not monitored by statd.
2. SHARE: A share reservation is a lock on the whole file
that is taken whenever a file is opened on windows clients.
This has ACCESS (N, R, W, RW) and DENY MODE (N, R, W, RW).
ACCESS: mode of access requested by the client;
DENY MODE: what the requesting client wants to
deny other clients.
3. UNSHARE: remove a share reservation obtained by SHARE.
Called while closing a file.
4. FREE_ALL: remove all share reservations and locks,
both monitored and unmonitored, of the calling client.
* lock and nm_lock use a common function with only
a flag conveying whether or not to monitor a lock.
* NOTES:
1. SHARE reservations are not STACK_WIND'd to subsequent xlators.
These are maintained in-memory in the nfs xlator.
2. Consequently, for SHARE reservations to work effectively,
all PC clients *must* mount from the same gNfs server.
Not doing so will result in different servers maintaining
separate SHARE reservations which will not be enforced
for obvious reasons.
Change-Id: Id4f22670a94ed58691a6a7f4c80aa8c11421a277
BUG: 800287
Signed-off-by: Rajesh Amaravathi <rajesh@redhat.com>
Reviewed-on: http://review.gluster.com/3212
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Krishna Srinivas <krishna@gluster.com>
-rw-r--r-- | rpc/xdr/src/msg-nfs3.c | 20 | ||||
-rw-r--r-- | rpc/xdr/src/msg-nfs3.h | 9 | ||||
-rw-r--r-- | rpc/xdr/src/nlm4-xdr.c | 11 | ||||
-rw-r--r-- | rpc/xdr/src/nlm4-xdr.h | 9 | ||||
-rw-r--r-- | rpc/xdr/src/nlm4.x | 9 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs-mem-types.h | 1 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs.c | 9 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs3.h | 2 | ||||
-rw-r--r-- | xlators/nfs/server/src/nlm4.c | 618 | ||||
-rw-r--r-- | xlators/nfs/server/src/nlm4.h | 10 |
10 files changed, 661 insertions, 37 deletions
diff --git a/rpc/xdr/src/msg-nfs3.c b/rpc/xdr/src/msg-nfs3.c index f800b3128fa..8078f23f097 100644 --- a/rpc/xdr/src/msg-nfs3.c +++ b/rpc/xdr/src/msg-nfs3.c @@ -517,6 +517,20 @@ xdr_to_nlm4_unlockargs (struct iovec inmsg, nlm4_unlockargs *args) } ssize_t +xdr_to_nlm4_shareargs (struct iovec inmsg, nlm4_shareargs *args) +{ + return xdr_to_generic (inmsg, (void*)args, + (xdrproc_t)xdr_nlm4_shareargs); +} + +ssize_t +xdr_serialize_nlm4_shareres (struct iovec outmsg, nlm4_shareres *res) +{ + return xdr_serialize_generic (outmsg, (void *)res, + (xdrproc_t)xdr_nlm4_shareres); +} + +ssize_t xdr_serialize_nlm4_testargs (struct iovec outmsg, nlm4_testargs *args) { return xdr_serialize_generic (outmsg, (void*)args, @@ -530,3 +544,9 @@ xdr_to_nlm4_res (struct iovec inmsg, nlm4_res *args) (xdrproc_t)xdr_nlm4_res); } +ssize_t +xdr_to_nlm4_freeallargs (struct iovec inmsg, nlm4_freeallargs *args) +{ + return xdr_to_generic (inmsg, (void*)args, + (xdrproc_t)xdr_nlm4_freeallargs); +} diff --git a/rpc/xdr/src/msg-nfs3.h b/rpc/xdr/src/msg-nfs3.h index 1310e02f897..701df300a6e 100644 --- a/rpc/xdr/src/msg-nfs3.h +++ b/rpc/xdr/src/msg-nfs3.h @@ -203,9 +203,18 @@ extern ssize_t xdr_to_nlm4_unlockargs (struct iovec inmsg, nlm4_unlockargs *args); extern ssize_t +xdr_to_nlm4_shareargs (struct iovec inmsg, nlm4_shareargs *args); + +extern ssize_t +xdr_serialize_nlm4_shareres (struct iovec outmsg, nlm4_shareres *res); + +extern ssize_t xdr_serialize_nlm4_testargs (struct iovec outmsg, nlm4_testargs *args); extern ssize_t xdr_to_nlm4_res (struct iovec inmsg, nlm4_res *args); +extern ssize_t +xdr_to_nlm4_freeallargs (struct iovec inmsg, nlm4_freeallargs *args); + #endif diff --git a/rpc/xdr/src/nlm4-xdr.c b/rpc/xdr/src/nlm4-xdr.c index b41fbb15cac..4cf6a51e8fd 100644 --- a/rpc/xdr/src/nlm4-xdr.c +++ b/rpc/xdr/src/nlm4-xdr.c @@ -228,6 +228,17 @@ xdr_nlm4_shareres (XDR *xdrs, nlm4_shareres *objp) return TRUE; } +bool_t +xdr_nlm4_freeallargs (XDR *xdrs, nlm4_freeallargs *objp) +{ + if (!xdr_string (xdrs, &objp->name, LM_MAXSTRLEN)) + return FALSE; + if (!xdr_uint32_t (xdrs, &objp->state)) + return FALSE; + return TRUE; +} + + /* bool_t xdr_nlm_sm_status (XDR *xdrs, nlm_sm_status *objp) diff --git a/rpc/xdr/src/nlm4-xdr.h b/rpc/xdr/src/nlm4-xdr.h index d95a6ad6e58..3799f6b1d98 100644 --- a/rpc/xdr/src/nlm4-xdr.h +++ b/rpc/xdr/src/nlm4-xdr.h @@ -183,6 +183,13 @@ struct nlm4_shareres { }; typedef struct nlm4_shareres nlm4_shareres; +struct nlm4_freeallargs { + char *name; + u_int32_t state; +}; +typedef struct nlm4_freeallargs nlm4_freeallargs; + + #define NLM4_NULL 0 #define NLM4_TEST 1 #define NLM4_LOCK 2 @@ -229,6 +236,7 @@ extern bool_t xdr_nlm4_cancargs (XDR *, nlm4_cancargs*); extern bool_t xdr_nlm4_unlockargs (XDR *, nlm4_unlockargs*); extern bool_t xdr_nlm4_shareargs (XDR *, nlm4_shareargs*); extern bool_t xdr_nlm4_shareres (XDR *, nlm4_shareres*); +extern bool_t xdr_nlm4_freeallargs (XDR *, nlm4_freeallargs*); #else /* K&R C */ extern bool_t xdr_netobj (); @@ -248,6 +256,7 @@ extern bool_t xdr_nlm4_cancargs (); extern bool_t xdr_nlm4_unlockargs (); extern bool_t xdr_nlm4_shareargs (); extern bool_t xdr_nlm4_shareres (); +extern bool_t xdr_nlm4_freeallargs (); #endif /* K&R C */ diff --git a/rpc/xdr/src/nlm4.x b/rpc/xdr/src/nlm4.x index d738b27770d..a6de6f32bf4 100644 --- a/rpc/xdr/src/nlm4.x +++ b/rpc/xdr/src/nlm4.x @@ -74,7 +74,7 @@ struct nlm4_holder { }; struct nlm4_lock { - string caller_name<MAXNAMELEN>; + string caller_name<LM_MAXSTRLEN>; netobj fh; netobj oh; u_int32_t svid; @@ -83,7 +83,7 @@ struct nlm4_lock { }; struct nlm4_share { - string caller_name<MAXNAMELEN>; + string caller_name<LM_MAXSTRLEN>; netobj fh; netobj oh; fsh_mode mode; @@ -146,6 +146,11 @@ struct nlm4_shareres { int sequence; }; +struct nlm4_freeallargs { + string name<LM_MAXSTRLEN>; /* client hostname */ + uint32 state; /* unused */ +}; + /* * argument for the procedure called by rpc.statd when a monitored host * status change. diff --git a/xlators/nfs/server/src/nfs-mem-types.h b/xlators/nfs/server/src/nfs-mem-types.h index e2dae4a3403..1a3b25281ba 100644 --- a/xlators/nfs/server/src/nfs-mem-types.h +++ b/xlators/nfs/server/src/nfs-mem-types.h @@ -47,6 +47,7 @@ enum gf_nfs_mem_types_ { gf_nfs_mt_nlm4_cm, gf_nfs_mt_nlm4_fde, gf_nfs_mt_nlm4_nlmclnt, + gf_nfs_mt_nlm4_share, gf_nfs_mt_end }; #endif diff --git a/xlators/nfs/server/src/nfs.c b/xlators/nfs/server/src/nfs.c index 42edc95f6d1..a48e114999a 100644 --- a/xlators/nfs/server/src/nfs.c +++ b/xlators/nfs/server/src/nfs.c @@ -849,6 +849,15 @@ fini (xlator_t *this) int32_t nfs_forget (xlator_t *this, inode_t *inode) { + uint64_t ctx = 0; + struct list_head *head = NULL; + + if (inode_ctx_del (inode, this, &ctx)) + return -1; + + head = (struct list_head *)ctx; + GF_FREE (head); + return 0; } diff --git a/xlators/nfs/server/src/nfs3.h b/xlators/nfs/server/src/nfs3.h index e6b9edee5ca..78eb01b60b9 100644 --- a/xlators/nfs/server/src/nfs3.h +++ b/xlators/nfs/server/src/nfs3.h @@ -154,6 +154,7 @@ typedef union args_ { nlm4_unlockargs nlm4_unlockargs; nlm4_shareargs nlm4_shareargs; nlm4_shareres nlm4_shareres; + nlm4_freeallargs nlm4_freeallargs; } args; @@ -230,6 +231,7 @@ struct nfs3_local { nlm4_lkowner_t lkowner; char cookiebytes[1024]; struct nfs3_fh lockfh; + int monitor; rpc_transport_t *trans; call_frame_t *frame; }; diff --git a/xlators/nfs/server/src/nlm4.c b/xlators/nfs/server/src/nlm4.c index 4f9a1c4fcef..72f71609a51 100644 --- a/xlators/nfs/server/src/nlm4.c +++ b/xlators/nfs/server/src/nlm4.c @@ -199,12 +199,40 @@ nlm4_prep_nlm4_unlockargs (nlm4_unlockargs *args, struct nfs3_fh *fh, } void +nlm4_prep_shareargs (nlm4_shareargs *args, struct nfs3_fh *fh, + nlm4_lkowner_t *oh, char *cookiebytes) +{ + memset (args, 0, sizeof (*args)); + args->share.fh.n_bytes = (void *)fh; + args->share.oh.n_bytes = (void *)oh; + args->cookie.n_bytes = (void *)cookiebytes; +} + +void +nlm4_prep_freeallargs (nlm4_freeallargs *args, nlm4_lkowner_t *oh) +{ + memset (args, 0, sizeof (*args)); + args->name = (void *)oh; +} + +void nlm_copy_lkowner (gf_lkowner_t *dst, netobj *src) { dst->len = src->n_len; memcpy (dst->data, src->n_bytes, dst->len); } +int +nlm_is_oh_same_lkowner (gf_lkowner_t *a, netobj *b) +{ + if (!a || !b) { + gf_log (GF_NLM, GF_LOG_ERROR, "invalid args"); + return -1; + } + + return (a->len == b->n_len && + !memcmp (a->data, b->n_bytes, a->len)); +} nfsstat3 nlm4_errno_to_nlm4stat (int errnum) @@ -251,6 +279,7 @@ nlm4_call_state_init (struct nfs3_state *s, rpcsvc_request_t *req) cs->req = req; cs->nfsx = s->nfsx; cs->nfs3state = s; + cs->monitor = 1; return cs; } @@ -270,9 +299,11 @@ nlm_monitor (char *caller_name) } } UNLOCK (&nlm_client_list_lk); - if (monitor == -1) { - gf_log (GF_NLM, GF_LOG_ERROR, "%s was not found in the nlmclnt list", caller_name); - } + + if (monitor == -1) + gf_log (GF_NLM, GF_LOG_ERROR, "%s was not found in " + "the nlmclnt list", caller_name); + return monitor; } @@ -401,6 +432,7 @@ nlm_add_nlmclnt (char *caller_name) INIT_LIST_HEAD(&nlmclnt->fdes); INIT_LIST_HEAD(&nlmclnt->nlm_clients); + INIT_LIST_HEAD(&nlmclnt->shares); list_add (&nlmclnt->nlm_clients, &nlm_client_list); nlmclnt->caller_name = gf_strdup (caller_name); @@ -541,23 +573,31 @@ out: } nlm_client_t * -nlm_get_uniq (char *caller_name) +__nlm_get_uniq (char *caller_name) { nlm_client_t *nlmclnt = NULL; - int nlmclnt_found = 0; - LOCK (&nlm_client_list_lk); + if (!caller_name) + return NULL; + list_for_each_entry (nlmclnt, &nlm_client_list, nlm_clients) { - if (!strcmp(caller_name, nlmclnt->caller_name)) { - nlmclnt_found = 1; - break; - } + if (!strcmp(caller_name, nlmclnt->caller_name)) + return nlmclnt; } + + return NULL; +} + +nlm_client_t * +nlm_get_uniq (char *caller_name) +{ + nlm_client_t *nlmclnt = NULL; + + LOCK (&nlm_client_list_lk); + nlmclnt = __nlm_get_uniq (caller_name); UNLOCK (&nlm_client_list_lk); - if (nlmclnt_found) - return nlmclnt; - else - return NULL; + + return nlmclnt; } @@ -1247,11 +1287,11 @@ nlm4svc_lock_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, struct gf_flock *flock, dict_t *xdata) { - nlm4_stats stat = nlm4_denied; - nfs3_call_state_t *cs = NULL; - int transit_cnt = -1; + nlm4_stats stat = nlm4_denied; + int transit_cnt = -1; char *caller_name = NULL; - pthread_t thr; + nfs3_call_state_t *cs = NULL; + pthread_t thr; cs = frame->local; caller_name = cs->args.nlm4_lockargs.alock.caller_name; @@ -1265,7 +1305,7 @@ nlm4svc_lock_cbk (call_frame_t *frame, void *cookie, xlator_t *this, goto err; } else { stat = nlm4_granted; - if (!nlm_monitor (caller_name)) { + if (cs->monitor && !nlm_monitor (caller_name)) { /* FIXME: handle nsm_monitor failure */ pthread_create (&thr, NULL, nsm_monitor, (void*)caller_name); } @@ -1331,8 +1371,8 @@ int nlm4_lock_resume (void *carg) { nlm4_stats stat = nlm4_failed; - int ret = -1; - nfs3_call_state_t *cs = NULL; + int ret = -1; + nfs3_call_state_t *cs = NULL; if (!carg) return ret; @@ -1354,17 +1394,16 @@ nlm4err: return ret; } - int -nlm4svc_lock (rpcsvc_request_t *req) +nlm4svc_lock_common (rpcsvc_request_t *req, int mon) { - xlator_t *vol = NULL; - nlm4_stats stat = nlm4_failed; - struct nfs_state *nfs = NULL; - nfs3_state_t *nfs3 = NULL; - nfs3_call_state_t *cs = NULL; - int ret = RPCSVC_ACTOR_ERROR; - struct nfs3_fh fh = {{0}, }; + int ret = RPCSVC_ACTOR_ERROR; + nlm4_stats stat = nlm4_failed; + struct nfs3_fh fh = {{0}, }; + xlator_t *vol = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + struct nfs_state *nfs = NULL; if (!req) return ret; @@ -1381,7 +1420,9 @@ nlm4svc_lock (rpcsvc_request_t *req) rpcsvc_request_seterr (req, GARBAGE_ARGS); goto rpcerr; } + fh = cs->lockfh; + cs->monitor = mon; nlm4_validate_gluster_fh (&fh, stat, nlm4err); nlm4_map_fh_to_volume (cs->nfs3state, fh, req, vol, stat, nlm4err); @@ -1415,10 +1456,23 @@ rpcerr: if (ret < 0) { nfs3_call_state_wipe (cs); } + return ret; } int +nlm4svc_lock (rpcsvc_request_t *req) +{ + return nlm4svc_lock_common (req, 1); +} + +int +nlm4svc_nm_lock (rpcsvc_request_t *req) +{ + return nlm4svc_lock_common (req, 0); +} + +int nlm4svc_cancel_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, struct gf_flock *flock, dict_t *xdata) @@ -1729,6 +1783,500 @@ rpcerr: return ret; } +int +nlm4_share_reply (nfs3_call_state_t *cs, nlm4_stats stat) +{ + nlm4_shareres res = {{0}, 0, 0}; + + if (!cs) + return -1; + + res.cookie = cs->args.nlm4_shareargs.cookie; + res.stat = stat; + res.sequence = 0; + + nlm4svc_submit_reply (cs->req, (void *)&res, + (nlm4_serializer)xdr_serialize_nlm4_shareres); + return 0; +} + +nlm_share_t * +nlm4_share_new () +{ + nlm_share_t *share = NULL; + + share = GF_CALLOC (1, sizeof (nlm_share_t), + gf_nfs_mt_nlm4_share); + if (!share) + goto out; + + INIT_LIST_HEAD (&share->client_list); + INIT_LIST_HEAD (&share->inode_list); + out: + return share; +} + +int +nlm4_add_share_to_inode (nlm_share_t *share) +{ + int ret = -1; + uint64_t ctx = 0; + struct list_head *head = NULL; + xlator_t *this = NULL; + inode_t *inode = NULL; + + this = THIS; + inode = share->inode; + ret = inode_ctx_get (inode, this, &ctx); + + head = (struct list_head *)ctx; + + if (ret || !head) { + head = GF_CALLOC (1, sizeof (struct list_head), + gf_common_mt_list_head); + if (!head ) { + ret = -1; + goto out; + } + + INIT_LIST_HEAD (head); + ret = inode_ctx_put (inode, this, (uint64_t)head); + if (ret) + goto out; + } + + list_add (&share->inode_list, head); + + out: + if (ret && head) + GF_FREE (head); + + return ret; +} + +int +nlm4_approve_share_reservation (nfs3_call_state_t *cs) +{ + int ret = -1; + uint64_t ctx = 0; + fsh_mode req_mode = 0; + fsh_access req_access = 0; + inode_t *inode = NULL; + nlm_share_t *share = NULL; + struct list_head *head = NULL; + + if (!cs) + goto out; + + inode = cs->resolvedloc.inode; + + ret = inode_ctx_get (inode, THIS, &ctx); + if (ret) { + ret = 0; + goto out; + } + + head = (struct list_head *)ctx; + if (!head || list_empty (head)) + goto out; + + req_mode = cs->args.nlm4_shareargs.share.mode; + req_access = cs->args.nlm4_shareargs.share.access; + + list_for_each_entry (share, head, inode_list) { + ret = (((req_mode & share->access) == 0) && + ((req_access & share->mode) == 0)); + if (!ret) { + ret = -1; + goto out; + } + } + ret = 0; + + out: + return ret; +} + +int +nlm4_create_share_reservation (nfs3_call_state_t *cs) +{ + int ret = -1; + nlm_share_t *share = NULL; + nlm_client_t *client = NULL; + inode_t *inode = NULL; + + LOCK (&nlm_client_list_lk); + + inode = inode_ref (cs->resolvedloc.inode); + if (!inode) { + gf_log (GF_NLM, GF_LOG_ERROR, "inode not found"); + goto out; + } + + client = __nlm_get_uniq (cs->args.nlm4_shareargs.share.caller_name); + if (!client) { + /* DO NOT add client. the client is supposed + to be here, since nlm4svc_share adds it */ + gf_log (GF_NLM, GF_LOG_ERROR, "client not found"); + goto out; + } + + ret = nlm4_approve_share_reservation (cs); + if (ret) + goto out; + + share = nlm4_share_new (); + if (!share) { + ret = -1; + goto out; + } + + share->inode = inode; + share->mode = cs->args.nlm4_shareargs.share.mode; + share->access = cs->args.nlm4_shareargs.share.access; + nlm_copy_lkowner (&share->lkowner, + &cs->args.nlm4_shareargs.share.oh); + + ret = nlm4_add_share_to_inode (share); + if (ret) + goto out; + + list_add (&share->client_list, &client->shares); + + out: + if (ret && inode) { + inode_unref (inode); + if (share) + GF_FREE (share); + } + + UNLOCK (&nlm_client_list_lk); + return ret; +} + +/* + SHARE and UNSHARE calls DO NOT perform STACK_WIND, + the (non-monitored) share reservations are maintained + at *nfs xlator level only*, in memory +*/ +int +nlm4_share_resume (void *call_state) +{ + int ret = -1; + nlm4_stats stat = nlm4_failed; + nfs3_call_state_t *cs = NULL; + + if (!call_state) + return ret; + + cs = (nfs3_call_state_t *)call_state; + nlm4_check_fh_resolve_status (cs, stat, out); + + ret = nlm4_create_share_reservation (cs); + if (!ret) + stat = nlm4_granted; + + out: + nlm4_share_reply (cs, stat); + nfs3_call_state_wipe (cs); + return 0; +} + +int +nlm4svc_share (rpcsvc_request_t *req) +{ + nlm4_stats stat = nlm4_failed; + xlator_t *vol = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + struct nfs_state *nfs = NULL; + struct nfs3_fh fh = {{0}, }; + int ret = RPCSVC_ACTOR_ERROR; + + if (!req) + return ret; + + nlm4_validate_nfs3_state (req, nfs3, stat, rpcerr, ret); + nfs = nfs_state (nfs3->nfsx); + nlm4_handle_call_state_init (nfs->nfs3state, cs, req, + stat, rpcerr); + + nlm4_prep_shareargs (&cs->args.nlm4_shareargs, &cs->lockfh, + &cs->lkowner, cs->cookiebytes); + + if (xdr_to_nlm4_shareargs (req->msg[0], + &cs->args.nlm4_shareargs) <= 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "Error decoding SHARE args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto rpcerr; + } + + fh = cs->lockfh; + nlm4_validate_gluster_fh (&fh, stat, nlm4err); + nlm4_map_fh_to_volume (cs->nfs3state, fh, req, + vol, stat, nlm4err); + + if (nlm_grace_period && !cs->args.nlm4_shareargs.reclaim) { + gf_log (GF_NLM, GF_LOG_DEBUG, "NLM in grace period"); + stat = nlm4_denied_grace_period; + nlm4_share_reply (cs, stat); + nfs3_call_state_wipe (cs); + return 0; + } + + cs->vol = vol; + cs->trans = rpcsvc_request_transport_ref(req); + nlm4_volume_started_check (nfs3, vol, ret, rpcerr); + + ret = nlm_add_nlmclnt (cs->args.nlm4_shareargs.share.caller_name); + + ret = nfs3_fh_resolve_and_resume (cs, &fh, NULL, nlm4_share_resume); + + nlm4err: + if (ret < 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "SHARE call failed"); + nlm4_share_reply (cs, stat); + nfs3_call_state_wipe (cs); + return 0; + } + + rpcerr: + if (ret < 0) + nfs3_call_state_wipe (cs); + + return ret; +} + +int +nlm4_remove_share_reservation (nfs3_call_state_t *cs) +{ + int ret = -1; + uint64_t ctx = 0; + fsh_mode req_mode = 0; + fsh_access req_access = 0; + nlm_share_t *share = NULL; + nlm_share_t *tmp = NULL; + nlm_client_t *client = NULL; + char *caller = NULL; + inode_t *inode = NULL; + xlator_t *this = NULL; + struct list_head *head = NULL; + nlm4_shareargs *args = NULL; + + LOCK (&nlm_client_list_lk); + + args = &cs->args.nlm4_shareargs; + caller = args->share.caller_name; + + client = __nlm_get_uniq (caller); + if (!client) { + gf_log (GF_NLM, GF_LOG_ERROR, + "client not found: %s", caller); + goto out; + } + + inode = cs->resolvedloc.inode; + if (!inode) { + gf_log (GF_NLM, GF_LOG_ERROR, + "inode not found: client: %s", caller); + goto out; + } + + this = THIS; + ret = inode_ctx_get (inode, this, &ctx); + if (ret) { + gf_log (GF_NLM, GF_LOG_ERROR, + "no shares found for inode:" + "gfid: %s; client: %s", + inode->gfid, caller); + goto out; + } + + head = (struct list_head *)ctx; + if (list_empty (head)) { + ret = -1; + goto out; + } + + ret = 0; + req_mode = args->share.mode; + req_access = args->share.access; + + list_for_each_entry_safe (share, tmp, head, inode_list) { + ret = ((req_mode == share->mode) && + (req_access == share->access) && + nlm_is_oh_same_lkowner (&share->lkowner, &args->share.oh)); + if (ret) { + list_del (&share->client_list); + list_del (&share->inode_list); + inode_unref (share->inode); + GF_FREE (share); + break; + } + } + + ret = 0; + out: + UNLOCK (&nlm_client_list_lk); + return ret; + +} + +int +nlm4_unshare_resume (void *call_state) +{ + int ret = -1; + nlm4_stats stat = nlm4_failed; + nfs3_call_state_t *cs = NULL; + + if (!call_state) + return ret; + + cs = (nfs3_call_state_t *)call_state; + + nlm4_check_fh_resolve_status (cs, stat, out); + ret = nlm4_remove_share_reservation (cs); + if (!ret) + stat = nlm4_granted; + + out: + nlm4_share_reply (cs, stat); + nfs3_call_state_wipe (cs); + return 0; +} + +int +nlm4svc_unshare (rpcsvc_request_t *req) +{ + nlm4_stats stat = nlm4_failed; + xlator_t *vol = NULL; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + struct nfs_state *nfs = NULL; + struct nfs3_fh fh = {{0}, }; + int ret = RPCSVC_ACTOR_ERROR; + + if (!req) + return ret; + + nlm4_validate_nfs3_state (req, nfs3, stat, rpcerr, ret); + nfs = nfs_state (nfs3->nfsx); + nlm4_handle_call_state_init (nfs->nfs3state, cs, req, + stat, rpcerr); + + nlm4_prep_shareargs (&cs->args.nlm4_shareargs, &cs->lockfh, + &cs->lkowner, cs->cookiebytes); + + if (xdr_to_nlm4_shareargs (req->msg[0], + &cs->args.nlm4_shareargs) <= 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "Error decoding UNSHARE args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto rpcerr; + } + + fh = cs->lockfh; + nlm4_validate_gluster_fh (&fh, stat, nlm4err); + nlm4_map_fh_to_volume (cs->nfs3state, fh, req, + vol, stat, nlm4err); + + if (nlm_grace_period && !cs->args.nlm4_shareargs.reclaim) { + gf_log (GF_NLM, GF_LOG_DEBUG, "NLM in grace period"); + stat = nlm4_denied_grace_period; + nlm4_share_reply (cs, stat); + nfs3_call_state_wipe (cs); + return 0; + } + + cs->vol = vol; + cs->trans = rpcsvc_request_transport_ref(req); + nlm4_volume_started_check (nfs3, vol, ret, rpcerr); + + ret = nfs3_fh_resolve_and_resume (cs, &fh, NULL, + nlm4_unshare_resume); + + nlm4err: + if (ret < 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "UNSHARE call failed"); + nlm4_share_reply (cs, stat); + ret = 0; + return 0; + } + + rpcerr: + if (ret < 0) + nfs3_call_state_wipe (cs); + + return ret; +} + +int +nlm4_free_all_shares (char *caller_name) +{ + nlm_share_t *share = NULL; + nlm_share_t *tmp = NULL; + nlm_client_t *client = NULL; + + LOCK (&nlm_client_list_lk); + + client = __nlm_get_uniq (caller_name); + if (!client) { + gf_log (GF_NLM, GF_LOG_DEBUG, + "client not found: %s", caller_name); + goto out; + } + + list_for_each_entry_safe (share, tmp, &client->shares, client_list) { + list_del (&share->inode_list); + list_del (&share->client_list); + inode_unref (share->inode); + GF_FREE (share); + } + out: + UNLOCK (&nlm_client_list_lk); + return 0; +} + +int +nlm4svc_free_all (rpcsvc_request_t *req) +{ + int ret = RPCSVC_ACTOR_ERROR; + nlm4_stats stat = nlm4_failed; + nfs3_state_t *nfs3 = NULL; + nfs3_call_state_t *cs = NULL; + struct nfs_state *nfs = NULL; + + nlm4_validate_nfs3_state (req, nfs3, stat, err, ret); + nfs = nfs_state (nfs3->nfsx); + nlm4_handle_call_state_init (nfs->nfs3state, cs, + req, stat, err); + + nlm4_prep_freeallargs (&cs->args.nlm4_freeallargs, + &cs->lkowner); + + if (xdr_to_nlm4_freeallargs (req->msg[0], + &cs->args.nlm4_freeallargs) <= 0) { + gf_log (GF_NLM, GF_LOG_ERROR, "Error decoding FREE_ALL args"); + rpcsvc_request_seterr (req, GARBAGE_ARGS); + goto err; + } + + ret = nlm4_free_all_shares (cs->args.nlm4_freeallargs.name); + if (ret) + goto err; + + ret = nlm_cleanup_fds (cs->args.nlm4_freeallargs.name); + if (ret) + goto err; + + err: + nfs3_call_state_wipe (cs); + if (ret) + gf_log (GF_NLM, GF_LOG_DEBUG, + "error in free all; stat: %d", stat); + return ret; + +} + void nlm4svc_sm_notify (struct nlm_sm_status *status) { @@ -1757,17 +2305,17 @@ rpcsvc_actor_t nlm4svc_actors[NLM4_PROC_COUNT] = { {"LOCK", NLM4_LOCK_RES, NULL, NULL, NULL}, {"CANCEL", NLM4_CANCEL_RES, NULL, NULL, NULL}, {"UNLOCK", NLM4_UNLOCK_RES, NULL, NULL, NULL}, - /* 15 ; 17,18,19 are dummy actors */ + /* 15 ; procedures 17,18,19 are not defined by nlm */ {"GRANTED", NLM4_GRANTED_RES, NULL, NULL, NULL}, {"SM_NOTIFY", NLM4_SM_NOTIFY, NULL, NULL, NULL}, {"SEVENTEEN", NLM4_SEVENTEEN, NULL, NULL, NULL}, {"EIGHTEEN", NLM4_EIGHTEEN, NULL, NULL, NULL}, {"NINETEEN", NLM4_NINETEEN, NULL, NULL, NULL}, /* 20 */ - {"SHARE", NLM4_SHARE, NULL, NULL, NULL}, - {"UNSHARE", NLM4_UNSHARE, NULL, NULL, NULL}, - {"NM_LOCK", NLM4_NM_LOCK, NULL, NULL, NULL}, - {"FREE_ALL", NLM4_FREE_ALL, nlm4svc_null, NULL, NULL}, + {"SHARE", NLM4_SHARE, nlm4svc_share, NULL, NULL}, + {"UNSHARE", NLM4_UNSHARE, nlm4svc_unshare, NULL, NULL}, + {"NM_LOCK", NLM4_NM_LOCK, nlm4svc_nm_lock, NULL, NULL}, + {"FREE_ALL", NLM4_FREE_ALL, nlm4svc_free_all, NULL, NULL}, }; rpcsvc_program_t nlm4prog = { diff --git a/xlators/nfs/server/src/nlm4.h b/xlators/nfs/server/src/nlm4.h index db5874387f4..bcc7ae57343 100644 --- a/xlators/nfs/server/src/nlm4.h +++ b/xlators/nfs/server/src/nlm4.h @@ -60,11 +60,21 @@ typedef struct nlm_client { pid_t uniq; struct list_head nlm_clients; struct list_head fdes; + struct list_head shares; struct rpc_clnt *rpc_clnt; char *caller_name; int nsm_monitor; } nlm_client_t; +typedef struct nlm_share { + struct list_head client_list; + struct list_head inode_list; + gf_lkowner_t lkowner; + inode_t *inode; + fsh_mode mode; + fsh_access access; +} nlm_share_t; + typedef struct nlm_fde { struct list_head fde_list; fd_t *fd; |