#define NLMDBG_FACILITY NLMDBG_CLIENT
+/*
+ * Wrapper structures combine xdrgen types with legacy nlm_lock.
+ * The xdrgen field must be first so the structure can be cast
+ * to its XDR type for the RPC dispatch layer.
+ */
+struct nlm4_testargs_wrapper {
+ struct nlm4_testargs xdrgen;
+ struct nlm_lock lock;
+};
+
+static_assert(offsetof(struct nlm4_testargs_wrapper, xdrgen) == 0);
+
+struct nlm4_testres_wrapper {
+ struct nlm4_testres xdrgen;
+ struct nlm_lock lock;
+};
+
+static_assert(offsetof(struct nlm4_testres_wrapper, xdrgen) == 0);
+
+static struct nlm_host *
+nlm4svc_lookup_host(struct svc_rqst *rqstp, string caller, bool monitored)
+{
+ struct nlm_host *host;
+
+ if (!nlmsvc_ops)
+ return NULL;
+ host = nlmsvc_lookup_host(rqstp, caller.data, caller.len);
+ if (!host)
+ return NULL;
+ if (monitored && nsm_monitor(host) < 0) {
+ nlmsvc_release_host(host);
+ return NULL;
+ }
+ return host;
+}
+
+static __be32
+nlm4svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host,
+ struct nlm_lock *lock, struct nlm_file **filp,
+ struct nlm4_lock *xdr_lock, unsigned char type)
+{
+ struct file_lock *fl = &lock->fl;
+ struct nlm_file *file = NULL;
+ __be32 error;
+
+ if (xdr_lock->fh.len > NFS_MAXFHSIZE)
+ return nlm_lck_denied_nolocks;
+ lock->fh.size = xdr_lock->fh.len;
+ memcpy(lock->fh.data, xdr_lock->fh.data, xdr_lock->fh.len);
+
+ lock->oh.len = xdr_lock->oh.len;
+ lock->oh.data = xdr_lock->oh.data;
+
+ lock->svid = xdr_lock->svid;
+ lock->lock_start = xdr_lock->l_offset;
+ lock->lock_len = xdr_lock->l_len;
+
+ if (lock->lock_start > OFFSET_MAX ||
+ (lock->lock_len && ((lock->lock_len - 1) > (OFFSET_MAX - lock->lock_start))))
+ return nlm4_fbig;
+
+ locks_init_lock(fl);
+ fl->c.flc_type = type;
+ lockd_set_file_lock_range4(fl, lock->lock_start, lock->lock_len);
+
+ error = nlm_lookup_file(rqstp, &file, lock);
+ switch (error) {
+ case nlm_granted:
+ break;
+ case nlm__int__stale_fh:
+ return nlm4_stale_fh;
+ case nlm__int__failed:
+ return nlm4_failed;
+ default:
+ return error;
+ }
+ *filp = file;
+
+ fl->c.flc_flags = FL_POSIX;
+ fl->c.flc_file = file->f_file[lock_to_openmode(fl)];
+ fl->c.flc_pid = current->tgid;
+ fl->fl_lmops = &nlmsvc_lock_operations;
+ nlmsvc_locks_init_private(fl, host, (pid_t)lock->svid);
+ if (!fl->c.flc_owner)
+ return nlm_lck_denied_nolocks;
+
+ return nlm_granted;
+}
+
/*
* Obtain client and file from arguments
*/
return rc;
}
-static __be32
-nlm4svc_proc_test(struct svc_rqst *rqstp)
+/**
+ * nlm4svc_proc_test - TEST: Check for conflicting lock
+ * @rqstp: RPC transaction context
+ *
+ * Returns:
+ * %rpc_success: RPC executed successfully.
+ * %rpc_drop_reply: Do not send an RPC reply.
+ *
+ * RPC synopsis:
+ * nlm4_testres NLMPROC4_TEST(nlm4_testargs) = 1;
+ *
+ * Permissible procedure status codes:
+ * %NLM4_GRANTED: The server would be able to grant the
+ * requested lock.
+ * %NLM4_DENIED: The requested lock conflicted with existing
+ * lock reservations for the file.
+ * %NLM4_DENIED_NOLOCKS: The server could not allocate the resources
+ * needed to process the request.
+ * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
+ * re-establishing existing locks, and is not
+ * yet ready to accept normal service requests.
+ *
+ * The Linux NLM server implementation also returns:
+ * %NLM4_STALE_FH: The request specified an invalid file handle.
+ * %NLM4_FBIG: The request specified a length or offset
+ * that exceeds the range supported by the
+ * server.
+ * %NLM4_FAILED: The request failed for an unspecified reason.
+ */
+static __be32 nlm4svc_proc_test(struct svc_rqst *rqstp)
{
- return __nlm4svc_proc_test(rqstp, rqstp->rq_resp);
+ struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
+ unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
+ struct nlm4_testres_wrapper *resp = rqstp->rq_resp;
+ struct nlm_file *file = NULL;
+ struct nlm_host *host;
+
+ resp->xdrgen.cookie = argp->xdrgen.cookie;
+
+ resp->xdrgen.stat.stat = nlm_lck_denied_nolocks;
+ host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
+ if (!host)
+ goto out;
+
+ resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock,
+ &file, &argp->xdrgen.alock,
+ type);
+ if (resp->xdrgen.stat.stat)
+ goto out;
+
+ resp->xdrgen.stat.stat = nlmsvc_testlock(rqstp, file, host,
+ &argp->lock, &resp->lock);
+ nlmsvc_release_lockowner(&argp->lock);
+
+ if (resp->xdrgen.stat.stat == nlm_lck_denied) {
+ struct nlm_lock *conf = &resp->lock;
+ struct nlm4_holder *holder = &resp->xdrgen.stat.u.holder;
+
+ holder->exclusive = (conf->fl.c.flc_type != F_RDLCK);
+ holder->svid = conf->svid;
+ holder->oh.len = conf->oh.len;
+ holder->oh.data = conf->oh.data;
+ holder->l_offset = conf->fl.fl_start;
+ if (conf->fl.fl_end == OFFSET_MAX)
+ holder->l_len = 0;
+ else
+ holder->l_len = conf->fl.fl_end - conf->fl.fl_start + 1;
+ }
+
+out:
+ if (file)
+ nlm_release_file(file);
+ nlmsvc_release_host(host);
+ return resp->xdrgen.stat.stat == nlm__int__drop_reply ?
+ rpc_drop_reply : rpc_success;
}
static __be32
.pc_xdrressize = XDR_void,
.pc_name = "NULL",
},
- [NLMPROC_TEST] = {
- .pc_func = nlm4svc_proc_test,
- .pc_decode = nlm4svc_decode_testargs,
- .pc_encode = nlm4svc_encode_testres,
- .pc_argsize = sizeof(struct nlm_args),
- .pc_argzero = sizeof(struct nlm_args),
- .pc_ressize = sizeof(struct nlm_res),
- .pc_xdrressize = Ck+St+2+No+Rg,
- .pc_name = "TEST",
+ [NLMPROC4_TEST] = {
+ .pc_func = nlm4svc_proc_test,
+ .pc_decode = nlm4_svc_decode_nlm4_testargs,
+ .pc_encode = nlm4_svc_encode_nlm4_testres,
+ .pc_argsize = sizeof(struct nlm4_testargs_wrapper),
+ .pc_argzero = 0,
+ .pc_ressize = sizeof(struct nlm4_testres_wrapper),
+ .pc_xdrressize = NLM4_nlm4_testres_sz,
+ .pc_name = "TEST",
},
[NLMPROC_LOCK] = {
.pc_func = nlm4svc_proc_lock,
* Storage requirements for XDR arguments and results
*/
union nlm4svc_xdrstore {
+ struct nlm4_testargs_wrapper testargs;
+ struct nlm4_testres_wrapper testres;
struct nlm_args args;
struct nlm_res res;
struct nlm_reboot reboot;