diff options
Diffstat (limited to 'fs/lockd')
-rw-r--r-- | fs/lockd/clntproc.c | 3 | ||||
-rw-r--r-- | fs/lockd/host.c | 24 | ||||
-rw-r--r-- | fs/lockd/mon.c | 2 | ||||
-rw-r--r-- | fs/lockd/svc.c | 257 | ||||
-rw-r--r-- | fs/lockd/svc4proc.c | 317 | ||||
-rw-r--r-- | fs/lockd/svclock.c | 94 | ||||
-rw-r--r-- | fs/lockd/svcproc.c | 311 | ||||
-rw-r--r-- | fs/lockd/svcsubs.c | 116 | ||||
-rw-r--r-- | fs/lockd/svcxdr.h | 142 | ||||
-rw-r--r-- | fs/lockd/xdr.c | 454 | ||||
-rw-r--r-- | fs/lockd/xdr4.c | 461 |
11 files changed, 1365 insertions, 816 deletions
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index b11f2afa84f1..99fffc9cb958 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -794,9 +794,6 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data) goto retry_cancel; } - dprintk("lockd: cancel status %u (task %u)\n", - status, task->tk_pid); - switch (status) { case NLM_LCK_GRANTED: case NLM_LCK_DENIED_GRACE_PERIOD: diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 0afb6d59bad0..cdc8e12cdac4 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -163,8 +163,8 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni, host->h_nsmhandle = nsm; host->h_addrbuf = nsm->sm_addrbuf; host->net = ni->net; - host->h_cred = get_cred(ni->cred), - strlcpy(host->nodename, utsname()->nodename, sizeof(host->nodename)); + host->h_cred = get_cred(ni->cred); + strscpy(host->nodename, utsname()->nodename, sizeof(host->nodename)); out: return host; @@ -439,12 +439,7 @@ nlm_bind_host(struct nlm_host *host) * RPC rebind is required */ if ((clnt = host->h_rpcclnt) != NULL) { - if (time_after_eq(jiffies, host->h_nextrebind)) { - rpc_force_rebind(clnt); - host->h_nextrebind = jiffies + NLM_HOST_REBIND; - dprintk("lockd: next rebind in %lu jiffies\n", - host->h_nextrebind - jiffies); - } + nlm_rebind_host(host); } else { unsigned long increment = nlmsvc_timeout; struct rpc_timeout timeparms = { @@ -494,13 +489,20 @@ nlm_bind_host(struct nlm_host *host) return clnt; } -/* - * Force a portmap lookup of the remote lockd port +/** + * nlm_rebind_host - If needed, force a portmap lookup of the peer's lockd port + * @host: NLM host handle for peer + * + * This is not needed when using a connection-oriented protocol, such as TCP. + * The existing autobind mechanism is sufficient to force a rebind when + * required, e.g. on connection state transitions. */ void nlm_rebind_host(struct nlm_host *host) { - dprintk("lockd: rebind host %s\n", host->h_name); + if (host->h_proto != IPPROTO_UDP) + return; + if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) { rpc_force_rebind(host->h_rpcclnt); host->h_nextrebind = jiffies + NLM_HOST_REBIND; diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 1eabd91870e6..1d9488cf0534 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -417,7 +417,7 @@ void nsm_release(struct nsm_handle *nsm) /* * XDR functions for NSM. * - * See http://www.opengroup.org/ for details on the Network + * See https://www.opengroup.org/ for details on the Network * Status Monitor wire protocol. */ diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 1a639e34847d..59ef8a1f843f 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -54,13 +54,9 @@ EXPORT_SYMBOL_GPL(nlmsvc_ops); static DEFINE_MUTEX(nlmsvc_mutex); static unsigned int nlmsvc_users; -static struct task_struct *nlmsvc_task; -static struct svc_rqst *nlmsvc_rqst; +static struct svc_serv *nlmsvc_serv; unsigned long nlmsvc_timeout; -static atomic_t nlm_ntf_refcnt = ATOMIC_INIT(0); -static DECLARE_WAIT_QUEUE_HEAD(nlm_ntf_wq); - unsigned int lockd_net_id; /* @@ -184,6 +180,10 @@ lockd(void *vrqstp) nlm_shutdown_hosts(); cancel_delayed_work_sync(&ln->grace_period_end); locks_end_grace(&ln->lockd_manager); + + dprintk("lockd_down: service stopped\n"); + + svc_exit_thread(rqstp); return 0; } @@ -196,8 +196,8 @@ static int create_lockd_listener(struct svc_serv *serv, const char *name, xprt = svc_find_xprt(serv, name, net, family, 0); if (xprt == NULL) - return svc_create_xprt(serv, name, net, family, port, - SVC_SOCK_DEFAULTS, cred); + return svc_xprt_create(serv, name, net, family, port, + SVC_SOCK_DEFAULTS, cred); svc_xprt_put(xprt); return 0; } @@ -247,7 +247,8 @@ out_err: if (warned++ == 0) printk(KERN_WARNING "lockd_up: makesock failed, error=%d\n", err); - svc_shutdown_net(serv, net); + svc_xprt_destroy_all(serv, net); + svc_rpcb_cleanup(serv, net); return err; } @@ -285,13 +286,12 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net) nlm_shutdown_hosts_net(net); cancel_delayed_work_sync(&ln->grace_period_end); locks_end_grace(&ln->lockd_manager); - svc_shutdown_net(serv, net); - dprintk("%s: per-net data destroyed; net=%x\n", - __func__, net->ns.inum); + svc_xprt_destroy_all(serv, net); + svc_rpcb_cleanup(serv, net); } } else { - pr_err("%s: no users! task=%p, net=%x\n", - __func__, nlmsvc_task, net->ns.inum); + pr_err("%s: no users! net=%x\n", + __func__, net->ns.inum); BUG(); } } @@ -302,20 +302,16 @@ static int lockd_inetaddr_event(struct notifier_block *this, struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; struct sockaddr_in sin; - if ((event != NETDEV_DOWN) || - !atomic_inc_not_zero(&nlm_ntf_refcnt)) + if (event != NETDEV_DOWN) goto out; - if (nlmsvc_rqst) { + if (nlmsvc_serv) { dprintk("lockd_inetaddr_event: removed %pI4\n", &ifa->ifa_local); sin.sin_family = AF_INET; sin.sin_addr.s_addr = ifa->ifa_local; - svc_age_temp_xprts_now(nlmsvc_rqst->rq_server, - (struct sockaddr *)&sin); + svc_age_temp_xprts_now(nlmsvc_serv, (struct sockaddr *)&sin); } - atomic_dec(&nlm_ntf_refcnt); - wake_up(&nlm_ntf_wq); out: return NOTIFY_DONE; @@ -332,21 +328,17 @@ static int lockd_inet6addr_event(struct notifier_block *this, struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; struct sockaddr_in6 sin6; - if ((event != NETDEV_DOWN) || - !atomic_inc_not_zero(&nlm_ntf_refcnt)) + if (event != NETDEV_DOWN) goto out; - if (nlmsvc_rqst) { + if (nlmsvc_serv) { dprintk("lockd_inet6addr_event: removed %pI6\n", &ifa->addr); sin6.sin6_family = AF_INET6; sin6.sin6_addr = ifa->addr; if (ipv6_addr_type(&sin6.sin6_addr) & IPV6_ADDR_LINKLOCAL) sin6.sin6_scope_id = ifa->idev->dev->ifindex; - svc_age_temp_xprts_now(nlmsvc_rqst->rq_server, - (struct sockaddr *)&sin6); + svc_age_temp_xprts_now(nlmsvc_serv, (struct sockaddr *)&sin6); } - atomic_dec(&nlm_ntf_refcnt); - wake_up(&nlm_ntf_wq); out: return NOTIFY_DONE; @@ -357,86 +349,15 @@ static struct notifier_block lockd_inet6addr_notifier = { }; #endif -static void lockd_unregister_notifiers(void) -{ - unregister_inetaddr_notifier(&lockd_inetaddr_notifier); -#if IS_ENABLED(CONFIG_IPV6) - unregister_inet6addr_notifier(&lockd_inet6addr_notifier); -#endif - wait_event(nlm_ntf_wq, atomic_read(&nlm_ntf_refcnt) == 0); -} - -static void lockd_svc_exit_thread(void) -{ - atomic_dec(&nlm_ntf_refcnt); - lockd_unregister_notifiers(); - svc_exit_thread(nlmsvc_rqst); -} - -static int lockd_start_svc(struct svc_serv *serv) +static int lockd_get(void) { + struct svc_serv *serv; int error; - if (nlmsvc_rqst) + if (nlmsvc_serv) { + svc_get(nlmsvc_serv); + nlmsvc_users++; return 0; - - /* - * Create the kernel thread and wait for it to start. - */ - nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE); - if (IS_ERR(nlmsvc_rqst)) { - error = PTR_ERR(nlmsvc_rqst); - printk(KERN_WARNING - "lockd_up: svc_rqst allocation failed, error=%d\n", - error); - lockd_unregister_notifiers(); - goto out_rqst; - } - - atomic_inc(&nlm_ntf_refcnt); - svc_sock_update_bufs(serv); - serv->sv_maxconn = nlm_max_connections; - - nlmsvc_task = kthread_create(lockd, nlmsvc_rqst, "%s", serv->sv_name); - if (IS_ERR(nlmsvc_task)) { - error = PTR_ERR(nlmsvc_task); - printk(KERN_WARNING - "lockd_up: kthread_run failed, error=%d\n", error); - goto out_task; - } - nlmsvc_rqst->rq_task = nlmsvc_task; - wake_up_process(nlmsvc_task); - - dprintk("lockd_up: service started\n"); - return 0; - -out_task: - lockd_svc_exit_thread(); - nlmsvc_task = NULL; -out_rqst: - nlmsvc_rqst = NULL; - return error; -} - -static const struct svc_serv_ops lockd_sv_ops = { - .svo_shutdown = svc_rpcb_cleanup, - .svo_enqueue_xprt = svc_xprt_do_enqueue, -}; - -static struct svc_serv *lockd_create_svc(void) -{ - struct svc_serv *serv; - - /* - * Check whether we're already up and running. - */ - if (nlmsvc_rqst) { - /* - * Note: increase service usage, because later in case of error - * svc_destroy() will be called. - */ - svc_get(nlmsvc_rqst->rq_server); - return nlmsvc_rqst->rq_server; } /* @@ -451,17 +372,44 @@ static struct svc_serv *lockd_create_svc(void) nlm_timeout = LOCKD_DFLT_TIMEO; nlmsvc_timeout = nlm_timeout * HZ; - serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, &lockd_sv_ops); + serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, lockd); if (!serv) { printk(KERN_WARNING "lockd_up: create service failed\n"); - return ERR_PTR(-ENOMEM); + return -ENOMEM; } + + serv->sv_maxconn = nlm_max_connections; + error = svc_set_num_threads(serv, NULL, 1); + /* The thread now holds the only reference */ + svc_put(serv); + if (error < 0) + return error; + + nlmsvc_serv = serv; register_inetaddr_notifier(&lockd_inetaddr_notifier); #if IS_ENABLED(CONFIG_IPV6) register_inet6addr_notifier(&lockd_inet6addr_notifier); #endif dprintk("lockd_up: service created\n"); - return serv; + nlmsvc_users++; + return 0; +} + +static void lockd_put(void) +{ + if (WARN(nlmsvc_users <= 0, "lockd_down: no users!\n")) + return; + if (--nlmsvc_users) + return; + + unregister_inetaddr_notifier(&lockd_inetaddr_notifier); +#if IS_ENABLED(CONFIG_IPV6) + unregister_inet6addr_notifier(&lockd_inet6addr_notifier); +#endif + + svc_set_num_threads(nlmsvc_serv, NULL, 0); + nlmsvc_serv = NULL; + dprintk("lockd_down: service destroyed\n"); } /* @@ -469,36 +417,21 @@ static struct svc_serv *lockd_create_svc(void) */ int lockd_up(struct net *net, const struct cred *cred) { - struct svc_serv *serv; int error; mutex_lock(&nlmsvc_mutex); - serv = lockd_create_svc(); - if (IS_ERR(serv)) { - error = PTR_ERR(serv); - goto err_create; - } + error = lockd_get(); + if (error) + goto err; - error = lockd_up_net(serv, net, cred); + error = lockd_up_net(nlmsvc_serv, net, cred); if (error < 0) { - lockd_unregister_notifiers(); - goto err_put; + lockd_put(); + goto err; } - error = lockd_start_svc(serv); - if (error < 0) { - lockd_down_net(serv, net); - goto err_put; - } - nlmsvc_users++; - /* - * Note: svc_serv structures have an initial use count of 1, - * so we exit through here on both success and failure. - */ -err_put: - svc_destroy(serv); -err_create: +err: mutex_unlock(&nlmsvc_mutex); return error; } @@ -511,27 +444,8 @@ void lockd_down(struct net *net) { mutex_lock(&nlmsvc_mutex); - lockd_down_net(nlmsvc_rqst->rq_server, net); - if (nlmsvc_users) { - if (--nlmsvc_users) - goto out; - } else { - printk(KERN_ERR "lockd_down: no users! task=%p\n", - nlmsvc_task); - BUG(); - } - - if (!nlmsvc_task) { - printk(KERN_ERR "lockd_down: no lockd running.\n"); - BUG(); - } - kthread_stop(nlmsvc_task); - dprintk("lockd_down: service stopped\n"); - lockd_svc_exit_thread(); - dprintk("lockd_down: service destroyed\n"); - nlmsvc_task = NULL; - nlmsvc_rqst = NULL; -out: + lockd_down_net(nlmsvc_serv, net); + lockd_put(); mutex_unlock(&nlmsvc_mutex); } EXPORT_SYMBOL_GPL(lockd_down); @@ -584,7 +498,7 @@ static struct ctl_table nlm_sysctls[] = { .data = &nsm_use_hostnames, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = proc_dobool, }, { .procname = "nsm_local_state", @@ -649,6 +563,7 @@ static int lockd_authenticate(struct svc_rqst *rqstp) switch (rqstp->rq_authop->flavour) { case RPC_AUTH_NULL: case RPC_AUTH_UNIX: + rqstp->rq_auth_stat = rpc_auth_ok; if (rqstp->rq_proc == 0) return SVC_OK; if (is_callback(rqstp->rq_proc)) { @@ -659,6 +574,7 @@ static int lockd_authenticate(struct svc_rqst *rqstp) } return svc_set_client(rqstp); } + rqstp->rq_auth_stat = rpc_autherr_badcred; return SVC_DENIED; } @@ -766,6 +682,44 @@ static void __exit exit_nlm(void) module_init(init_nlm); module_exit(exit_nlm); +/** + * nlmsvc_dispatch - Process an NLM Request + * @rqstp: incoming request + * @statp: pointer to location of accept_stat field in RPC Reply buffer + * + * Return values: + * %0: Processing complete; do not send a Reply + * %1: Processing complete; send Reply in rqstp->rq_res + */ +static int nlmsvc_dispatch(struct svc_rqst *rqstp, __be32 *statp) +{ + const struct svc_procedure *procp = rqstp->rq_procinfo; + + svcxdr_init_decode(rqstp); + if (!procp->pc_decode(rqstp, &rqstp->rq_arg_stream)) + goto out_decode_err; + + *statp = procp->pc_func(rqstp); + if (*statp == rpc_drop_reply) + return 0; + if (*statp != rpc_success) + return 1; + + svcxdr_init_encode(rqstp); + if (!procp->pc_encode(rqstp, &rqstp->rq_res_stream)) + goto out_encode_err; + + return 1; + +out_decode_err: + *statp = rpc_garbage_args; + return 1; + +out_encode_err: + *statp = rpc_system_err; + return 1; +} + /* * Define NLM program and procedures */ @@ -775,6 +729,7 @@ static const struct svc_version nlmsvc_version1 = { .vs_nproc = 17, .vs_proc = nlmsvc_procedures, .vs_count = nlmsvc_version1_count, + .vs_dispatch = nlmsvc_dispatch, .vs_xdrsize = NLMSVC_XDRSIZE, }; static unsigned int nlmsvc_version3_count[24]; @@ -783,6 +738,7 @@ static const struct svc_version nlmsvc_version3 = { .vs_nproc = 24, .vs_proc = nlmsvc_procedures, .vs_count = nlmsvc_version3_count, + .vs_dispatch = nlmsvc_dispatch, .vs_xdrsize = NLMSVC_XDRSIZE, }; #ifdef CONFIG_LOCKD_V4 @@ -792,6 +748,7 @@ static const struct svc_version nlmsvc_version4 = { .vs_nproc = 24, .vs_proc = nlmsvc_procedures4, .vs_count = nlmsvc_version4_count, + .vs_dispatch = nlmsvc_dispatch, .vs_xdrsize = NLMSVC_XDRSIZE, }; #endif diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index e4d3f783e06a..284b019cb652 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -32,6 +32,10 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, if (!nlmsvc_ops) return nlm_lck_denied_nolocks; + if (lock->lock_start > OFFSET_MAX || + (lock->lock_len && ((lock->lock_len - 1) > (OFFSET_MAX - lock->lock_start)))) + return nlm4_fbig; + /* Obtain host handle */ if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len)) || (argp->monitor && nsm_monitor(host) < 0)) @@ -40,13 +44,20 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain file pointer. Not used by FREE_ALL call. */ if (filp != NULL) { - if ((error = nlm_lookup_file(rqstp, &file, &lock->fh)) != 0) + int mode = lock_to_openmode(&lock->fl); + + error = nlm_lookup_file(rqstp, &file, lock); + if (error) goto no_locks; *filp = file; /* Set up the missing parts of the file_lock structure */ - lock->fl.fl_file = file->f_file; + lock->fl.fl_file = file->f_file[mode]; lock->fl.fl_pid = current->tgid; + lock->fl.fl_start = (loff_t)lock->lock_start; + lock->fl.fl_end = lock->lock_len ? + (loff_t)(lock->lock_start + lock->lock_len - 1) : + OFFSET_MAX; lock->fl.fl_lmops = &nlmsvc_lock_operations; nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid); if (!lock->fl.fl_owner) { @@ -84,6 +95,7 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) struct nlm_args *argp = rqstp->rq_argp; struct nlm_host *host; struct nlm_file *file; + struct nlm_lockowner *test_owner; __be32 rc = rpc_success; dprintk("lockd: TEST4 called\n"); @@ -93,6 +105,7 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; + test_owner = argp->lock.fl.fl_owner; /* Now check for conflicting locks */ resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie); if (resp->status == nlm_drop_reply) @@ -100,7 +113,7 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) else dprintk("lockd: TEST4 status %d\n", ntohl(resp->status)); - nlmsvc_release_lockowner(&argp->lock); + nlmsvc_put_lockowner(test_owner); nlmsvc_release_host(host); nlm_release_file(file); return rc; @@ -266,8 +279,6 @@ nlm4svc_proc_granted(struct svc_rqst *rqstp) */ static void nlm4svc_callback_exit(struct rpc_task *task, void *data) { - dprintk("lockd: %5u callback returned %d\n", task->tk_pid, - -task->tk_status); } static void nlm4svc_callback_release(void *data) @@ -486,65 +497,263 @@ nlm4svc_proc_granted_res(struct svc_rqst *rqstp) return rpc_success; } +static __be32 +nlm4svc_proc_unused(struct svc_rqst *rqstp) +{ + return rpc_proc_unavail; +} + /* * NLM Server procedures. */ -#define nlm4svc_encode_norep nlm4svc_encode_void -#define nlm4svc_decode_norep nlm4svc_decode_void -#define nlm4svc_decode_testres nlm4svc_decode_void -#define nlm4svc_decode_lockres nlm4svc_decode_void -#define nlm4svc_decode_unlockres nlm4svc_decode_void -#define nlm4svc_decode_cancelres nlm4svc_decode_void -#define nlm4svc_decode_grantedres nlm4svc_decode_void - -#define nlm4svc_proc_none nlm4svc_proc_null -#define nlm4svc_proc_test_res nlm4svc_proc_null -#define nlm4svc_proc_lock_res nlm4svc_proc_null -#define nlm4svc_proc_cancel_res nlm4svc_proc_null -#define nlm4svc_proc_unlock_res nlm4svc_proc_null - struct nlm_void { int dummy; }; -#define PROC(name, xargt, xrest, argt, rest, respsize) \ - { .pc_func = nlm4svc_proc_##name, \ - .pc_decode = nlm4svc_decode_##xargt, \ - .pc_encode = nlm4svc_encode_##xrest, \ - .pc_release = NULL, \ - .pc_argsize = sizeof(struct nlm_##argt), \ - .pc_ressize = sizeof(struct nlm_##rest), \ - .pc_xdrressize = respsize, \ - } #define Ck (1+XDR_QUADLEN(NLM_MAXCOOKIELEN)) /* cookie */ #define No (1+1024/4) /* netobj */ #define St 1 /* status */ #define Rg 4 /* range (offset + length) */ -const struct svc_procedure nlmsvc_procedures4[] = { - PROC(null, void, void, void, void, 1), - PROC(test, testargs, testres, args, res, Ck+St+2+No+Rg), - PROC(lock, lockargs, res, args, res, Ck+St), - PROC(cancel, cancargs, res, args, res, Ck+St), - PROC(unlock, unlockargs, res, args, res, Ck+St), - PROC(granted, testargs, res, args, res, Ck+St), - PROC(test_msg, testargs, norep, args, void, 1), - PROC(lock_msg, lockargs, norep, args, void, 1), - PROC(cancel_msg, cancargs, norep, args, void, 1), - PROC(unlock_msg, unlockargs, norep, args, void, 1), - PROC(granted_msg, testargs, norep, args, void, 1), - PROC(test_res, testres, norep, res, void, 1), - PROC(lock_res, lockres, norep, res, void, 1), - PROC(cancel_res, cancelres, norep, res, void, 1), - PROC(unlock_res, unlockres, norep, res, void, 1), - PROC(granted_res, res, norep, res, void, 1), - /* statd callback */ - PROC(sm_notify, reboot, void, reboot, void, 1), - PROC(none, void, void, void, void, 0), - PROC(none, void, void, void, void, 0), - PROC(none, void, void, void, void, 0), - PROC(share, shareargs, shareres, args, res, Ck+St+1), - PROC(unshare, shareargs, shareres, args, res, Ck+St+1), - PROC(nm_lock, lockargs, res, args, res, Ck+St), - PROC(free_all, notify, void, args, void, 1), +const struct svc_procedure nlmsvc_procedures4[24] = { + [NLMPROC_NULL] = { + .pc_func = nlm4svc_proc_null, + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_void), + .pc_argzero = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .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", + }, + [NLMPROC_LOCK] = { + .pc_func = nlm4svc_proc_lock, + .pc_decode = nlm4svc_decode_lockargs, + .pc_encode = nlm4svc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "LOCK", + }, + [NLMPROC_CANCEL] = { + .pc_func = nlm4svc_proc_cancel, + .pc_decode = nlm4svc_decode_cancargs, + .pc_encode = nlm4svc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "CANCEL", + }, + [NLMPROC_UNLOCK] = { + .pc_func = nlm4svc_proc_unlock, + .pc_decode = nlm4svc_decode_unlockargs, + .pc_encode = nlm4svc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "UNLOCK", + }, + [NLMPROC_GRANTED] = { + .pc_func = nlm4svc_proc_granted, + .pc_decode = nlm4svc_decode_testargs, + .pc_encode = nlm4svc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "GRANTED", + }, + [NLMPROC_TEST_MSG] = { + .pc_func = nlm4svc_proc_test_msg, + .pc_decode = nlm4svc_decode_testargs, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "TEST_MSG", + }, + [NLMPROC_LOCK_MSG] = { + .pc_func = nlm4svc_proc_lock_msg, + .pc_decode = nlm4svc_decode_lockargs, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "LOCK_MSG", + }, + [NLMPROC_CANCEL_MSG] = { + .pc_func = nlm4svc_proc_cancel_msg, + .pc_decode = nlm4svc_decode_cancargs, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "CANCEL_MSG", + }, + [NLMPROC_UNLOCK_MSG] = { + .pc_func = nlm4svc_proc_unlock_msg, + .pc_decode = nlm4svc_decode_unlockargs, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "UNLOCK_MSG", + }, + [NLMPROC_GRANTED_MSG] = { + .pc_func = nlm4svc_proc_granted_msg, + .pc_decode = nlm4svc_decode_testargs, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "GRANTED_MSG", + }, + [NLMPROC_TEST_RES] = { + .pc_func = nlm4svc_proc_null, + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "TEST_RES", + }, + [NLMPROC_LOCK_RES] = { + .pc_func = nlm4svc_proc_null, + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "LOCK_RES", + }, + [NLMPROC_CANCEL_RES] = { + .pc_func = nlm4svc_proc_null, + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "CANCEL_RES", + }, + [NLMPROC_UNLOCK_RES] = { + .pc_func = nlm4svc_proc_null, + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "UNLOCK_RES", + }, + [NLMPROC_GRANTED_RES] = { + .pc_func = nlm4svc_proc_granted_res, + .pc_decode = nlm4svc_decode_res, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "GRANTED_RES", + }, + [NLMPROC_NSM_NOTIFY] = { + .pc_func = nlm4svc_proc_sm_notify, + .pc_decode = nlm4svc_decode_reboot, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_reboot), + .pc_argzero = sizeof(struct nlm_reboot), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "SM_NOTIFY", + }, + [17] = { + .pc_func = nlm4svc_proc_unused, + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_void), + .pc_argzero = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = 0, + .pc_name = "UNUSED", + }, + [18] = { + .pc_func = nlm4svc_proc_unused, + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_void), + .pc_argzero = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = 0, + .pc_name = "UNUSED", + }, + [19] = { + .pc_func = nlm4svc_proc_unused, + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_void), + .pc_argzero = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = 0, + .pc_name = "UNUSED", + }, + [NLMPROC_SHARE] = { + .pc_func = nlm4svc_proc_share, + .pc_decode = nlm4svc_decode_shareargs, + .pc_encode = nlm4svc_encode_shareres, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+1, + .pc_name = "SHARE", + }, + [NLMPROC_UNSHARE] = { + .pc_func = nlm4svc_proc_unshare, + .pc_decode = nlm4svc_decode_shareargs, + .pc_encode = nlm4svc_encode_shareres, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+1, + .pc_name = "UNSHARE", + }, + [NLMPROC_NM_LOCK] = { + .pc_func = nlm4svc_proc_nm_lock, + .pc_decode = nlm4svc_decode_lockargs, + .pc_encode = nlm4svc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "NM_LOCK", + }, + [NLMPROC_FREE_ALL] = { + .pc_func = nlm4svc_proc_free_all, + .pc_decode = nlm4svc_decode_notify, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "FREE_ALL", + }, }; diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index 61d3cc2283dc..9c1aa75441e1 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -31,6 +31,7 @@ #include <linux/lockd/nlm.h> #include <linux/lockd/lockd.h> #include <linux/kthread.h> +#include <linux/exportfs.h> #define NLMDBG_FACILITY NLMDBG_SVCLOCK @@ -339,7 +340,7 @@ nlmsvc_get_lockowner(struct nlm_lockowner *lockowner) return lockowner; } -static void nlmsvc_put_lockowner(struct nlm_lockowner *lockowner) +void nlmsvc_put_lockowner(struct nlm_lockowner *lockowner) { if (!refcount_dec_and_lock(&lockowner->count, &lockowner->host->h_lock)) return; @@ -395,28 +396,10 @@ nlmsvc_release_lockowner(struct nlm_lock *lock) nlmsvc_put_lockowner(lock->fl.fl_owner); } -static void nlmsvc_locks_copy_lock(struct file_lock *new, struct file_lock *fl) -{ - struct nlm_lockowner *nlm_lo = (struct nlm_lockowner *)fl->fl_owner; - new->fl_owner = nlmsvc_get_lockowner(nlm_lo); -} - -static void nlmsvc_locks_release_private(struct file_lock *fl) -{ - nlmsvc_put_lockowner((struct nlm_lockowner *)fl->fl_owner); -} - -static const struct file_lock_operations nlmsvc_lock_ops = { - .fl_copy_lock = nlmsvc_locks_copy_lock, - .fl_release_private = nlmsvc_locks_release_private, -}; - void nlmsvc_locks_init_private(struct file_lock *fl, struct nlm_host *host, pid_t pid) { fl->fl_owner = nlmsvc_find_lockowner(host, pid); - if (fl->fl_owner != NULL) - fl->fl_ops = &nlmsvc_lock_ops; } /* @@ -487,18 +470,27 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, struct nlm_host *host, struct nlm_lock *lock, int wait, struct nlm_cookie *cookie, int reclaim) { +#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) + struct inode *inode = nlmsvc_file_inode(file); +#endif struct nlm_block *block = NULL; int error; + int mode; + int async_block = 0; __be32 ret; dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n", - locks_inode(file->f_file)->i_sb->s_id, - locks_inode(file->f_file)->i_ino, + inode->i_sb->s_id, inode->i_ino, lock->fl.fl_type, lock->fl.fl_pid, (long long)lock->fl.fl_start, (long long)lock->fl.fl_end, wait); + if (nlmsvc_file_file(file)->f_op->lock) { + async_block = wait; + wait = 0; + } + /* Lock file against concurrent access */ mutex_lock(&file->f_mutex); /* Get existing block (in case client is busy-waiting) @@ -542,7 +534,8 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, if (!wait) lock->fl.fl_flags &= ~FL_SLEEP; - error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL); + mode = lock_to_openmode(&lock->fl); + error = vfs_lock_file(file->f_file[mode], F_SETLK, &lock->fl, NULL); lock->fl.fl_flags &= ~FL_SLEEP; dprintk("lockd: vfs_lock_file returned %d\n", error); @@ -558,7 +551,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, */ if (wait) break; - ret = nlm_lck_denied; + ret = async_block ? nlm_lck_blocked : nlm_lck_denied; goto out; case FILE_LOCK_DEFERRED: if (wait) @@ -595,12 +588,12 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, struct nlm_lock *conflock, struct nlm_cookie *cookie) { int error; + int mode; __be32 ret; - struct nlm_lockowner *test_owner; dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n", - locks_inode(file->f_file)->i_sb->s_id, - locks_inode(file->f_file)->i_ino, + nlmsvc_file_inode(file)->i_sb->s_id, + nlmsvc_file_inode(file)->i_ino, lock->fl.fl_type, (long long)lock->fl.fl_start, (long long)lock->fl.fl_end); @@ -610,10 +603,8 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, goto out; } - /* If there's a conflicting lock, remember to clean up the test lock */ - test_owner = (struct nlm_lockowner *)lock->fl.fl_owner; - - error = vfs_test_lock(file->f_file, &lock->fl); + mode = lock_to_openmode(&lock->fl); + error = vfs_test_lock(file->f_file[mode], &lock->fl); if (error) { /* We can't currently deal with deferred test requests */ if (error == FILE_LOCK_DEFERRED) @@ -634,16 +625,12 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, conflock->caller = "somehost"; /* FIXME */ conflock->len = strlen(conflock->caller); conflock->oh.len = 0; /* don't return OH info */ - conflock->svid = ((struct nlm_lockowner *)lock->fl.fl_owner)->pid; + conflock->svid = lock->fl.fl_pid; conflock->fl.fl_type = lock->fl.fl_type; conflock->fl.fl_start = lock->fl.fl_start; conflock->fl.fl_end = lock->fl.fl_end; locks_release_private(&lock->fl); - /* Clean up the test lock */ - lock->fl.fl_owner = NULL; - nlmsvc_put_lockowner(test_owner); - ret = nlm_lck_denied; out: return ret; @@ -659,11 +646,11 @@ out: __be32 nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock) { - int error; + int error = 0; dprintk("lockd: nlmsvc_unlock(%s/%ld, pi=%d, %Ld-%Ld)\n", - locks_inode(file->f_file)->i_sb->s_id, - locks_inode(file->f_file)->i_ino, + nlmsvc_file_inode(file)->i_sb->s_id, + nlmsvc_file_inode(file)->i_ino, lock->fl.fl_pid, (long long)lock->fl.fl_start, (long long)lock->fl.fl_end); @@ -672,7 +659,12 @@ nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock) nlmsvc_cancel_blocked(net, file, lock); lock->fl.fl_type = F_UNLCK; - error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL); + if (file->f_file[O_RDONLY]) + error = vfs_lock_file(file->f_file[O_RDONLY], F_SETLK, + &lock->fl, NULL); + if (file->f_file[O_WRONLY]) + error = vfs_lock_file(file->f_file[O_WRONLY], F_SETLK, + &lock->fl, NULL); return (error < 0)? nlm_lck_denied_nolocks : nlm_granted; } @@ -689,10 +681,11 @@ nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *l { struct nlm_block *block; int status = 0; + int mode; dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n", - locks_inode(file->f_file)->i_sb->s_id, - locks_inode(file->f_file)->i_ino, + nlmsvc_file_inode(file)->i_sb->s_id, + nlmsvc_file_inode(file)->i_ino, lock->fl.fl_pid, (long long)lock->fl.fl_start, (long long)lock->fl.fl_end); @@ -704,7 +697,8 @@ nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *l block = nlmsvc_lookup_block(file, lock); mutex_unlock(&file->f_mutex); if (block != NULL) { - vfs_cancel_lock(block->b_file->f_file, + mode = lock_to_openmode(&lock->fl); + vfs_cancel_lock(block->b_file->f_file[mode], &block->b_call->a_args.lock.fl); status = nlmsvc_unlink_block(block); nlmsvc_release_block(block); @@ -788,9 +782,21 @@ nlmsvc_notify_blocked(struct file_lock *fl) printk(KERN_WARNING "lockd: notification for unknown block!\n"); } +static fl_owner_t nlmsvc_get_owner(fl_owner_t owner) +{ + return nlmsvc_get_lockowner(owner); +} + +static void nlmsvc_put_owner(fl_owner_t owner) +{ + nlmsvc_put_lockowner(owner); +} + const struct lock_manager_operations nlmsvc_lock_operations = { .lm_notify = nlmsvc_notify_blocked, .lm_grant = nlmsvc_grant_deferred, + .lm_get_owner = nlmsvc_get_owner, + .lm_put_owner = nlmsvc_put_owner, }; /* @@ -809,6 +815,7 @@ nlmsvc_grant_blocked(struct nlm_block *block) { struct nlm_file *file = block->b_file; struct nlm_lock *lock = &block->b_call->a_args.lock; + int mode; int error; loff_t fl_start, fl_end; @@ -834,7 +841,8 @@ nlmsvc_grant_blocked(struct nlm_block *block) lock->fl.fl_flags |= FL_SLEEP; fl_start = lock->fl.fl_start; fl_end = lock->fl.fl_end; - error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL); + mode = lock_to_openmode(&lock->fl); + error = vfs_lock_file(file->f_file[mode], F_SETLK, &lock->fl, NULL); lock->fl.fl_flags &= ~FL_SLEEP; lock->fl.fl_start = fl_start; lock->fl.fl_end = fl_end; diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index d0bb7a6bf005..e35c05e27806 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -55,6 +55,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, struct nlm_host *host = NULL; struct nlm_file *file = NULL; struct nlm_lock *lock = &argp->lock; + int mode; __be32 error = 0; /* nfsd callbacks must have been installed for this procedure */ @@ -69,13 +70,14 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, /* Obtain file pointer. Not used by FREE_ALL call. */ if (filp != NULL) { - error = cast_status(nlm_lookup_file(rqstp, &file, &lock->fh)); + error = cast_status(nlm_lookup_file(rqstp, &file, lock)); if (error != 0) goto no_locks; *filp = file; /* Set up the missing parts of the file_lock structure */ - lock->fl.fl_file = file->f_file; + mode = lock_to_openmode(&lock->fl); + lock->fl.fl_file = file->f_file[mode]; lock->fl.fl_pid = current->tgid; lock->fl.fl_lmops = &nlmsvc_lock_operations; nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid); @@ -114,6 +116,7 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) struct nlm_args *argp = rqstp->rq_argp; struct nlm_host *host; struct nlm_file *file; + struct nlm_lockowner *test_owner; __be32 rc = rpc_success; dprintk("lockd: TEST called\n"); @@ -123,6 +126,8 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; + test_owner = argp->lock.fl.fl_owner; + /* Now check for conflicting locks */ resp->status = cast_status(nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie)); if (resp->status == nlm_drop_reply) @@ -131,7 +136,7 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) dprintk("lockd: TEST status %d vers %d\n", ntohl(resp->status), rqstp->rq_vers); - nlmsvc_release_lockowner(&argp->lock); + nlmsvc_put_lockowner(test_owner); nlmsvc_release_host(host); nlm_release_file(file); return rc; @@ -299,8 +304,6 @@ nlmsvc_proc_granted(struct svc_rqst *rqstp) */ static void nlmsvc_callback_exit(struct rpc_task *task, void *data) { - dprintk("lockd: %5u callback returned %d\n", task->tk_pid, - -task->tk_status); } void nlmsvc_release_call(struct nlm_rqst *call) @@ -529,66 +532,262 @@ nlmsvc_proc_granted_res(struct svc_rqst *rqstp) return rpc_success; } +static __be32 +nlmsvc_proc_unused(struct svc_rqst *rqstp) +{ + return rpc_proc_unavail; +} + /* * NLM Server procedures. */ -#define nlmsvc_encode_norep nlmsvc_encode_void -#define nlmsvc_decode_norep nlmsvc_decode_void -#define nlmsvc_decode_testres nlmsvc_decode_void -#define nlmsvc_decode_lockres nlmsvc_decode_void -#define nlmsvc_decode_unlockres nlmsvc_decode_void -#define nlmsvc_decode_cancelres nlmsvc_decode_void -#define nlmsvc_decode_grantedres nlmsvc_decode_void - -#define nlmsvc_proc_none nlmsvc_proc_null -#define nlmsvc_proc_test_res nlmsvc_proc_null -#define nlmsvc_proc_lock_res nlmsvc_proc_null -#define nlmsvc_proc_cancel_res nlmsvc_proc_null -#define nlmsvc_proc_unlock_res nlmsvc_proc_null - struct nlm_void { int dummy; }; -#define PROC(name, xargt, xrest, argt, rest, respsize) \ - { .pc_func = nlmsvc_proc_##name, \ - .pc_decode = nlmsvc_decode_##xargt, \ - .pc_encode = nlmsvc_encode_##xrest, \ - .pc_release = NULL, \ - .pc_argsize = sizeof(struct nlm_##argt), \ - .pc_ressize = sizeof(struct nlm_##rest), \ - .pc_xdrressize = respsize, \ - } - #define Ck (1+XDR_QUADLEN(NLM_MAXCOOKIELEN)) /* cookie */ #define St 1 /* status */ #define No (1+1024/4) /* Net Obj */ #define Rg 2 /* range - offset + size */ -const struct svc_procedure nlmsvc_procedures[] = { - PROC(null, void, void, void, void, 1), - PROC(test, testargs, testres, args, res, Ck+St+2+No+Rg), - PROC(lock, lockargs, res, args, res, Ck+St), - PROC(cancel, cancargs, res, args, res, Ck+St), - PROC(unlock, unlockargs, res, args, res, Ck+St), - PROC(granted, testargs, res, args, res, Ck+St), - PROC(test_msg, testargs, norep, args, void, 1), - PROC(lock_msg, lockargs, norep, args, void, 1), - PROC(cancel_msg, cancargs, norep, args, void, 1), - PROC(unlock_msg, unlockargs, norep, args, void, 1), - PROC(granted_msg, testargs, norep, args, void, 1), - PROC(test_res, testres, norep, res, void, 1), - PROC(lock_res, lockres, norep, res, void, 1), - PROC(cancel_res, cancelres, norep, res, void, 1), - PROC(unlock_res, unlockres, norep, res, void, 1), - PROC(granted_res, res, norep, res, void, 1), - /* statd callback */ - PROC(sm_notify, reboot, void, reboot, void, 1), - PROC(none, void, void, void, void, 1), - PROC(none, void, void, void, void, 1), - PROC(none, void, void, void, void, 1), - PROC(share, shareargs, shareres, args, res, Ck+St+1), - PROC(unshare, shareargs, shareres, args, res, Ck+St+1), - PROC(nm_lock, lockargs, res, args, res, Ck+St), - PROC(free_all, notify, void, args, void, 0), - +const struct svc_procedure nlmsvc_procedures[24] = { + [NLMPROC_NULL] = { + .pc_func = nlmsvc_proc_null, + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_void), + .pc_argzero = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "NULL", + }, + [NLMPROC_TEST] = { + .pc_func = nlmsvc_proc_test, + .pc_decode = nlmsvc_decode_testargs, + .pc_encode = nlmsvc_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", + }, + [NLMPROC_LOCK] = { + .pc_func = nlmsvc_proc_lock, + .pc_decode = nlmsvc_decode_lockargs, + .pc_encode = nlmsvc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "LOCK", + }, + [NLMPROC_CANCEL] = { + .pc_func = nlmsvc_proc_cancel, + .pc_decode = nlmsvc_decode_cancargs, + .pc_encode = nlmsvc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "CANCEL", + }, + [NLMPROC_UNLOCK] = { + .pc_func = nlmsvc_proc_unlock, + .pc_decode = nlmsvc_decode_unlockargs, + .pc_encode = nlmsvc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "UNLOCK", + }, + [NLMPROC_GRANTED] = { + .pc_func = nlmsvc_proc_granted, + .pc_decode = nlmsvc_decode_testargs, + .pc_encode = nlmsvc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "GRANTED", + }, + [NLMPROC_TEST_MSG] = { + .pc_func = nlmsvc_proc_test_msg, + .pc_decode = nlmsvc_decode_testargs, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "TEST_MSG", + }, + [NLMPROC_LOCK_MSG] = { + .pc_func = nlmsvc_proc_lock_msg, + .pc_decode = nlmsvc_decode_lockargs, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "LOCK_MSG", + }, + [NLMPROC_CANCEL_MSG] = { + .pc_func = nlmsvc_proc_cancel_msg, + .pc_decode = nlmsvc_decode_cancargs, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "CANCEL_MSG", + }, + [NLMPROC_UNLOCK_MSG] = { + .pc_func = nlmsvc_proc_unlock_msg, + .pc_decode = nlmsvc_decode_unlockargs, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "UNLOCK_MSG", + }, + [NLMPROC_GRANTED_MSG] = { + .pc_func = nlmsvc_proc_granted_msg, + .pc_decode = nlmsvc_decode_testargs, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "GRANTED_MSG", + }, + [NLMPROC_TEST_RES] = { + .pc_func = nlmsvc_proc_null, + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "TEST_RES", + }, + [NLMPROC_LOCK_RES] = { + .pc_func = nlmsvc_proc_null, + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "LOCK_RES", + }, + [NLMPROC_CANCEL_RES] = { + .pc_func = nlmsvc_proc_null, + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "CANCEL_RES", + }, + [NLMPROC_UNLOCK_RES] = { + .pc_func = nlmsvc_proc_null, + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "UNLOCK_RES", + }, + [NLMPROC_GRANTED_RES] = { + .pc_func = nlmsvc_proc_granted_res, + .pc_decode = nlmsvc_decode_res, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "GRANTED_RES", + }, + [NLMPROC_NSM_NOTIFY] = { + .pc_func = nlmsvc_proc_sm_notify, + .pc_decode = nlmsvc_decode_reboot, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_reboot), + .pc_argzero = sizeof(struct nlm_reboot), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "SM_NOTIFY", + }, + [17] = { + .pc_func = nlmsvc_proc_unused, + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_void), + .pc_argzero = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "UNUSED", + }, + [18] = { + .pc_func = nlmsvc_proc_unused, + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_void), + .pc_argzero = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "UNUSED", + }, + [19] = { + .pc_func = nlmsvc_proc_unused, + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_void), + .pc_argzero = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "UNUSED", + }, + [NLMPROC_SHARE] = { + .pc_func = nlmsvc_proc_share, + .pc_decode = nlmsvc_decode_shareargs, + .pc_encode = nlmsvc_encode_shareres, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+1, + .pc_name = "SHARE", + }, + [NLMPROC_UNSHARE] = { + .pc_func = nlmsvc_proc_unshare, + .pc_decode = nlmsvc_decode_shareargs, + .pc_encode = nlmsvc_encode_shareres, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+1, + .pc_name = "UNSHARE", + }, + [NLMPROC_NM_LOCK] = { + .pc_func = nlmsvc_proc_nm_lock, + .pc_decode = nlmsvc_decode_lockargs, + .pc_encode = nlmsvc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "NM_LOCK", + }, + [NLMPROC_FREE_ALL] = { + .pc_func = nlmsvc_proc_free_all, + .pc_decode = nlmsvc_decode_notify, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = 0, + .pc_name = "FREE_ALL", + }, }; diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index 028fc152da22..e1c4617de771 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -45,7 +45,7 @@ static inline void nlm_debug_print_fh(char *msg, struct nfs_fh *f) static inline void nlm_debug_print_file(char *msg, struct nlm_file *file) { - struct inode *inode = locks_inode(file->f_file); + struct inode *inode = nlmsvc_file_inode(file); dprintk("lockd: %s %s/%ld\n", msg, inode->i_sb->s_id, inode->i_ino); @@ -71,56 +71,75 @@ static inline unsigned int file_hash(struct nfs_fh *f) return tmp & (FILE_NRHASH - 1); } +int lock_to_openmode(struct file_lock *lock) +{ + return (lock->fl_type == F_WRLCK) ? O_WRONLY : O_RDONLY; +} + +/* + * Open the file. Note that if we're reexporting, for example, + * this could block the lockd thread for a while. + * + * We have to make sure we have the right credential to open + * the file. + */ +static __be32 nlm_do_fopen(struct svc_rqst *rqstp, + struct nlm_file *file, int mode) +{ + struct file **fp = &file->f_file[mode]; + __be32 nfserr; + + if (*fp) + return 0; + nfserr = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, mode); + if (nfserr) + dprintk("lockd: open failed (error %d)\n", nfserr); + return nfserr; +} + /* * Lookup file info. If it doesn't exist, create a file info struct * and open a (VFS) file for the given inode. - * - * FIXME: - * Note that we open the file O_RDONLY even when creating write locks. - * This is not quite right, but for now, we assume the client performs - * the proper R/W checking. */ __be32 nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, - struct nfs_fh *f) + struct nlm_lock *lock) { struct nlm_file *file; unsigned int hash; __be32 nfserr; + int mode; - nlm_debug_print_fh("nlm_lookup_file", f); + nlm_debug_print_fh("nlm_lookup_file", &lock->fh); - hash = file_hash(f); + hash = file_hash(&lock->fh); + mode = lock_to_openmode(&lock->fl); /* Lock file table */ mutex_lock(&nlm_file_mutex); hlist_for_each_entry(file, &nlm_files[hash], f_list) - if (!nfs_compare_fh(&file->f_handle, f)) + if (!nfs_compare_fh(&file->f_handle, &lock->fh)) { + mutex_lock(&file->f_mutex); + nfserr = nlm_do_fopen(rqstp, file, mode); + mutex_unlock(&file->f_mutex); goto found; - - nlm_debug_print_fh("creating file for", f); + } + nlm_debug_print_fh("creating file for", &lock->fh); nfserr = nlm_lck_denied_nolocks; file = kzalloc(sizeof(*file), GFP_KERNEL); if (!file) - goto out_unlock; + goto out_free; - memcpy(&file->f_handle, f, sizeof(struct nfs_fh)); + memcpy(&file->f_handle, &lock->fh, sizeof(struct nfs_fh)); mutex_init(&file->f_mutex); INIT_HLIST_NODE(&file->f_list); INIT_LIST_HEAD(&file->f_blocks); - /* Open the file. Note that this must not sleep for too long, else - * we would lock up lockd:-) So no NFS re-exports, folks. - * - * We have to make sure we have the right credential to open - * the file. - */ - if ((nfserr = nlmsvc_ops->fopen(rqstp, f, &file->f_file)) != 0) { - dprintk("lockd: open failed (error %d)\n", nfserr); - goto out_free; - } + nfserr = nlm_do_fopen(rqstp, file, mode); + if (nfserr) + goto out_unlock; hlist_add_head(&file->f_list, &nlm_files[hash]); @@ -128,7 +147,6 @@ found: dprintk("lockd: found file %p (count %d)\n", file, file->f_count); *result = file; file->f_count++; - nfserr = 0; out_unlock: mutex_unlock(&nlm_file_mutex); @@ -148,13 +166,37 @@ nlm_delete_file(struct nlm_file *file) nlm_debug_print_file("closing file", file); if (!hlist_unhashed(&file->f_list)) { hlist_del(&file->f_list); - nlmsvc_ops->fclose(file->f_file); + if (file->f_file[O_RDONLY]) + nlmsvc_ops->fclose(file->f_file[O_RDONLY]); + if (file->f_file[O_WRONLY]) + nlmsvc_ops->fclose(file->f_file[O_WRONLY]); kfree(file); } else { printk(KERN_WARNING "lockd: attempt to release unknown file!\n"); } } +static int nlm_unlock_files(struct nlm_file *file, fl_owner_t owner) +{ + struct file_lock lock; + + locks_init_lock(&lock); + lock.fl_type = F_UNLCK; + lock.fl_start = 0; + lock.fl_end = OFFSET_MAX; + lock.fl_owner = owner; + if (file->f_file[O_RDONLY] && + vfs_lock_file(file->f_file[O_RDONLY], F_SETLK, &lock, NULL)) + goto out_err; + if (file->f_file[O_WRONLY] && + vfs_lock_file(file->f_file[O_WRONLY], F_SETLK, &lock, NULL)) + goto out_err; + return 0; +out_err: + pr_warn("lockd: unlock failure in %s:%d\n", __FILE__, __LINE__); + return 1; +} + /* * Loop over all locks on the given file and perform the specified * action. @@ -182,17 +224,10 @@ again: lockhost = ((struct nlm_lockowner *)fl->fl_owner)->host; if (match(lockhost, host)) { - struct file_lock lock = *fl; spin_unlock(&flctx->flc_lock); - lock.fl_type = F_UNLCK; - lock.fl_start = 0; - lock.fl_end = OFFSET_MAX; - if (vfs_lock_file(file->f_file, F_SETLK, &lock, NULL) < 0) { - printk("lockd: unlock failure in %s:%d\n", - __FILE__, __LINE__); + if (nlm_unlock_files(file, fl->fl_owner)) return 1; - } goto again; } } @@ -246,6 +281,14 @@ nlm_file_inuse(struct nlm_file *file) return 0; } +static void nlm_close_files(struct nlm_file *file) +{ + if (file->f_file[O_RDONLY]) + nlmsvc_ops->fclose(file->f_file[O_RDONLY]); + if (file->f_file[O_WRONLY]) + nlmsvc_ops->fclose(file->f_file[O_WRONLY]); +} + /* * Loop over all files in the file table. */ @@ -276,7 +319,7 @@ nlm_traverse_files(void *data, nlm_host_match_fn_t match, if (list_empty(&file->f_blocks) && !file->f_locks && !file->f_shares && !file->f_count) { hlist_del(&file->f_list); - nlmsvc_ops->fclose(file->f_file); + nlm_close_files(file); kfree(file); } } @@ -410,12 +453,13 @@ nlmsvc_invalidate_all(void) nlm_traverse_files(NULL, nlmsvc_is_client, NULL); } + static int nlmsvc_match_sb(void *datap, struct nlm_file *file) { struct super_block *sb = datap; - return sb == locks_inode(file->f_file)->i_sb; + return sb == nlmsvc_file_inode(file)->i_sb; } /** diff --git a/fs/lockd/svcxdr.h b/fs/lockd/svcxdr.h new file mode 100644 index 000000000000..4f1a451da5ba --- /dev/null +++ b/fs/lockd/svcxdr.h @@ -0,0 +1,142 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Encode/decode NLM basic data types + * + * Basic NLMv3 XDR data types are not defined in an IETF standards + * document. X/Open has a description of these data types that + * is useful. See Chapter 10 of "Protocols for Interworking: + * XNFS, Version 3W". + * + * Basic NLMv4 XDR data types are defined in Appendix II.1.4 of + * RFC 1813: "NFS Version 3 Protocol Specification". + * + * Author: Chuck Lever <chuck.lever@oracle.com> + * + * Copyright (c) 2020, Oracle and/or its affiliates. + */ + +#ifndef _LOCKD_SVCXDR_H_ +#define _LOCKD_SVCXDR_H_ + +static inline bool +svcxdr_decode_stats(struct xdr_stream *xdr, __be32 *status) +{ + __be32 *p; + + p = xdr_inline_decode(xdr, XDR_UNIT); + if (!p) + return false; + *status = *p; + + return true; +} + +static inline bool +svcxdr_encode_stats(struct xdr_stream *xdr, __be32 status) +{ + __be32 *p; + + p = xdr_reserve_space(xdr, XDR_UNIT); + if (!p) + return false; + *p = status; + + return true; +} + +static inline bool +svcxdr_decode_string(struct xdr_stream *xdr, char **data, unsigned int *data_len) +{ + __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len > NLM_MAXSTRLEN) + return false; + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + *data_len = len; + *data = (char *)p; + + return true; +} + +/* + * NLM cookies are defined by specification to be a variable-length + * XDR opaque no longer than 1024 bytes. However, this implementation + * limits their length to 32 bytes, and treats zero-length cookies + * specially. + */ +static inline bool +svcxdr_decode_cookie(struct xdr_stream *xdr, struct nlm_cookie *cookie) +{ + __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len > NLM_MAXCOOKIELEN) + return false; + if (!len) + goto out_hpux; + + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + cookie->len = len; + memcpy(cookie->data, p, len); + + return true; + + /* apparently HPUX can return empty cookies */ +out_hpux: + cookie->len = 4; + memset(cookie->data, 0, 4); + return true; +} + +static inline bool +svcxdr_encode_cookie(struct xdr_stream *xdr, const struct nlm_cookie *cookie) +{ + __be32 *p; + + if (xdr_stream_encode_u32(xdr, cookie->len) < 0) + return false; + p = xdr_reserve_space(xdr, cookie->len); + if (!p) + return false; + memcpy(p, cookie->data, cookie->len); + + return true; +} + +static inline bool +svcxdr_decode_owner(struct xdr_stream *xdr, struct xdr_netobj *obj) +{ + __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len > XDR_MAX_NETOBJ) + return false; + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + obj->len = len; + obj->data = (u8 *)p; + + return true; +} + +static inline bool +svcxdr_encode_owner(struct xdr_stream *xdr, const struct xdr_netobj *obj) +{ + if (obj->len > XDR_MAX_NETOBJ) + return false; + return xdr_stream_encode_opaque(xdr, obj->data, obj->len) > 0; +} + +#endif /* _LOCKD_SVCXDR_H_ */ diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c index 982629f7b120..2fb5748dae0c 100644 --- a/fs/lockd/xdr.c +++ b/fs/lockd/xdr.c @@ -19,7 +19,7 @@ #include <uapi/linux/nfs2.h> -#define NLMDBG_FACILITY NLMDBG_XDR +#include "svcxdr.h" static inline loff_t @@ -42,311 +42,313 @@ loff_t_to_s32(loff_t offset) } /* - * XDR functions for basic NLM types + * NLM file handles are defined by specification to be a variable-length + * XDR opaque no longer than 1024 bytes. However, this implementation + * constrains their length to exactly the length of an NFSv2 file + * handle. */ -static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c) +static bool +svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) { - unsigned int len; - - len = ntohl(*p++); - - if(len==0) - { - c->len=4; - memset(c->data, 0, 4); /* hockeypux brain damage */ - } - else if(len<=NLM_MAXCOOKIELEN) - { - c->len=len; - memcpy(c->data, p, len); - p+=XDR_QUADLEN(len); - } - else - { - dprintk("lockd: bad cookie size %d (only cookies under " - "%d bytes are supported.)\n", - len, NLM_MAXCOOKIELEN); - return NULL; - } - return p; -} - -static inline __be32 * -nlm_encode_cookie(__be32 *p, struct nlm_cookie *c) -{ - *p++ = htonl(c->len); - memcpy(p, c->data, c->len); - p+=XDR_QUADLEN(c->len); - return p; -} - -static __be32 * -nlm_decode_fh(__be32 *p, struct nfs_fh *f) -{ - unsigned int len; - - if ((len = ntohl(*p++)) != NFS2_FHSIZE) { - dprintk("lockd: bad fhandle size %d (should be %d)\n", - len, NFS2_FHSIZE); - return NULL; - } - f->size = NFS2_FHSIZE; - memset(f->data, 0, sizeof(f->data)); - memcpy(f->data, p, NFS2_FHSIZE); - return p + XDR_QUADLEN(NFS2_FHSIZE); -} - -/* - * Encode and decode owner handle - */ -static inline __be32 * -nlm_decode_oh(__be32 *p, struct xdr_netobj *oh) -{ - return xdr_decode_netobj(p, oh); -} - -static inline __be32 * -nlm_encode_oh(__be32 *p, struct xdr_netobj *oh) -{ - return xdr_encode_netobj(p, oh); + __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len != NFS2_FHSIZE) + return false; + + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + fh->size = NFS2_FHSIZE; + memcpy(fh->data, p, len); + memset(fh->data + NFS2_FHSIZE, 0, sizeof(fh->data) - NFS2_FHSIZE); + + return true; } -static __be32 * -nlm_decode_lock(__be32 *p, struct nlm_lock *lock) +static bool +svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) { - struct file_lock *fl = &lock->fl; - s32 start, len, end; - - if (!(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, - NLM_MAXSTRLEN)) - || !(p = nlm_decode_fh(p, &lock->fh)) - || !(p = nlm_decode_oh(p, &lock->oh))) - return NULL; - lock->svid = ntohl(*p++); + struct file_lock *fl = &lock->fl; + s32 start, len, end; + + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return false; + if (!svcxdr_decode_fhandle(xdr, &lock->fh)) + return false; + if (!svcxdr_decode_owner(xdr, &lock->oh)) + return false; + if (xdr_stream_decode_u32(xdr, &lock->svid) < 0) + return false; + if (xdr_stream_decode_u32(xdr, &start) < 0) + return false; + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; locks_init_lock(fl); fl->fl_flags = FL_POSIX; - fl->fl_type = F_RDLCK; /* as good as anything else */ - start = ntohl(*p++); - len = ntohl(*p++); + fl->fl_type = F_RDLCK; end = start + len - 1; - fl->fl_start = s32_to_loff_t(start); - if (len == 0 || end < 0) fl->fl_end = OFFSET_MAX; else fl->fl_end = s32_to_loff_t(end); - return p; + + return true; } -/* - * Encode result of a TEST/TEST_MSG call - */ -static __be32 * -nlm_encode_testres(__be32 *p, struct nlm_res *resp) +static bool +svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock) { - s32 start, len; - - if (!(p = nlm_encode_cookie(p, &resp->cookie))) - return NULL; - *p++ = resp->status; - - if (resp->status == nlm_lck_denied) { - struct file_lock *fl = &resp->lock.fl; - - *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one; - *p++ = htonl(resp->lock.svid); - - /* Encode owner handle. */ - if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) - return NULL; + const struct file_lock *fl = &lock->fl; + s32 start, len; + + /* exclusive */ + if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0) + return false; + if (xdr_stream_encode_u32(xdr, lock->svid) < 0) + return false; + if (!svcxdr_encode_owner(xdr, &lock->oh)) + return false; + start = loff_t_to_s32(fl->fl_start); + if (fl->fl_end == OFFSET_MAX) + len = 0; + else + len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); + if (xdr_stream_encode_u32(xdr, start) < 0) + return false; + if (xdr_stream_encode_u32(xdr, len) < 0) + return false; - start = loff_t_to_s32(fl->fl_start); - if (fl->fl_end == OFFSET_MAX) - len = 0; - else - len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); + return true; +} - *p++ = htonl(start); - *p++ = htonl(len); +static bool +svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp) +{ + if (!svcxdr_encode_stats(xdr, resp->status)) + return false; + switch (resp->status) { + case nlm_lck_denied: + if (!svcxdr_encode_holder(xdr, &resp->lock)) + return false; } - return p; + return true; } /* - * First, the server side XDR functions + * Decode Call arguments */ -int -nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; - - if (!(p = nlm_decode_cookie(p, &argp->cookie))) - return 0; - - exclusive = ntohl(*p++); - if (!(p = nlm_decode_lock(p, &argp->lock))) - return 0; - if (exclusive) - argp->lock.fl.fl_type = F_WRLCK; - return xdr_argsize_check(rqstp, p); +bool +nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ + return true; } -int -nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) +bool +nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) { - struct nlm_res *resp = rqstp->rq_resp; + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return false; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return false; + if (!svcxdr_decode_lock(xdr, &argp->lock)) + return false; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; - if (!(p = nlm_encode_testres(p, resp))) - return 0; - return xdr_ressize_check(rqstp, p); + return true; } -int -nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) +bool +nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) { struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; - - if (!(p = nlm_decode_cookie(p, &argp->cookie))) - return 0; - argp->block = ntohl(*p++); - exclusive = ntohl(*p++); - if (!(p = nlm_decode_lock(p, &argp->lock))) - return 0; + u32 exclusive; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return false; + if (xdr_stream_decode_bool(xdr, &argp->block) < 0) + return false; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return false; + if (!svcxdr_decode_lock(xdr, &argp->lock)) + return false; if (exclusive) argp->lock.fl.fl_type = F_WRLCK; - argp->reclaim = ntohl(*p++); - argp->state = ntohl(*p++); + if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0) + return false; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return false; argp->monitor = 1; /* monitor client by default */ - return xdr_argsize_check(rqstp, p); + return true; } -int -nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) +bool +nlmsvc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) { struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; - - if (!(p = nlm_decode_cookie(p, &argp->cookie))) - return 0; - argp->block = ntohl(*p++); - exclusive = ntohl(*p++); - if (!(p = nlm_decode_lock(p, &argp->lock))) - return 0; + u32 exclusive; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return false; + if (xdr_stream_decode_bool(xdr, &argp->block) < 0) + return false; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return false; + if (!svcxdr_decode_lock(xdr, &argp->lock)) + return false; if (exclusive) argp->lock.fl.fl_type = F_WRLCK; - return xdr_argsize_check(rqstp, p); + + return true; } -int -nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) +bool +nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) { struct nlm_args *argp = rqstp->rq_argp; - if (!(p = nlm_decode_cookie(p, &argp->cookie)) - || !(p = nlm_decode_lock(p, &argp->lock))) - return 0; + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return false; + if (!svcxdr_decode_lock(xdr, &argp->lock)) + return false; argp->lock.fl.fl_type = F_UNLCK; - return xdr_argsize_check(rqstp, p); + + return true; } -int -nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) +bool +nlmsvc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) { - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_lock *lock = &argp->lock; + struct nlm_res *resp = rqstp->rq_argp; - memset(lock, 0, sizeof(*lock)); - locks_init_lock(&lock->fl); - lock->svid = ~(u32) 0; - - if (!(p = nlm_decode_cookie(p, &argp->cookie)) - || !(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, NLM_MAXSTRLEN)) - || !(p = nlm_decode_fh(p, &lock->fh)) - || !(p = nlm_decode_oh(p, &lock->oh))) - return 0; - argp->fsm_mode = ntohl(*p++); - argp->fsm_access = ntohl(*p++); - return xdr_argsize_check(rqstp, p); + if (!svcxdr_decode_cookie(xdr, &resp->cookie)) + return false; + if (!svcxdr_decode_stats(xdr, &resp->status)) + return false; + + return true; } -int -nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) +bool +nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr) { - struct nlm_res *resp = rqstp->rq_resp; + struct nlm_reboot *argp = rqstp->rq_argp; + __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len > SM_MAXSTRLEN) + return false; + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + argp->len = len; + argp->mon = (char *)p; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return false; + p = xdr_inline_decode(xdr, SM_PRIV_SIZE); + if (!p) + return false; + memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); - if (!(p = nlm_encode_cookie(p, &resp->cookie))) - return 0; - *p++ = resp->status; - *p++ = xdr_zero; /* sequence argument */ - return xdr_ressize_check(rqstp, p); + return true; } -int -nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p) +bool +nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) { - struct nlm_res *resp = rqstp->rq_resp; + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; - if (!(p = nlm_encode_cookie(p, &resp->cookie))) - return 0; - *p++ = resp->status; - return xdr_ressize_check(rqstp, p); + memset(lock, 0, sizeof(*lock)); + locks_init_lock(&lock->fl); + lock->svid = ~(u32)0; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return false; + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return false; + if (!svcxdr_decode_fhandle(xdr, &lock->fh)) + return false; + if (!svcxdr_decode_owner(xdr, &lock->oh)) + return false; + /* XXX: Range checks are missing in the original code */ + if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0) + return false; + if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0) + return false; + + return true; } -int -nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p) +bool +nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr) { struct nlm_args *argp = rqstp->rq_argp; struct nlm_lock *lock = &argp->lock; - if (!(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, NLM_MAXSTRLEN))) - return 0; - argp->state = ntohl(*p++); - return xdr_argsize_check(rqstp, p); + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return false; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return false; + + return true; } -int -nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_reboot *argp = rqstp->rq_argp; - if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) - return 0; - argp->state = ntohl(*p++); - memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); - p += XDR_QUADLEN(SM_PRIV_SIZE); - return xdr_argsize_check(rqstp, p); +/* + * Encode Reply results + */ + +bool +nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ + return true; } -int -nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p) +bool +nlmsvc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr) { - struct nlm_res *resp = rqstp->rq_argp; + struct nlm_res *resp = rqstp->rq_resp; - if (!(p = nlm_decode_cookie(p, &resp->cookie))) - return 0; - resp->status = *p++; - return xdr_argsize_check(rqstp, p); + return svcxdr_encode_cookie(xdr, &resp->cookie) && + svcxdr_encode_testrply(xdr, resp); } -int -nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p) +bool +nlmsvc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) { - return xdr_argsize_check(rqstp, p); + struct nlm_res *resp = rqstp->rq_resp; + + return svcxdr_encode_cookie(xdr, &resp->cookie) && + svcxdr_encode_stats(xdr, resp->status); } -int -nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) +bool +nlmsvc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr) { - return xdr_ressize_check(rqstp, p); + struct nlm_res *resp = rqstp->rq_resp; + + if (!svcxdr_encode_cookie(xdr, &resp->cookie)) + return false; + if (!svcxdr_encode_stats(xdr, resp->status)) + return false; + /* sequence */ + if (xdr_stream_encode_u32(xdr, 0) < 0) + return false; + + return true; } diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c index 5fa9f48a9dba..712fdfeb8ef0 100644 --- a/fs/lockd/xdr4.c +++ b/fs/lockd/xdr4.c @@ -18,14 +18,7 @@ #include <linux/sunrpc/stats.h> #include <linux/lockd/lockd.h> -#define NLMDBG_FACILITY NLMDBG_XDR - -static inline loff_t -s64_to_loff_t(__s64 offset) -{ - return (loff_t)offset; -} - +#include "svcxdr.h" static inline s64 loff_t_to_s64(loff_t offset) @@ -41,309 +34,305 @@ loff_t_to_s64(loff_t offset) } /* - * XDR functions for basic NLM types - */ -static __be32 * -nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c) -{ - unsigned int len; - - len = ntohl(*p++); - - if(len==0) - { - c->len=4; - memset(c->data, 0, 4); /* hockeypux brain damage */ - } - else if(len<=NLM_MAXCOOKIELEN) - { - c->len=len; - memcpy(c->data, p, len); - p+=XDR_QUADLEN(len); - } - else - { - dprintk("lockd: bad cookie size %d (only cookies under " - "%d bytes are supported.)\n", - len, NLM_MAXCOOKIELEN); - return NULL; - } - return p; -} - -static __be32 * -nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c) -{ - *p++ = htonl(c->len); - memcpy(p, c->data, c->len); - p+=XDR_QUADLEN(c->len); - return p; -} - -static __be32 * -nlm4_decode_fh(__be32 *p, struct nfs_fh *f) -{ - memset(f->data, 0, sizeof(f->data)); - f->size = ntohl(*p++); - if (f->size > NFS_MAXFHSIZE) { - dprintk("lockd: bad fhandle size %d (should be <=%d)\n", - f->size, NFS_MAXFHSIZE); - return NULL; - } - memcpy(f->data, p, f->size); - return p + XDR_QUADLEN(f->size); -} - -/* - * Encode and decode owner handle + * NLM file handles are defined by specification to be a variable-length + * XDR opaque no longer than 1024 bytes. However, this implementation + * limits their length to the size of an NFSv3 file handle. */ -static __be32 * -nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh) +static bool +svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) { - return xdr_decode_netobj(p, oh); + __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len > NFS_MAXFHSIZE) + return false; + + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + fh->size = len; + memcpy(fh->data, p, len); + memset(fh->data + len, 0, sizeof(fh->data) - len); + + return true; } -static __be32 * -nlm4_decode_lock(__be32 *p, struct nlm_lock *lock) +static bool +svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) { - struct file_lock *fl = &lock->fl; - __u64 len, start; - __s64 end; - - if (!(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, NLM_MAXSTRLEN)) - || !(p = nlm4_decode_fh(p, &lock->fh)) - || !(p = nlm4_decode_oh(p, &lock->oh))) - return NULL; - lock->svid = ntohl(*p++); + struct file_lock *fl = &lock->fl; + + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return false; + if (!svcxdr_decode_fhandle(xdr, &lock->fh)) + return false; + if (!svcxdr_decode_owner(xdr, &lock->oh)) + return false; + if (xdr_stream_decode_u32(xdr, &lock->svid) < 0) + return false; + if (xdr_stream_decode_u64(xdr, &lock->lock_start) < 0) + return false; + if (xdr_stream_decode_u64(xdr, &lock->lock_len) < 0) + return false; locks_init_lock(fl); fl->fl_flags = FL_POSIX; - fl->fl_type = F_RDLCK; /* as good as anything else */ - p = xdr_decode_hyper(p, &start); - p = xdr_decode_hyper(p, &len); - end = start + len - 1; + fl->fl_type = F_RDLCK; - fl->fl_start = s64_to_loff_t(start); + return true; +} - if (len == 0 || end < 0) - fl->fl_end = OFFSET_MAX; +static bool +svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock) +{ + const struct file_lock *fl = &lock->fl; + s64 start, len; + + /* exclusive */ + if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0) + return false; + if (xdr_stream_encode_u32(xdr, lock->svid) < 0) + return false; + if (!svcxdr_encode_owner(xdr, &lock->oh)) + return false; + start = loff_t_to_s64(fl->fl_start); + if (fl->fl_end == OFFSET_MAX) + len = 0; else - fl->fl_end = s64_to_loff_t(end); - return p; + len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); + if (xdr_stream_encode_u64(xdr, start) < 0) + return false; + if (xdr_stream_encode_u64(xdr, len) < 0) + return false; + + return true; } -/* - * Encode result of a TEST/TEST_MSG call - */ -static __be32 * -nlm4_encode_testres(__be32 *p, struct nlm_res *resp) +static bool +svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp) { - s64 start, len; - - dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp); - if (!(p = nlm4_encode_cookie(p, &resp->cookie))) - return NULL; - *p++ = resp->status; - - if (resp->status == nlm_lck_denied) { - struct file_lock *fl = &resp->lock.fl; - - *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one; - *p++ = htonl(resp->lock.svid); - - /* Encode owner handle. */ - if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) - return NULL; - - start = loff_t_to_s64(fl->fl_start); - if (fl->fl_end == OFFSET_MAX) - len = 0; - else - len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); - - p = xdr_encode_hyper(p, start); - p = xdr_encode_hyper(p, len); - dprintk("xdr: encode_testres (status %u pid %d type %d start %Ld end %Ld)\n", - resp->status, (int)resp->lock.svid, fl->fl_type, - (long long)fl->fl_start, (long long)fl->fl_end); + if (!svcxdr_encode_stats(xdr, resp->status)) + return false; + switch (resp->status) { + case nlm_lck_denied: + if (!svcxdr_encode_holder(xdr, &resp->lock)) + return false; } - dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp); - return p; + return true; } /* - * First, the server side XDR functions + * Decode Call arguments */ -int -nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; - - if (!(p = nlm4_decode_cookie(p, &argp->cookie))) - return 0; - - exclusive = ntohl(*p++); - if (!(p = nlm4_decode_lock(p, &argp->lock))) - return 0; - if (exclusive) - argp->lock.fl.fl_type = F_WRLCK; - return xdr_argsize_check(rqstp, p); +bool +nlm4svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ + return true; } -int -nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) +bool +nlm4svc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) { - struct nlm_res *resp = rqstp->rq_resp; + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return false; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return false; + if (!svcxdr_decode_lock(xdr, &argp->lock)) + return false; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; - if (!(p = nlm4_encode_testres(p, resp))) - return 0; - return xdr_ressize_check(rqstp, p); + return true; } -int -nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) +bool +nlm4svc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) { struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; - - if (!(p = nlm4_decode_cookie(p, &argp->cookie))) - return 0; - argp->block = ntohl(*p++); - exclusive = ntohl(*p++); - if (!(p = nlm4_decode_lock(p, &argp->lock))) - return 0; + u32 exclusive; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return false; + if (xdr_stream_decode_bool(xdr, &argp->block) < 0) + return false; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return false; + if (!svcxdr_decode_lock(xdr, &argp->lock)) + return false; if (exclusive) argp->lock.fl.fl_type = F_WRLCK; - argp->reclaim = ntohl(*p++); - argp->state = ntohl(*p++); + if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0) + return false; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return false; argp->monitor = 1; /* monitor client by default */ - return xdr_argsize_check(rqstp, p); + return true; } -int -nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) +bool +nlm4svc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) { struct nlm_args *argp = rqstp->rq_argp; - u32 exclusive; - - if (!(p = nlm4_decode_cookie(p, &argp->cookie))) - return 0; - argp->block = ntohl(*p++); - exclusive = ntohl(*p++); - if (!(p = nlm4_decode_lock(p, &argp->lock))) - return 0; + u32 exclusive; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return false; + if (xdr_stream_decode_bool(xdr, &argp->block) < 0) + return false; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) + return false; + if (!svcxdr_decode_lock(xdr, &argp->lock)) + return false; if (exclusive) argp->lock.fl.fl_type = F_WRLCK; - return xdr_argsize_check(rqstp, p); + + return true; } -int -nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) +bool +nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) { struct nlm_args *argp = rqstp->rq_argp; - if (!(p = nlm4_decode_cookie(p, &argp->cookie)) - || !(p = nlm4_decode_lock(p, &argp->lock))) - return 0; + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return false; + if (!svcxdr_decode_lock(xdr, &argp->lock)) + return false; argp->lock.fl.fl_type = F_UNLCK; - return xdr_argsize_check(rqstp, p); + + return true; } -int -nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) +bool +nlm4svc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) { - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_lock *lock = &argp->lock; + struct nlm_res *resp = rqstp->rq_argp; - memset(lock, 0, sizeof(*lock)); - locks_init_lock(&lock->fl); - lock->svid = ~(u32) 0; - - if (!(p = nlm4_decode_cookie(p, &argp->cookie)) - || !(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, NLM_MAXSTRLEN)) - || !(p = nlm4_decode_fh(p, &lock->fh)) - || !(p = nlm4_decode_oh(p, &lock->oh))) - return 0; - argp->fsm_mode = ntohl(*p++); - argp->fsm_access = ntohl(*p++); - return xdr_argsize_check(rqstp, p); + if (!svcxdr_decode_cookie(xdr, &resp->cookie)) + return false; + if (!svcxdr_decode_stats(xdr, &resp->status)) + return false; + + return true; } -int -nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) +bool +nlm4svc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr) { - struct nlm_res *resp = rqstp->rq_resp; + struct nlm_reboot *argp = rqstp->rq_argp; + __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) + return false; + if (len > SM_MAXSTRLEN) + return false; + p = xdr_inline_decode(xdr, len); + if (!p) + return false; + argp->len = len; + argp->mon = (char *)p; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return false; + p = xdr_inline_decode(xdr, SM_PRIV_SIZE); + if (!p) + return false; + memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); - if (!(p = nlm4_encode_cookie(p, &resp->cookie))) - return 0; - *p++ = resp->status; - *p++ = xdr_zero; /* sequence argument */ - return xdr_ressize_check(rqstp, p); + return true; } -int -nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p) +bool +nlm4svc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) { - struct nlm_res *resp = rqstp->rq_resp; + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; - if (!(p = nlm4_encode_cookie(p, &resp->cookie))) - return 0; - *p++ = resp->status; - return xdr_ressize_check(rqstp, p); + memset(lock, 0, sizeof(*lock)); + locks_init_lock(&lock->fl); + lock->svid = ~(u32)0; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return false; + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return false; + if (!svcxdr_decode_fhandle(xdr, &lock->fh)) + return false; + if (!svcxdr_decode_owner(xdr, &lock->oh)) + return false; + /* XXX: Range checks are missing in the original code */ + if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0) + return false; + if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0) + return false; + + return true; } -int -nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p) +bool +nlm4svc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr) { struct nlm_args *argp = rqstp->rq_argp; struct nlm_lock *lock = &argp->lock; - if (!(p = xdr_decode_string_inplace(p, &lock->caller, - &lock->len, NLM_MAXSTRLEN))) - return 0; - argp->state = ntohl(*p++); - return xdr_argsize_check(rqstp, p); + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return false; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) + return false; + + return true; } -int -nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) -{ - struct nlm_reboot *argp = rqstp->rq_argp; - if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) - return 0; - argp->state = ntohl(*p++); - memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); - p += XDR_QUADLEN(SM_PRIV_SIZE); - return xdr_argsize_check(rqstp, p); +/* + * Encode Reply results + */ + +bool +nlm4svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ + return true; } -int -nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p) +bool +nlm4svc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr) { - struct nlm_res *resp = rqstp->rq_argp; + struct nlm_res *resp = rqstp->rq_resp; - if (!(p = nlm4_decode_cookie(p, &resp->cookie))) - return 0; - resp->status = *p++; - return xdr_argsize_check(rqstp, p); + return svcxdr_encode_cookie(xdr, &resp->cookie) && + svcxdr_encode_testrply(xdr, resp); } -int -nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p) +bool +nlm4svc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) { - return xdr_argsize_check(rqstp, p); + struct nlm_res *resp = rqstp->rq_resp; + + return svcxdr_encode_cookie(xdr, &resp->cookie) && + svcxdr_encode_stats(xdr, resp->status); } -int -nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) +bool +nlm4svc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr) { - return xdr_ressize_check(rqstp, p); + struct nlm_res *resp = rqstp->rq_resp; + + if (!svcxdr_encode_cookie(xdr, &resp->cookie)) + return false; + if (!svcxdr_encode_stats(xdr, resp->status)) + return false; + /* sequence */ + if (xdr_stream_encode_u32(xdr, 0) < 0) + return false; + + return true; } |