diff options
Diffstat (limited to 'fs/lockd')
| -rw-r--r-- | fs/lockd/Makefile | 19 | ||||
| -rw-r--r-- | fs/lockd/clnt4xdr.c | 42 | ||||
| -rw-r--r-- | fs/lockd/clntlock.c | 2 | ||||
| -rw-r--r-- | fs/lockd/clntproc.c | 17 | ||||
| -rw-r--r-- | fs/lockd/clntxdr.c | 44 | ||||
| -rw-r--r-- | fs/lockd/host.c | 4 | ||||
| -rw-r--r-- | fs/lockd/lockd.h | 67 | ||||
| -rw-r--r-- | fs/lockd/mon.c | 2 | ||||
| -rw-r--r-- | fs/lockd/nlm3xdr_gen.c | 686 | ||||
| -rw-r--r-- | fs/lockd/nlm3xdr_gen.h | 30 | ||||
| -rw-r--r-- | fs/lockd/nlm4xdr_gen.c | 75 | ||||
| -rw-r--r-- | fs/lockd/nlm4xdr_gen.h | 4 | ||||
| -rw-r--r-- | fs/lockd/share.h | 12 | ||||
| -rw-r--r-- | fs/lockd/svc.c | 4 | ||||
| -rw-r--r-- | fs/lockd/svc4proc.c | 136 | ||||
| -rw-r--r-- | fs/lockd/svclock.c | 80 | ||||
| -rw-r--r-- | fs/lockd/svcproc.c | 1727 | ||||
| -rw-r--r-- | fs/lockd/svcshare.c | 44 | ||||
| -rw-r--r-- | fs/lockd/svcsubs.c | 141 | ||||
| -rw-r--r-- | fs/lockd/svcxdr.h | 142 | ||||
| -rw-r--r-- | fs/lockd/trace.h | 16 | ||||
| -rw-r--r-- | fs/lockd/xdr.c | 354 | ||||
| -rw-r--r-- | fs/lockd/xdr.h | 39 |
23 files changed, 2311 insertions, 1376 deletions
diff --git a/fs/lockd/Makefile b/fs/lockd/Makefile index 808f0f2a7be1..3f9569d3ba0e 100644 --- a/fs/lockd/Makefile +++ b/fs/lockd/Makefile @@ -8,7 +8,8 @@ ccflags-y += -I$(src) # needed for trace events obj-$(CONFIG_LOCKD) += lockd.o lockd-y := clntlock.o clntproc.o clntxdr.o host.o svc.o svclock.o \ - svcshare.o svcproc.o svcsubs.o mon.o trace.o xdr.o netlink.o + svcshare.o svcproc.o svcsubs.o mon.o trace.o netlink.o \ + nlm3xdr_gen.o lockd-$(CONFIG_LOCKD_V4) += clnt4xdr.o svc4proc.o nlm4xdr_gen.o lockd-$(CONFIG_PROC_FS) += procfs.o @@ -25,17 +26,27 @@ lockd-$(CONFIG_PROC_FS) += procfs.o XDRGEN = ../../tools/net/sunrpc/xdrgen/xdrgen -XDRGEN_DEFINITIONS = ../../include/linux/sunrpc/xdrgen/nlm4.h -XDRGEN_DECLARATIONS = nlm4xdr_gen.h -XDRGEN_SOURCE = nlm4xdr_gen.c +XDRGEN_DEFINITIONS = ../../include/linux/sunrpc/xdrgen/nlm4.h \ + ../../include/linux/sunrpc/xdrgen/nlm3.h +XDRGEN_DECLARATIONS = nlm4xdr_gen.h nlm3xdr_gen.h +XDRGEN_SOURCE = nlm4xdr_gen.c nlm3xdr_gen.c xdrgen: $(XDRGEN_DEFINITIONS) $(XDRGEN_DECLARATIONS) $(XDRGEN_SOURCE) ../../include/linux/sunrpc/xdrgen/nlm4.h: ../../Documentation/sunrpc/xdr/nlm4.x $(XDRGEN) definitions $< > $@ +../../include/linux/sunrpc/xdrgen/nlm3.h: ../../Documentation/sunrpc/xdr/nlm3.x + $(XDRGEN) definitions $< > $@ + nlm4xdr_gen.h: ../../Documentation/sunrpc/xdr/nlm4.x $(XDRGEN) declarations $< > $@ +nlm3xdr_gen.h: ../../Documentation/sunrpc/xdr/nlm3.x + $(XDRGEN) declarations $< > $@ + nlm4xdr_gen.c: ../../Documentation/sunrpc/xdr/nlm4.x $(XDRGEN) source --peer server $< > $@ + +nlm3xdr_gen.c: ../../Documentation/sunrpc/xdr/nlm3.x + $(XDRGEN) source --peer server $< > $@ diff --git a/fs/lockd/clnt4xdr.c b/fs/lockd/clnt4xdr.c index 2058733eacf8..96a4a1e6a6b6 100644 --- a/fs/lockd/clnt4xdr.c +++ b/fs/lockd/clnt4xdr.c @@ -63,7 +63,7 @@ static s64 loff_t_to_s64(loff_t offset) return res; } -static void nlm4_compute_offsets(const struct nlm_lock *lock, +static void nlm4_compute_offsets(const struct lockd_lock *lock, u64 *l_offset, u64 *l_len) { const struct file_lock *fl = &lock->fl; @@ -132,13 +132,13 @@ static int decode_netobj(struct xdr_stream *xdr, * netobj cookie; */ static void encode_cookie(struct xdr_stream *xdr, - const struct nlm_cookie *cookie) + const struct lockd_cookie *cookie) { encode_netobj(xdr, (u8 *)&cookie->data, cookie->len); } static int decode_cookie(struct xdr_stream *xdr, - struct nlm_cookie *cookie) + struct lockd_cookie *cookie) { u32 length; __be32 *p; @@ -238,9 +238,9 @@ out_overflow: * }; */ static void encode_nlm4_holder(struct xdr_stream *xdr, - const struct nlm_res *result) + const struct lockd_res *result) { - const struct nlm_lock *lock = &result->lock; + const struct lockd_lock *lock = &result->lock; u64 l_offset, l_len; __be32 *p; @@ -254,9 +254,9 @@ static void encode_nlm4_holder(struct xdr_stream *xdr, xdr_encode_hyper(p, l_len); } -static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result) +static int decode_nlm4_holder(struct xdr_stream *xdr, struct lockd_res *result) { - struct nlm_lock *lock = &result->lock; + struct lockd_lock *lock = &result->lock; struct file_lock *fl = &lock->fl; u64 l_offset, l_len; u32 exclusive; @@ -317,7 +317,7 @@ static void encode_caller_name(struct xdr_stream *xdr, const char *name) * }; */ static void encode_nlm4_lock(struct xdr_stream *xdr, - const struct nlm_lock *lock) + const struct lockd_lock *lock) { u64 l_offset, l_len; __be32 *p; @@ -354,8 +354,8 @@ static void nlm4_xdr_enc_testargs(struct rpc_rqst *req, struct xdr_stream *xdr, const void *data) { - const struct nlm_args *args = data; - const struct nlm_lock *lock = &args->lock; + const struct lockd_args *args = data; + const struct lockd_lock *lock = &args->lock; encode_cookie(xdr, &args->cookie); encode_bool(xdr, lock->fl.c.flc_type == F_WRLCK); @@ -376,8 +376,8 @@ static void nlm4_xdr_enc_lockargs(struct rpc_rqst *req, struct xdr_stream *xdr, const void *data) { - const struct nlm_args *args = data; - const struct nlm_lock *lock = &args->lock; + const struct lockd_args *args = data; + const struct lockd_lock *lock = &args->lock; encode_cookie(xdr, &args->cookie); encode_bool(xdr, args->block); @@ -399,8 +399,8 @@ static void nlm4_xdr_enc_cancargs(struct rpc_rqst *req, struct xdr_stream *xdr, const void *data) { - const struct nlm_args *args = data; - const struct nlm_lock *lock = &args->lock; + const struct lockd_args *args = data; + const struct lockd_lock *lock = &args->lock; encode_cookie(xdr, &args->cookie); encode_bool(xdr, args->block); @@ -418,8 +418,8 @@ static void nlm4_xdr_enc_unlockargs(struct rpc_rqst *req, struct xdr_stream *xdr, const void *data) { - const struct nlm_args *args = data; - const struct nlm_lock *lock = &args->lock; + const struct lockd_args *args = data; + const struct lockd_lock *lock = &args->lock; encode_cookie(xdr, &args->cookie); encode_nlm4_lock(xdr, lock); @@ -435,7 +435,7 @@ static void nlm4_xdr_enc_res(struct rpc_rqst *req, struct xdr_stream *xdr, const void *data) { - const struct nlm_res *result = data; + const struct lockd_res *result = data; encode_cookie(xdr, &result->cookie); encode_nlm4_stat(xdr, result->status); @@ -458,7 +458,7 @@ static void nlm4_xdr_enc_testres(struct rpc_rqst *req, struct xdr_stream *xdr, const void *data) { - const struct nlm_res *result = data; + const struct lockd_res *result = data; encode_cookie(xdr, &result->cookie); encode_nlm4_stat(xdr, result->status); @@ -489,7 +489,7 @@ static void nlm4_xdr_enc_testres(struct rpc_rqst *req, * }; */ static int decode_nlm4_testrply(struct xdr_stream *xdr, - struct nlm_res *result) + struct lockd_res *result) { int error; @@ -506,7 +506,7 @@ static int nlm4_xdr_dec_testres(struct rpc_rqst *req, struct xdr_stream *xdr, void *data) { - struct nlm_res *result = data; + struct lockd_res *result = data; int error; error = decode_cookie(xdr, &result->cookie); @@ -527,7 +527,7 @@ static int nlm4_xdr_dec_res(struct rpc_rqst *req, struct xdr_stream *xdr, void *data) { - struct nlm_res *result = data; + struct lockd_res *result = data; int error; error = decode_cookie(xdr, &result->cookie); diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c index 8fa30c42c92a..f797cc99f94d 100644 --- a/fs/lockd/clntlock.c +++ b/fs/lockd/clntlock.c @@ -158,7 +158,7 @@ int nlmclnt_wait(struct nlm_wait *block, struct nlm_rqst *req, long timeout) /* * The server lockd has called us back to tell us the lock was granted */ -__be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock) +__be32 nlmclnt_grant(const struct sockaddr *addr, const struct lockd_lock *lock) { const struct file_lock *fl = &lock->fl; const struct nfs_fh *fh = &lock->fh; diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 7f211008a5d2..f8018bfe9c64 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -42,7 +42,7 @@ static const struct rpc_call_ops nlmclnt_cancel_ops; */ static atomic_t nlm_cookie = ATOMIC_INIT(0x1234); -void nlmclnt_next_cookie(struct nlm_cookie *c) +void nlmclnt_next_cookie(struct lockd_cookie *c) { u32 cookie = atomic_inc_return(&nlm_cookie); @@ -128,8 +128,8 @@ static struct nlm_lockowner *nlmclnt_find_lockowner(struct nlm_host *host, fl_ow */ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) { - struct nlm_args *argp = &req->a_args; - struct nlm_lock *lock = &argp->lock; + struct lockd_args *argp = &req->a_args; + struct lockd_lock *lock = &argp->lock; char *nodename = req->a_host->h_rpcclnt->cl_nodename; nlmclnt_next_cookie(&argp->cookie); @@ -266,8 +266,8 @@ nlmclnt_call(const struct cred *cred, struct nlm_rqst *req, u32 proc) { struct nlm_host *host = req->a_host; struct rpc_clnt *clnt; - struct nlm_args *argp = &req->a_args; - struct nlm_res *resp = &req->a_res; + struct lockd_args *argp = &req->a_args; + struct lockd_res *resp = &req->a_res; struct rpc_message msg = { .rpc_argp = argp, .rpc_resp = resp, @@ -487,9 +487,12 @@ static const struct file_lock_operations nlmclnt_lock_ops = { static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host) { fl->fl_u.nfs_fl.state = 0; + fl->fl_ops = NULL; fl->fl_u.nfs_fl.owner = nlmclnt_find_lockowner(host, fl->c.flc_owner); INIT_LIST_HEAD(&fl->fl_u.nfs_fl.list); + if (!fl->fl_u.nfs_fl.owner) + return; fl->fl_ops = &nlmclnt_lock_ops; } @@ -523,7 +526,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) { const struct cred *cred = nfs_file_cred(fl->c.flc_file); struct nlm_host *host = req->a_host; - struct nlm_res *resp = &req->a_res; + struct lockd_res *resp = &req->a_res; struct nlm_wait block; unsigned char flags = fl->c.flc_flags; unsigned char type; @@ -686,7 +689,7 @@ static int nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) { struct nlm_host *host = req->a_host; - struct nlm_res *resp = &req->a_res; + struct lockd_res *resp = &req->a_res; int status; unsigned char flags = fl->c.flc_flags; diff --git a/fs/lockd/clntxdr.c b/fs/lockd/clntxdr.c index 65555f5224b1..3789ecb0b984 100644 --- a/fs/lockd/clntxdr.c +++ b/fs/lockd/clntxdr.c @@ -60,7 +60,7 @@ static s32 loff_t_to_s32(loff_t offset) return res; } -static void nlm_compute_offsets(const struct nlm_lock *lock, +static void nlm_compute_offsets(const struct lockd_lock *lock, u32 *l_offset, u32 *l_len) { const struct file_lock *fl = &lock->fl; @@ -130,13 +130,13 @@ static int decode_netobj(struct xdr_stream *xdr, * netobj cookie; */ static void encode_cookie(struct xdr_stream *xdr, - const struct nlm_cookie *cookie) + const struct lockd_cookie *cookie) { encode_netobj(xdr, (u8 *)&cookie->data, cookie->len); } static int decode_cookie(struct xdr_stream *xdr, - struct nlm_cookie *cookie) + struct lockd_cookie *cookie) { u32 length; __be32 *p; @@ -234,9 +234,9 @@ out_overflow: * }; */ static void encode_nlm_holder(struct xdr_stream *xdr, - const struct nlm_res *result) + const struct lockd_res *result) { - const struct nlm_lock *lock = &result->lock; + const struct lockd_lock *lock = &result->lock; u32 l_offset, l_len; __be32 *p; @@ -250,9 +250,9 @@ static void encode_nlm_holder(struct xdr_stream *xdr, *p = cpu_to_be32(l_len); } -static int decode_nlm_holder(struct xdr_stream *xdr, struct nlm_res *result) +static int decode_nlm_holder(struct xdr_stream *xdr, struct lockd_res *result) { - struct nlm_lock *lock = &result->lock; + struct lockd_lock *lock = &result->lock; struct file_lock *fl = &lock->fl; u32 exclusive, l_offset, l_len; int error; @@ -319,7 +319,7 @@ static void encode_caller_name(struct xdr_stream *xdr, const char *name) * }; */ static void encode_nlm_lock(struct xdr_stream *xdr, - const struct nlm_lock *lock) + const struct lockd_lock *lock) { u32 l_offset, l_len; __be32 *p; @@ -355,8 +355,8 @@ static void nlm_xdr_enc_testargs(struct rpc_rqst *req, struct xdr_stream *xdr, const void *data) { - const struct nlm_args *args = data; - const struct nlm_lock *lock = &args->lock; + const struct lockd_args *args = data; + const struct lockd_lock *lock = &args->lock; encode_cookie(xdr, &args->cookie); encode_bool(xdr, lock->fl.c.flc_type == F_WRLCK); @@ -377,8 +377,8 @@ static void nlm_xdr_enc_lockargs(struct rpc_rqst *req, struct xdr_stream *xdr, const void *data) { - const struct nlm_args *args = data; - const struct nlm_lock *lock = &args->lock; + const struct lockd_args *args = data; + const struct lockd_lock *lock = &args->lock; encode_cookie(xdr, &args->cookie); encode_bool(xdr, args->block); @@ -400,8 +400,8 @@ static void nlm_xdr_enc_cancargs(struct rpc_rqst *req, struct xdr_stream *xdr, const void *data) { - const struct nlm_args *args = data; - const struct nlm_lock *lock = &args->lock; + const struct lockd_args *args = data; + const struct lockd_lock *lock = &args->lock; encode_cookie(xdr, &args->cookie); encode_bool(xdr, args->block); @@ -419,8 +419,8 @@ static void nlm_xdr_enc_unlockargs(struct rpc_rqst *req, struct xdr_stream *xdr, const void *data) { - const struct nlm_args *args = data; - const struct nlm_lock *lock = &args->lock; + const struct lockd_args *args = data; + const struct lockd_lock *lock = &args->lock; encode_cookie(xdr, &args->cookie); encode_nlm_lock(xdr, lock); @@ -436,7 +436,7 @@ static void nlm_xdr_enc_res(struct rpc_rqst *req, struct xdr_stream *xdr, const void *data) { - const struct nlm_res *result = data; + const struct lockd_res *result = data; encode_cookie(xdr, &result->cookie); encode_nlm_stat(xdr, result->status); @@ -456,7 +456,7 @@ static void nlm_xdr_enc_res(struct rpc_rqst *req, * }; */ static void encode_nlm_testrply(struct xdr_stream *xdr, - const struct nlm_res *result) + const struct lockd_res *result) { if (result->status == nlm_lck_denied) encode_nlm_holder(xdr, result); @@ -466,7 +466,7 @@ static void nlm_xdr_enc_testres(struct rpc_rqst *req, struct xdr_stream *xdr, const void *data) { - const struct nlm_res *result = data; + const struct lockd_res *result = data; encode_cookie(xdr, &result->cookie); encode_nlm_stat(xdr, result->status); @@ -495,7 +495,7 @@ static void nlm_xdr_enc_testres(struct rpc_rqst *req, * }; */ static int decode_nlm_testrply(struct xdr_stream *xdr, - struct nlm_res *result) + struct lockd_res *result) { int error; @@ -512,7 +512,7 @@ static int nlm_xdr_dec_testres(struct rpc_rqst *req, struct xdr_stream *xdr, void *data) { - struct nlm_res *result = data; + struct lockd_res *result = data; int error; error = decode_cookie(xdr, &result->cookie); @@ -533,7 +533,7 @@ static int nlm_xdr_dec_res(struct rpc_rqst *req, struct xdr_stream *xdr, void *data) { - struct nlm_res *result = data; + struct lockd_res *result = data; int error; error = decode_cookie(xdr, &result->cookie); diff --git a/fs/lockd/host.c b/fs/lockd/host.c index ea8a8e166f7e..d572cb27533f 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -552,7 +552,7 @@ struct nlm_host * nlm_get_host(struct nlm_host *host) static struct nlm_host *next_host_state(struct hlist_head *cache, struct nsm_handle *nsm, - const struct nlm_reboot *info) + const struct lockd_reboot *info) { struct nlm_host *host; struct hlist_head *chain; @@ -582,7 +582,7 @@ static struct nlm_host *next_host_state(struct hlist_head *cache, * We were notified that the specified host has rebooted. Release * all resources held by that peer. */ -void nlm_host_rebooted(const struct net *net, const struct nlm_reboot *info) +void nlm_host_rebooted(const struct net *net, const struct lockd_reboot *info) { struct nsm_handle *nsm; struct nlm_host *host; diff --git a/fs/lockd/lockd.h b/fs/lockd/lockd.h index a7c85ab6d4b5..14cc952fe81a 100644 --- a/fs/lockd/lockd.h +++ b/fs/lockd/lockd.h @@ -52,6 +52,14 @@ */ #define LOCKD_DFLT_TIMEO 10 +/* + * Number of leading bytes of nfs_fh.data that file_hash() + * digests when bucketing nlm_files[]. Sized for historical + * NFSv2 handles; nfs_fh.data must be initialized at least + * this far before lookup, regardless of fh.size. + */ +#define LOCKD_FH_HASH_SIZE 32 + /* error codes new to NLMv4 */ #define nlm4_deadlock cpu_to_be32(NLM_DEADLCK) #define nlm4_rofs cpu_to_be32(NLM_ROFS) @@ -171,15 +179,15 @@ struct nlm_rqst { refcount_t a_count; unsigned int a_flags; /* initial RPC task flags */ struct nlm_host * a_host; /* host handle */ - struct nlm_args a_args; /* arguments */ - struct nlm_res a_res; /* result */ + struct lockd_args a_args; /* arguments */ + struct lockd_res a_res; /* result */ struct nlm_block * a_block; unsigned int a_retries; /* Retry count */ u8 a_owner[NLMCLNT_OHSIZE]; void * a_callback_data; /* sent to nlmclnt_operations callbacks */ }; -struct nlm_share; +struct lockd_share; /* * This struct describes a file held open by lockd on behalf of @@ -190,7 +198,7 @@ struct nlm_file { struct nfs_fh f_handle; /* NFS file handle */ struct file * f_file[2]; /* VFS file pointers, indexed by O_ flags */ - struct nlm_share * f_shares; /* DOS shares */ + struct lockd_share * f_shares; /* DOS shares */ struct list_head f_blocks; /* blocked locks */ unsigned int f_locks; /* guesstimate # of locks */ unsigned int f_count; /* reference count */ @@ -253,11 +261,11 @@ void nlmclnt_queue_block(struct nlm_wait *block); __be32 nlmclnt_dequeue_block(struct nlm_wait *block); int nlmclnt_wait(struct nlm_wait *block, struct nlm_rqst *req, long timeout); __be32 nlmclnt_grant(const struct sockaddr *addr, - const struct nlm_lock *lock); + const struct lockd_lock *lock); void nlmclnt_recovery(struct nlm_host *); int nlmclnt_reclaim(struct nlm_host *, struct file_lock *, struct nlm_rqst *); -void nlmclnt_next_cookie(struct nlm_cookie *); +void nlmclnt_next_cookie(struct lockd_cookie *); #ifdef CONFIG_LOCKD_V4 extern const struct rpc_version nlm_version4; @@ -285,7 +293,7 @@ struct nlm_host * nlm_get_host(struct nlm_host *); void nlm_shutdown_hosts(void); void nlm_shutdown_hosts_net(struct net *net); void nlm_host_rebooted(const struct net *net, - const struct nlm_reboot *); + const struct lockd_reboot *); /* * Host monitoring @@ -299,31 +307,31 @@ struct nsm_handle *nsm_get_handle(const struct net *net, const char *hostname, const size_t hostname_len); struct nsm_handle *nsm_reboot_lookup(const struct net *net, - const struct nlm_reboot *info); + const struct lockd_reboot *info); void nsm_release(struct nsm_handle *nsm); /* * This is used in garbage collection and resource reclaim * A return value != 0 means destroy the lock/block/share */ -typedef int (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref); +typedef int (*nlm_host_match_fn_t)(void *owner, struct nlm_host *ref); /* * Server-side lock handling */ int lock_to_openmode(struct file_lock *); __be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *, - struct nlm_host *, struct nlm_lock *, int, - struct nlm_cookie *, int); -__be32 nlmsvc_unlock(struct net *net, struct nlm_file *, struct nlm_lock *); + struct nlm_host *, struct lockd_lock *, int, + struct lockd_cookie *, int); +__be32 nlmsvc_unlock(struct net *net, struct nlm_file *, struct lockd_lock *); __be32 nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, - struct nlm_host *host, struct nlm_lock *lock, - struct nlm_lock *conflock); -__be32 nlmsvc_cancel_blocked(struct net *net, struct nlm_file *, struct nlm_lock *); + struct nlm_host *host, struct lockd_lock *lock, + struct lockd_lock *conflock); +__be32 nlmsvc_cancel_blocked(struct net *net, struct nlm_file *, struct lockd_lock *); void nlmsvc_retry_blocked(struct svc_rqst *rqstp); void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, nlm_host_match_fn_t match); -void nlmsvc_grant_reply(struct nlm_cookie *, __be32); +void nlmsvc_grant_reply(struct lockd_cookie *, __be32); void nlmsvc_release_call(struct nlm_rqst *); void nlmsvc_locks_init_private(struct file_lock *, struct nlm_host *, pid_t); int nlmsvc_dispatch(struct svc_rqst *rqstp); @@ -332,10 +340,10 @@ int nlmsvc_dispatch(struct svc_rqst *rqstp); * File handling for the server personality */ __be32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **, - struct nlm_lock *); + struct lockd_lock *, int); void nlm_release_file(struct nlm_file *); void nlmsvc_put_lockowner(struct nlm_lockowner *); -void nlmsvc_release_lockowner(struct nlm_lock *); +void nlmsvc_release_lockowner(struct lockd_lock *); void nlmsvc_mark_resources(struct net *); void nlmsvc_free_host_resources(struct nlm_host *); void nlmsvc_invalidate_all(void); @@ -423,6 +431,29 @@ static inline int nlm_compare_locks(const struct file_lock *fl1, } /** + * lockd_set_file_lock_range3 - set the byte range of a file_lock + * @fl: file_lock whose length fields are to be initialized + * @off: starting offset of the lock, in bytes + * @len: length of the byte range, in bytes, or zero + * + * NLMv3 uses a (start, length) representation for lock byte ranges, + * while the kernel's file_lock uses (start, end). Treat a length of + * zero or arithmetic overflow (end wrapping negative when the sum + * exceeds S32_MAX) as "lock to end of file." + */ +static inline void +lockd_set_file_lock_range3(struct file_lock *fl, u32 off, u32 len) +{ + s32 end = off + len - 1; + + fl->fl_start = off; + if (len == 0 || end < 0) + fl->fl_end = OFFSET_MAX; + else + fl->fl_end = end; +} + +/** * lockd_set_file_lock_range4 - set the byte range of a file_lock * @fl: file_lock whose length fields are to be initialized * @off: starting offset of the lock, in bytes diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 3d3ee88ca4dc..a8f5ac6f0577 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -377,7 +377,7 @@ retry: * error occurred. */ struct nsm_handle *nsm_reboot_lookup(const struct net *net, - const struct nlm_reboot *info) + const struct lockd_reboot *info) { struct nsm_handle *cached; struct lockd_net *ln = net_generic(net, lockd_net_id); diff --git a/fs/lockd/nlm3xdr_gen.c b/fs/lockd/nlm3xdr_gen.c new file mode 100644 index 000000000000..4b6e3ee7a719 --- /dev/null +++ b/fs/lockd/nlm3xdr_gen.c @@ -0,0 +1,686 @@ +// SPDX-License-Identifier: GPL-2.0 +// Generated by xdrgen. Manual edits will be lost. +// XDR specification file: ../../Documentation/sunrpc/xdr/nlm3.x +// XDR specification modification time: Mon Jun 29 20:42:29 2026 + +#include <linux/sunrpc/svc.h> + +#include "nlm3xdr_gen.h" + +static bool __maybe_unused +xdrgen_decode_netobj(struct xdr_stream *xdr, netobj *ptr) +{ + return xdrgen_decode_opaque(xdr, ptr, MAXNETOBJ_SZ); +} + +static bool __maybe_unused +xdrgen_decode_nlm_stats(struct xdr_stream *xdr, nlm_stats *ptr) +{ + __be32 raw; + u32 val; + + if (xdr_stream_decode_be32(xdr, &raw) < 0) + return false; + val = be32_to_cpu(raw); + /* Compiler may optimize to a range check for dense enums */ + switch (val) { + case LCK_GRANTED: + case LCK_DENIED: + case LCK_DENIED_NOLOCKS: + case LCK_BLOCKED: + case LCK_DENIED_GRACE_PERIOD: + break; + default: + return false; + } + *ptr = raw; + return true; +} + +static bool __maybe_unused +xdrgen_decode_nlm_stat(struct xdr_stream *xdr, struct nlm_stat *ptr) +{ + if (!xdrgen_decode_nlm_stats(xdr, &ptr->stat)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_nlm_res(struct xdr_stream *xdr, struct nlm_res *ptr) +{ + if (!xdrgen_decode_netobj(xdr, &ptr->cookie)) + return false; + if (!xdrgen_decode_nlm_stat(xdr, &ptr->stat)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_nlm_holder(struct xdr_stream *xdr, struct nlm_holder *ptr) +{ + if (!xdrgen_decode_bool(xdr, &ptr->exclusive)) + return false; + if (!xdrgen_decode_int(xdr, &ptr->uppid)) + return false; + if (!xdrgen_decode_netobj(xdr, &ptr->oh)) + return false; + if (!xdrgen_decode_unsigned_int(xdr, &ptr->l_offset)) + return false; + if (!xdrgen_decode_unsigned_int(xdr, &ptr->l_len)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_nlm_testrply(struct xdr_stream *xdr, struct nlm_testrply *ptr) +{ + if (!xdrgen_decode_nlm_stats(xdr, &ptr->stat)) + return false; + switch (ptr->stat) { + case __constant_cpu_to_be32(LCK_DENIED): + if (!xdrgen_decode_nlm_holder(xdr, &ptr->u.holder)) + return false; + break; + default: + break; + } + return true; +} + +static bool __maybe_unused +xdrgen_decode_nlm_testres(struct xdr_stream *xdr, struct nlm_testres *ptr) +{ + if (!xdrgen_decode_netobj(xdr, &ptr->cookie)) + return false; + if (!xdrgen_decode_nlm_testrply(xdr, &ptr->test_stat)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_nlm_lock(struct xdr_stream *xdr, struct nlm_lock *ptr) +{ + if (!xdrgen_decode_string(xdr, (string *)ptr, LM_MAXSTRLEN)) + return false; + if (!xdrgen_decode_netobj(xdr, &ptr->fh)) + return false; + if (!xdrgen_decode_netobj(xdr, &ptr->oh)) + return false; + if (!xdrgen_decode_int(xdr, &ptr->uppid)) + return false; + if (!xdrgen_decode_unsigned_int(xdr, &ptr->l_offset)) + return false; + if (!xdrgen_decode_unsigned_int(xdr, &ptr->l_len)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_nlm_lockargs(struct xdr_stream *xdr, struct nlm_lockargs *ptr) +{ + if (!xdrgen_decode_netobj(xdr, &ptr->cookie)) + return false; + if (!xdrgen_decode_bool(xdr, &ptr->block)) + return false; + if (!xdrgen_decode_bool(xdr, &ptr->exclusive)) + return false; + if (!xdrgen_decode_nlm_lock(xdr, &ptr->alock)) + return false; + if (!xdrgen_decode_bool(xdr, &ptr->reclaim)) + return false; + if (!xdrgen_decode_int(xdr, &ptr->state)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_nlm_cancargs(struct xdr_stream *xdr, struct nlm_cancargs *ptr) +{ + if (!xdrgen_decode_netobj(xdr, &ptr->cookie)) + return false; + if (!xdrgen_decode_bool(xdr, &ptr->block)) + return false; + if (!xdrgen_decode_bool(xdr, &ptr->exclusive)) + return false; + if (!xdrgen_decode_nlm_lock(xdr, &ptr->alock)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_nlm_testargs(struct xdr_stream *xdr, struct nlm_testargs *ptr) +{ + if (!xdrgen_decode_netobj(xdr, &ptr->cookie)) + return false; + if (!xdrgen_decode_bool(xdr, &ptr->exclusive)) + return false; + if (!xdrgen_decode_nlm_lock(xdr, &ptr->alock)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_nlm_unlockargs(struct xdr_stream *xdr, struct nlm_unlockargs *ptr) +{ + if (!xdrgen_decode_netobj(xdr, &ptr->cookie)) + return false; + if (!xdrgen_decode_nlm_lock(xdr, &ptr->alock)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_fsh_mode(struct xdr_stream *xdr, fsh_mode *ptr) +{ + u32 val; + + if (xdr_stream_decode_u32(xdr, &val) < 0) + return false; + /* Compiler may optimize to a range check for dense enums */ + switch (val) { + case fsm_DN: + case fsm_DR: + case fsm_DW: + case fsm_DRW: + break; + default: + return false; + } + *ptr = val; + return true; +} + +static bool __maybe_unused +xdrgen_decode_fsh_access(struct xdr_stream *xdr, fsh_access *ptr) +{ + u32 val; + + if (xdr_stream_decode_u32(xdr, &val) < 0) + return false; + /* Compiler may optimize to a range check for dense enums */ + switch (val) { + case fsa_NONE: + case fsa_R: + case fsa_W: + case fsa_RW: + break; + default: + return false; + } + *ptr = val; + return true; +} + +static bool __maybe_unused +xdrgen_decode_nlm_share(struct xdr_stream *xdr, struct nlm_share *ptr) +{ + if (!xdrgen_decode_string(xdr, (string *)ptr, LM_MAXSTRLEN)) + return false; + if (!xdrgen_decode_netobj(xdr, &ptr->fh)) + return false; + if (!xdrgen_decode_netobj(xdr, &ptr->oh)) + return false; + if (!xdrgen_decode_fsh_mode(xdr, &ptr->mode)) + return false; + if (!xdrgen_decode_fsh_access(xdr, &ptr->access)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_nlm_shareargs(struct xdr_stream *xdr, struct nlm_shareargs *ptr) +{ + if (!xdrgen_decode_netobj(xdr, &ptr->cookie)) + return false; + if (!xdrgen_decode_nlm_share(xdr, &ptr->share)) + return false; + if (!xdrgen_decode_bool(xdr, &ptr->reclaim)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_nlm_shareres(struct xdr_stream *xdr, struct nlm_shareres *ptr) +{ + if (!xdrgen_decode_netobj(xdr, &ptr->cookie)) + return false; + if (!xdrgen_decode_nlm_stats(xdr, &ptr->stat)) + return false; + if (!xdrgen_decode_int(xdr, &ptr->sequence)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_nlm_notify(struct xdr_stream *xdr, struct nlm_notify *ptr) +{ + if (!xdrgen_decode_string(xdr, (string *)ptr, LM_MAXNAMELEN)) + return false; + if (!xdrgen_decode_long(xdr, &ptr->state)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_decode_nlm_notifyargs(struct xdr_stream *xdr, struct nlm_notifyargs *ptr) +{ + if (!xdrgen_decode_nlm_notify(xdr, &ptr->notify)) + return false; + if (xdr_stream_decode_opaque_fixed(xdr, ptr->private, SM_PRIV_SIZE) < 0) + return false; + return true; +} + +/** + * nlm_svc_decode_nlm_testargs - Decode a nlm_testargs argument + * @rqstp: RPC transaction context + * @xdr: source XDR data stream + * + * Return values: + * %true: procedure arguments decoded successfully + * %false: decode failed + */ +bool nlm_svc_decode_nlm_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ + struct nlm_testargs *argp = rqstp->rq_argp; + + return xdrgen_decode_nlm_testargs(xdr, argp); +} + +/** + * nlm_svc_decode_nlm_lockargs - Decode a nlm_lockargs argument + * @rqstp: RPC transaction context + * @xdr: source XDR data stream + * + * Return values: + * %true: procedure arguments decoded successfully + * %false: decode failed + */ +bool nlm_svc_decode_nlm_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ + struct nlm_lockargs *argp = rqstp->rq_argp; + + return xdrgen_decode_nlm_lockargs(xdr, argp); +} + +/** + * nlm_svc_decode_nlm_cancargs - Decode a nlm_cancargs argument + * @rqstp: RPC transaction context + * @xdr: source XDR data stream + * + * Return values: + * %true: procedure arguments decoded successfully + * %false: decode failed + */ +bool nlm_svc_decode_nlm_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ + struct nlm_cancargs *argp = rqstp->rq_argp; + + return xdrgen_decode_nlm_cancargs(xdr, argp); +} + +/** + * nlm_svc_decode_nlm_unlockargs - Decode a nlm_unlockargs argument + * @rqstp: RPC transaction context + * @xdr: source XDR data stream + * + * Return values: + * %true: procedure arguments decoded successfully + * %false: decode failed + */ +bool nlm_svc_decode_nlm_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ + struct nlm_unlockargs *argp = rqstp->rq_argp; + + return xdrgen_decode_nlm_unlockargs(xdr, argp); +} + +/** + * nlm_svc_decode_nlm_testres - Decode a nlm_testres argument + * @rqstp: RPC transaction context + * @xdr: source XDR data stream + * + * Return values: + * %true: procedure arguments decoded successfully + * %false: decode failed + */ +bool nlm_svc_decode_nlm_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ + struct nlm_testres *argp = rqstp->rq_argp; + + return xdrgen_decode_nlm_testres(xdr, argp); +} + +/** + * nlm_svc_decode_nlm_res - Decode a nlm_res argument + * @rqstp: RPC transaction context + * @xdr: source XDR data stream + * + * Return values: + * %true: procedure arguments decoded successfully + * %false: decode failed + */ +bool nlm_svc_decode_nlm_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ + struct nlm_res *argp = rqstp->rq_argp; + + return xdrgen_decode_nlm_res(xdr, argp); +} + +/** + * nlm_svc_decode_nlm_notifyargs - Decode a nlm_notifyargs argument + * @rqstp: RPC transaction context + * @xdr: source XDR data stream + * + * Return values: + * %true: procedure arguments decoded successfully + * %false: decode failed + */ +bool nlm_svc_decode_nlm_notifyargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ + struct nlm_notifyargs *argp = rqstp->rq_argp; + + return xdrgen_decode_nlm_notifyargs(xdr, argp); +} + +/** + * nlm_svc_decode_nlm_shareargs - Decode a nlm_shareargs argument + * @rqstp: RPC transaction context + * @xdr: source XDR data stream + * + * Return values: + * %true: procedure arguments decoded successfully + * %false: decode failed + */ +bool nlm_svc_decode_nlm_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ + struct nlm_shareargs *argp = rqstp->rq_argp; + + return xdrgen_decode_nlm_shareargs(xdr, argp); +} + +/** + * nlm_svc_decode_nlm_notify - Decode a nlm_notify argument + * @rqstp: RPC transaction context + * @xdr: source XDR data stream + * + * Return values: + * %true: procedure arguments decoded successfully + * %false: decode failed + */ +bool nlm_svc_decode_nlm_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ + struct nlm_notify *argp = rqstp->rq_argp; + + return xdrgen_decode_nlm_notify(xdr, argp); +} + +static bool __maybe_unused +xdrgen_encode_netobj(struct xdr_stream *xdr, const netobj value) +{ + return xdr_stream_encode_opaque(xdr, value.data, value.len) >= 0; +} + +static bool __maybe_unused +xdrgen_encode_nlm_stats(struct xdr_stream *xdr, nlm_stats value) +{ + return xdr_stream_encode_be32(xdr, value) == XDR_UNIT; +} + +static bool __maybe_unused +xdrgen_encode_nlm_stat(struct xdr_stream *xdr, const struct nlm_stat *value) +{ + if (!xdrgen_encode_nlm_stats(xdr, value->stat)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_nlm_res(struct xdr_stream *xdr, const struct nlm_res *value) +{ + if (!xdrgen_encode_netobj(xdr, value->cookie)) + return false; + if (!xdrgen_encode_nlm_stat(xdr, &value->stat)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_nlm_holder(struct xdr_stream *xdr, const struct nlm_holder *value) +{ + if (!xdrgen_encode_bool(xdr, value->exclusive)) + return false; + if (!xdrgen_encode_int(xdr, value->uppid)) + return false; + if (!xdrgen_encode_netobj(xdr, value->oh)) + return false; + if (!xdrgen_encode_unsigned_int(xdr, value->l_offset)) + return false; + if (!xdrgen_encode_unsigned_int(xdr, value->l_len)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_nlm_testrply(struct xdr_stream *xdr, const struct nlm_testrply *ptr) +{ + if (!xdrgen_encode_nlm_stats(xdr, ptr->stat)) + return false; + switch (ptr->stat) { + case __constant_cpu_to_be32(LCK_DENIED): + if (!xdrgen_encode_nlm_holder(xdr, &ptr->u.holder)) + return false; + break; + default: + break; + } + return true; +} + +static bool __maybe_unused +xdrgen_encode_nlm_testres(struct xdr_stream *xdr, const struct nlm_testres *value) +{ + if (!xdrgen_encode_netobj(xdr, value->cookie)) + return false; + if (!xdrgen_encode_nlm_testrply(xdr, &value->test_stat)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_nlm_lock(struct xdr_stream *xdr, const struct nlm_lock *value) +{ + if (value->caller_name.len > LM_MAXSTRLEN) + return false; + if (xdr_stream_encode_opaque(xdr, value->caller_name.data, value->caller_name.len) < 0) + return false; + if (!xdrgen_encode_netobj(xdr, value->fh)) + return false; + if (!xdrgen_encode_netobj(xdr, value->oh)) + return false; + if (!xdrgen_encode_int(xdr, value->uppid)) + return false; + if (!xdrgen_encode_unsigned_int(xdr, value->l_offset)) + return false; + if (!xdrgen_encode_unsigned_int(xdr, value->l_len)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_nlm_lockargs(struct xdr_stream *xdr, const struct nlm_lockargs *value) +{ + if (!xdrgen_encode_netobj(xdr, value->cookie)) + return false; + if (!xdrgen_encode_bool(xdr, value->block)) + return false; + if (!xdrgen_encode_bool(xdr, value->exclusive)) + return false; + if (!xdrgen_encode_nlm_lock(xdr, &value->alock)) + return false; + if (!xdrgen_encode_bool(xdr, value->reclaim)) + return false; + if (!xdrgen_encode_int(xdr, value->state)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_nlm_cancargs(struct xdr_stream *xdr, const struct nlm_cancargs *value) +{ + if (!xdrgen_encode_netobj(xdr, value->cookie)) + return false; + if (!xdrgen_encode_bool(xdr, value->block)) + return false; + if (!xdrgen_encode_bool(xdr, value->exclusive)) + return false; + if (!xdrgen_encode_nlm_lock(xdr, &value->alock)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_nlm_testargs(struct xdr_stream *xdr, const struct nlm_testargs *value) +{ + if (!xdrgen_encode_netobj(xdr, value->cookie)) + return false; + if (!xdrgen_encode_bool(xdr, value->exclusive)) + return false; + if (!xdrgen_encode_nlm_lock(xdr, &value->alock)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_nlm_unlockargs(struct xdr_stream *xdr, const struct nlm_unlockargs *value) +{ + if (!xdrgen_encode_netobj(xdr, value->cookie)) + return false; + if (!xdrgen_encode_nlm_lock(xdr, &value->alock)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_fsh_mode(struct xdr_stream *xdr, fsh_mode value) +{ + return xdr_stream_encode_u32(xdr, value) == XDR_UNIT; +} + +static bool __maybe_unused +xdrgen_encode_fsh_access(struct xdr_stream *xdr, fsh_access value) +{ + return xdr_stream_encode_u32(xdr, value) == XDR_UNIT; +} + +static bool __maybe_unused +xdrgen_encode_nlm_share(struct xdr_stream *xdr, const struct nlm_share *value) +{ + if (value->caller_name.len > LM_MAXSTRLEN) + return false; + if (xdr_stream_encode_opaque(xdr, value->caller_name.data, value->caller_name.len) < 0) + return false; + if (!xdrgen_encode_netobj(xdr, value->fh)) + return false; + if (!xdrgen_encode_netobj(xdr, value->oh)) + return false; + if (!xdrgen_encode_fsh_mode(xdr, value->mode)) + return false; + if (!xdrgen_encode_fsh_access(xdr, value->access)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_nlm_shareargs(struct xdr_stream *xdr, const struct nlm_shareargs *value) +{ + if (!xdrgen_encode_netobj(xdr, value->cookie)) + return false; + if (!xdrgen_encode_nlm_share(xdr, &value->share)) + return false; + if (!xdrgen_encode_bool(xdr, value->reclaim)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_nlm_shareres(struct xdr_stream *xdr, const struct nlm_shareres *value) +{ + if (!xdrgen_encode_netobj(xdr, value->cookie)) + return false; + if (!xdrgen_encode_nlm_stats(xdr, value->stat)) + return false; + if (!xdrgen_encode_int(xdr, value->sequence)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_nlm_notify(struct xdr_stream *xdr, const struct nlm_notify *value) +{ + if (value->name.len > LM_MAXNAMELEN) + return false; + if (xdr_stream_encode_opaque(xdr, value->name.data, value->name.len) < 0) + return false; + if (!xdrgen_encode_long(xdr, value->state)) + return false; + return true; +} + +static bool __maybe_unused +xdrgen_encode_nlm_notifyargs(struct xdr_stream *xdr, const struct nlm_notifyargs *value) +{ + if (!xdrgen_encode_nlm_notify(xdr, &value->notify)) + return false; + if (xdr_stream_encode_opaque_fixed(xdr, value->private, SM_PRIV_SIZE) < 0) + return false; + return true; +} + +/** + * nlm_svc_encode_nlm_testres - Encode a nlm_testres result + * @rqstp: RPC transaction context + * @xdr: target XDR data stream + * + * Return values: + * %true: procedure results encoded successfully + * %false: encode failed + */ +bool nlm_svc_encode_nlm_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ + struct nlm_testres *resp = rqstp->rq_resp; + + return xdrgen_encode_nlm_testres(xdr, resp); +} + +/** + * nlm_svc_encode_nlm_res - Encode a nlm_res result + * @rqstp: RPC transaction context + * @xdr: target XDR data stream + * + * Return values: + * %true: procedure results encoded successfully + * %false: encode failed + */ +bool nlm_svc_encode_nlm_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ + struct nlm_res *resp = rqstp->rq_resp; + + return xdrgen_encode_nlm_res(xdr, resp); +} + +/** + * nlm_svc_encode_nlm_shareres - Encode a nlm_shareres result + * @rqstp: RPC transaction context + * @xdr: target XDR data stream + * + * Return values: + * %true: procedure results encoded successfully + * %false: encode failed + */ +bool nlm_svc_encode_nlm_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr) +{ + struct nlm_shareres *resp = rqstp->rq_resp; + + return xdrgen_encode_nlm_shareres(xdr, resp); +} diff --git a/fs/lockd/nlm3xdr_gen.h b/fs/lockd/nlm3xdr_gen.h new file mode 100644 index 000000000000..bdbfc26ba0e4 --- /dev/null +++ b/fs/lockd/nlm3xdr_gen.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Generated by xdrgen. Manual edits will be lost. */ +/* XDR specification file: ../../Documentation/sunrpc/xdr/nlm3.x */ +/* XDR specification modification time: Mon Jun 29 20:42:29 2026 */ + +#ifndef _LINUX_XDRGEN_NLM3_DECL_H +#define _LINUX_XDRGEN_NLM3_DECL_H + +#include <linux/types.h> + +#include <linux/sunrpc/xdr.h> +#include <linux/sunrpc/xdrgen/_defs.h> +#include <linux/sunrpc/xdrgen/_builtins.h> +#include <linux/sunrpc/xdrgen/nlm3.h> + +bool nlm_svc_decode_nlm_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +bool nlm_svc_decode_nlm_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +bool nlm_svc_decode_nlm_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +bool nlm_svc_decode_nlm_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +bool nlm_svc_decode_nlm_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +bool nlm_svc_decode_nlm_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); +bool nlm_svc_decode_nlm_notifyargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +bool nlm_svc_decode_nlm_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +bool nlm_svc_decode_nlm_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr); + +bool nlm_svc_encode_nlm_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +bool nlm_svc_encode_nlm_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); +bool nlm_svc_encode_nlm_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr); + +#endif /* _LINUX_XDRGEN_NLM3_DECL_H */ diff --git a/fs/lockd/nlm4xdr_gen.c b/fs/lockd/nlm4xdr_gen.c index 1c8c221db456..f98d74ee3d41 100644 --- a/fs/lockd/nlm4xdr_gen.c +++ b/fs/lockd/nlm4xdr_gen.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 // Generated by xdrgen. Manual edits will be lost. // XDR specification file: ../../Documentation/sunrpc/xdr/nlm4.x -// XDR specification modification time: Thu Dec 25 13:10:19 2025 +// XDR specification modification time: Mon Jun 29 20:42:29 2026 #include <linux/sunrpc/svc.h> @@ -20,6 +20,16 @@ xdrgen_decode_fsh4_mode(struct xdr_stream *xdr, fsh4_mode *ptr) if (xdr_stream_decode_u32(xdr, &val) < 0) return false; + /* Compiler may optimize to a range check for dense enums */ + switch (val) { + case fsm_DN: + case fsm_DR: + case fsm_DW: + case fsm_DRW: + break; + default: + return false; + } *ptr = val; return true; } @@ -31,6 +41,16 @@ xdrgen_decode_fsh4_access(struct xdr_stream *xdr, fsh4_access *ptr) if (xdr_stream_decode_u32(xdr, &val) < 0) return false; + /* Compiler may optimize to a range check for dense enums */ + switch (val) { + case fsa_NONE: + case fsa_R: + case fsa_W: + case fsa_RW: + break; + default: + return false; + } *ptr = val; return true; } @@ -62,7 +82,30 @@ xdrgen_decode_int32(struct xdr_stream *xdr, int32 *ptr) static bool __maybe_unused xdrgen_decode_nlm4_stats(struct xdr_stream *xdr, nlm4_stats *ptr) { - return xdr_stream_decode_be32(xdr, ptr) == 0; + __be32 raw; + u32 val; + + if (xdr_stream_decode_be32(xdr, &raw) < 0) + return false; + val = be32_to_cpu(raw); + /* Compiler may optimize to a range check for dense enums */ + switch (val) { + case NLM4_GRANTED: + case NLM4_DENIED: + case NLM4_DENIED_NOLOCKS: + case NLM4_BLOCKED: + case NLM4_DENIED_GRACE_PERIOD: + case NLM4_DEADLCK: + case NLM4_ROFS: + case NLM4_STALE_FH: + case NLM4_FBIG: + case NLM4_FAILED: + break; + default: + return false; + } + *ptr = raw; + return true; } static bool __maybe_unused @@ -258,20 +301,6 @@ xdrgen_decode_nlm4_notifyargs(struct xdr_stream *xdr, struct nlm4_notifyargs *pt } /** - * nlm4_svc_decode_void - Decode a void argument - * @rqstp: RPC transaction context - * @xdr: source XDR data stream - * - * Return values: - * %true: procedure arguments decoded successfully - * %false: decode failed - */ -bool nlm4_svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) -{ - return xdrgen_decode_void(xdr); -} - -/** * nlm4_svc_decode_nlm4_testargs - Decode a nlm4_testargs argument * @rqstp: RPC transaction context * @xdr: source XDR data stream @@ -662,20 +691,6 @@ xdrgen_encode_nlm4_notifyargs(struct xdr_stream *xdr, const struct nlm4_notifyar } /** - * nlm4_svc_encode_void - Encode a void result - * @rqstp: RPC transaction context - * @xdr: target XDR data stream - * - * Return values: - * %true: procedure results encoded successfully - * %false: encode failed - */ -bool nlm4_svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) -{ - return xdrgen_encode_void(xdr); -} - -/** * nlm4_svc_encode_nlm4_testres - Encode a nlm4_testres result * @rqstp: RPC transaction context * @xdr: target XDR data stream diff --git a/fs/lockd/nlm4xdr_gen.h b/fs/lockd/nlm4xdr_gen.h index b6008b296a3e..1a72c26ad18a 100644 --- a/fs/lockd/nlm4xdr_gen.h +++ b/fs/lockd/nlm4xdr_gen.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Generated by xdrgen. Manual edits will be lost. */ /* XDR specification file: ../../Documentation/sunrpc/xdr/nlm4.x */ -/* XDR specification modification time: Thu Dec 25 13:10:19 2025 */ +/* XDR specification modification time: Mon Jun 29 20:42:29 2026 */ #ifndef _LINUX_XDRGEN_NLM4_DECL_H #define _LINUX_XDRGEN_NLM4_DECL_H @@ -13,7 +13,6 @@ #include <linux/sunrpc/xdrgen/_builtins.h> #include <linux/sunrpc/xdrgen/nlm4.h> -bool nlm4_svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); bool nlm4_svc_decode_nlm4_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); bool nlm4_svc_decode_nlm4_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); bool nlm4_svc_decode_nlm4_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); @@ -24,7 +23,6 @@ bool nlm4_svc_decode_nlm4_notifyargs(struct svc_rqst *rqstp, struct xdr_stream * bool nlm4_svc_decode_nlm4_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); bool nlm4_svc_decode_nlm4_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr); -bool nlm4_svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); bool nlm4_svc_encode_nlm4_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr); bool nlm4_svc_encode_nlm4_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); bool nlm4_svc_encode_nlm4_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr); diff --git a/fs/lockd/share.h b/fs/lockd/share.h index 20ea8ee49168..a12b6c454f58 100644 --- a/fs/lockd/share.h +++ b/fs/lockd/share.h @@ -8,25 +8,31 @@ #ifndef _LOCKD_SHARE_H #define _LOCKD_SHARE_H +#include <linux/bits.h> + /* Synthetic svid for lockowner lookup during share operations */ #define LOCKD_SHARE_SVID (~(u32)0) +/* One bit per (access, deny) pair; index = (access << 2) | deny */ +#define LOCKD_FSH_BIT(a, d) BIT(((a) << 2) | (d)) + /* * DOS share for a specific file */ -struct nlm_share { - struct nlm_share * s_next; /* linked list */ +struct lockd_share { + struct lockd_share * s_next; /* linked list */ struct nlm_host * s_host; /* client host */ struct nlm_file * s_file; /* shared file */ struct xdr_netobj s_owner; /* owner handle */ u32 s_access; /* access mode */ u32 s_mode; /* deny mode */ + u16 s_access_deny_bmap; /* held (access, deny) pairs */ }; __be32 nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file, struct xdr_netobj *oh, u32 access, u32 mode); __be32 nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file, - struct xdr_netobj *oh); + struct xdr_netobj *oh, u32 access, u32 mode); void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *, nlm_host_match_fn_t); diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 490551369ef2..ee90e743064a 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -47,7 +47,7 @@ static struct svc_program nlmsvc_program; -const struct nlmsvc_binding *nlmsvc_ops; +const struct nlmsvc_binding __rcu *nlmsvc_ops; EXPORT_SYMBOL_GPL(nlmsvc_ops); static DEFINE_MUTEX(nlmsvc_mutex); @@ -142,7 +142,7 @@ lockd(void *vrqstp) nlmsvc_retry_blocked(rqstp); svc_recv(rqstp, 0); } - if (nlmsvc_ops) + if (rcu_access_pointer(nlmsvc_ops)) nlmsvc_invalidate_all(); nlm_shutdown_hosts(); cancel_delayed_work_sync(&ln->grace_period_end); diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index 5de41e249534..03c5554ca579 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -26,42 +26,42 @@ #include "nlm4xdr_gen.h" /* - * Wrapper structures combine xdrgen types with legacy nlm_lock. + * 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 nlm4_testargs_wrapper { struct nlm4_testargs xdrgen; - struct nlm_lock lock; + struct lockd_lock lock; }; static_assert(offsetof(struct nlm4_testargs_wrapper, xdrgen) == 0); struct nlm4_lockargs_wrapper { struct nlm4_lockargs xdrgen; - struct nlm_cookie cookie; - struct nlm_lock lock; + struct lockd_cookie cookie; + struct lockd_lock lock; }; static_assert(offsetof(struct nlm4_lockargs_wrapper, xdrgen) == 0); struct nlm4_cancargs_wrapper { struct nlm4_cancargs xdrgen; - struct nlm_lock lock; + struct lockd_lock lock; }; static_assert(offsetof(struct nlm4_cancargs_wrapper, xdrgen) == 0); struct nlm4_unlockargs_wrapper { struct nlm4_unlockargs xdrgen; - struct nlm_lock lock; + struct lockd_lock lock; }; static_assert(offsetof(struct nlm4_unlockargs_wrapper, xdrgen) == 0); struct nlm4_notifyargs_wrapper { struct nlm4_notifyargs xdrgen; - struct nlm_reboot reboot; + struct lockd_reboot reboot; }; static_assert(offsetof(struct nlm4_notifyargs_wrapper, xdrgen) == 0); @@ -74,12 +74,12 @@ static_assert(offsetof(struct nlm4_notify_wrapper, xdrgen) == 0); struct nlm4_testres_wrapper { struct nlm4_testres xdrgen; - struct nlm_lock lock; + struct lockd_lock lock; }; struct nlm4_shareargs_wrapper { struct nlm4_shareargs xdrgen; - struct nlm_lock lock; + struct lockd_lock lock; }; static_assert(offsetof(struct nlm4_shareargs_wrapper, xdrgen) == 0); @@ -88,7 +88,7 @@ static_assert(offsetof(struct nlm4_testres_wrapper, xdrgen) == 0); struct nlm4_res_wrapper { struct nlm4_res xdrgen; - struct nlm_cookie cookie; + struct lockd_cookie cookie; }; static_assert(offsetof(struct nlm4_res_wrapper, xdrgen) == 0); @@ -100,7 +100,7 @@ struct nlm4_shareres_wrapper { static_assert(offsetof(struct nlm4_shareres_wrapper, xdrgen) == 0); static __be32 -nlm4_netobj_to_cookie(struct nlm_cookie *cookie, netobj *object) +nlm4_netobj_to_cookie(struct lockd_cookie *cookie, netobj *object) { if (object->len > NLM_MAXCOOKIELEN) return nlm_lck_denied_nolocks; @@ -110,7 +110,7 @@ nlm4_netobj_to_cookie(struct nlm_cookie *cookie, netobj *object) } static __be32 -nlm4_lock_to_nlm_lock(struct nlm_lock *lock, struct nlm4_lock *alock) +nlm4_lock_to_lockd_lock(struct lockd_lock *lock, struct nlm4_lock *alock) { if (alock->fh.len > NFS_MAXFHSIZE) return nlm_lck_denied; @@ -119,7 +119,6 @@ nlm4_lock_to_nlm_lock(struct nlm_lock *lock, struct nlm4_lock *alock) lock->oh.len = alock->oh.len; lock->oh.data = alock->oh.data; lock->svid = alock->svid; - locks_init_lock(&lock->fl); lockd_set_file_lock_range4(&lock->fl, alock->l_offset, alock->l_len); return nlm_granted; } @@ -129,7 +128,7 @@ nlm4svc_lookup_host(struct svc_rqst *rqstp, string caller, bool monitored) { struct nlm_host *host; - if (!nlmsvc_ops) + if (!rcu_access_pointer(nlmsvc_ops)) return NULL; host = nlmsvc_lookup_host(rqstp, caller.data, caller.len); if (!host) @@ -143,17 +142,23 @@ nlm4svc_lookup_host(struct svc_rqst *rqstp, string caller, bool monitored) static __be32 nlm4svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host, - struct nlm_lock *lock, struct nlm_file **filp, + struct lockd_lock *lock, struct nlm_file **filp, struct nlm4_lock *xdr_lock, unsigned char type) { + bool is_test = (rqstp->rq_proc == NLMPROC4_TEST || + rqstp->rq_proc == NLMPROC4_TEST_MSG); struct file_lock *fl = &lock->fl; struct nlm_file *file = NULL; + int mode; __be32 error; if (xdr_lock->fh.len > NFS_MAXFHSIZE) return nlm_lck_denied_nolocks; lock->fh.size = xdr_lock->fh.len; memcpy(lock->fh.data, xdr_lock->fh.data, xdr_lock->fh.len); + if (xdr_lock->fh.len < LOCKD_FH_HASH_SIZE) + memset(lock->fh.data + xdr_lock->fh.len, 0, + LOCKD_FH_HASH_SIZE - xdr_lock->fh.len); lock->oh.len = xdr_lock->oh.len; lock->oh.data = xdr_lock->oh.data; @@ -170,7 +175,8 @@ nlm4svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host, fl->c.flc_type = type; lockd_set_file_lock_range4(fl, lock->lock_start, lock->lock_len); - error = nlm_lookup_file(rqstp, &file, lock); + mode = is_test ? O_RDWR : lock_to_openmode(fl); + error = nlm_lookup_file(rqstp, &file, lock, mode); switch (error) { case nlm_granted: break; @@ -184,7 +190,8 @@ nlm4svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host, *filp = file; fl->c.flc_flags = FL_POSIX; - fl->c.flc_file = file->f_file[lock_to_openmode(fl)]; + fl->c.flc_file = is_test ? nlmsvc_file_file(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); @@ -265,7 +272,7 @@ static __be32 nlm4svc_proc_test(struct svc_rqst *rqstp) nlmsvc_release_lockowner(&argp->lock); if (resp->xdrgen.stat.stat == nlm_lck_denied) { - struct nlm_lock *conf = &resp->lock; + struct lockd_lock *conf = &resp->lock; struct nlm4_holder *holder = &resp->xdrgen.stat.u.holder; holder->exclusive = (conf->fl.c.flc_type != F_RDLCK); @@ -508,12 +515,12 @@ out: * nlm4_res NLMPROC4_GRANTED(nlm4_testargs) = 5; * * Permissible procedure status codes: - * %NLM4_GRANTED: The requested lock was granted. - * %NLM4_DENIED: The server could not allocate the resources - * needed to process the request. - * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is - * re-establishing existing locks, and is not - * yet ready to accept normal service requests. + * %NLM4_GRANTED: The granted lock was accepted. + * %NLM4_DENIED: The procedure failed, possibly due to + * internal resource constraints. + * %NLM4_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 nlm4svc_proc_granted(struct svc_rqst *rqstp) @@ -523,8 +530,8 @@ nlm4svc_proc_granted(struct svc_rqst *rqstp) resp->xdrgen.cookie = argp->xdrgen.cookie; - resp->xdrgen.stat.stat = nlm4_lock_to_nlm_lock(&argp->lock, - &argp->xdrgen.alock); + resp->xdrgen.stat.stat = nlm4_lock_to_lockd_lock(&argp->lock, + &argp->xdrgen.alock); if (resp->xdrgen.stat.stat) goto out; @@ -558,7 +565,7 @@ static const struct rpc_call_ops nlm4svc_callback_ops = { */ static __be32 nlm4svc_callback(struct svc_rqst *rqstp, struct nlm_host *host, u32 proc, - __be32 (*func)(struct svc_rqst *, struct nlm_res *)) + __be32 (*func)(struct svc_rqst *, struct lockd_res *)) { struct nlm_rqst *call; __be32 stat; @@ -581,7 +588,7 @@ nlm4svc_callback(struct svc_rqst *rqstp, struct nlm_host *host, u32 proc, } static __be32 -__nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_res *resp) +__nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct lockd_res *resp) { struct nlm4_testargs_wrapper *argp = rqstp->rq_argp; unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK; @@ -641,7 +648,7 @@ static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp) } static __be32 -__nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_res *resp) +__nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct lockd_res *resp) { struct nlm4_lockargs_wrapper *argp = rqstp->rq_argp; unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK; @@ -664,6 +671,8 @@ __nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_res *resp) resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock, argp->xdrgen.block, &resp->cookie, argp->xdrgen.reclaim); + if (resp->status == nlm__int__deadlock) + resp->status = nlm4_deadlock; nlmsvc_release_lockowner(&argp->lock); out: @@ -692,7 +701,7 @@ static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp) struct nlm4_lockargs_wrapper *argp = rqstp->rq_argp; struct nlm_host *host; - host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, true); + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); if (!host) return rpc_system_err; @@ -701,7 +710,7 @@ static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp) } static __be32 -__nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_res *resp) +__nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct lockd_res *resp) { struct nlm4_cancargs_wrapper *argp = rqstp->rq_argp; unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK; @@ -765,7 +774,7 @@ static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp) } static __be32 -__nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_res *resp) +__nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct lockd_res *resp) { struct nlm4_unlockargs_wrapper *argp = rqstp->rq_argp; struct net *net = SVC_NET(rqstp); @@ -828,7 +837,7 @@ static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp) } static __be32 -__nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_res *resp) +__nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct lockd_res *resp) { struct nlm4_testargs_wrapper *argp = rqstp->rq_argp; @@ -836,7 +845,7 @@ __nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_res *resp) if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie)) goto out; - if (nlm4_lock_to_nlm_lock(&argp->lock, &argp->xdrgen.alock)) + if (nlm4_lock_to_lockd_lock(&argp->lock, &argp->xdrgen.alock)) goto out; resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock); @@ -863,7 +872,8 @@ static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp) struct nlm4_testargs_wrapper *argp = rqstp->rq_argp; struct nlm_host *host; - host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); + host = nlmsvc_lookup_host(rqstp, argp->xdrgen.alock.caller_name.data, + argp->xdrgen.alock.caller_name.len); if (!host) return rpc_system_err; @@ -885,7 +895,7 @@ static __be32 nlm4svc_proc_granted_res(struct svc_rqst *rqstp) { struct nlm4_res_wrapper *argp = rqstp->rq_argp; - if (!nlmsvc_ops) + if (!rcu_access_pointer(nlmsvc_ops)) return rpc_success; if (nlm4_netobj_to_cookie(&argp->cookie, &argp->xdrgen.cookie)) @@ -912,7 +922,7 @@ static __be32 nlm4svc_proc_granted_res(struct svc_rqst *rqstp) static __be32 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp) { struct nlm4_notifyargs_wrapper *argp = rqstp->rq_argp; - struct nlm_reboot *reboot = &argp->reboot; + struct lockd_reboot *reboot = &argp->reboot; if (!nlm_privileged_requester(rqstp)) { char buf[RPC_MAX_ADDRBUFLEN]; @@ -976,7 +986,7 @@ static __be32 nlm4svc_proc_share(struct svc_rqst *rqstp) { struct nlm4_shareargs_wrapper *argp = rqstp->rq_argp; struct nlm4_shareres_wrapper *resp = rqstp->rq_resp; - struct nlm_lock *lock = &argp->lock; + struct lockd_lock *lock = &argp->lock; struct nlm_host *host = NULL; struct nlm_file *file = NULL; struct nlm4_lock xdr_lock = { @@ -1044,7 +1054,7 @@ static __be32 nlm4svc_proc_unshare(struct svc_rqst *rqstp) { struct nlm4_shareargs_wrapper *argp = rqstp->rq_argp; struct nlm4_shareres_wrapper *resp = rqstp->rq_resp; - struct nlm_lock *lock = &argp->lock; + struct lockd_lock *lock = &argp->lock; struct nlm4_lock xdr_lock = { .fh = argp->xdrgen.share.fh, .oh = argp->xdrgen.share.oh, @@ -1069,7 +1079,9 @@ static __be32 nlm4svc_proc_unshare(struct svc_rqst *rqstp) if (resp->xdrgen.stat) goto out; - resp->xdrgen.stat = nlmsvc_unshare_file(host, file, &lock->oh); + resp->xdrgen.stat = nlmsvc_unshare_file(host, file, &lock->oh, + argp->xdrgen.share.access, + argp->xdrgen.share.mode); nlmsvc_release_lockowner(lock); @@ -1155,8 +1167,8 @@ out: static const struct svc_procedure nlm4svc_procedures[24] = { [NLMPROC4_NULL] = { .pc_func = nlm4svc_proc_null, - .pc_decode = nlm4_svc_decode_void, - .pc_encode = nlm4_svc_encode_void, + .pc_decode = xdrgen_svc_decode_void, + .pc_encode = xdrgen_svc_encode_void, .pc_argsize = XDR_void, .pc_argzero = 0, .pc_ressize = 0, @@ -1216,7 +1228,7 @@ static const struct svc_procedure nlm4svc_procedures[24] = { [NLMPROC4_TEST_MSG] = { .pc_func = nlm4svc_proc_test_msg, .pc_decode = nlm4_svc_decode_nlm4_testargs, - .pc_encode = nlm4_svc_encode_void, + .pc_encode = xdrgen_svc_encode_void, .pc_argsize = sizeof(struct nlm4_testargs_wrapper), .pc_argzero = 0, .pc_ressize = 0, @@ -1226,7 +1238,7 @@ static const struct svc_procedure nlm4svc_procedures[24] = { [NLMPROC4_LOCK_MSG] = { .pc_func = nlm4svc_proc_lock_msg, .pc_decode = nlm4_svc_decode_nlm4_lockargs, - .pc_encode = nlm4_svc_encode_void, + .pc_encode = xdrgen_svc_encode_void, .pc_argsize = sizeof(struct nlm4_lockargs_wrapper), .pc_argzero = 0, .pc_ressize = 0, @@ -1236,7 +1248,7 @@ static const struct svc_procedure nlm4svc_procedures[24] = { [NLMPROC4_CANCEL_MSG] = { .pc_func = nlm4svc_proc_cancel_msg, .pc_decode = nlm4_svc_decode_nlm4_cancargs, - .pc_encode = nlm4_svc_encode_void, + .pc_encode = xdrgen_svc_encode_void, .pc_argsize = sizeof(struct nlm4_cancargs_wrapper), .pc_argzero = 0, .pc_ressize = 0, @@ -1246,7 +1258,7 @@ static const struct svc_procedure nlm4svc_procedures[24] = { [NLMPROC4_UNLOCK_MSG] = { .pc_func = nlm4svc_proc_unlock_msg, .pc_decode = nlm4_svc_decode_nlm4_unlockargs, - .pc_encode = nlm4_svc_encode_void, + .pc_encode = xdrgen_svc_encode_void, .pc_argsize = sizeof(struct nlm4_unlockargs_wrapper), .pc_argzero = 0, .pc_ressize = 0, @@ -1256,7 +1268,7 @@ static const struct svc_procedure nlm4svc_procedures[24] = { [NLMPROC4_GRANTED_MSG] = { .pc_func = nlm4svc_proc_granted_msg, .pc_decode = nlm4_svc_decode_nlm4_testargs, - .pc_encode = nlm4_svc_encode_void, + .pc_encode = xdrgen_svc_encode_void, .pc_argsize = sizeof(struct nlm4_testargs_wrapper), .pc_argzero = 0, .pc_ressize = 0, @@ -1266,7 +1278,7 @@ static const struct svc_procedure nlm4svc_procedures[24] = { [NLMPROC4_TEST_RES] = { .pc_func = nlm4svc_proc_null, .pc_decode = nlm4_svc_decode_nlm4_testres, - .pc_encode = nlm4_svc_encode_void, + .pc_encode = xdrgen_svc_encode_void, .pc_argsize = sizeof(struct nlm4_testres), .pc_argzero = 0, .pc_ressize = 0, @@ -1276,7 +1288,7 @@ static const struct svc_procedure nlm4svc_procedures[24] = { [NLMPROC4_LOCK_RES] = { .pc_func = nlm4svc_proc_null, .pc_decode = nlm4_svc_decode_nlm4_res, - .pc_encode = nlm4_svc_encode_void, + .pc_encode = xdrgen_svc_encode_void, .pc_argsize = sizeof(struct nlm4_res), .pc_argzero = 0, .pc_ressize = 0, @@ -1286,7 +1298,7 @@ static const struct svc_procedure nlm4svc_procedures[24] = { [NLMPROC4_CANCEL_RES] = { .pc_func = nlm4svc_proc_null, .pc_decode = nlm4_svc_decode_nlm4_res, - .pc_encode = nlm4_svc_encode_void, + .pc_encode = xdrgen_svc_encode_void, .pc_argsize = sizeof(struct nlm4_res), .pc_argzero = 0, .pc_ressize = 0, @@ -1296,7 +1308,7 @@ static const struct svc_procedure nlm4svc_procedures[24] = { [NLMPROC4_UNLOCK_RES] = { .pc_func = nlm4svc_proc_null, .pc_decode = nlm4_svc_decode_nlm4_res, - .pc_encode = nlm4_svc_encode_void, + .pc_encode = xdrgen_svc_encode_void, .pc_argsize = sizeof(struct nlm4_res), .pc_argzero = 0, .pc_ressize = 0, @@ -1306,7 +1318,7 @@ static const struct svc_procedure nlm4svc_procedures[24] = { [NLMPROC4_GRANTED_RES] = { .pc_func = nlm4svc_proc_granted_res, .pc_decode = nlm4_svc_decode_nlm4_res, - .pc_encode = nlm4_svc_encode_void, + .pc_encode = xdrgen_svc_encode_void, .pc_argsize = sizeof(struct nlm4_res_wrapper), .pc_argzero = 0, .pc_ressize = 0, @@ -1316,7 +1328,7 @@ static const struct svc_procedure nlm4svc_procedures[24] = { [NLMPROC4_SM_NOTIFY] = { .pc_func = nlm4svc_proc_sm_notify, .pc_decode = nlm4_svc_decode_nlm4_notifyargs, - .pc_encode = nlm4_svc_encode_void, + .pc_encode = xdrgen_svc_encode_void, .pc_argsize = sizeof(struct nlm4_notifyargs_wrapper), .pc_argzero = 0, .pc_ressize = 0, @@ -1325,8 +1337,8 @@ static const struct svc_procedure nlm4svc_procedures[24] = { }, [17] = { .pc_func = nlm4svc_proc_unused, - .pc_decode = nlm4_svc_decode_void, - .pc_encode = nlm4_svc_encode_void, + .pc_decode = xdrgen_svc_decode_void, + .pc_encode = xdrgen_svc_encode_void, .pc_argsize = 0, .pc_argzero = 0, .pc_ressize = 0, @@ -1335,8 +1347,8 @@ static const struct svc_procedure nlm4svc_procedures[24] = { }, [18] = { .pc_func = nlm4svc_proc_unused, - .pc_decode = nlm4_svc_decode_void, - .pc_encode = nlm4_svc_encode_void, + .pc_decode = xdrgen_svc_decode_void, + .pc_encode = xdrgen_svc_encode_void, .pc_argsize = 0, .pc_argzero = 0, .pc_ressize = 0, @@ -1345,8 +1357,8 @@ static const struct svc_procedure nlm4svc_procedures[24] = { }, [19] = { .pc_func = nlm4svc_proc_unused, - .pc_decode = nlm4_svc_decode_void, - .pc_encode = nlm4_svc_encode_void, + .pc_decode = xdrgen_svc_decode_void, + .pc_encode = xdrgen_svc_encode_void, .pc_argsize = 0, .pc_argzero = 0, .pc_ressize = 0, @@ -1386,7 +1398,7 @@ static const struct svc_procedure nlm4svc_procedures[24] = { [NLMPROC4_FREE_ALL] = { .pc_func = nlm4svc_proc_free_all, .pc_decode = nlm4_svc_decode_nlm4_notify, - .pc_encode = nlm4_svc_encode_void, + .pc_encode = xdrgen_svc_encode_void, .pc_argsize = sizeof(struct nlm4_notify_wrapper), .pc_argzero = 0, .pc_ressize = 0, @@ -1411,14 +1423,10 @@ union nlm4svc_xdrstore { struct nlm4_shareres_wrapper shareres; }; -static DEFINE_PER_CPU_ALIGNED(unsigned long, - nlm4svc_call_counters[ARRAY_SIZE(nlm4svc_procedures)]); - const struct svc_version nlmsvc_version4 = { .vs_vers = 4, .vs_nproc = ARRAY_SIZE(nlm4svc_procedures), .vs_proc = nlm4svc_procedures, - .vs_count = nlm4svc_call_counters, .vs_dispatch = nlmsvc_dispatch, .vs_xdrsize = sizeof(union nlm4svc_xdrstore), }; diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index b98b1d0ada35..e628b5d35507 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -37,7 +37,7 @@ static void nlmsvc_release_block(struct nlm_block *block); static void nlmsvc_insert_block(struct nlm_block *block, unsigned long); static void nlmsvc_remove_block(struct nlm_block *block); -static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock); +static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct lockd_lock *lock); static void nlmsvc_freegrantargs(struct nlm_rqst *call); static const struct rpc_call_ops nlmsvc_grant_ops; @@ -47,40 +47,6 @@ static const struct rpc_call_ops nlmsvc_grant_ops; static LIST_HEAD(nlm_blocked); static DEFINE_SPINLOCK(nlm_blocked_lock); -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) -static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) -{ - /* - * We can get away with a static buffer because this is only called - * from lockd, which is single-threaded. - */ - static char buf[2*NLM_MAXCOOKIELEN+1]; - unsigned int i, len = sizeof(buf); - char *p = buf; - - len--; /* allow for trailing \0 */ - if (len < 3) - return "???"; - for (i = 0 ; i < cookie->len ; i++) { - if (len < 2) { - strcpy(p-3, "..."); - break; - } - sprintf(p, "%02x", cookie->data[i]); - p += 2; - len -= 2; - } - *p = '\0'; - - return buf; -} -#else -static inline const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) -{ - return "???"; -} -#endif - /* * Insert a blocked lock into the global list */ @@ -142,7 +108,7 @@ nlmsvc_remove_block(struct nlm_block *block) * Find a block for a given lock */ static struct nlm_block * -nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock) +nlmsvc_lookup_block(struct nlm_file *file, struct lockd_lock *lock) { struct nlm_block *block; struct file_lock *fl; @@ -155,11 +121,12 @@ nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock) spin_lock(&nlm_blocked_lock); list_for_each_entry(block, &nlm_blocked, b_list) { fl = &block->b_call->a_args.lock.fl; - dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n", + dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%*phN\n", block->b_file, fl->c.flc_pid, (long long)fl->fl_start, (long long)fl->fl_end, fl->c.flc_type, - nlmdbg_cookie2a(&block->b_call->a_args.cookie)); + block->b_call->a_args.cookie.len, + block->b_call->a_args.cookie.data); if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) { kref_get(&block->b_count); spin_unlock(&nlm_blocked_lock); @@ -171,7 +138,7 @@ nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock) return NULL; } -static inline int nlm_cookie_match(struct nlm_cookie *a, struct nlm_cookie *b) +static int lockd_cookie_match(struct lockd_cookie *a, struct lockd_cookie *b) { if (a->len != b->len) return 0; @@ -184,13 +151,13 @@ static inline int nlm_cookie_match(struct nlm_cookie *a, struct nlm_cookie *b) * Find a block with a given NLM cookie. */ static inline struct nlm_block * -nlmsvc_find_block(struct nlm_cookie *cookie) +nlmsvc_find_block(struct lockd_cookie *cookie) { struct nlm_block *block; spin_lock(&nlm_blocked_lock); list_for_each_entry(block, &nlm_blocked, b_list) { - if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie)) + if (lockd_cookie_match(&block->b_call->a_args.cookie, cookie)) goto found; } spin_unlock(&nlm_blocked_lock); @@ -198,7 +165,8 @@ nlmsvc_find_block(struct nlm_cookie *cookie) return NULL; found: - dprintk("nlmsvc_find_block(%s): block=%p\n", nlmdbg_cookie2a(cookie), block); + dprintk("nlmsvc_find_block(%*phN): block=%p\n", + cookie->len, cookie->data, block); kref_get(&block->b_count); spin_unlock(&nlm_blocked_lock); return block; @@ -221,8 +189,8 @@ found: */ static struct nlm_block * nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_host *host, - struct nlm_file *file, struct nlm_lock *lock, - struct nlm_cookie *cookie) + struct nlm_file *file, struct lockd_lock *lock, + struct lockd_cookie *cookie) { struct nlm_block *block; struct nlm_rqst *call = NULL; @@ -399,7 +367,7 @@ static struct nlm_lockowner *nlmsvc_find_lockowner(struct nlm_host *host, pid_t } void -nlmsvc_release_lockowner(struct nlm_lock *lock) +nlmsvc_release_lockowner(struct lockd_lock *lock) { if (lock->fl.c.flc_owner) nlmsvc_put_lockowner(lock->fl.c.flc_owner); @@ -415,7 +383,7 @@ void nlmsvc_locks_init_private(struct file_lock *fl, struct nlm_host *host, * Initialize arguments for GRANTED call. The nlm_rqst structure * has been cleared already. */ -static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock) +static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct lockd_lock *lock) { locks_copy_lock(&call->a_args.lock.fl, &lock->fl); memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh)); @@ -476,8 +444,8 @@ nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block) */ __be32 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) + struct nlm_host *host, struct lockd_lock *lock, int wait, + struct lockd_cookie *cookie, int reclaim) { struct inode *inode __maybe_unused = nlmsvc_file_inode(file); struct nlm_block *block = NULL; @@ -609,11 +577,10 @@ out: */ __be32 nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, - struct nlm_host *host, struct nlm_lock *lock, - struct nlm_lock *conflock) + struct nlm_host *host, struct lockd_lock *lock, + struct lockd_lock *conflock) { int error; - int mode; __be32 ret; dprintk("lockd: nlmsvc_testlock(%s/%llu, ty=%d, %Ld-%Ld)\n", @@ -631,14 +598,13 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, goto out; } - mode = lock_to_openmode(&lock->fl); locks_init_lock(&conflock->fl); /* vfs_test_lock only uses start, end, and owner, but tests flc_file */ conflock->fl.c.flc_file = lock->fl.c.flc_file; conflock->fl.fl_start = lock->fl.fl_start; conflock->fl.fl_end = lock->fl.fl_end; conflock->fl.c.flc_owner = lock->fl.c.flc_owner; - error = vfs_test_lock(file->f_file[mode], &conflock->fl); + error = vfs_test_lock(lock->fl.c.flc_file, &conflock->fl); if (error) { ret = nlm_lck_denied_nolocks; goto out; @@ -671,7 +637,7 @@ out: * must be removed. */ __be32 -nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock) +nlmsvc_unlock(struct net *net, struct nlm_file *file, struct lockd_lock *lock) { int error = 0; @@ -709,7 +675,7 @@ nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock) * The calling procedure must check whether the file can be closed. */ __be32 -nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *lock) +nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct lockd_lock *lock) { struct nlm_block *block; int status = 0; @@ -850,7 +816,7 @@ static void nlmsvc_grant_blocked(struct nlm_block *block) { struct nlm_file *file = block->b_file; - struct nlm_lock *lock = &block->b_call->a_args.lock; + struct lockd_lock *lock = &block->b_call->a_args.lock; int mode; int error; loff_t fl_start, fl_end; @@ -984,7 +950,7 @@ static const struct rpc_call_ops nlmsvc_grant_ops = { * block. */ void -nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status) +nlmsvc_grant_reply(struct lockd_cookie *cookie, __be32 status) { struct nlm_block *block; struct file_lock *fl; diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 749abf8886ba..a8b5195c2c6b 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -13,11 +13,196 @@ #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; -#define NLMDBG_FACILITY NLMDBG_CLIENT + 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; +} -#ifdef CONFIG_LOCKD_V4 static inline __be32 cast_status(__be32 status) { switch (status) { @@ -32,275 +217,330 @@ static inline __be32 cast_status(__be32 status) status = nlm_lck_denied; break; default: + pr_warn_once("lockd: unhandled internal status %u\n", + be32_to_cpu(status)); status = nlm_lck_denied_nolocks; - } - - return status; -} -#else -static inline __be32 cast_status(__be32 status) -{ - switch (status) { - case nlm__int__deadlock: - status = nlm_lck_denied; - break; - case nlm__int__stale_fh: - case nlm__int__failed: - status = nlm_lck_denied_nolocks; - break; - default: - if (be32_to_cpu(status) >= 30000) - pr_warn_once("lockd: unhandled internal status %u\n", - be32_to_cpu(status)); break; } return status; } -#endif - -/* - * Obtain client and file from arguments - */ -static __be32 -nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, - struct nlm_host **hostp, struct nlm_file **filp) -{ - 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 */ - if (!nlmsvc_ops) - return nlm_lck_denied_nolocks; - /* Obtain host handle */ - if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len)) - || (argp->monitor && nsm_monitor(host) < 0)) - goto no_locks; - *hostp = host; - - /* Obtain file pointer. Not used by FREE_ALL call. */ - if (filp != NULL) { - 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 */ - mode = lock_to_openmode(&lock->fl); - lock->fl.c.flc_flags = FL_POSIX; - lock->fl.c.flc_file = file->f_file[mode]; - lock->fl.c.flc_pid = current->tgid; - lock->fl.fl_lmops = &nlmsvc_lock_operations; - nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid); - if (!lock->fl.c.flc_owner) { - /* lockowner allocation has failed */ - nlmsvc_release_host(host); - return nlm_lck_denied_nolocks; - } - } - - return 0; - -no_locks: - nlmsvc_release_host(host); - if (error) - return error; - return nlm_lck_denied_nolocks; -} - -/* - * NULL: Test for presence of service +/** + * 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) +static __be32 nlmsvc_proc_null(struct svc_rqst *rqstp) { - dprintk("lockd: NULL called\n"); return rpc_success; } -/* - * TEST: Check for conflicting lock +/** + * 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_res *resp) +static __be32 nlmsvc_proc_test(struct svc_rqst *rqstp) { - struct nlm_args *argp = rqstp->rq_argp; + 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; - struct nlm_file *file; - __be32 rc = rpc_success; - dprintk("lockd: TEST called\n"); - resp->cookie = argp->cookie; + resp->xdrgen.cookie = argp->xdrgen.cookie; - /* Obtain client and file */ - if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return resp->status == nlm__int__drop_reply ? - rpc_drop_reply : rpc_success; + resp->xdrgen.test_stat.stat = nlm_lck_denied_nolocks; + host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); + if (!host) + goto out; - /* Now check for conflicting locks */ - resp->status = cast_status(nlmsvc_testlock(rqstp, file, host, - &argp->lock, &resp->lock)); - if (resp->status == nlm__int__drop_reply) - rc = rpc_drop_reply; - else - dprintk("lockd: TEST status %d vers %d\n", - ntohl(resp->status), rqstp->rq_vers); + 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); - nlmsvc_release_host(host); - nlm_release_file(file); - return rc; -} -static __be32 -nlmsvc_proc_test(struct svc_rqst *rqstp) -{ - return __nlmsvc_proc_test(rqstp, rqstp->rq_resp); + 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_proc_lock(struct svc_rqst *rqstp, struct nlm_res *resp) +nlmsvc_do_lock(struct svc_rqst *rqstp, bool monitored) { - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_host *host; - struct nlm_file *file; - __be32 rc = rpc_success; - - dprintk("lockd: LOCK called\n"); - - resp->cookie = argp->cookie; - - /* Obtain client and file */ - if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return resp->status == nlm__int__drop_reply ? - rpc_drop_reply : rpc_success; - - /* Now try to lock the file */ - resp->status = cast_status(nlmsvc_lock(rqstp, file, host, &argp->lock, - argp->block, &argp->cookie, - argp->reclaim)); - if (resp->status == nlm__int__drop_reply) - rc = rpc_drop_reply; - else - dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); + 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); - nlm_release_file(file); - return rc; + 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_proc_lock(rqstp, rqstp->rq_resp); + 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_res *resp) +nlmsvc_proc_cancel(struct svc_rqst *rqstp) { - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_host *host; - struct nlm_file *file; + 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; - dprintk("lockd: CANCEL called\n"); + resp->xdrgen.cookie = argp->xdrgen.cookie; - resp->cookie = argp->cookie; - - /* Don't accept requests during grace period */ - if (locks_in_grace(net)) { - resp->status = nlm_lck_denied_grace_period; - return rpc_success; - } + resp->xdrgen.stat.stat = nlm_lck_denied_grace_period; + if (locks_in_grace(net)) + goto out; - /* Obtain client and file */ - if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return resp->status == nlm__int__drop_reply ? - rpc_drop_reply : rpc_success; + resp->xdrgen.stat.stat = nlm_lck_denied_nolocks; + host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); + if (!host) + goto out; - /* Try to cancel request. */ - resp->status = cast_status(nlmsvc_cancel_blocked(net, file, &argp->lock)); + resp->xdrgen.stat.stat = nlm3svc_lookup_file(rqstp, host, &argp->lock, + &file, &argp->xdrgen.alock, + type); + if (resp->xdrgen.stat.stat) + goto out; - dprintk("lockd: CANCEL status %d\n", ntohl(resp->status)); + resp->xdrgen.stat.stat = nlmsvc_cancel_blocked(net, file, &argp->lock); nlmsvc_release_lockowner(&argp->lock); - nlmsvc_release_host(host); - nlm_release_file(file); - return rpc_success; -} -static __be32 -nlmsvc_proc_cancel(struct svc_rqst *rqstp) -{ - return __nlmsvc_proc_cancel(rqstp, rqstp->rq_resp); +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; } -/* - * UNLOCK: release a lock +/** + * 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_res *resp) +nlmsvc_proc_unlock(struct svc_rqst *rqstp) { - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_host *host; - struct nlm_file *file; + 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; - dprintk("lockd: UNLOCK called\n"); + resp->xdrgen.cookie = argp->xdrgen.cookie; - resp->cookie = argp->cookie; + resp->xdrgen.stat.stat = nlm_lck_denied_grace_period; + if (locks_in_grace(net)) + goto out; - /* Don't accept new lock requests during grace period */ - if (locks_in_grace(net)) { - resp->status = nlm_lck_denied_grace_period; - return rpc_success; - } - - /* Obtain client and file */ - if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return resp->status == nlm__int__drop_reply ? - rpc_drop_reply : rpc_success; + resp->xdrgen.stat.stat = nlm_lck_denied_nolocks; + host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); + if (!host) + goto out; - /* Now try to remove the lock */ - resp->status = cast_status(nlmsvc_unlock(net, file, &argp->lock)); + resp->xdrgen.stat.stat = nlm3svc_lookup_file(rqstp, host, &argp->lock, + &file, &argp->xdrgen.alock, + F_UNLCK); + if (resp->xdrgen.stat.stat) + goto out; - dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status)); + resp->xdrgen.stat.stat = nlmsvc_unlock(net, file, &argp->lock); nlmsvc_release_lockowner(&argp->lock); - nlmsvc_release_host(host); - nlm_release_file(file); - return rpc_success; -} -static __be32 -nlmsvc_proc_unlock(struct svc_rqst *rqstp) -{ - return __nlmsvc_proc_unlock(rqstp, rqstp->rq_resp); +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; } -/* - * GRANTED: A server calls us to tell that a process' lock request - * was granted +/** + * 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_res *resp) +nlmsvc_proc_granted(struct svc_rqst *rqstp) { - struct nlm_args *argp = rqstp->rq_argp; + struct nlm_testargs_wrapper *argp = rqstp->rq_argp; + struct nlm_res_wrapper *resp = rqstp->rq_resp; - resp->cookie = argp->cookie; + resp->xdrgen.cookie = argp->xdrgen.cookie; - dprintk("lockd: GRANTED called\n"); - resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock); - dprintk("lockd: GRANTED status %d\n", ntohl(resp->status)); - return rpc_success; -} + resp->xdrgen.stat.stat = nlm_lock_to_lockd_lock(&argp->lock, + &argp->xdrgen.alock); + if (resp->xdrgen.stat.stat) + goto out; -static __be32 -nlmsvc_proc_granted(struct svc_rqst *rqstp) -{ - return __nlmsvc_proc_granted(rqstp, rqstp->rq_resp); + resp->xdrgen.stat.stat = nlmclnt_grant(svc_addr(rqstp), &argp->lock); + +out: + return rpc_success; } /* @@ -333,20 +573,13 @@ static const struct rpc_call_ops nlmsvc_callback_ops = { * 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, u32 proc, - __be32 (*func)(struct svc_rqst *, struct nlm_res *)) +static __be32 +nlmsvc_callback(struct svc_rqst *rqstp, struct nlm_host *host, u32 proc, + __be32 (*func)(struct svc_rqst *, struct lockd_res *)) { - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_host *host; struct nlm_rqst *call; __be32 stat; - host = nlmsvc_lookup_host(rqstp, - argp->lock.caller, - argp->lock.len); - if (host == NULL) - return rpc_system_err; - call = nlm_alloc_call(host); nlmsvc_release_host(host); if (call == NULL) @@ -364,440 +597,822 @@ static __be32 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, return rpc_success; } -static __be32 nlmsvc_proc_test_msg(struct svc_rqst *rqstp) +static __be32 +__nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct lockd_res *resp) { - dprintk("lockd: TEST_MSG called\n"); - return nlmsvc_callback(rqstp, NLMPROC_TEST_RES, __nlmsvc_proc_test); + 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; } -static __be32 nlmsvc_proc_lock_msg(struct svc_rqst *rqstp) +/** + * 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) { - dprintk("lockd: LOCK_MSG called\n"); - return nlmsvc_callback(rqstp, NLMPROC_LOCK_RES, __nlmsvc_proc_lock); + 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_cancel_msg(struct svc_rqst *rqstp) +static __be32 +__nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct lockd_res *resp) { - dprintk("lockd: CANCEL_MSG called\n"); - return nlmsvc_callback(rqstp, NLMPROC_CANCEL_RES, __nlmsvc_proc_cancel); + 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; } -static __be32 -nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp) +/** + * 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) { - dprintk("lockd: UNLOCK_MSG called\n"); - return nlmsvc_callback(rqstp, NLMPROC_UNLOCK_RES, __nlmsvc_proc_unlock); + 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_granted_msg(struct svc_rqst *rqstp) +__nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct lockd_res *resp) { - dprintk("lockd: GRANTED_MSG called\n"); - return nlmsvc_callback(rqstp, NLMPROC_GRANTED_RES, __nlmsvc_proc_granted); + 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; } -/* - * SHARE: create a DOS share or alter existing share. +/** + * 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_share(struct svc_rqst *rqstp) +static __be32 nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp) { - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_res *resp = rqstp->rq_resp; - struct nlm_host *host; - struct nlm_file *file; + struct nlm_cancargs_wrapper *argp = rqstp->rq_argp; + struct nlm_host *host; - dprintk("lockd: SHARE called\n"); + if (argp->xdrgen.cookie.len > NLM_MAXCOOKIELEN) + return rpc_garbage_args; - resp->cookie = argp->cookie; + host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); + if (!host) + return rpc_system_err; - /* Don't accept new lock requests during grace period */ - if (locks_in_grace(SVC_NET(rqstp)) && !argp->reclaim) { - resp->status = nlm_lck_denied_grace_period; - return rpc_success; - } + return nlmsvc_callback(rqstp, host, NLMPROC_CANCEL_RES, + __nlmsvc_proc_cancel_msg); +} - /* Obtain client and file */ - if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return resp->status == nlm__int__drop_reply ? - rpc_drop_reply : rpc_success; +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; - /* Now try to create the share */ - resp->status = cast_status(nlmsvc_share_file(host, file, &argp->lock.oh, - argp->fsm_access, - argp->fsm_mode)); + resp->status = nlm_lck_denied_nolocks; + host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); + if (!host) + goto out; - dprintk("lockd: SHARE status %d\n", ntohl(resp->status)); + 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); - nlm_release_file(file); - return rpc_success; + return resp->status == nlm__int__drop_reply ? rpc_drop_reply : rpc_success; } -/* - * UNSHARE: Release a DOS share. +/** + * 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_unshare(struct svc_rqst *rqstp) +static __be32 nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp) { - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_res *resp = rqstp->rq_resp; - struct nlm_host *host; - struct nlm_file *file; + struct nlm_unlockargs_wrapper *argp = rqstp->rq_argp; + struct nlm_host *host; - dprintk("lockd: UNSHARE called\n"); + if (argp->xdrgen.cookie.len > NLM_MAXCOOKIELEN) + return rpc_garbage_args; - resp->cookie = argp->cookie; + host = nlm3svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); + if (!host) + return rpc_system_err; - /* Don't accept requests during grace period */ - if (locks_in_grace(SVC_NET(rqstp))) { - resp->status = nlm_lck_denied_grace_period; - return rpc_success; - } + return nlmsvc_callback(rqstp, host, NLMPROC_UNLOCK_RES, + __nlmsvc_proc_unlock_msg); +} - /* Obtain client and file */ - if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) - return resp->status == nlm__int__drop_reply ? - rpc_drop_reply : rpc_success; +static __be32 +__nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct lockd_res *resp) +{ + struct nlm_testargs_wrapper *argp = rqstp->rq_argp; - /* Now try to unshare the file */ - resp->status = cast_status(nlmsvc_unshare_file(host, file, - &argp->lock.oh)); + resp->status = nlm_lck_denied; + if (nlm_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie)) + goto out; - dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status)); - nlmsvc_release_lockowner(&argp->lock); - nlmsvc_release_host(host); - nlm_release_file(file); + 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; } -/* - * NM_LOCK: Create an unmonitored lock +/** + * 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_nm_lock(struct svc_rqst *rqstp) +static __be32 nlmsvc_proc_granted_msg(struct svc_rqst *rqstp) { - struct nlm_args *argp = rqstp->rq_argp; + struct nlm_testargs_wrapper *argp = rqstp->rq_argp; + struct nlm_host *host; - dprintk("lockd: NM_LOCK called\n"); + if (argp->xdrgen.cookie.len > NLM_MAXCOOKIELEN) + return rpc_garbage_args; - argp->monitor = 0; /* just clean the monitor flag */ - return nlmsvc_proc_lock(rqstp); + 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); } -/* - * FREE_ALL: Release all locks and shares held by client +/** + * 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_free_all(struct svc_rqst *rqstp) +static __be32 nlmsvc_proc_granted_res(struct svc_rqst *rqstp) { - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_host *host; + struct nlm_res_wrapper *argp = rqstp->rq_argp; - /* Obtain client */ - if (nlmsvc_retrieve_args(rqstp, argp, &host, NULL)) + if (!rcu_access_pointer(nlmsvc_ops)) return rpc_success; - nlmsvc_free_host_resources(host); - nlmsvc_release_host(host); + 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; } -/* - * SM_NOTIFY: private callback from statd (not part of official NLM proto) +/** + * 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) +static __be32 nlmsvc_proc_sm_notify(struct svc_rqst *rqstp) { - struct nlm_reboot *argp = rqstp->rq_argp; - - dprintk("lockd: SM_NOTIFY called\n"); + struct nlm_notifyargs_wrapper *argp = rqstp->rq_argp; + struct lockd_reboot *reboot = &argp->reboot; if (!nlm_privileged_requester(rqstp)) { char buf[RPC_MAX_ADDRBUFLEN]; - printk(KERN_WARNING "lockd: rejected NSM callback from %s\n", - svc_print_addr(rqstp, buf, sizeof(buf))); + + pr_warn("lockd: rejected NSM callback from %s\n", + svc_print_addr(rqstp, buf, sizeof(buf))); return rpc_system_err; } - nlm_host_rebooted(SVC_NET(rqstp), argp); + 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; } -/* - * client sent a GRANTED_RES, let's remove the associated block +/** + * nlmsvc_proc_unused - stub for unused procedures + * @rqstp: RPC transaction context + * + * Returns: + * %rpc_proc_unavail: Program can't support procedure. */ -static __be32 -nlmsvc_proc_granted_res(struct svc_rqst *rqstp) +static __be32 nlmsvc_proc_unused(struct svc_rqst *rqstp) { - struct nlm_res *argp = rqstp->rq_argp; - - if (!nlmsvc_ops) - return rpc_success; + return rpc_proc_unavail; +} - dprintk("lockd: GRANTED_RES called\n"); +/** + * 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_grant_reply(&argp->cookie, argp->status); - return 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; } -static __be32 -nlmsvc_proc_unused(struct svc_rqst *rqstp) +/** + * 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 rpc_proc_unavail; + return nlmsvc_do_lock(rqstp, false); } -/* - * NLM Server procedures. +/** + * 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; -struct nlm_void { int dummy; }; + nlmsvc_free_host_resources(host); + + nlmsvc_release_host(host); + +out: + return rpc_success; +} -#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 */ +/* + * NLMv3 Server procedures. + */ static 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", + [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", }, - [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", + [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", }, - [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", + [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", }, - [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", + [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", }, - [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", + [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", }, - [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", + [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", }, - [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", + [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", }, - [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", + [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", }, - [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", + [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", }, - [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", + [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", }, - [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", + [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", }, - [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", + [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", }, - [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", + [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", }, - [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", + [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", }, - [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", + [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", }, - [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", + [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", }, - [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", + [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 = 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", + .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 = 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", + .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 = 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", + .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", }, - [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", + [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", }, - [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", + [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", }, - [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", + [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", }, - [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", + [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", }, }; @@ -805,34 +1420,34 @@ static const struct svc_procedure nlmsvc_procedures[24] = { * Storage requirements for XDR arguments and results */ union nlmsvc_xdrstore { - struct nlm_args args; - struct nlm_res res; - struct nlm_reboot reboot; + 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). */ -static DEFINE_PER_CPU_ALIGNED(unsigned long, nlm1svc_call_counters[17]); - const struct svc_version nlmsvc_version1 = { .vs_vers = 1, .vs_nproc = 17, .vs_proc = nlmsvc_procedures, - .vs_count = nlm1svc_call_counters, .vs_dispatch = nlmsvc_dispatch, .vs_xdrsize = sizeof(union nlmsvc_xdrstore), }; -static DEFINE_PER_CPU_ALIGNED(unsigned long, - nlm3svc_call_counters[ARRAY_SIZE(nlmsvc_procedures)]); - const struct svc_version nlmsvc_version3 = { .vs_vers = 3, .vs_nproc = ARRAY_SIZE(nlmsvc_procedures), .vs_proc = nlmsvc_procedures, - .vs_count = nlm3svc_call_counters, .vs_dispatch = nlmsvc_dispatch, .vs_xdrsize = sizeof(union nlmsvc_xdrstore), }; diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c index 53f5655c128c..a58b7035b58b 100644 --- a/fs/lockd/svcshare.c +++ b/fs/lockd/svcshare.c @@ -19,12 +19,31 @@ #include "share.h" static inline int -nlm_cmp_owner(struct nlm_share *share, struct xdr_netobj *oh) +nlm_cmp_owner(struct lockd_share *share, struct xdr_netobj *oh) { return share->s_owner.len == oh->len && !memcmp(share->s_owner.data, oh->data, oh->len); } +/* + * Recompute s_access / s_mode as the union of every (access, deny) pair + * whose bit is currently set in s_access_deny_bmap. + */ +static void nlm_recompute_share(struct lockd_share *share) +{ + u32 new_access = 0, new_mode = 0; + unsigned int i; + + for (i = 0; i < 16; i++) { + if (share->s_access_deny_bmap & BIT(i)) { + new_access |= i >> 2; + new_mode |= i & 3; + } + } + share->s_access = new_access; + share->s_mode = new_mode; +} + /** * nlmsvc_share_file - create a share * @host: Network client peer @@ -39,7 +58,7 @@ __be32 nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file, struct xdr_netobj *oh, u32 access, u32 mode) { - struct nlm_share *share; + struct lockd_share *share; u8 *ohdata; if (nlmsvc_file_cannot_lock(file)) @@ -64,12 +83,13 @@ nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file, share->s_host = host; share->s_owner.data = ohdata; share->s_owner.len = oh->len; + share->s_access_deny_bmap = 0; share->s_next = file->f_shares; file->f_shares = share; update: - share->s_access = access; - share->s_mode = mode; + share->s_access_deny_bmap |= LOCKD_FSH_BIT(access, mode); + nlm_recompute_share(share); return nlm_granted; } @@ -78,14 +98,16 @@ update: * @host: Network client peer * @file: File to be unshared * @oh: Share owner handle + * @access: Access mode of the SHARE being released + * @mode: Deny mode of the SHARE being released * * Returns an NLM status code. */ __be32 nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file, - struct xdr_netobj *oh) + struct xdr_netobj *oh, u32 access, u32 mode) { - struct nlm_share *share, **shpp; + struct lockd_share *share, **shpp; if (nlmsvc_file_cannot_lock(file)) return nlm_lck_denied_nolocks; @@ -93,8 +115,12 @@ nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file, for (shpp = &file->f_shares; (share = *shpp) != NULL; shpp = &share->s_next) { if (share->s_host == host && nlm_cmp_owner(share, oh)) { - *shpp = share->s_next; - kfree(share); + share->s_access_deny_bmap &= ~LOCKD_FSH_BIT(access, mode); + nlm_recompute_share(share); + if (!share->s_access_deny_bmap) { + *shpp = share->s_next; + kfree(share); + } return nlm_granted; } } @@ -111,7 +137,7 @@ nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file, void nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, nlm_host_match_fn_t match) { - struct nlm_share *share, **shpp; + struct lockd_share *share, **shpp; shpp = &file->f_shares; while ((share = *shpp) != NULL) { diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index 344e6c187cde..ffab76278bb2 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -17,7 +17,6 @@ #include <linux/sunrpc/addr.h> #include <linux/module.h> #include <linux/mount.h> -#include <uapi/linux/nfs2.h> #include "lockd.h" #include "share.h" @@ -67,7 +66,7 @@ static inline unsigned int file_hash(struct nfs_fh *f) { unsigned int tmp=0; int i; - for (i=0; i<NFS2_FHSIZE;i++) + for (i = 0; i < LOCKD_FH_HASH_SIZE; i++) tmp += f->data[i]; return tmp & (FILE_NRHASH - 1); } @@ -83,23 +82,49 @@ int lock_to_openmode(struct file_lock *lock) * * We have to make sure we have the right credential to open * the file. + * + * @mode is O_RDONLY, O_WRONLY, or O_RDWR. O_RDWR means success + * is achieved with EITHER O_RDONLY or O_WRONLY; it does not + * require both. */ static __be32 nlm_do_fopen(struct svc_rqst *rqstp, struct nlm_file *file, int mode) { - struct file **fp = &file->f_file[mode]; - __be32 nlmerr = nlm_granted; + const struct nlmsvc_binding *ops; + __be32 nlmerr = nlm__int__failed; + __be32 deferred = 0; int error; + int m; + + rcu_read_lock(); + ops = rcu_dereference(nlmsvc_ops); + if (!ops || !try_module_get(ops->owner)) { + rcu_read_unlock(); + return nlm__int__failed; + } + rcu_read_unlock(); + + for (m = O_RDONLY; m <= O_WRONLY; m++) { + struct file **fp = &file->f_file[m]; - if (*fp) - return nlmerr; + if (mode != O_RDWR && mode != m) + continue; + if (*fp) { + module_put(ops->owner); + return nlm_granted; + } + + error = ops->fopen(rqstp, &file->f_handle, fp, m); + if (!error) { + module_put(ops->owner); + return nlm_granted; + } - error = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, mode); - if (error) { dprintk("lockd: open failed (errno %d)\n", error); switch (error) { case -EWOULDBLOCK: nlmerr = nlm__int__drop_reply; + deferred = nlmerr; break; case -ESTALE: nlmerr = nlm__int__stale_fh; @@ -110,7 +135,8 @@ static __be32 nlm_do_fopen(struct svc_rqst *rqstp, } } - return nlmerr; + module_put(ops->owner); + return deferred ? deferred : nlmerr; } /* @@ -119,17 +145,15 @@ static __be32 nlm_do_fopen(struct svc_rqst *rqstp, */ __be32 nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, - struct nlm_lock *lock) + struct lockd_lock *lock, int mode) { struct nlm_file *file; unsigned int hash; __be32 nfserr; - int mode; nlm_debug_print_fh("nlm_lookup_file", &lock->fh); hash = file_hash(&lock->fh); - mode = lock_to_openmode(&lock->fl); /* Lock file table */ mutex_lock(&nlm_file_mutex); @@ -139,6 +163,8 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, mutex_lock(&file->f_mutex); nfserr = nlm_do_fopen(rqstp, file, mode); mutex_unlock(&file->f_mutex); + if (nfserr) + goto out_unlock; goto found; } nlm_debug_print_fh("creating file for", &lock->fh); @@ -155,7 +181,7 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, nfserr = nlm_do_fopen(rqstp, file, mode); if (nfserr) - goto out_unlock; + goto out_free; hlist_add_head(&file->f_list, &nlm_files[hash]); @@ -174,6 +200,33 @@ out_free: } /* + * Release the struct file references held by a nlm_file. + */ +static void nlm_release_files(struct nlm_file *file) +{ + const struct nlmsvc_binding *ops; + bool have_ops; + + rcu_read_lock(); + ops = rcu_dereference(nlmsvc_ops); + have_ops = ops && try_module_get(ops->owner); + rcu_read_unlock(); + + if (have_ops) { + if (file->f_file[O_RDONLY]) + ops->fclose(file->f_file[O_RDONLY]); + if (file->f_file[O_WRONLY]) + ops->fclose(file->f_file[O_WRONLY]); + module_put(ops->owner); + } else { + if (file->f_file[O_RDONLY]) + fput(file->f_file[O_RDONLY]); + if (file->f_file[O_WRONLY]) + fput(file->f_file[O_WRONLY]); + } +} + +/* * Delete a file after having released all locks, blocks and shares */ static inline void @@ -182,10 +235,7 @@ 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); - 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]); + nlm_release_files(file); kfree(file); } else { printk(KERN_WARNING "lockd: attempt to release unknown file!\n"); @@ -300,12 +350,10 @@ nlm_file_inuse(struct nlm_file *file) return 0; } -static void nlm_close_files(struct nlm_file *file) +static void nlm_file_release(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]); + if (!nlm_file_inuse(file)) + nlm_delete_file(file); } /* @@ -315,32 +363,41 @@ static int nlm_traverse_files(void *data, nlm_host_match_fn_t match, int (*is_failover_file)(void *data, struct nlm_file *file)) { - struct hlist_node *next; - struct nlm_file *file; + struct nlm_file *file, *next; int i, ret = 0; mutex_lock(&nlm_file_mutex); for (i = 0; i < FILE_NRHASH; i++) { - hlist_for_each_entry_safe(file, next, &nlm_files[i], f_list) { - if (is_failover_file && !is_failover_file(data, file)) - continue; + file = hlist_entry_safe(nlm_files[i].first, + struct nlm_file, f_list); + if (file) file->f_count++; - mutex_unlock(&nlm_file_mutex); - - /* Traverse locks, blocks and shares of this file - * and update file->f_locks count */ - if (nlm_inspect_file(data, file, match)) - ret = 1; + while (file) { + /* + * Pin the next neighbour before we drop the mutex + * for nlm_inspect_file(); a concurrent + * nlm_release_file() under the same mutex would + * otherwise be free to unlink and kfree it during + * the unlock window, leaving us to dereference a + * freed slab when we walked to next afterwards. + */ + next = hlist_entry_safe(file->f_list.next, + struct nlm_file, f_list); + if (next) + next->f_count++; + + if (!is_failover_file || is_failover_file(data, file)) { + mutex_unlock(&nlm_file_mutex); + + if (nlm_inspect_file(data, file, match)) + ret = 1; + + mutex_lock(&nlm_file_mutex); + } - mutex_lock(&nlm_file_mutex); file->f_count--; - /* No more references to this file. Let go of it. */ - if (list_empty(&file->f_blocks) && !file->f_locks - && !file->f_shares && !file->f_count) { - hlist_del(&file->f_list); - nlm_close_files(file); - kfree(file); - } + nlm_file_release(file); + file = next; } } mutex_unlock(&nlm_file_mutex); @@ -500,7 +557,7 @@ EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb); static int nlmsvc_match_ip(void *datap, struct nlm_host *host) { - return rpc_cmp_addr(nlm_srcaddr(host), datap); + return rpc_cmp_addr(nlm_srcaddr(datap), (struct sockaddr *)host); } /** diff --git a/fs/lockd/svcxdr.h b/fs/lockd/svcxdr.h deleted file mode 100644 index 4f1a451da5ba..000000000000 --- a/fs/lockd/svcxdr.h +++ /dev/null @@ -1,142 +0,0 @@ -/* 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/trace.h b/fs/lockd/trace.h index 7214d7e96a42..a11d04e8c835 100644 --- a/fs/lockd/trace.h +++ b/fs/lockd/trace.h @@ -48,7 +48,7 @@ NLM_STATUS_LIST DECLARE_EVENT_CLASS(nlmclnt_lock_event, TP_PROTO( - const struct nlm_lock *lock, + const struct lockd_lock *lock, const struct sockaddr *addr, unsigned int addrlen, __be32 status @@ -61,8 +61,8 @@ DECLARE_EVENT_CLASS(nlmclnt_lock_event, __field(u32, svid) __field(u32, fh) __field(unsigned long, status) - __field(u64, start) - __field(u64, len) + __field(loff_t, start) + __field(loff_t, end) __sockaddr(addr, addrlen) ), @@ -70,16 +70,16 @@ DECLARE_EVENT_CLASS(nlmclnt_lock_event, __entry->oh = ~crc32_le(0xffffffff, lock->oh.data, lock->oh.len); __entry->svid = lock->svid; __entry->fh = nfs_fhandle_hash(&lock->fh); - __entry->start = lock->lock_start; - __entry->len = lock->lock_len; + __entry->start = lock->fl.fl_start; + __entry->end = lock->fl.fl_end; __entry->status = be32_to_cpu(status); __assign_sockaddr(addr, addr, addrlen); ), TP_printk( - "addr=%pISpc oh=0x%08x svid=0x%08x fh=0x%08x start=%llu len=%llu status=%s", + "addr=%pISpc oh=0x%08x svid=0x%08x fh=0x%08x start=%lld end=%lld status=%s", __get_sockaddr(addr), __entry->oh, __entry->svid, - __entry->fh, __entry->start, __entry->len, + __entry->fh, __entry->start, __entry->end, show_nlm_status(__entry->status) ) ); @@ -87,7 +87,7 @@ DECLARE_EVENT_CLASS(nlmclnt_lock_event, #define DEFINE_NLMCLNT_EVENT(name) \ DEFINE_EVENT(nlmclnt_lock_event, name, \ TP_PROTO( \ - const struct nlm_lock *lock, \ + const struct lockd_lock *lock, \ const struct sockaddr *addr, \ unsigned int addrlen, \ __be32 status \ diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c deleted file mode 100644 index dfca8b8dab73..000000000000 --- a/fs/lockd/xdr.c +++ /dev/null @@ -1,354 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * linux/fs/lockd/xdr.c - * - * XDR support for lockd and the lock client. - * - * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> - */ - -#include <linux/types.h> -#include <linux/sched.h> -#include <linux/nfs.h> - -#include <linux/sunrpc/xdr.h> -#include <linux/sunrpc/clnt.h> -#include <linux/sunrpc/svc.h> -#include <linux/sunrpc/stats.h> - -#include <uapi/linux/nfs2.h> - -#include "lockd.h" -#include "share.h" -#include "svcxdr.h" - -static inline loff_t -s32_to_loff_t(__s32 offset) -{ - return (loff_t)offset; -} - -static inline __s32 -loff_t_to_s32(loff_t offset) -{ - __s32 res; - if (offset >= NLM_OFFSET_MAX) - res = NLM_OFFSET_MAX; - else if (offset <= -NLM_OFFSET_MAX) - res = -NLM_OFFSET_MAX; - else - res = offset; - return res; -} - -/* - * 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 bool -svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) -{ - __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 bool -svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) -{ - 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->c.flc_flags = FL_POSIX; - fl->c.flc_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 true; -} - -static bool -svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock) -{ - const struct file_lock *fl = &lock->fl; - s32 start, len; - - /* exclusive */ - if (xdr_stream_encode_bool(xdr, fl->c.flc_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; - - return true; -} - -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 true; -} - - -/* - * Decode Call arguments - */ - -bool -nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) -{ - return true; -} - -bool -nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) -{ - 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.c.flc_type = F_WRLCK; - - return true; -} - -bool -nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) -{ - struct nlm_args *argp = rqstp->rq_argp; - 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.c.flc_type = F_WRLCK; - 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 true; -} - -bool -nlmsvc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) -{ - struct nlm_args *argp = rqstp->rq_argp; - 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.c.flc_type = F_WRLCK; - - return true; -} - -bool -nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) -{ - struct nlm_args *argp = rqstp->rq_argp; - - if (!svcxdr_decode_cookie(xdr, &argp->cookie)) - return false; - if (!svcxdr_decode_lock(xdr, &argp->lock)) - return false; - argp->lock.fl.c.flc_type = F_UNLCK; - - return true; -} - -bool -nlmsvc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) -{ - struct nlm_res *resp = rqstp->rq_argp; - - if (!svcxdr_decode_cookie(xdr, &resp->cookie)) - return false; - if (!svcxdr_decode_stats(xdr, &resp->status)) - return false; - - return true; -} - -bool -nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr) -{ - 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)); - - return true; -} - -bool -nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) -{ - struct nlm_args *argp = rqstp->rq_argp; - struct nlm_lock *lock = &argp->lock; - - memset(lock, 0, sizeof(*lock)); - locks_init_lock(&lock->fl); - lock->svid = LOCKD_SHARE_SVID; - - 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; -} - -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 (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) - return false; - if (xdr_stream_decode_u32(xdr, &argp->state) < 0) - return false; - - return true; -} - - -/* - * Encode Reply results - */ - -bool -nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) -{ - return true; -} - -bool -nlmsvc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr) -{ - struct nlm_res *resp = rqstp->rq_resp; - - return svcxdr_encode_cookie(xdr, &resp->cookie) && - svcxdr_encode_testrply(xdr, resp); -} - -bool -nlmsvc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) -{ - struct nlm_res *resp = rqstp->rq_resp; - - return svcxdr_encode_cookie(xdr, &resp->cookie) && - svcxdr_encode_stats(xdr, resp->status); -} - -bool -nlmsvc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr) -{ - 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/xdr.h b/fs/lockd/xdr.h index 3c60817c4349..a1126cca98c6 100644 --- a/fs/lockd/xdr.h +++ b/fs/lockd/xdr.h @@ -20,8 +20,6 @@ struct nsm_private { unsigned char data[SM_PRIV_SIZE]; }; -struct svc_rqst; - #define NLM_MAXCOOKIELEN 32 #define NLM_MAXSTRLEN 1024 @@ -32,7 +30,7 @@ struct svc_rqst; #define nlm_lck_denied_grace_period cpu_to_be32(NLM_LCK_DENIED_GRACE_PERIOD) /* Lock info passed via NLM */ -struct nlm_lock { +struct lockd_lock { char * caller; unsigned int len; /* length of "caller" */ struct nfs_fh fh; @@ -49,8 +47,7 @@ struct nlm_lock { * 32 bytes. */ -struct nlm_cookie -{ +struct lockd_cookie { unsigned char data[NLM_MAXCOOKIELEN]; unsigned int len; }; @@ -58,49 +55,31 @@ struct nlm_cookie /* * Generic lockd arguments for all but sm_notify */ -struct nlm_args { - struct nlm_cookie cookie; - struct nlm_lock lock; +struct lockd_args { + struct lockd_cookie cookie; + struct lockd_lock lock; u32 block; u32 reclaim; u32 state; - u32 monitor; - u32 fsm_access; - u32 fsm_mode; }; /* * Generic lockd result */ -struct nlm_res { - struct nlm_cookie cookie; +struct lockd_res { + struct lockd_cookie cookie; __be32 status; - struct nlm_lock lock; + struct lockd_lock lock; }; /* * statd callback when client has rebooted */ -struct nlm_reboot { +struct lockd_reboot { char *mon; unsigned int len; u32 state; struct nsm_private priv; }; -bool nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); -bool nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); -bool nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); -bool nlmsvc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); -bool nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); -bool nlmsvc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); -bool nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr); -bool nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); -bool nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr); - -bool nlmsvc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr); -bool nlmsvc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); -bool nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); -bool nlmsvc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr); - #endif /* _LOCKD_XDR_H */ |
