13460f29aSChuck Lever /* 23460f29aSChuck Lever * linux/fs/lockd/clnt4xdr.c 33460f29aSChuck Lever * 43460f29aSChuck Lever * XDR functions to encode/decode NLM version 4 RPC arguments and results. 53460f29aSChuck Lever * 63460f29aSChuck Lever * NLM client-side only. 73460f29aSChuck Lever * 83460f29aSChuck Lever * Copyright (C) 2010, Oracle. All rights reserved. 93460f29aSChuck Lever */ 103460f29aSChuck Lever 113460f29aSChuck Lever #include <linux/types.h> 123460f29aSChuck Lever #include <linux/sunrpc/xdr.h> 133460f29aSChuck Lever #include <linux/sunrpc/clnt.h> 143460f29aSChuck Lever #include <linux/sunrpc/stats.h> 153460f29aSChuck Lever #include <linux/lockd/lockd.h> 163460f29aSChuck Lever 179c69de4cSChristoph Hellwig #include <uapi/linux/nfs3.h> 189c69de4cSChristoph Hellwig 193460f29aSChuck Lever #define NLMDBG_FACILITY NLMDBG_XDR 203460f29aSChuck Lever 213460f29aSChuck Lever #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ) 223460f29aSChuck Lever # error "NLM host name cannot be larger than XDR_MAX_NETOBJ!" 233460f29aSChuck Lever #endif 243460f29aSChuck Lever 253460f29aSChuck Lever #if (NLMCLNT_OHSIZE > NLM_MAXSTRLEN) 263460f29aSChuck Lever # error "NLM host name cannot be larger than NLM's maximum string length!" 273460f29aSChuck Lever #endif 283460f29aSChuck Lever 293460f29aSChuck Lever /* 303460f29aSChuck Lever * Declare the space requirements for NLM arguments and replies as 313460f29aSChuck Lever * number of 32bit-words 323460f29aSChuck Lever */ 333460f29aSChuck Lever #define NLM4_void_sz (0) 343460f29aSChuck Lever #define NLM4_cookie_sz (1+(NLM_MAXCOOKIELEN>>2)) 353460f29aSChuck Lever #define NLM4_caller_sz (1+(NLMCLNT_OHSIZE>>2)) 363460f29aSChuck Lever #define NLM4_owner_sz (1+(NLMCLNT_OHSIZE>>2)) 373460f29aSChuck Lever #define NLM4_fhandle_sz (1+(NFS3_FHSIZE>>2)) 383460f29aSChuck Lever #define NLM4_lock_sz (5+NLM4_caller_sz+NLM4_owner_sz+NLM4_fhandle_sz) 393460f29aSChuck Lever #define NLM4_holder_sz (6+NLM4_owner_sz) 403460f29aSChuck Lever 413460f29aSChuck Lever #define NLM4_testargs_sz (NLM4_cookie_sz+1+NLM4_lock_sz) 423460f29aSChuck Lever #define NLM4_lockargs_sz (NLM4_cookie_sz+4+NLM4_lock_sz) 433460f29aSChuck Lever #define NLM4_cancargs_sz (NLM4_cookie_sz+2+NLM4_lock_sz) 443460f29aSChuck Lever #define NLM4_unlockargs_sz (NLM4_cookie_sz+NLM4_lock_sz) 453460f29aSChuck Lever 463460f29aSChuck Lever #define NLM4_testres_sz (NLM4_cookie_sz+1+NLM4_holder_sz) 473460f29aSChuck Lever #define NLM4_res_sz (NLM4_cookie_sz+1) 483460f29aSChuck Lever #define NLM4_norep_sz (0) 493460f29aSChuck Lever 503460f29aSChuck Lever 513460f29aSChuck Lever static s64 loff_t_to_s64(loff_t offset) 523460f29aSChuck Lever { 533460f29aSChuck Lever s64 res; 543460f29aSChuck Lever 553460f29aSChuck Lever if (offset >= NLM4_OFFSET_MAX) 563460f29aSChuck Lever res = NLM4_OFFSET_MAX; 573460f29aSChuck Lever else if (offset <= -NLM4_OFFSET_MAX) 583460f29aSChuck Lever res = -NLM4_OFFSET_MAX; 593460f29aSChuck Lever else 603460f29aSChuck Lever res = offset; 613460f29aSChuck Lever return res; 623460f29aSChuck Lever } 633460f29aSChuck Lever 643460f29aSChuck Lever static void nlm4_compute_offsets(const struct nlm_lock *lock, 653460f29aSChuck Lever u64 *l_offset, u64 *l_len) 663460f29aSChuck Lever { 673460f29aSChuck Lever const struct file_lock *fl = &lock->fl; 683460f29aSChuck Lever 693460f29aSChuck Lever *l_offset = loff_t_to_s64(fl->fl_start); 703460f29aSChuck Lever if (fl->fl_end == OFFSET_MAX) 713460f29aSChuck Lever *l_len = 0; 723460f29aSChuck Lever else 733460f29aSChuck Lever *l_len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); 743460f29aSChuck Lever } 753460f29aSChuck Lever 763460f29aSChuck Lever /* 773460f29aSChuck Lever * Handle decode buffer overflows out-of-line. 783460f29aSChuck Lever */ 793460f29aSChuck Lever static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) 803460f29aSChuck Lever { 813460f29aSChuck Lever dprintk("lockd: %s prematurely hit the end of our receive buffer. " 823460f29aSChuck Lever "Remaining buffer length is %tu words.\n", 833460f29aSChuck Lever func, xdr->end - xdr->p); 843460f29aSChuck Lever } 853460f29aSChuck Lever 863460f29aSChuck Lever 873460f29aSChuck Lever /* 883460f29aSChuck Lever * Encode/decode NLMv4 basic data types 893460f29aSChuck Lever * 903460f29aSChuck Lever * Basic NLMv4 data types are defined in Appendix II, section 6.1.4 913460f29aSChuck Lever * of RFC 1813: "NFS Version 3 Protocol Specification" and in Chapter 923460f29aSChuck Lever * 10 of X/Open's "Protocols for Interworking: XNFS, Version 3W". 933460f29aSChuck Lever * 943460f29aSChuck Lever * Not all basic data types have their own encoding and decoding 953460f29aSChuck Lever * functions. For run-time efficiency, some data types are encoded 963460f29aSChuck Lever * or decoded inline. 973460f29aSChuck Lever */ 983460f29aSChuck Lever 993460f29aSChuck Lever static void encode_bool(struct xdr_stream *xdr, const int value) 1003460f29aSChuck Lever { 1013460f29aSChuck Lever __be32 *p; 1023460f29aSChuck Lever 1033460f29aSChuck Lever p = xdr_reserve_space(xdr, 4); 1043460f29aSChuck Lever *p = value ? xdr_one : xdr_zero; 1053460f29aSChuck Lever } 1063460f29aSChuck Lever 1073460f29aSChuck Lever static void encode_int32(struct xdr_stream *xdr, const s32 value) 1083460f29aSChuck Lever { 1093460f29aSChuck Lever __be32 *p; 1103460f29aSChuck Lever 1113460f29aSChuck Lever p = xdr_reserve_space(xdr, 4); 1123460f29aSChuck Lever *p = cpu_to_be32(value); 1133460f29aSChuck Lever } 1143460f29aSChuck Lever 1153460f29aSChuck Lever /* 1163460f29aSChuck Lever * typedef opaque netobj<MAXNETOBJ_SZ> 1173460f29aSChuck Lever */ 1183460f29aSChuck Lever static void encode_netobj(struct xdr_stream *xdr, 1193460f29aSChuck Lever const u8 *data, const unsigned int length) 1203460f29aSChuck Lever { 1213460f29aSChuck Lever __be32 *p; 1223460f29aSChuck Lever 1233460f29aSChuck Lever p = xdr_reserve_space(xdr, 4 + length); 1243460f29aSChuck Lever xdr_encode_opaque(p, data, length); 1253460f29aSChuck Lever } 1263460f29aSChuck Lever 1273460f29aSChuck Lever static int decode_netobj(struct xdr_stream *xdr, 1283460f29aSChuck Lever struct xdr_netobj *obj) 1293460f29aSChuck Lever { 1303460f29aSChuck Lever u32 length; 1313460f29aSChuck Lever __be32 *p; 1323460f29aSChuck Lever 1333460f29aSChuck Lever p = xdr_inline_decode(xdr, 4); 1343460f29aSChuck Lever if (unlikely(p == NULL)) 1353460f29aSChuck Lever goto out_overflow; 1363460f29aSChuck Lever length = be32_to_cpup(p++); 1373460f29aSChuck Lever if (unlikely(length > XDR_MAX_NETOBJ)) 1383460f29aSChuck Lever goto out_size; 1393460f29aSChuck Lever obj->len = length; 1403460f29aSChuck Lever obj->data = (u8 *)p; 1413460f29aSChuck Lever return 0; 1423460f29aSChuck Lever out_size: 1433460f29aSChuck Lever dprintk("NFS: returned netobj was too long: %u\n", length); 1443460f29aSChuck Lever return -EIO; 1453460f29aSChuck Lever out_overflow: 1463460f29aSChuck Lever print_overflow_msg(__func__, xdr); 1473460f29aSChuck Lever return -EIO; 1483460f29aSChuck Lever } 1493460f29aSChuck Lever 1503460f29aSChuck Lever /* 1513460f29aSChuck Lever * netobj cookie; 1523460f29aSChuck Lever */ 1533460f29aSChuck Lever static void encode_cookie(struct xdr_stream *xdr, 1543460f29aSChuck Lever const struct nlm_cookie *cookie) 1553460f29aSChuck Lever { 1563460f29aSChuck Lever encode_netobj(xdr, (u8 *)&cookie->data, cookie->len); 1573460f29aSChuck Lever } 1583460f29aSChuck Lever 1593460f29aSChuck Lever static int decode_cookie(struct xdr_stream *xdr, 1603460f29aSChuck Lever struct nlm_cookie *cookie) 1613460f29aSChuck Lever { 1623460f29aSChuck Lever u32 length; 1633460f29aSChuck Lever __be32 *p; 1643460f29aSChuck Lever 1653460f29aSChuck Lever p = xdr_inline_decode(xdr, 4); 1663460f29aSChuck Lever if (unlikely(p == NULL)) 1673460f29aSChuck Lever goto out_overflow; 1683460f29aSChuck Lever length = be32_to_cpup(p++); 1693460f29aSChuck Lever /* apparently HPUX can return empty cookies */ 1703460f29aSChuck Lever if (length == 0) 1713460f29aSChuck Lever goto out_hpux; 1723460f29aSChuck Lever if (length > NLM_MAXCOOKIELEN) 1733460f29aSChuck Lever goto out_size; 1743460f29aSChuck Lever p = xdr_inline_decode(xdr, length); 1753460f29aSChuck Lever if (unlikely(p == NULL)) 1763460f29aSChuck Lever goto out_overflow; 1773460f29aSChuck Lever cookie->len = length; 1783460f29aSChuck Lever memcpy(cookie->data, p, length); 1793460f29aSChuck Lever return 0; 1803460f29aSChuck Lever out_hpux: 1813460f29aSChuck Lever cookie->len = 4; 1823460f29aSChuck Lever memset(cookie->data, 0, 4); 1833460f29aSChuck Lever return 0; 1843460f29aSChuck Lever out_size: 1853460f29aSChuck Lever dprintk("NFS: returned cookie was too long: %u\n", length); 1863460f29aSChuck Lever return -EIO; 1873460f29aSChuck Lever out_overflow: 1883460f29aSChuck Lever print_overflow_msg(__func__, xdr); 1893460f29aSChuck Lever return -EIO; 1903460f29aSChuck Lever } 1913460f29aSChuck Lever 1923460f29aSChuck Lever /* 1933460f29aSChuck Lever * netobj fh; 1943460f29aSChuck Lever */ 1953460f29aSChuck Lever static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh) 1963460f29aSChuck Lever { 1973460f29aSChuck Lever encode_netobj(xdr, (u8 *)&fh->data, fh->size); 1983460f29aSChuck Lever } 1993460f29aSChuck Lever 2003460f29aSChuck Lever /* 2013460f29aSChuck Lever * enum nlm4_stats { 2023460f29aSChuck Lever * NLM4_GRANTED = 0, 2033460f29aSChuck Lever * NLM4_DENIED = 1, 2043460f29aSChuck Lever * NLM4_DENIED_NOLOCKS = 2, 2053460f29aSChuck Lever * NLM4_BLOCKED = 3, 2063460f29aSChuck Lever * NLM4_DENIED_GRACE_PERIOD = 4, 2073460f29aSChuck Lever * NLM4_DEADLCK = 5, 2083460f29aSChuck Lever * NLM4_ROFS = 6, 2093460f29aSChuck Lever * NLM4_STALE_FH = 7, 2103460f29aSChuck Lever * NLM4_FBIG = 8, 2113460f29aSChuck Lever * NLM4_FAILED = 9 2123460f29aSChuck Lever * }; 2133460f29aSChuck Lever * 2143460f29aSChuck Lever * struct nlm4_stat { 2153460f29aSChuck Lever * nlm4_stats stat; 2163460f29aSChuck Lever * }; 2173460f29aSChuck Lever * 2183460f29aSChuck Lever * NB: we don't swap bytes for the NLM status values. The upper 2193460f29aSChuck Lever * layers deal directly with the status value in network byte 2203460f29aSChuck Lever * order. 2213460f29aSChuck Lever */ 2223460f29aSChuck Lever static void encode_nlm4_stat(struct xdr_stream *xdr, 2233460f29aSChuck Lever const __be32 stat) 2243460f29aSChuck Lever { 2253460f29aSChuck Lever __be32 *p; 2263460f29aSChuck Lever 2273460f29aSChuck Lever BUG_ON(be32_to_cpu(stat) > NLM_FAILED); 2283460f29aSChuck Lever p = xdr_reserve_space(xdr, 4); 2293460f29aSChuck Lever *p = stat; 2303460f29aSChuck Lever } 2313460f29aSChuck Lever 2323460f29aSChuck Lever static int decode_nlm4_stat(struct xdr_stream *xdr, __be32 *stat) 2333460f29aSChuck Lever { 2343460f29aSChuck Lever __be32 *p; 2353460f29aSChuck Lever 2363460f29aSChuck Lever p = xdr_inline_decode(xdr, 4); 2373460f29aSChuck Lever if (unlikely(p == NULL)) 2383460f29aSChuck Lever goto out_overflow; 239e847469bSAl Viro if (unlikely(ntohl(*p) > ntohl(nlm4_failed))) 2403460f29aSChuck Lever goto out_bad_xdr; 2413460f29aSChuck Lever *stat = *p; 2423460f29aSChuck Lever return 0; 2433460f29aSChuck Lever out_bad_xdr: 2443460f29aSChuck Lever dprintk("%s: server returned invalid nlm4_stats value: %u\n", 2453460f29aSChuck Lever __func__, be32_to_cpup(p)); 2463460f29aSChuck Lever return -EIO; 2473460f29aSChuck Lever out_overflow: 2483460f29aSChuck Lever print_overflow_msg(__func__, xdr); 2493460f29aSChuck Lever return -EIO; 2503460f29aSChuck Lever } 2513460f29aSChuck Lever 2523460f29aSChuck Lever /* 2533460f29aSChuck Lever * struct nlm4_holder { 2543460f29aSChuck Lever * bool exclusive; 2553460f29aSChuck Lever * int32 svid; 2563460f29aSChuck Lever * netobj oh; 2573460f29aSChuck Lever * uint64 l_offset; 2583460f29aSChuck Lever * uint64 l_len; 2593460f29aSChuck Lever * }; 2603460f29aSChuck Lever */ 2613460f29aSChuck Lever static void encode_nlm4_holder(struct xdr_stream *xdr, 2623460f29aSChuck Lever const struct nlm_res *result) 2633460f29aSChuck Lever { 2643460f29aSChuck Lever const struct nlm_lock *lock = &result->lock; 2653460f29aSChuck Lever u64 l_offset, l_len; 2663460f29aSChuck Lever __be32 *p; 2673460f29aSChuck Lever 2683460f29aSChuck Lever encode_bool(xdr, lock->fl.fl_type == F_RDLCK); 2693460f29aSChuck Lever encode_int32(xdr, lock->svid); 2703460f29aSChuck Lever encode_netobj(xdr, lock->oh.data, lock->oh.len); 2713460f29aSChuck Lever 2723460f29aSChuck Lever p = xdr_reserve_space(xdr, 4 + 4); 2733460f29aSChuck Lever nlm4_compute_offsets(lock, &l_offset, &l_len); 2743460f29aSChuck Lever p = xdr_encode_hyper(p, l_offset); 2753460f29aSChuck Lever xdr_encode_hyper(p, l_len); 2763460f29aSChuck Lever } 2773460f29aSChuck Lever 2783460f29aSChuck Lever static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result) 2793460f29aSChuck Lever { 2803460f29aSChuck Lever struct nlm_lock *lock = &result->lock; 2813460f29aSChuck Lever struct file_lock *fl = &lock->fl; 2823460f29aSChuck Lever u64 l_offset, l_len; 2833460f29aSChuck Lever u32 exclusive; 2843460f29aSChuck Lever int error; 2853460f29aSChuck Lever __be32 *p; 2863460f29aSChuck Lever s32 end; 2873460f29aSChuck Lever 2883460f29aSChuck Lever memset(lock, 0, sizeof(*lock)); 2893460f29aSChuck Lever locks_init_lock(fl); 2903460f29aSChuck Lever 2913460f29aSChuck Lever p = xdr_inline_decode(xdr, 4 + 4); 2923460f29aSChuck Lever if (unlikely(p == NULL)) 2933460f29aSChuck Lever goto out_overflow; 2943460f29aSChuck Lever exclusive = be32_to_cpup(p++); 2953460f29aSChuck Lever lock->svid = be32_to_cpup(p); 2963460f29aSChuck Lever fl->fl_pid = (pid_t)lock->svid; 2973460f29aSChuck Lever 2983460f29aSChuck Lever error = decode_netobj(xdr, &lock->oh); 2993460f29aSChuck Lever if (unlikely(error)) 3003460f29aSChuck Lever goto out; 3013460f29aSChuck Lever 3023460f29aSChuck Lever p = xdr_inline_decode(xdr, 8 + 8); 3033460f29aSChuck Lever if (unlikely(p == NULL)) 3043460f29aSChuck Lever goto out_overflow; 3053460f29aSChuck Lever 3063460f29aSChuck Lever fl->fl_flags = FL_POSIX; 3073460f29aSChuck Lever fl->fl_type = exclusive != 0 ? F_WRLCK : F_RDLCK; 3083460f29aSChuck Lever p = xdr_decode_hyper(p, &l_offset); 3093460f29aSChuck Lever xdr_decode_hyper(p, &l_len); 3103460f29aSChuck Lever end = l_offset + l_len - 1; 3113460f29aSChuck Lever 3123460f29aSChuck Lever fl->fl_start = (loff_t)l_offset; 3133460f29aSChuck Lever if (l_len == 0 || end < 0) 3143460f29aSChuck Lever fl->fl_end = OFFSET_MAX; 3153460f29aSChuck Lever else 3163460f29aSChuck Lever fl->fl_end = (loff_t)end; 3173460f29aSChuck Lever error = 0; 3183460f29aSChuck Lever out: 3193460f29aSChuck Lever return error; 3203460f29aSChuck Lever out_overflow: 3213460f29aSChuck Lever print_overflow_msg(__func__, xdr); 3223460f29aSChuck Lever return -EIO; 3233460f29aSChuck Lever } 3243460f29aSChuck Lever 3253460f29aSChuck Lever /* 3263460f29aSChuck Lever * string caller_name<LM_MAXSTRLEN>; 3273460f29aSChuck Lever */ 3283460f29aSChuck Lever static void encode_caller_name(struct xdr_stream *xdr, const char *name) 3293460f29aSChuck Lever { 3303460f29aSChuck Lever /* NB: client-side does not set lock->len */ 3313460f29aSChuck Lever u32 length = strlen(name); 3323460f29aSChuck Lever __be32 *p; 3333460f29aSChuck Lever 3343460f29aSChuck Lever p = xdr_reserve_space(xdr, 4 + length); 3353460f29aSChuck Lever xdr_encode_opaque(p, name, length); 3363460f29aSChuck Lever } 3373460f29aSChuck Lever 3383460f29aSChuck Lever /* 3393460f29aSChuck Lever * struct nlm4_lock { 3403460f29aSChuck Lever * string caller_name<LM_MAXSTRLEN>; 3413460f29aSChuck Lever * netobj fh; 3423460f29aSChuck Lever * netobj oh; 3433460f29aSChuck Lever * int32 svid; 3443460f29aSChuck Lever * uint64 l_offset; 3453460f29aSChuck Lever * uint64 l_len; 3463460f29aSChuck Lever * }; 3473460f29aSChuck Lever */ 3483460f29aSChuck Lever static void encode_nlm4_lock(struct xdr_stream *xdr, 3493460f29aSChuck Lever const struct nlm_lock *lock) 3503460f29aSChuck Lever { 3513460f29aSChuck Lever u64 l_offset, l_len; 3523460f29aSChuck Lever __be32 *p; 3533460f29aSChuck Lever 3543460f29aSChuck Lever encode_caller_name(xdr, lock->caller); 3553460f29aSChuck Lever encode_fh(xdr, &lock->fh); 3563460f29aSChuck Lever encode_netobj(xdr, lock->oh.data, lock->oh.len); 3573460f29aSChuck Lever 3583460f29aSChuck Lever p = xdr_reserve_space(xdr, 4 + 8 + 8); 3593460f29aSChuck Lever *p++ = cpu_to_be32(lock->svid); 3603460f29aSChuck Lever 3613460f29aSChuck Lever nlm4_compute_offsets(lock, &l_offset, &l_len); 3623460f29aSChuck Lever p = xdr_encode_hyper(p, l_offset); 3633460f29aSChuck Lever xdr_encode_hyper(p, l_len); 3643460f29aSChuck Lever } 3653460f29aSChuck Lever 3663460f29aSChuck Lever 3673460f29aSChuck Lever /* 3683460f29aSChuck Lever * NLMv4 XDR encode functions 3693460f29aSChuck Lever * 3703460f29aSChuck Lever * NLMv4 argument types are defined in Appendix II of RFC 1813: 3713460f29aSChuck Lever * "NFS Version 3 Protocol Specification" and Chapter 10 of X/Open's 3723460f29aSChuck Lever * "Protocols for Interworking: XNFS, Version 3W". 3733460f29aSChuck Lever */ 3743460f29aSChuck Lever 3753460f29aSChuck Lever /* 3763460f29aSChuck Lever * struct nlm4_testargs { 3773460f29aSChuck Lever * netobj cookie; 3783460f29aSChuck Lever * bool exclusive; 3793460f29aSChuck Lever * struct nlm4_lock alock; 3803460f29aSChuck Lever * }; 3813460f29aSChuck Lever */ 3829f06c719SChuck Lever static void nlm4_xdr_enc_testargs(struct rpc_rqst *req, 3839f06c719SChuck Lever struct xdr_stream *xdr, 384bf96391eSChristoph Hellwig const void *data) 3853460f29aSChuck Lever { 386bf96391eSChristoph Hellwig const struct nlm_args *args = data; 3873460f29aSChuck Lever const struct nlm_lock *lock = &args->lock; 3883460f29aSChuck Lever 3899f06c719SChuck Lever encode_cookie(xdr, &args->cookie); 3909f06c719SChuck Lever encode_bool(xdr, lock->fl.fl_type == F_WRLCK); 3919f06c719SChuck Lever encode_nlm4_lock(xdr, lock); 3923460f29aSChuck Lever } 3933460f29aSChuck Lever 3943460f29aSChuck Lever /* 3953460f29aSChuck Lever * struct nlm4_lockargs { 3963460f29aSChuck Lever * netobj cookie; 3973460f29aSChuck Lever * bool block; 3983460f29aSChuck Lever * bool exclusive; 3993460f29aSChuck Lever * struct nlm4_lock alock; 4003460f29aSChuck Lever * bool reclaim; 4013460f29aSChuck Lever * int state; 4023460f29aSChuck Lever * }; 4033460f29aSChuck Lever */ 4049f06c719SChuck Lever static void nlm4_xdr_enc_lockargs(struct rpc_rqst *req, 4059f06c719SChuck Lever struct xdr_stream *xdr, 406bf96391eSChristoph Hellwig const void *data) 4073460f29aSChuck Lever { 408bf96391eSChristoph Hellwig const struct nlm_args *args = data; 4093460f29aSChuck Lever const struct nlm_lock *lock = &args->lock; 4103460f29aSChuck Lever 4119f06c719SChuck Lever encode_cookie(xdr, &args->cookie); 4129f06c719SChuck Lever encode_bool(xdr, args->block); 4139f06c719SChuck Lever encode_bool(xdr, lock->fl.fl_type == F_WRLCK); 4149f06c719SChuck Lever encode_nlm4_lock(xdr, lock); 4159f06c719SChuck Lever encode_bool(xdr, args->reclaim); 4169f06c719SChuck Lever encode_int32(xdr, args->state); 4173460f29aSChuck Lever } 4183460f29aSChuck Lever 4193460f29aSChuck Lever /* 4203460f29aSChuck Lever * struct nlm4_cancargs { 4213460f29aSChuck Lever * netobj cookie; 4223460f29aSChuck Lever * bool block; 4233460f29aSChuck Lever * bool exclusive; 4243460f29aSChuck Lever * struct nlm4_lock alock; 4253460f29aSChuck Lever * }; 4263460f29aSChuck Lever */ 4279f06c719SChuck Lever static void nlm4_xdr_enc_cancargs(struct rpc_rqst *req, 4289f06c719SChuck Lever struct xdr_stream *xdr, 429bf96391eSChristoph Hellwig const void *data) 4303460f29aSChuck Lever { 431bf96391eSChristoph Hellwig const struct nlm_args *args = data; 4323460f29aSChuck Lever const struct nlm_lock *lock = &args->lock; 4333460f29aSChuck Lever 4349f06c719SChuck Lever encode_cookie(xdr, &args->cookie); 4359f06c719SChuck Lever encode_bool(xdr, args->block); 4369f06c719SChuck Lever encode_bool(xdr, lock->fl.fl_type == F_WRLCK); 4379f06c719SChuck Lever encode_nlm4_lock(xdr, lock); 4383460f29aSChuck Lever } 4393460f29aSChuck Lever 4403460f29aSChuck Lever /* 4413460f29aSChuck Lever * struct nlm4_unlockargs { 4423460f29aSChuck Lever * netobj cookie; 4433460f29aSChuck Lever * struct nlm4_lock alock; 4443460f29aSChuck Lever * }; 4453460f29aSChuck Lever */ 4469f06c719SChuck Lever static void nlm4_xdr_enc_unlockargs(struct rpc_rqst *req, 4479f06c719SChuck Lever struct xdr_stream *xdr, 448bf96391eSChristoph Hellwig const void *data) 4493460f29aSChuck Lever { 450bf96391eSChristoph Hellwig const struct nlm_args *args = data; 4513460f29aSChuck Lever const struct nlm_lock *lock = &args->lock; 4523460f29aSChuck Lever 4539f06c719SChuck Lever encode_cookie(xdr, &args->cookie); 4549f06c719SChuck Lever encode_nlm4_lock(xdr, lock); 4553460f29aSChuck Lever } 4563460f29aSChuck Lever 4573460f29aSChuck Lever /* 4583460f29aSChuck Lever * struct nlm4_res { 4593460f29aSChuck Lever * netobj cookie; 4603460f29aSChuck Lever * nlm4_stat stat; 4613460f29aSChuck Lever * }; 4623460f29aSChuck Lever */ 4639f06c719SChuck Lever static void nlm4_xdr_enc_res(struct rpc_rqst *req, 4649f06c719SChuck Lever struct xdr_stream *xdr, 465bf96391eSChristoph Hellwig const void *data) 4663460f29aSChuck Lever { 467bf96391eSChristoph Hellwig const struct nlm_res *result = data; 468bf96391eSChristoph Hellwig 4699f06c719SChuck Lever encode_cookie(xdr, &result->cookie); 4709f06c719SChuck Lever encode_nlm4_stat(xdr, result->status); 4713460f29aSChuck Lever } 4723460f29aSChuck Lever 4733460f29aSChuck Lever /* 4743460f29aSChuck Lever * union nlm4_testrply switch (nlm4_stats stat) { 4753460f29aSChuck Lever * case NLM4_DENIED: 4763460f29aSChuck Lever * struct nlm4_holder holder; 4773460f29aSChuck Lever * default: 4783460f29aSChuck Lever * void; 4793460f29aSChuck Lever * }; 4803460f29aSChuck Lever * 4813460f29aSChuck Lever * struct nlm4_testres { 4823460f29aSChuck Lever * netobj cookie; 4833460f29aSChuck Lever * nlm4_testrply test_stat; 4843460f29aSChuck Lever * }; 4853460f29aSChuck Lever */ 4869f06c719SChuck Lever static void nlm4_xdr_enc_testres(struct rpc_rqst *req, 4879f06c719SChuck Lever struct xdr_stream *xdr, 488bf96391eSChristoph Hellwig const void *data) 4893460f29aSChuck Lever { 490bf96391eSChristoph Hellwig const struct nlm_res *result = data; 491bf96391eSChristoph Hellwig 4929f06c719SChuck Lever encode_cookie(xdr, &result->cookie); 4939f06c719SChuck Lever encode_nlm4_stat(xdr, result->status); 4943460f29aSChuck Lever if (result->status == nlm_lck_denied) 4959f06c719SChuck Lever encode_nlm4_holder(xdr, result); 4963460f29aSChuck Lever } 4973460f29aSChuck Lever 4983460f29aSChuck Lever 4993460f29aSChuck Lever /* 5003460f29aSChuck Lever * NLMv4 XDR decode functions 5013460f29aSChuck Lever * 5023460f29aSChuck Lever * NLMv4 argument types are defined in Appendix II of RFC 1813: 5033460f29aSChuck Lever * "NFS Version 3 Protocol Specification" and Chapter 10 of X/Open's 5043460f29aSChuck Lever * "Protocols for Interworking: XNFS, Version 3W". 5053460f29aSChuck Lever */ 5063460f29aSChuck Lever 5073460f29aSChuck Lever /* 5083460f29aSChuck Lever * union nlm4_testrply switch (nlm4_stats stat) { 5093460f29aSChuck Lever * case NLM4_DENIED: 5103460f29aSChuck Lever * struct nlm4_holder holder; 5113460f29aSChuck Lever * default: 5123460f29aSChuck Lever * void; 5133460f29aSChuck Lever * }; 5143460f29aSChuck Lever * 5153460f29aSChuck Lever * struct nlm4_testres { 5163460f29aSChuck Lever * netobj cookie; 5173460f29aSChuck Lever * nlm4_testrply test_stat; 5183460f29aSChuck Lever * }; 5193460f29aSChuck Lever */ 5203460f29aSChuck Lever static int decode_nlm4_testrply(struct xdr_stream *xdr, 5213460f29aSChuck Lever struct nlm_res *result) 5223460f29aSChuck Lever { 5233460f29aSChuck Lever int error; 5243460f29aSChuck Lever 5253460f29aSChuck Lever error = decode_nlm4_stat(xdr, &result->status); 5263460f29aSChuck Lever if (unlikely(error)) 5273460f29aSChuck Lever goto out; 5283460f29aSChuck Lever if (result->status == nlm_lck_denied) 5293460f29aSChuck Lever error = decode_nlm4_holder(xdr, result); 5303460f29aSChuck Lever out: 5313460f29aSChuck Lever return error; 5323460f29aSChuck Lever } 5333460f29aSChuck Lever 534bf269551SChuck Lever static int nlm4_xdr_dec_testres(struct rpc_rqst *req, 535bf269551SChuck Lever struct xdr_stream *xdr, 5361fa23391SChristoph Hellwig void *data) 5373460f29aSChuck Lever { 5381fa23391SChristoph Hellwig struct nlm_res *result = data; 5393460f29aSChuck Lever int error; 5403460f29aSChuck Lever 541bf269551SChuck Lever error = decode_cookie(xdr, &result->cookie); 5423460f29aSChuck Lever if (unlikely(error)) 5433460f29aSChuck Lever goto out; 544bf269551SChuck Lever error = decode_nlm4_testrply(xdr, result); 5453460f29aSChuck Lever out: 5463460f29aSChuck Lever return error; 5473460f29aSChuck Lever } 5483460f29aSChuck Lever 5493460f29aSChuck Lever /* 5503460f29aSChuck Lever * struct nlm4_res { 5513460f29aSChuck Lever * netobj cookie; 5523460f29aSChuck Lever * nlm4_stat stat; 5533460f29aSChuck Lever * }; 5543460f29aSChuck Lever */ 555bf269551SChuck Lever static int nlm4_xdr_dec_res(struct rpc_rqst *req, 556bf269551SChuck Lever struct xdr_stream *xdr, 5571fa23391SChristoph Hellwig void *data) 5583460f29aSChuck Lever { 5591fa23391SChristoph Hellwig struct nlm_res *result = data; 5603460f29aSChuck Lever int error; 5613460f29aSChuck Lever 562bf269551SChuck Lever error = decode_cookie(xdr, &result->cookie); 5633460f29aSChuck Lever if (unlikely(error)) 5643460f29aSChuck Lever goto out; 565bf269551SChuck Lever error = decode_nlm4_stat(xdr, &result->status); 5663460f29aSChuck Lever out: 5673460f29aSChuck Lever return error; 5683460f29aSChuck Lever } 5693460f29aSChuck Lever 5703460f29aSChuck Lever 5713460f29aSChuck Lever /* 5723460f29aSChuck Lever * For NLM, a void procedure really returns nothing 5733460f29aSChuck Lever */ 5743460f29aSChuck Lever #define nlm4_xdr_dec_norep NULL 5753460f29aSChuck Lever 5763460f29aSChuck Lever #define PROC(proc, argtype, restype) \ 5773460f29aSChuck Lever [NLMPROC_##proc] = { \ 5783460f29aSChuck Lever .p_proc = NLMPROC_##proc, \ 579bf96391eSChristoph Hellwig .p_encode = nlm4_xdr_enc_##argtype, \ 5801fa23391SChristoph Hellwig .p_decode = nlm4_xdr_dec_##restype, \ 5813460f29aSChuck Lever .p_arglen = NLM4_##argtype##_sz, \ 5823460f29aSChuck Lever .p_replen = NLM4_##restype##_sz, \ 5833460f29aSChuck Lever .p_statidx = NLMPROC_##proc, \ 5843460f29aSChuck Lever .p_name = #proc, \ 5853460f29aSChuck Lever } 5863460f29aSChuck Lever 587*499b4988SChristoph Hellwig static const struct rpc_procinfo nlm4_procedures[] = { 5883460f29aSChuck Lever PROC(TEST, testargs, testres), 5893460f29aSChuck Lever PROC(LOCK, lockargs, res), 5903460f29aSChuck Lever PROC(CANCEL, cancargs, res), 5913460f29aSChuck Lever PROC(UNLOCK, unlockargs, res), 5923460f29aSChuck Lever PROC(GRANTED, testargs, res), 5933460f29aSChuck Lever PROC(TEST_MSG, testargs, norep), 5943460f29aSChuck Lever PROC(LOCK_MSG, lockargs, norep), 5953460f29aSChuck Lever PROC(CANCEL_MSG, cancargs, norep), 5963460f29aSChuck Lever PROC(UNLOCK_MSG, unlockargs, norep), 5973460f29aSChuck Lever PROC(GRANTED_MSG, testargs, norep), 5983460f29aSChuck Lever PROC(TEST_RES, testres, norep), 5993460f29aSChuck Lever PROC(LOCK_RES, res, norep), 6003460f29aSChuck Lever PROC(CANCEL_RES, res, norep), 6013460f29aSChuck Lever PROC(UNLOCK_RES, res, norep), 6023460f29aSChuck Lever PROC(GRANTED_RES, res, norep), 6033460f29aSChuck Lever }; 6043460f29aSChuck Lever 6051c5876ddSChristoph Hellwig static unsigned int nlm_version4_counts[ARRAY_SIZE(nlm4_procedures)]; 606a613fa16STrond Myklebust const struct rpc_version nlm_version4 = { 6073460f29aSChuck Lever .number = 4, 6083460f29aSChuck Lever .nrprocs = ARRAY_SIZE(nlm4_procedures), 6093460f29aSChuck Lever .procs = nlm4_procedures, 6101c5876ddSChristoph Hellwig .counts = nlm_version4_counts, 6113460f29aSChuck Lever }; 612