| // SPDX-License-Identifier: GPL-2.0 | |
| /* | |
| * linux/fs/lockd/svcproc.c | |
| * | |
| * Lockd server procedures. We don't implement the NLM_*_RES | |
| * procedures because we don't use the async procedures. | |
| * | |
| * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> | |
| */ | |
| #include <linux/types.h> | |
| #include <linux/time.h> | |
| #include <linux/sunrpc/svc_xprt.h> | |
| #include "lockd.h" | |
| /* | |
| * xdr.h defines SM_PRIV_SIZE as a macro. nlm3xdr_gen.h defines | |
| * it as an enum constant. Undefine the macro before including | |
| * the generated header. | |
| */ | |
| #undef SM_PRIV_SIZE | |
| #include "share.h" | |
| #include "nlm3xdr_gen.h" | |
| /* | |
| * Size of an NFSv2 file handle, in bytes, which is 32. | |
| * Defined locally to avoid including uapi/linux/nfs2.h. | |
| */ | |
| #define NLM3_FHSIZE 32 | |
| /* | |
| * Wrapper structures combine xdrgen types with legacy lockd_lock. | |
| * The xdrgen field must be first so the structure can be cast | |
| * to its XDR type for the RPC dispatch layer. | |
| */ | |
| struct nlm_testargs_wrapper { | |
| struct nlm_testargs xdrgen; | |
| struct lockd_lock lock; | |
| }; | |
| static_assert(offsetof(struct nlm_testargs_wrapper, xdrgen) == 0); | |
| struct nlm_testres_wrapper { | |
| struct nlm_testres xdrgen; | |
| struct lockd_lock lock; | |
| }; | |
| static_assert(offsetof(struct nlm_testres_wrapper, xdrgen) == 0); | |
| struct nlm_lockargs_wrapper { | |
| struct nlm_lockargs xdrgen; | |
| struct lockd_cookie cookie; | |
| struct lockd_lock lock; | |
| }; | |
| static_assert(offsetof(struct nlm_lockargs_wrapper, xdrgen) == 0); | |
| struct nlm_res_wrapper { | |
| struct nlm_res xdrgen; | |
| struct lockd_cookie cookie; | |
| }; | |
| static_assert(offsetof(struct nlm_res_wrapper, xdrgen) == 0); | |
| struct nlm_cancargs_wrapper { | |
| struct nlm_cancargs xdrgen; | |
| struct lockd_lock lock; | |
| }; | |
| static_assert(offsetof(struct nlm_cancargs_wrapper, xdrgen) == 0); | |
| struct nlm_unlockargs_wrapper { | |
| struct nlm_unlockargs xdrgen; | |
| struct lockd_lock lock; | |
| }; | |
| static_assert(offsetof(struct nlm_unlockargs_wrapper, xdrgen) == 0); | |
| struct nlm_notifyargs_wrapper { | |
| struct nlm_notifyargs xdrgen; | |
| struct lockd_reboot reboot; | |
| }; | |
| static_assert(offsetof(struct nlm_notifyargs_wrapper, xdrgen) == 0); | |
| struct nlm_shareargs_wrapper { | |
| struct nlm_shareargs xdrgen; | |
| struct lockd_lock lock; | |
| }; | |
| static_assert(offsetof(struct nlm_shareargs_wrapper, xdrgen) == 0); | |
| struct nlm_shareres_wrapper { | |
| struct nlm_shareres xdrgen; | |
| }; | |
| static_assert(offsetof(struct nlm_shareres_wrapper, xdrgen) == 0); | |
| struct nlm_notify_wrapper { | |
| struct nlm_notify xdrgen; | |
| }; | |
| static_assert(offsetof(struct nlm_notify_wrapper, xdrgen) == 0); | |
| static __be32 | |
| nlm_netobj_to_cookie(struct lockd_cookie *cookie, netobj *object) | |
| { | |
| if (object->len > NLM_MAXCOOKIELEN) | |
| return nlm_lck_denied_nolocks; | |
| cookie->len = object->len; | |
| memcpy(cookie->data, object->data, object->len); | |
| return nlm_granted; | |
| } | |
| static __be32 | |
| nlm_lock_to_lockd_lock(struct lockd_lock *lock, struct nlm_lock *alock) | |
| { | |
| if (alock->fh.len != NLM3_FHSIZE) | |
| return nlm_lck_denied; | |
| lock->fh.size = alock->fh.len; | |
| memcpy(lock->fh.data, alock->fh.data, alock->fh.len); | |
| lock->oh.len = alock->oh.len; | |
| lock->oh.data = alock->oh.data; | |
| lock->svid = alock->uppid; | |
| lockd_set_file_lock_range3(&lock->fl, alock->l_offset, alock->l_len); | |
| return nlm_granted; | |
| } | |
| static struct nlm_host * | |
| nlm3svc_lookup_host(struct svc_rqst *rqstp, string caller, bool monitored) | |
| { | |
| struct nlm_host *host; | |
| if (!rcu_access_pointer(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 | |
| nlm3svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host, | |
| struct lockd_lock *lock, struct nlm_file **filp, | |
| struct nlm_lock *xdr_lock, unsigned char type) | |
| { | |
| bool is_test = (rqstp->rq_proc == NLMPROC_TEST || | |
| rqstp->rq_proc == NLMPROC_TEST_MSG); | |
| struct file_lock *fl = &lock->fl; | |
| struct nlm_file *file = NULL; | |
| __be32 error; | |
| int mode; | |
| if (xdr_lock->fh.len != NLM3_FHSIZE) | |
| 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->uppid; | |
| lock->lock_start = xdr_lock->l_offset; | |
| lock->lock_len = xdr_lock->l_len; | |
| locks_init_lock(fl); | |
| fl->c.flc_type = type; | |
| lockd_set_file_lock_range3(fl, lock->lock_start, lock->lock_len); | |
| mode = lock_to_openmode(fl); | |
| if (is_test) | |
| mode = O_RDWR; | |
| error = nlm_lookup_file(rqstp, &file, lock, mode); | |
| switch (error) { | |
| case nlm_granted: | |
| break; | |
| case nlm__int__stale_fh: | |
| case nlm__int__failed: | |
| return nlm_lck_denied_nolocks; | |
| default: | |
| return error; | |
| } | |
| *filp = file; | |
| fl->c.flc_flags = FL_POSIX; | |
| if (is_test) | |
| fl->c.flc_file = nlmsvc_file_file(file); | |
| else | |
| fl->c.flc_file = file->f_file[mode]; | |
| 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; | |
| } | |
| static inline __be32 cast_status(__be32 status) | |
| { | |
| switch (status) { | |
| case nlm_granted: | |
| case nlm_lck_denied: | |
| case nlm_lck_denied_nolocks: | |
| case nlm_lck_blocked: | |
| case nlm_lck_denied_grace_period: | |
| case nlm__int__drop_reply: | |
| break; | |
| case nlm__int__deadlock: | |
| status = nlm_lck_denied; | |
| break; | |
| default: | |
| pr_warn_once("lockd: unhandled internal status %u\n", | |
| be32_to_cpu(status)); | |
| status = nlm_lck_denied_nolocks; | |
| break; | |
| } | |
| return status; | |
| } | |
| /** | |
| * nlmsvc_proc_null - NULL: Test for presence of service | |
| * @rqstp: RPC transaction context | |
| * | |
| * Return: | |
| * %rpc_success: RPC executed successfully | |
| * | |
| * RPC synopsis: | |
| * void NLM_NULL(void) = 0; | |
| */ | |
| static __be32 nlmsvc_proc_null(struct svc_rqst *rqstp) | |
| { | |
| return rpc_success; | |
| } | |
| /** | |
| * nlmsvc_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: | |
| * nlm_testres NLM_TEST(nlm_testargs) = 1; | |
| * | |
| * Permissible procedure status codes: | |
| * %LCK_GRANTED: The server would be able to grant the | |
| * requested lock. | |
| * %LCK_DENIED: The requested lock conflicted with existing | |
| * lock reservations for the file. | |
| * %LCK_DENIED_NOLOCKS: The server could not allocate the resources | |
| * needed to process the request. | |
| * %LCK_DENIED_GRACE_PERIOD: The server has recently restarted and is | |
| * re-establishing existing locks, and is not | |
| * yet ready to accept normal service requests. | |
| */ | |
| static __be32 nlmsvc_proc_test(struct svc_rqst *rqstp) | |
| { | |
| struct nlm_testargs_wrapper *argp = rqstp->rq_argp; | |
| unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK; | |
| struct nlm_testres_wrapper *resp = rqstp->rq_resp; | |
| struct nlm_file *file = NULL; | |
| struct nlm_host *host; | |
| resp->xdrgen.cookie = argp->xdrgen.cookie; | |
| resp->xdrgen.test_stat.stat = nlm_lck_denied_nolocks; | |
| host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); | |
| if (!host) | |
| goto out; | |
| resp->xdrgen.test_stat.stat = | |
| nlm3svc_lookup_file(rqstp, host, &argp->lock, &file, | |
| &argp->xdrgen.alock, type); | |
| if (resp->xdrgen.test_stat.stat) | |
| goto out; | |
| resp->xdrgen.test_stat.stat = | |
| cast_status(nlmsvc_testlock(rqstp, file, host, &argp->lock, | |
| &resp->lock)); | |
| nlmsvc_release_lockowner(&argp->lock); | |
| if (resp->xdrgen.test_stat.stat == nlm_lck_denied) { | |
| struct lockd_lock *conf = &resp->lock; | |
| struct nlm_holder *holder = &resp->xdrgen.test_stat.u.holder; | |
| holder->exclusive = (conf->fl.c.flc_type != F_RDLCK); | |
| holder->uppid = conf->svid; | |
| holder->oh.len = conf->oh.len; | |
| holder->oh.data = conf->oh.data; | |
| holder->l_offset = min_t(loff_t, conf->fl.fl_start, | |
| NLM_OFFSET_MAX); | |
| if (conf->fl.fl_end == OFFSET_MAX) | |
| holder->l_len = 0; | |
| else | |
| holder->l_len = min_t(loff_t, | |
| conf->fl.fl_end - | |
| conf->fl.fl_start + 1, | |
| NLM_OFFSET_MAX); | |
| } | |
| out: | |
| if (file) | |
| nlm_release_file(file); | |
| nlmsvc_release_host(host); | |
| return resp->xdrgen.test_stat.stat == nlm__int__drop_reply ? | |
| rpc_drop_reply : rpc_success; | |
| } | |
| static __be32 | |
| nlmsvc_do_lock(struct svc_rqst *rqstp, bool monitored) | |
| { | |
| struct nlm_lockargs_wrapper *argp = rqstp->rq_argp; | |
| unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK; | |
| struct nlm_res_wrapper *resp = rqstp->rq_resp; | |
| struct nlm_file *file = NULL; | |
| struct nlm_host *host = NULL; | |
| resp->xdrgen.cookie = argp->xdrgen.cookie; | |
| resp->xdrgen.stat.stat = nlm_netobj_to_cookie(&argp->cookie, | |
| &argp->xdrgen.cookie); | |
| if (resp->xdrgen.stat.stat) | |
| goto out; | |
| resp->xdrgen.stat.stat = nlm_lck_denied_nolocks; | |
| host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, | |
| monitored); | |
| if (!host) | |
| goto out; | |
| resp->xdrgen.stat.stat = nlm3svc_lookup_file(rqstp, host, &argp->lock, | |
| &file, &argp->xdrgen.alock, | |
| type); | |
| if (resp->xdrgen.stat.stat) | |
| goto out; | |
| resp->xdrgen.stat.stat = cast_status(nlmsvc_lock(rqstp, file, host, | |
| &argp->lock, | |
| argp->xdrgen.block, | |
| &argp->cookie, | |
| argp->xdrgen.reclaim)); | |
| nlmsvc_release_lockowner(&argp->lock); | |
| 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; | |
| } | |
| /** | |
| * nlmsvc_proc_lock - LOCK: Establish a monitored lock | |
| * @rqstp: RPC transaction context | |
| * | |
| * Returns: | |
| * %rpc_success: RPC executed successfully. | |
| * %rpc_drop_reply: Do not send an RPC reply. | |
| * | |
| * RPC synopsis: | |
| * nlm_res NLM_LOCK(nlm_lockargs) = 2; | |
| * | |
| * Permissible procedure status codes: | |
| * %LCK_GRANTED: The requested lock was granted. | |
| * %LCK_DENIED: The requested lock conflicted with existing | |
| * lock reservations for the file. | |
| * %LCK_DENIED_NOLOCKS: The server could not allocate the resources | |
| * needed to process the request. | |
| * %LCK_BLOCKED: The blocking request cannot be granted | |
| * immediately. The server will send an | |
| * NLM_GRANTED callback to the client when | |
| * the lock can be granted. | |
| * %LCK_DENIED_GRACE_PERIOD: The server has recently restarted and is | |
| * re-establishing existing locks, and is not | |
| * yet ready to accept normal service requests. | |
| */ | |
| static __be32 | |
| nlmsvc_proc_lock(struct svc_rqst *rqstp) | |
| { | |
| return nlmsvc_do_lock(rqstp, true); | |
| } | |
| /** | |
| * nlmsvc_proc_cancel - CANCEL: Cancel an outstanding blocked lock request | |
| * @rqstp: RPC transaction context | |
| * | |
| * Returns: | |
| * %rpc_success: RPC executed successfully. | |
| * %rpc_drop_reply: Do not send an RPC reply. | |
| * | |
| * RPC synopsis: | |
| * nlm_res NLM_CANCEL(nlm_cancargs) = 3; | |
| * | |
| * Permissible procedure status codes: | |
| * %LCK_GRANTED: The requested lock was canceled. | |
| * %LCK_DENIED: There was no lock to cancel. | |
| * %LCK_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: | |
| * %LCK_DENIED_NOLOCKS: A needed resource could not be allocated. | |
| */ | |
| static __be32 | |
| nlmsvc_proc_cancel(struct svc_rqst *rqstp) | |
| { | |
| struct nlm_cancargs_wrapper *argp = rqstp->rq_argp; | |
| unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK; | |
| struct nlm_res_wrapper *resp = rqstp->rq_resp; | |
| struct net *net = SVC_NET(rqstp); | |
| struct nlm_host *host = NULL; | |
| struct nlm_file *file = NULL; | |
| resp->xdrgen.cookie = argp->xdrgen.cookie; | |
| resp->xdrgen.stat.stat = nlm_lck_denied_grace_period; | |
| if (locks_in_grace(net)) | |
| goto out; | |
| resp->xdrgen.stat.stat = nlm_lck_denied_nolocks; | |
| host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); | |
| if (!host) | |
| goto out; | |
| resp->xdrgen.stat.stat = nlm3svc_lookup_file(rqstp, host, &argp->lock, | |
| &file, &argp->xdrgen.alock, | |
| type); | |
| if (resp->xdrgen.stat.stat) | |
| goto out; | |
| resp->xdrgen.stat.stat = nlmsvc_cancel_blocked(net, file, &argp->lock); | |
| nlmsvc_release_lockowner(&argp->lock); | |
| 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; | |
| } | |
| /** | |
| * nlmsvc_proc_unlock - UNLOCK: Remove a lock | |
| * @rqstp: RPC transaction context | |
| * | |
| * Returns: | |
| * %rpc_success: RPC executed successfully. | |
| * %rpc_drop_reply: Do not send an RPC reply. | |
| * | |
| * RPC synopsis: | |
| * nlm_res NLM_UNLOCK(nlm_unlockargs) = 4; | |
| * | |
| * Permissible procedure status codes: | |
| * %LCK_GRANTED: The requested lock was released. | |
| * %LCK_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: | |
| * %LCK_DENIED_NOLOCKS: A needed resource could not be allocated. | |
| */ | |
| static __be32 | |
| nlmsvc_proc_unlock(struct svc_rqst *rqstp) | |
| { | |
| struct nlm_unlockargs_wrapper *argp = rqstp->rq_argp; | |
| struct nlm_res_wrapper *resp = rqstp->rq_resp; | |
| struct net *net = SVC_NET(rqstp); | |
| struct nlm_host *host = NULL; | |
| struct nlm_file *file = NULL; | |
| resp->xdrgen.cookie = argp->xdrgen.cookie; | |
| resp->xdrgen.stat.stat = nlm_lck_denied_grace_period; | |
| if (locks_in_grace(net)) | |
| goto out; | |
| resp->xdrgen.stat.stat = nlm_lck_denied_nolocks; | |
| host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); | |
| if (!host) | |
| goto out; | |
| resp->xdrgen.stat.stat = nlm3svc_lookup_file(rqstp, host, &argp->lock, | |
| &file, &argp->xdrgen.alock, | |
| F_UNLCK); | |
| if (resp->xdrgen.stat.stat) | |
| goto out; | |
| resp->xdrgen.stat.stat = nlmsvc_unlock(net, file, &argp->lock); | |
| nlmsvc_release_lockowner(&argp->lock); | |
| 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; | |
| } | |
| /** | |
| * nlmsvc_proc_granted - GRANTED: Blocked lock has been granted | |
| * @rqstp: RPC transaction context | |
| * | |
| * Returns: | |
| * %rpc_success: RPC executed successfully. | |
| * | |
| * RPC synopsis: | |
| * nlm_res NLM_GRANTED(nlm_testargs) = 5; | |
| * | |
| * Permissible procedure status codes: | |
| * %LCK_GRANTED: The granted lock was accepted. | |
| * %LCK_DENIED: The procedure failed, possibly due to | |
| * internal resource constraints. | |
| * %LCK_DENIED_GRACE_PERIOD: The client host recently restarted and | |
| * its NLM is re-establishing existing locks, | |
| * so it is not yet ready to accept callbacks. | |
| */ | |
| static __be32 | |
| nlmsvc_proc_granted(struct svc_rqst *rqstp) | |
| { | |
| struct nlm_testargs_wrapper *argp = rqstp->rq_argp; | |
| struct nlm_res_wrapper *resp = rqstp->rq_resp; | |
| resp->xdrgen.cookie = argp->xdrgen.cookie; | |
| resp->xdrgen.stat.stat = nlm_lock_to_lockd_lock(&argp->lock, | |
| &argp->xdrgen.alock); | |
| if (resp->xdrgen.stat.stat) | |
| goto out; | |
| resp->xdrgen.stat.stat = nlmclnt_grant(svc_addr(rqstp), &argp->lock); | |
| out: | |
| return rpc_success; | |
| } | |
| /* | |
| * This is the generic lockd callback for async RPC calls | |
| */ | |
| static void nlmsvc_callback_exit(struct rpc_task *task, void *data) | |
| { | |
| } | |
| void nlmsvc_release_call(struct nlm_rqst *call) | |
| { | |
| if (!refcount_dec_and_test(&call->a_count)) | |
| return; | |
| nlmsvc_release_host(call->a_host); | |
| kfree(call); | |
| } | |
| static void nlmsvc_callback_release(void *data) | |
| { | |
| nlmsvc_release_call(data); | |
| } | |
| static const struct rpc_call_ops nlmsvc_callback_ops = { | |
| .rpc_call_done = nlmsvc_callback_exit, | |
| .rpc_release = nlmsvc_callback_release, | |
| }; | |
| /* | |
| * `Async' versions of the above service routines. They aren't really, | |
| * because we send the callback before the reply proper. I hope this | |
| * doesn't break any clients. | |
| */ | |
| static __be32 | |
| nlmsvc_callback(struct svc_rqst *rqstp, struct nlm_host *host, u32 proc, | |
| __be32 (*func)(struct svc_rqst *, struct lockd_res *)) | |
| { | |
| struct nlm_rqst *call; | |
| __be32 stat; | |
| call = nlm_alloc_call(host); | |
| nlmsvc_release_host(host); | |
| if (call == NULL) | |
| return rpc_system_err; | |
| stat = func(rqstp, &call->a_res); | |
| if (stat != 0) { | |
| nlmsvc_release_call(call); | |
| return stat; | |
| } | |
| call->a_flags = RPC_TASK_ASYNC; | |
| if (nlm_async_reply(call, proc, &nlmsvc_callback_ops) < 0) | |
| return rpc_system_err; | |
| return rpc_success; | |
| } | |
| static __be32 | |
| __nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct lockd_res *resp) | |
| { | |
| struct nlm_testargs_wrapper *argp = rqstp->rq_argp; | |
| unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK; | |
| struct nlm_lockowner *owner; | |
| struct nlm_file *file = NULL; | |
| struct nlm_host *host = NULL; | |
| resp->status = nlm_lck_denied_nolocks; | |
| if (nlm_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie)) | |
| goto out; | |
| host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); | |
| if (!host) | |
| goto out; | |
| resp->status = nlm3svc_lookup_file(rqstp, host, &argp->lock, | |
| &file, &argp->xdrgen.alock, type); | |
| if (resp->status) | |
| goto out; | |
| owner = argp->lock.fl.c.flc_owner; | |
| resp->status = cast_status(nlmsvc_testlock(rqstp, file, host, | |
| &argp->lock, &resp->lock)); | |
| nlmsvc_put_lockowner(owner); | |
| out: | |
| if (file) | |
| nlm_release_file(file); | |
| nlmsvc_release_host(host); | |
| return resp->status == nlm__int__drop_reply ? rpc_drop_reply : rpc_success; | |
| } | |
| /** | |
| * nlmsvc_proc_test_msg - TEST_MSG: Check for conflicting lock | |
| * @rqstp: RPC transaction context | |
| * | |
| * Returns: | |
| * %rpc_success: RPC executed successfully. | |
| * %rpc_drop_reply: Do not send an RPC reply. | |
| * %rpc_garbage_args: The request arguments are malformed. | |
| * %rpc_system_err: RPC execution failed. | |
| * | |
| * RPC synopsis: | |
| * void NLMPROC_TEST_MSG(nlm_testargs) = 6; | |
| * | |
| * The response to this request is delivered via the TEST_RES procedure. | |
| */ | |
| static __be32 nlmsvc_proc_test_msg(struct svc_rqst *rqstp) | |
| { | |
| struct nlm_testargs_wrapper *argp = rqstp->rq_argp; | |
| struct nlm_host *host; | |
| if (argp->xdrgen.cookie.len > NLM_MAXCOOKIELEN) | |
| return rpc_garbage_args; | |
| host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); | |
| if (!host) | |
| return rpc_system_err; | |
| return nlmsvc_callback(rqstp, host, NLMPROC_TEST_RES, | |
| __nlmsvc_proc_test_msg); | |
| } | |
| static __be32 | |
| __nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct lockd_res *resp) | |
| { | |
| struct nlm_lockargs_wrapper *argp = rqstp->rq_argp; | |
| unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK; | |
| struct nlm_file *file = NULL; | |
| struct nlm_host *host = NULL; | |
| resp->status = nlm_lck_denied_nolocks; | |
| if (nlm_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie)) | |
| goto out; | |
| host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, true); | |
| if (!host) | |
| goto out; | |
| resp->status = nlm3svc_lookup_file(rqstp, host, &argp->lock, | |
| &file, &argp->xdrgen.alock, type); | |
| if (resp->status) | |
| goto out; | |
| resp->status = cast_status(nlmsvc_lock(rqstp, file, host, &argp->lock, | |
| argp->xdrgen.block, &resp->cookie, | |
| argp->xdrgen.reclaim)); | |
| nlmsvc_release_lockowner(&argp->lock); | |
| out: | |
| if (file) | |
| nlm_release_file(file); | |
| nlmsvc_release_host(host); | |
| return resp->status == nlm__int__drop_reply ? rpc_drop_reply : rpc_success; | |
| } | |
| /** | |
| * nlmsvc_proc_lock_msg - LOCK_MSG: Establish a monitored lock | |
| * @rqstp: RPC transaction context | |
| * | |
| * Returns: | |
| * %rpc_success: RPC executed successfully. | |
| * %rpc_drop_reply: Do not send an RPC reply. | |
| * %rpc_garbage_args: The request arguments are malformed. | |
| * %rpc_system_err: RPC execution failed. | |
| * | |
| * RPC synopsis: | |
| * void NLMPROC_LOCK_MSG(nlm_lockargs) = 7; | |
| * | |
| * The response to this request is delivered via the LOCK_RES procedure. | |
| */ | |
| static __be32 nlmsvc_proc_lock_msg(struct svc_rqst *rqstp) | |
| { | |
| struct nlm_lockargs_wrapper *argp = rqstp->rq_argp; | |
| struct nlm_host *host; | |
| if (argp->xdrgen.cookie.len > NLM_MAXCOOKIELEN) | |
| return rpc_garbage_args; | |
| host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); | |
| if (!host) | |
| return rpc_system_err; | |
| return nlmsvc_callback(rqstp, host, NLMPROC_LOCK_RES, | |
| __nlmsvc_proc_lock_msg); | |
| } | |
| static __be32 | |
| __nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct lockd_res *resp) | |
| { | |
| struct nlm_cancargs_wrapper *argp = rqstp->rq_argp; | |
| unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK; | |
| struct net *net = SVC_NET(rqstp); | |
| struct nlm_file *file = NULL; | |
| struct nlm_host *host = NULL; | |
| resp->status = nlm_lck_denied_nolocks; | |
| if (nlm_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie)) | |
| goto out; | |
| resp->status = nlm_lck_denied_grace_period; | |
| if (locks_in_grace(net)) | |
| goto out; | |
| resp->status = nlm_lck_denied_nolocks; | |
| host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); | |
| if (!host) | |
| goto out; | |
| resp->status = nlm3svc_lookup_file(rqstp, host, &argp->lock, | |
| &file, &argp->xdrgen.alock, type); | |
| if (resp->status) | |
| goto out; | |
| resp->status = nlmsvc_cancel_blocked(net, file, &argp->lock); | |
| nlmsvc_release_lockowner(&argp->lock); | |
| out: | |
| if (file) | |
| nlm_release_file(file); | |
| nlmsvc_release_host(host); | |
| return resp->status == nlm__int__drop_reply ? rpc_drop_reply : rpc_success; | |
| } | |
| /** | |
| * nlmsvc_proc_cancel_msg - CANCEL_MSG: Cancel an outstanding lock request | |
| * @rqstp: RPC transaction context | |
| * | |
| * Returns: | |
| * %rpc_success: RPC executed successfully. | |
| * %rpc_drop_reply: Do not send an RPC reply. | |
| * %rpc_garbage_args: The request arguments are malformed. | |
| * %rpc_system_err: RPC execution failed. | |
| * | |
| * RPC synopsis: | |
| * void NLMPROC_CANCEL_MSG(nlm_cancargs) = 8; | |
| * | |
| * The response to this request is delivered via the CANCEL_RES procedure. | |
| */ | |
| static __be32 nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp) | |
| { | |
| struct nlm_cancargs_wrapper *argp = rqstp->rq_argp; | |
| struct nlm_host *host; | |
| if (argp->xdrgen.cookie.len > NLM_MAXCOOKIELEN) | |
| return rpc_garbage_args; | |
| host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); | |
| if (!host) | |
| return rpc_system_err; | |
| return nlmsvc_callback(rqstp, host, NLMPROC_CANCEL_RES, | |
| __nlmsvc_proc_cancel_msg); | |
| } | |
| static __be32 | |
| __nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct lockd_res *resp) | |
| { | |
| struct nlm_unlockargs_wrapper *argp = rqstp->rq_argp; | |
| struct net *net = SVC_NET(rqstp); | |
| struct nlm_file *file = NULL; | |
| struct nlm_host *host = NULL; | |
| resp->status = nlm_lck_denied_nolocks; | |
| if (nlm_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie)) | |
| goto out; | |
| resp->status = nlm_lck_denied_grace_period; | |
| if (locks_in_grace(net)) | |
| goto out; | |
| resp->status = nlm_lck_denied_nolocks; | |
| host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); | |
| if (!host) | |
| goto out; | |
| resp->status = nlm3svc_lookup_file(rqstp, host, &argp->lock, | |
| &file, &argp->xdrgen.alock, F_UNLCK); | |
| if (resp->status) | |
| goto out; | |
| resp->status = nlmsvc_unlock(net, file, &argp->lock); | |
| nlmsvc_release_lockowner(&argp->lock); | |
| out: | |
| if (file) | |
| nlm_release_file(file); | |
| nlmsvc_release_host(host); | |
| return resp->status == nlm__int__drop_reply ? rpc_drop_reply : rpc_success; | |
| } | |
| /** | |
| * nlmsvc_proc_unlock_msg - UNLOCK_MSG: Remove an existing lock | |
| * @rqstp: RPC transaction context | |
| * | |
| * Returns: | |
| * %rpc_success: RPC executed successfully. | |
| * %rpc_drop_reply: Do not send an RPC reply. | |
| * %rpc_garbage_args: The request arguments are malformed. | |
| * %rpc_system_err: RPC execution failed. | |
| * | |
| * RPC synopsis: | |
| * void NLMPROC_UNLOCK_MSG(nlm_unlockargs) = 9; | |
| * | |
| * The response to this request is delivered via the UNLOCK_RES procedure. | |
| */ | |
| static __be32 nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp) | |
| { | |
| struct nlm_unlockargs_wrapper *argp = rqstp->rq_argp; | |
| struct nlm_host *host; | |
| if (argp->xdrgen.cookie.len > NLM_MAXCOOKIELEN) | |
| return rpc_garbage_args; | |
| host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); | |
| if (!host) | |
| return rpc_system_err; | |
| return nlmsvc_callback(rqstp, host, NLMPROC_UNLOCK_RES, | |
| __nlmsvc_proc_unlock_msg); | |
| } | |
| static __be32 | |
| __nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct lockd_res *resp) | |
| { | |
| struct nlm_testargs_wrapper *argp = rqstp->rq_argp; | |
| resp->status = nlm_lck_denied; | |
| if (nlm_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie)) | |
| goto out; | |
| if (nlm_lock_to_lockd_lock(&argp->lock, &argp->xdrgen.alock)) | |
| goto out; | |
| resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock); | |
| out: | |
| return rpc_success; | |
| } | |
| /** | |
| * nlmsvc_proc_granted_msg - GRANTED_MSG: Blocked lock has been granted | |
| * @rqstp: RPC transaction context | |
| * | |
| * Returns: | |
| * %rpc_success: RPC executed successfully. | |
| * %rpc_garbage_args: The request arguments are malformed. | |
| * %rpc_system_err: RPC execution failed. | |
| * | |
| * RPC synopsis: | |
| * void NLMPROC_GRANTED_MSG(nlm_testargs) = 10; | |
| * | |
| * The response to this request is delivered via the GRANTED_RES procedure. | |
| */ | |
| static __be32 nlmsvc_proc_granted_msg(struct svc_rqst *rqstp) | |
| { | |
| struct nlm_testargs_wrapper *argp = rqstp->rq_argp; | |
| struct nlm_host *host; | |
| if (argp->xdrgen.cookie.len > NLM_MAXCOOKIELEN) | |
| return rpc_garbage_args; | |
| host = nlmsvc_lookup_host(rqstp, argp->xdrgen.alock.caller_name.data, | |
| argp->xdrgen.alock.caller_name.len); | |
| if (!host) | |
| return rpc_system_err; | |
| return nlmsvc_callback(rqstp, host, NLMPROC_GRANTED_RES, | |
| __nlmsvc_proc_granted_msg); | |
| } | |
| /** | |
| * nlmsvc_proc_granted_res - GRANTED_RES: Lock Granted result | |
| * @rqstp: RPC transaction context | |
| * | |
| * Returns: | |
| * %rpc_success: RPC executed successfully. | |
| * | |
| * RPC synopsis: | |
| * void NLMPROC_GRANTED_RES(nlm_res) = 15; | |
| */ | |
| static __be32 nlmsvc_proc_granted_res(struct svc_rqst *rqstp) | |
| { | |
| struct nlm_res_wrapper *argp = rqstp->rq_argp; | |
| if (!rcu_access_pointer(nlmsvc_ops)) | |
| return rpc_success; | |
| if (nlm_netobj_to_cookie(&argp->cookie, &argp->xdrgen.cookie)) | |
| return rpc_success; | |
| nlmsvc_grant_reply(&argp->cookie, argp->xdrgen.stat.stat); | |
| return rpc_success; | |
| } | |
| /** | |
| * nlmsvc_proc_sm_notify - SM_NOTIFY: Peer has rebooted | |
| * @rqstp: RPC transaction context | |
| * | |
| * Returns: | |
| * %rpc_success: RPC executed successfully. | |
| * %rpc_system_err: RPC execution failed. | |
| * | |
| * The SM_NOTIFY procedure is a private callback from Linux statd and is | |
| * not part of the official NLM protocol. | |
| * | |
| * RPC synopsis: | |
| * void NLM_SM_NOTIFY(nlm_notifyargs) = 16; | |
| */ | |
| static __be32 nlmsvc_proc_sm_notify(struct svc_rqst *rqstp) | |
| { | |
| struct nlm_notifyargs_wrapper *argp = rqstp->rq_argp; | |
| struct lockd_reboot *reboot = &argp->reboot; | |
| if (!nlm_privileged_requester(rqstp)) { | |
| char buf[RPC_MAX_ADDRBUFLEN]; | |
| pr_warn("lockd: rejected NSM callback from %s\n", | |
| svc_print_addr(rqstp, buf, sizeof(buf))); | |
| return rpc_system_err; | |
| } | |
| reboot->len = argp->xdrgen.notify.name.len; | |
| reboot->mon = (char *)argp->xdrgen.notify.name.data; | |
| reboot->state = argp->xdrgen.notify.state; | |
| memcpy(&reboot->priv.data, argp->xdrgen.private, | |
| sizeof(reboot->priv.data)); | |
| nlm_host_rebooted(SVC_NET(rqstp), reboot); | |
| return rpc_success; | |
| } | |
| /** | |
| * nlmsvc_proc_unused - stub for unused procedures | |
| * @rqstp: RPC transaction context | |
| * | |
| * Returns: | |
| * %rpc_proc_unavail: Program can't support procedure. | |
| */ | |
| static __be32 nlmsvc_proc_unused(struct svc_rqst *rqstp) | |
| { | |
| return rpc_proc_unavail; | |
| } | |
| /** | |
| * nlmsvc_proc_share - SHARE: Open a file using DOS file-sharing modes | |
| * @rqstp: RPC transaction context | |
| * | |
| * Returns: | |
| * %rpc_success: RPC executed successfully. | |
| * %rpc_drop_reply: Do not send an RPC reply. | |
| * | |
| * RPC synopsis: | |
| * nlm_shareres NLM_SHARE(nlm_shareargs) = 20; | |
| * | |
| * Permissible procedure status codes: | |
| * %LCK_GRANTED: The requested share lock was granted. | |
| * %LCK_DENIED: The requested lock conflicted with existing | |
| * lock reservations for the file. | |
| * %LCK_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: | |
| * %LCK_DENIED_NOLOCKS: A needed resource could not be allocated. | |
| */ | |
| static __be32 nlmsvc_proc_share(struct svc_rqst *rqstp) | |
| { | |
| struct nlm_shareargs_wrapper *argp = rqstp->rq_argp; | |
| struct nlm_shareres_wrapper *resp = rqstp->rq_resp; | |
| struct lockd_lock *lock = &argp->lock; | |
| struct nlm_host *host = NULL; | |
| struct nlm_file *file = NULL; | |
| struct nlm_lock xdr_lock = { | |
| .fh = argp->xdrgen.share.fh, | |
| .oh = argp->xdrgen.share.oh, | |
| .uppid = LOCKD_SHARE_SVID, | |
| }; | |
| resp->xdrgen.cookie = argp->xdrgen.cookie; | |
| resp->xdrgen.stat = nlm_lck_denied_grace_period; | |
| if (locks_in_grace(SVC_NET(rqstp)) && !argp->xdrgen.reclaim) | |
| goto out; | |
| resp->xdrgen.stat = nlm_lck_denied_nolocks; | |
| host = nlm3svc_lookup_host(rqstp, argp->xdrgen.share.caller_name, false); | |
| if (!host) | |
| goto out; | |
| resp->xdrgen.stat = nlm3svc_lookup_file(rqstp, host, lock, &file, | |
| &xdr_lock, F_RDLCK); | |
| if (resp->xdrgen.stat) | |
| goto out; | |
| resp->xdrgen.stat = nlmsvc_share_file(host, file, &lock->oh, | |
| argp->xdrgen.share.access, | |
| argp->xdrgen.share.mode); | |
| nlmsvc_release_lockowner(lock); | |
| out: | |
| if (file) | |
| nlm_release_file(file); | |
| nlmsvc_release_host(host); | |
| return resp->xdrgen.stat == nlm__int__drop_reply ? | |
| rpc_drop_reply : rpc_success; | |
| } | |
| /** | |
| * nlmsvc_proc_unshare - UNSHARE: Release a share reservation | |
| * @rqstp: RPC transaction context | |
| * | |
| * Returns: | |
| * %rpc_success: RPC executed successfully. | |
| * %rpc_drop_reply: Do not send an RPC reply. | |
| * | |
| * RPC synopsis: | |
| * nlm_shareres NLM_UNSHARE(nlm_shareargs) = 21; | |
| * | |
| * Permissible procedure status codes: | |
| * %LCK_GRANTED: The share reservation was released. | |
| * %LCK_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: | |
| * %LCK_DENIED_NOLOCKS: A needed resource could not be allocated. | |
| */ | |
| static __be32 nlmsvc_proc_unshare(struct svc_rqst *rqstp) | |
| { | |
| struct nlm_shareargs_wrapper *argp = rqstp->rq_argp; | |
| struct nlm_shareres_wrapper *resp = rqstp->rq_resp; | |
| struct lockd_lock *lock = &argp->lock; | |
| struct nlm_lock xdr_lock = { | |
| .fh = argp->xdrgen.share.fh, | |
| .oh = argp->xdrgen.share.oh, | |
| .uppid = LOCKD_SHARE_SVID, | |
| }; | |
| struct nlm_host *host = NULL; | |
| struct nlm_file *file = NULL; | |
| resp->xdrgen.cookie = argp->xdrgen.cookie; | |
| resp->xdrgen.stat = nlm_lck_denied_grace_period; | |
| if (locks_in_grace(SVC_NET(rqstp))) | |
| goto out; | |
| resp->xdrgen.stat = nlm_lck_denied_nolocks; | |
| host = nlm3svc_lookup_host(rqstp, argp->xdrgen.share.caller_name, false); | |
| if (!host) | |
| goto out; | |
| resp->xdrgen.stat = nlm3svc_lookup_file(rqstp, host, lock, &file, | |
| &xdr_lock, F_RDLCK); | |
| if (resp->xdrgen.stat) | |
| goto out; | |
| resp->xdrgen.stat = nlmsvc_unshare_file(host, file, &lock->oh, | |
| argp->xdrgen.share.access, | |
| argp->xdrgen.share.mode); | |
| nlmsvc_release_lockowner(lock); | |
| out: | |
| if (file) | |
| nlm_release_file(file); | |
| nlmsvc_release_host(host); | |
| return resp->xdrgen.stat == nlm__int__drop_reply ? | |
| rpc_drop_reply : rpc_success; | |
| } | |
| /** | |
| * nlmsvc_proc_nm_lock - NM_LOCK: Establish a non-monitored lock | |
| * @rqstp: RPC transaction context | |
| * | |
| * Returns: | |
| * %rpc_success: RPC executed successfully. | |
| * %rpc_drop_reply: Do not send an RPC reply. | |
| * | |
| * RPC synopsis: | |
| * nlm_res NLM_NM_LOCK(nlm_lockargs) = 22; | |
| * | |
| * Permissible procedure status codes: | |
| * %LCK_GRANTED: The requested lock was granted. | |
| * %LCK_DENIED: The requested lock conflicted with existing | |
| * lock reservations for the file. | |
| * %LCK_DENIED_NOLOCKS: The server could not allocate the resources | |
| * needed to process the request. | |
| * %LCK_BLOCKED: The blocking request cannot be granted | |
| * immediately. The server will send an | |
| * NLM_GRANTED callback to the client when | |
| * the lock can be granted. | |
| * %LCK_DENIED_GRACE_PERIOD: The server has recently restarted and is | |
| * re-establishing existing locks, and is not | |
| * yet ready to accept normal service requests. | |
| */ | |
| static __be32 nlmsvc_proc_nm_lock(struct svc_rqst *rqstp) | |
| { | |
| return nlmsvc_do_lock(rqstp, false); | |
| } | |
| /** | |
| * nlmsvc_proc_free_all - FREE_ALL: Discard client's lock and share state | |
| * @rqstp: RPC transaction context | |
| * | |
| * Returns: | |
| * %rpc_success: RPC executed successfully. | |
| * | |
| * RPC synopsis: | |
| * void NLMPROC_FREE_ALL(nlm_notify) = 23; | |
| */ | |
| static __be32 nlmsvc_proc_free_all(struct svc_rqst *rqstp) | |
| { | |
| struct nlm_notify_wrapper *argp = rqstp->rq_argp; | |
| struct nlm_host *host; | |
| host = nlm3svc_lookup_host(rqstp, argp->xdrgen.name, false); | |
| if (!host) | |
| goto out; | |
| nlmsvc_free_host_resources(host); | |
| nlmsvc_release_host(host); | |
| out: | |
| return rpc_success; | |
| } | |
| /* | |
| * NLMv3 Server procedures. | |
| */ | |
| static const struct svc_procedure nlmsvc_procedures[24] = { | |
| [NLM_NULL] = { | |
| .pc_func = nlmsvc_proc_null, | |
| .pc_decode = xdrgen_svc_decode_void, | |
| .pc_encode = xdrgen_svc_encode_void, | |
| .pc_argsize = XDR_void, | |
| .pc_argzero = 0, | |
| .pc_ressize = 0, | |
| .pc_xdrressize = XDR_void, | |
| .pc_name = "NULL", | |
| }, | |
| [NLM_TEST] = { | |
| .pc_func = nlmsvc_proc_test, | |
| .pc_decode = nlm_svc_decode_nlm_testargs, | |
| .pc_encode = nlm_svc_encode_nlm_testres, | |
| .pc_argsize = sizeof(struct nlm_testargs_wrapper), | |
| .pc_argzero = 0, | |
| .pc_ressize = sizeof(struct nlm_testres_wrapper), | |
| .pc_xdrressize = NLM3_nlm_testres_sz, | |
| .pc_name = "TEST", | |
| }, | |
| [NLM_LOCK] = { | |
| .pc_func = nlmsvc_proc_lock, | |
| .pc_decode = nlm_svc_decode_nlm_lockargs, | |
| .pc_encode = nlm_svc_encode_nlm_res, | |
| .pc_argsize = sizeof(struct nlm_lockargs_wrapper), | |
| .pc_argzero = 0, | |
| .pc_ressize = sizeof(struct nlm_res_wrapper), | |
| .pc_xdrressize = NLM3_nlm_res_sz, | |
| .pc_name = "LOCK", | |
| }, | |
| [NLM_CANCEL] = { | |
| .pc_func = nlmsvc_proc_cancel, | |
| .pc_decode = nlm_svc_decode_nlm_cancargs, | |
| .pc_encode = nlm_svc_encode_nlm_res, | |
| .pc_argsize = sizeof(struct nlm_cancargs_wrapper), | |
| .pc_argzero = 0, | |
| .pc_ressize = sizeof(struct nlm_res_wrapper), | |
| .pc_xdrressize = NLM3_nlm_res_sz, | |
| .pc_name = "CANCEL", | |
| }, | |
| [NLM_UNLOCK] = { | |
| .pc_func = nlmsvc_proc_unlock, | |
| .pc_decode = nlm_svc_decode_nlm_unlockargs, | |
| .pc_encode = nlm_svc_encode_nlm_res, | |
| .pc_argsize = sizeof(struct nlm_unlockargs_wrapper), | |
| .pc_argzero = 0, | |
| .pc_ressize = sizeof(struct nlm_res_wrapper), | |
| .pc_xdrressize = NLM3_nlm_res_sz, | |
| .pc_name = "UNLOCK", | |
| }, | |
| [NLM_GRANTED] = { | |
| .pc_func = nlmsvc_proc_granted, | |
| .pc_decode = nlm_svc_decode_nlm_testargs, | |
| .pc_encode = nlm_svc_encode_nlm_res, | |
| .pc_argsize = sizeof(struct nlm_testargs_wrapper), | |
| .pc_argzero = 0, | |
| .pc_ressize = sizeof(struct nlm_res_wrapper), | |
| .pc_xdrressize = NLM3_nlm_res_sz, | |
| .pc_name = "GRANTED", | |
| }, | |
| [NLM_TEST_MSG] = { | |
| .pc_func = nlmsvc_proc_test_msg, | |
| .pc_decode = nlm_svc_decode_nlm_testargs, | |
| .pc_encode = xdrgen_svc_encode_void, | |
| .pc_argsize = sizeof(struct nlm_testargs_wrapper), | |
| .pc_argzero = 0, | |
| .pc_ressize = 0, | |
| .pc_xdrressize = XDR_void, | |
| .pc_name = "TEST_MSG", | |
| }, | |
| [NLM_LOCK_MSG] = { | |
| .pc_func = nlmsvc_proc_lock_msg, | |
| .pc_decode = nlm_svc_decode_nlm_lockargs, | |
| .pc_encode = xdrgen_svc_encode_void, | |
| .pc_argsize = sizeof(struct nlm_lockargs_wrapper), | |
| .pc_argzero = 0, | |
| .pc_ressize = 0, | |
| .pc_xdrressize = XDR_void, | |
| .pc_name = "LOCK_MSG", | |
| }, | |
| [NLM_CANCEL_MSG] = { | |
| .pc_func = nlmsvc_proc_cancel_msg, | |
| .pc_decode = nlm_svc_decode_nlm_cancargs, | |
| .pc_encode = xdrgen_svc_encode_void, | |
| .pc_argsize = sizeof(struct nlm_cancargs_wrapper), | |
| .pc_argzero = 0, | |
| .pc_ressize = 0, | |
| .pc_xdrressize = XDR_void, | |
| .pc_name = "CANCEL_MSG", | |
| }, | |
| [NLM_UNLOCK_MSG] = { | |
| .pc_func = nlmsvc_proc_unlock_msg, | |
| .pc_decode = nlm_svc_decode_nlm_unlockargs, | |
| .pc_encode = xdrgen_svc_encode_void, | |
| .pc_argsize = sizeof(struct nlm_unlockargs_wrapper), | |
| .pc_argzero = 0, | |
| .pc_ressize = 0, | |
| .pc_xdrressize = XDR_void, | |
| .pc_name = "UNLOCK_MSG", | |
| }, | |
| [NLM_GRANTED_MSG] = { | |
| .pc_func = nlmsvc_proc_granted_msg, | |
| .pc_decode = nlm_svc_decode_nlm_testargs, | |
| .pc_encode = xdrgen_svc_encode_void, | |
| .pc_argsize = sizeof(struct nlm_testargs_wrapper), | |
| .pc_argzero = 0, | |
| .pc_ressize = 0, | |
| .pc_xdrressize = XDR_void, | |
| .pc_name = "GRANTED_MSG", | |
| }, | |
| [NLM_TEST_RES] = { | |
| .pc_func = nlmsvc_proc_null, | |
| .pc_decode = nlm_svc_decode_nlm_testres, | |
| .pc_encode = xdrgen_svc_encode_void, | |
| .pc_argsize = sizeof(struct nlm_testres), | |
| .pc_argzero = 0, | |
| .pc_ressize = 0, | |
| .pc_xdrressize = XDR_void, | |
| .pc_name = "TEST_RES", | |
| }, | |
| [NLM_LOCK_RES] = { | |
| .pc_func = nlmsvc_proc_null, | |
| .pc_decode = nlm_svc_decode_nlm_res, | |
| .pc_encode = xdrgen_svc_encode_void, | |
| .pc_argsize = sizeof(struct nlm_res), | |
| .pc_argzero = 0, | |
| .pc_ressize = 0, | |
| .pc_xdrressize = XDR_void, | |
| .pc_name = "LOCK_RES", | |
| }, | |
| [NLM_CANCEL_RES] = { | |
| .pc_func = nlmsvc_proc_null, | |
| .pc_decode = nlm_svc_decode_nlm_res, | |
| .pc_encode = xdrgen_svc_encode_void, | |
| .pc_argsize = sizeof(struct nlm_res), | |
| .pc_argzero = 0, | |
| .pc_ressize = 0, | |
| .pc_xdrressize = XDR_void, | |
| .pc_name = "CANCEL_RES", | |
| }, | |
| [NLM_UNLOCK_RES] = { | |
| .pc_func = nlmsvc_proc_null, | |
| .pc_decode = nlm_svc_decode_nlm_res, | |
| .pc_encode = xdrgen_svc_encode_void, | |
| .pc_argsize = sizeof(struct nlm_res), | |
| .pc_argzero = 0, | |
| .pc_ressize = 0, | |
| .pc_xdrressize = XDR_void, | |
| .pc_name = "UNLOCK_RES", | |
| }, | |
| [NLM_GRANTED_RES] = { | |
| .pc_func = nlmsvc_proc_granted_res, | |
| .pc_decode = nlm_svc_decode_nlm_res, | |
| .pc_encode = xdrgen_svc_encode_void, | |
| .pc_argsize = sizeof(struct nlm_res_wrapper), | |
| .pc_argzero = 0, | |
| .pc_ressize = 0, | |
| .pc_xdrressize = XDR_void, | |
| .pc_name = "GRANTED_RES", | |
| }, | |
| [NLM_SM_NOTIFY] = { | |
| .pc_func = nlmsvc_proc_sm_notify, | |
| .pc_decode = nlm_svc_decode_nlm_notifyargs, | |
| .pc_encode = xdrgen_svc_encode_void, | |
| .pc_argsize = sizeof(struct nlm_notifyargs_wrapper), | |
| .pc_argzero = 0, | |
| .pc_ressize = 0, | |
| .pc_xdrressize = XDR_void, | |
| .pc_name = "SM_NOTIFY", | |
| }, | |
| [17] = { | |
| .pc_func = nlmsvc_proc_unused, | |
| .pc_decode = xdrgen_svc_decode_void, | |
| .pc_encode = xdrgen_svc_encode_void, | |
| .pc_argsize = 0, | |
| .pc_argzero = 0, | |
| .pc_ressize = 0, | |
| .pc_xdrressize = XDR_void, | |
| .pc_name = "UNUSED", | |
| }, | |
| [18] = { | |
| .pc_func = nlmsvc_proc_unused, | |
| .pc_decode = xdrgen_svc_decode_void, | |
| .pc_encode = xdrgen_svc_encode_void, | |
| .pc_argsize = 0, | |
| .pc_argzero = 0, | |
| .pc_ressize = 0, | |
| .pc_xdrressize = XDR_void, | |
| .pc_name = "UNUSED", | |
| }, | |
| [19] = { | |
| .pc_func = nlmsvc_proc_unused, | |
| .pc_decode = xdrgen_svc_decode_void, | |
| .pc_encode = xdrgen_svc_encode_void, | |
| .pc_argsize = 0, | |
| .pc_argzero = 0, | |
| .pc_ressize = 0, | |
| .pc_xdrressize = XDR_void, | |
| .pc_name = "UNUSED", | |
| }, | |
| [NLM_SHARE] = { | |
| .pc_func = nlmsvc_proc_share, | |
| .pc_decode = nlm_svc_decode_nlm_shareargs, | |
| .pc_encode = nlm_svc_encode_nlm_shareres, | |
| .pc_argsize = sizeof(struct nlm_shareargs_wrapper), | |
| .pc_argzero = 0, | |
| .pc_ressize = sizeof(struct nlm_shareres_wrapper), | |
| .pc_xdrressize = NLM3_nlm_shareres_sz, | |
| .pc_name = "SHARE", | |
| }, | |
| [NLM_UNSHARE] = { | |
| .pc_func = nlmsvc_proc_unshare, | |
| .pc_decode = nlm_svc_decode_nlm_shareargs, | |
| .pc_encode = nlm_svc_encode_nlm_shareres, | |
| .pc_argsize = sizeof(struct nlm_shareargs_wrapper), | |
| .pc_argzero = 0, | |
| .pc_ressize = sizeof(struct nlm_shareres_wrapper), | |
| .pc_xdrressize = NLM3_nlm_shareres_sz, | |
| .pc_name = "UNSHARE", | |
| }, | |
| [NLM_NM_LOCK] = { | |
| .pc_func = nlmsvc_proc_nm_lock, | |
| .pc_decode = nlm_svc_decode_nlm_lockargs, | |
| .pc_encode = nlm_svc_encode_nlm_res, | |
| .pc_argsize = sizeof(struct nlm_lockargs_wrapper), | |
| .pc_argzero = 0, | |
| .pc_ressize = sizeof(struct nlm_res_wrapper), | |
| .pc_xdrressize = NLM3_nlm_res_sz, | |
| .pc_name = "NM_LOCK", | |
| }, | |
| [NLM_FREE_ALL] = { | |
| .pc_func = nlmsvc_proc_free_all, | |
| .pc_decode = nlm_svc_decode_nlm_notify, | |
| .pc_encode = xdrgen_svc_encode_void, | |
| .pc_argsize = sizeof(struct nlm_notify_wrapper), | |
| .pc_argzero = 0, | |
| .pc_ressize = 0, | |
| .pc_xdrressize = XDR_void, | |
| .pc_name = "FREE_ALL", | |
| }, | |
| }; | |
| /* | |
| * Storage requirements for XDR arguments and results | |
| */ | |
| union nlmsvc_xdrstore { | |
| struct nlm_testargs_wrapper testargs; | |
| struct nlm_lockargs_wrapper lockargs; | |
| struct nlm_cancargs_wrapper cancargs; | |
| struct nlm_unlockargs_wrapper unlockargs; | |
| struct nlm_notifyargs_wrapper notifyargs; | |
| struct nlm_shareargs_wrapper shareargs; | |
| struct nlm_notify_wrapper notify; | |
| struct nlm_testres_wrapper testres; | |
| struct nlm_res_wrapper res; | |
| struct nlm_shareres_wrapper shareres; | |
| }; | |
| /* | |
| * NLMv1 defines only procedures 1 - 15. Linux lockd also implements | |
| * procedures 0 (NULL) and 16 (SM_NOTIFY). | |
| */ | |
| const struct svc_version nlmsvc_version1 = { | |
| .vs_vers = 1, | |
| .vs_nproc = 17, | |
| .vs_proc = nlmsvc_procedures, | |
| .vs_dispatch = nlmsvc_dispatch, | |
| .vs_xdrsize = sizeof(union nlmsvc_xdrstore), | |
| }; | |
| const struct svc_version nlmsvc_version3 = { | |
| .vs_vers = 3, | |
| .vs_nproc = ARRAY_SIZE(nlmsvc_procedures), | |
| .vs_proc = nlmsvc_procedures, | |
| .vs_dispatch = nlmsvc_dispatch, | |
| .vs_xdrsize = sizeof(union nlmsvc_xdrstore), | |
| }; |