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 173460f29aSChuck Lever #define NLMDBG_FACILITY NLMDBG_XDR 183460f29aSChuck Lever 193460f29aSChuck Lever #if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ) 203460f29aSChuck Lever # error "NLM host name cannot be larger than XDR_MAX_NETOBJ!" 213460f29aSChuck Lever #endif 223460f29aSChuck Lever 233460f29aSChuck Lever #if (NLMCLNT_OHSIZE > NLM_MAXSTRLEN) 243460f29aSChuck Lever # error "NLM host name cannot be larger than NLM's maximum string length!" 253460f29aSChuck Lever #endif 263460f29aSChuck Lever 273460f29aSChuck Lever /* 283460f29aSChuck Lever * Declare the space requirements for NLM arguments and replies as 293460f29aSChuck Lever * number of 32bit-words 303460f29aSChuck Lever */ 313460f29aSChuck Lever #define NLM4_void_sz (0) 323460f29aSChuck Lever #define NLM4_cookie_sz (1+(NLM_MAXCOOKIELEN>>2)) 333460f29aSChuck Lever #define NLM4_caller_sz (1+(NLMCLNT_OHSIZE>>2)) 343460f29aSChuck Lever #define NLM4_owner_sz (1+(NLMCLNT_OHSIZE>>2)) 353460f29aSChuck Lever #define NLM4_fhandle_sz (1+(NFS3_FHSIZE>>2)) 363460f29aSChuck Lever #define NLM4_lock_sz (5+NLM4_caller_sz+NLM4_owner_sz+NLM4_fhandle_sz) 373460f29aSChuck Lever #define NLM4_holder_sz (6+NLM4_owner_sz) 383460f29aSChuck Lever 393460f29aSChuck Lever #define NLM4_testargs_sz (NLM4_cookie_sz+1+NLM4_lock_sz) 403460f29aSChuck Lever #define NLM4_lockargs_sz (NLM4_cookie_sz+4+NLM4_lock_sz) 413460f29aSChuck Lever #define NLM4_cancargs_sz (NLM4_cookie_sz+2+NLM4_lock_sz) 423460f29aSChuck Lever #define NLM4_unlockargs_sz (NLM4_cookie_sz+NLM4_lock_sz) 433460f29aSChuck Lever 443460f29aSChuck Lever #define NLM4_testres_sz (NLM4_cookie_sz+1+NLM4_holder_sz) 453460f29aSChuck Lever #define NLM4_res_sz (NLM4_cookie_sz+1) 463460f29aSChuck Lever #define NLM4_norep_sz (0) 473460f29aSChuck Lever 483460f29aSChuck Lever 493460f29aSChuck Lever static s64 loff_t_to_s64(loff_t offset) 503460f29aSChuck Lever { 513460f29aSChuck Lever s64 res; 523460f29aSChuck Lever 533460f29aSChuck Lever if (offset >= NLM4_OFFSET_MAX) 543460f29aSChuck Lever res = NLM4_OFFSET_MAX; 553460f29aSChuck Lever else if (offset <= -NLM4_OFFSET_MAX) 563460f29aSChuck Lever res = -NLM4_OFFSET_MAX; 573460f29aSChuck Lever else 583460f29aSChuck Lever res = offset; 593460f29aSChuck Lever return res; 603460f29aSChuck Lever } 613460f29aSChuck Lever 623460f29aSChuck Lever static void nlm4_compute_offsets(const struct nlm_lock *lock, 633460f29aSChuck Lever u64 *l_offset, u64 *l_len) 643460f29aSChuck Lever { 653460f29aSChuck Lever const struct file_lock *fl = &lock->fl; 663460f29aSChuck Lever 673460f29aSChuck Lever BUG_ON(fl->fl_start > NLM4_OFFSET_MAX); 683460f29aSChuck Lever BUG_ON(fl->fl_end > NLM4_OFFSET_MAX && 693460f29aSChuck Lever fl->fl_end != OFFSET_MAX); 703460f29aSChuck Lever 713460f29aSChuck Lever *l_offset = loff_t_to_s64(fl->fl_start); 723460f29aSChuck Lever if (fl->fl_end == OFFSET_MAX) 733460f29aSChuck Lever *l_len = 0; 743460f29aSChuck Lever else 753460f29aSChuck Lever *l_len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); 763460f29aSChuck Lever } 773460f29aSChuck Lever 783460f29aSChuck Lever /* 793460f29aSChuck Lever * Handle decode buffer overflows out-of-line. 803460f29aSChuck Lever */ 813460f29aSChuck Lever static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) 823460f29aSChuck Lever { 833460f29aSChuck Lever dprintk("lockd: %s prematurely hit the end of our receive buffer. " 843460f29aSChuck Lever "Remaining buffer length is %tu words.\n", 853460f29aSChuck Lever func, xdr->end - xdr->p); 863460f29aSChuck Lever } 873460f29aSChuck Lever 883460f29aSChuck Lever 893460f29aSChuck Lever /* 903460f29aSChuck Lever * Encode/decode NLMv4 basic data types 913460f29aSChuck Lever * 923460f29aSChuck Lever * Basic NLMv4 data types are defined in Appendix II, section 6.1.4 933460f29aSChuck Lever * of RFC 1813: "NFS Version 3 Protocol Specification" and in Chapter 943460f29aSChuck Lever * 10 of X/Open's "Protocols for Interworking: XNFS, Version 3W". 953460f29aSChuck Lever * 963460f29aSChuck Lever * Not all basic data types have their own encoding and decoding 973460f29aSChuck Lever * functions. For run-time efficiency, some data types are encoded 983460f29aSChuck Lever * or decoded inline. 993460f29aSChuck Lever */ 1003460f29aSChuck Lever 1013460f29aSChuck Lever static void encode_bool(struct xdr_stream *xdr, const int value) 1023460f29aSChuck Lever { 1033460f29aSChuck Lever __be32 *p; 1043460f29aSChuck Lever 1053460f29aSChuck Lever p = xdr_reserve_space(xdr, 4); 1063460f29aSChuck Lever *p = value ? xdr_one : xdr_zero; 1073460f29aSChuck Lever } 1083460f29aSChuck Lever 1093460f29aSChuck Lever static void encode_int32(struct xdr_stream *xdr, const s32 value) 1103460f29aSChuck Lever { 1113460f29aSChuck Lever __be32 *p; 1123460f29aSChuck Lever 1133460f29aSChuck Lever p = xdr_reserve_space(xdr, 4); 1143460f29aSChuck Lever *p = cpu_to_be32(value); 1153460f29aSChuck Lever } 1163460f29aSChuck Lever 1173460f29aSChuck Lever /* 1183460f29aSChuck Lever * typedef opaque netobj<MAXNETOBJ_SZ> 1193460f29aSChuck Lever */ 1203460f29aSChuck Lever static void encode_netobj(struct xdr_stream *xdr, 1213460f29aSChuck Lever const u8 *data, const unsigned int length) 1223460f29aSChuck Lever { 1233460f29aSChuck Lever __be32 *p; 1243460f29aSChuck Lever 1253460f29aSChuck Lever BUG_ON(length > XDR_MAX_NETOBJ); 1263460f29aSChuck Lever p = xdr_reserve_space(xdr, 4 + length); 1273460f29aSChuck Lever xdr_encode_opaque(p, data, length); 1283460f29aSChuck Lever } 1293460f29aSChuck Lever 1303460f29aSChuck Lever static int decode_netobj(struct xdr_stream *xdr, 1313460f29aSChuck Lever struct xdr_netobj *obj) 1323460f29aSChuck Lever { 1333460f29aSChuck Lever u32 length; 1343460f29aSChuck Lever __be32 *p; 1353460f29aSChuck Lever 1363460f29aSChuck Lever p = xdr_inline_decode(xdr, 4); 1373460f29aSChuck Lever if (unlikely(p == NULL)) 1383460f29aSChuck Lever goto out_overflow; 1393460f29aSChuck Lever length = be32_to_cpup(p++); 1403460f29aSChuck Lever if (unlikely(length > XDR_MAX_NETOBJ)) 1413460f29aSChuck Lever goto out_size; 1423460f29aSChuck Lever obj->len = length; 1433460f29aSChuck Lever obj->data = (u8 *)p; 1443460f29aSChuck Lever return 0; 1453460f29aSChuck Lever out_size: 1463460f29aSChuck Lever dprintk("NFS: returned netobj was too long: %u\n", length); 1473460f29aSChuck Lever return -EIO; 1483460f29aSChuck Lever out_overflow: 1493460f29aSChuck Lever print_overflow_msg(__func__, xdr); 1503460f29aSChuck Lever return -EIO; 1513460f29aSChuck Lever } 1523460f29aSChuck Lever 1533460f29aSChuck Lever /* 1543460f29aSChuck Lever * netobj cookie; 1553460f29aSChuck Lever */ 1563460f29aSChuck Lever static void encode_cookie(struct xdr_stream *xdr, 1573460f29aSChuck Lever const struct nlm_cookie *cookie) 1583460f29aSChuck Lever { 1593460f29aSChuck Lever BUG_ON(cookie->len > NLM_MAXCOOKIELEN); 1603460f29aSChuck Lever encode_netobj(xdr, (u8 *)&cookie->data, cookie->len); 1613460f29aSChuck Lever } 1623460f29aSChuck Lever 1633460f29aSChuck Lever static int decode_cookie(struct xdr_stream *xdr, 1643460f29aSChuck Lever struct nlm_cookie *cookie) 1653460f29aSChuck Lever { 1663460f29aSChuck Lever u32 length; 1673460f29aSChuck Lever __be32 *p; 1683460f29aSChuck Lever 1693460f29aSChuck Lever p = xdr_inline_decode(xdr, 4); 1703460f29aSChuck Lever if (unlikely(p == NULL)) 1713460f29aSChuck Lever goto out_overflow; 1723460f29aSChuck Lever length = be32_to_cpup(p++); 1733460f29aSChuck Lever /* apparently HPUX can return empty cookies */ 1743460f29aSChuck Lever if (length == 0) 1753460f29aSChuck Lever goto out_hpux; 1763460f29aSChuck Lever if (length > NLM_MAXCOOKIELEN) 1773460f29aSChuck Lever goto out_size; 1783460f29aSChuck Lever p = xdr_inline_decode(xdr, length); 1793460f29aSChuck Lever if (unlikely(p == NULL)) 1803460f29aSChuck Lever goto out_overflow; 1813460f29aSChuck Lever cookie->len = length; 1823460f29aSChuck Lever memcpy(cookie->data, p, length); 1833460f29aSChuck Lever return 0; 1843460f29aSChuck Lever out_hpux: 1853460f29aSChuck Lever cookie->len = 4; 1863460f29aSChuck Lever memset(cookie->data, 0, 4); 1873460f29aSChuck Lever return 0; 1883460f29aSChuck Lever out_size: 1893460f29aSChuck Lever dprintk("NFS: returned cookie was too long: %u\n", length); 1903460f29aSChuck Lever return -EIO; 1913460f29aSChuck Lever out_overflow: 1923460f29aSChuck Lever print_overflow_msg(__func__, xdr); 1933460f29aSChuck Lever return -EIO; 1943460f29aSChuck Lever } 1953460f29aSChuck Lever 1963460f29aSChuck Lever /* 1973460f29aSChuck Lever * netobj fh; 1983460f29aSChuck Lever */ 1993460f29aSChuck Lever static void encode_fh(struct xdr_stream *xdr, const struct nfs_fh *fh) 2003460f29aSChuck Lever { 2013460f29aSChuck Lever BUG_ON(fh->size > NFS3_FHSIZE); 2023460f29aSChuck Lever encode_netobj(xdr, (u8 *)&fh->data, fh->size); 2033460f29aSChuck Lever } 2043460f29aSChuck Lever 2053460f29aSChuck Lever /* 2063460f29aSChuck Lever * enum nlm4_stats { 2073460f29aSChuck Lever * NLM4_GRANTED = 0, 2083460f29aSChuck Lever * NLM4_DENIED = 1, 2093460f29aSChuck Lever * NLM4_DENIED_NOLOCKS = 2, 2103460f29aSChuck Lever * NLM4_BLOCKED = 3, 2113460f29aSChuck Lever * NLM4_DENIED_GRACE_PERIOD = 4, 2123460f29aSChuck Lever * NLM4_DEADLCK = 5, 2133460f29aSChuck Lever * NLM4_ROFS = 6, 2143460f29aSChuck Lever * NLM4_STALE_FH = 7, 2153460f29aSChuck Lever * NLM4_FBIG = 8, 2163460f29aSChuck Lever * NLM4_FAILED = 9 2173460f29aSChuck Lever * }; 2183460f29aSChuck Lever * 2193460f29aSChuck Lever * struct nlm4_stat { 2203460f29aSChuck Lever * nlm4_stats stat; 2213460f29aSChuck Lever * }; 2223460f29aSChuck Lever * 2233460f29aSChuck Lever * NB: we don't swap bytes for the NLM status values. The upper 2243460f29aSChuck Lever * layers deal directly with the status value in network byte 2253460f29aSChuck Lever * order. 2263460f29aSChuck Lever */ 2273460f29aSChuck Lever static void encode_nlm4_stat(struct xdr_stream *xdr, 2283460f29aSChuck Lever const __be32 stat) 2293460f29aSChuck Lever { 2303460f29aSChuck Lever __be32 *p; 2313460f29aSChuck Lever 2323460f29aSChuck Lever BUG_ON(be32_to_cpu(stat) > NLM_FAILED); 2333460f29aSChuck Lever p = xdr_reserve_space(xdr, 4); 2343460f29aSChuck Lever *p = stat; 2353460f29aSChuck Lever } 2363460f29aSChuck Lever 2373460f29aSChuck Lever static int decode_nlm4_stat(struct xdr_stream *xdr, __be32 *stat) 2383460f29aSChuck Lever { 2393460f29aSChuck Lever __be32 *p; 2403460f29aSChuck Lever 2413460f29aSChuck Lever p = xdr_inline_decode(xdr, 4); 2423460f29aSChuck Lever if (unlikely(p == NULL)) 2433460f29aSChuck Lever goto out_overflow; 2443460f29aSChuck Lever if (unlikely(*p > nlm4_failed)) 2453460f29aSChuck Lever goto out_bad_xdr; 2463460f29aSChuck Lever *stat = *p; 2473460f29aSChuck Lever return 0; 2483460f29aSChuck Lever out_bad_xdr: 2493460f29aSChuck Lever dprintk("%s: server returned invalid nlm4_stats value: %u\n", 2503460f29aSChuck Lever __func__, be32_to_cpup(p)); 2513460f29aSChuck Lever return -EIO; 2523460f29aSChuck Lever out_overflow: 2533460f29aSChuck Lever print_overflow_msg(__func__, xdr); 2543460f29aSChuck Lever return -EIO; 2553460f29aSChuck Lever } 2563460f29aSChuck Lever 2573460f29aSChuck Lever /* 2583460f29aSChuck Lever * struct nlm4_holder { 2593460f29aSChuck Lever * bool exclusive; 2603460f29aSChuck Lever * int32 svid; 2613460f29aSChuck Lever * netobj oh; 2623460f29aSChuck Lever * uint64 l_offset; 2633460f29aSChuck Lever * uint64 l_len; 2643460f29aSChuck Lever * }; 2653460f29aSChuck Lever */ 2663460f29aSChuck Lever static void encode_nlm4_holder(struct xdr_stream *xdr, 2673460f29aSChuck Lever const struct nlm_res *result) 2683460f29aSChuck Lever { 2693460f29aSChuck Lever const struct nlm_lock *lock = &result->lock; 2703460f29aSChuck Lever u64 l_offset, l_len; 2713460f29aSChuck Lever __be32 *p; 2723460f29aSChuck Lever 2733460f29aSChuck Lever encode_bool(xdr, lock->fl.fl_type == F_RDLCK); 2743460f29aSChuck Lever encode_int32(xdr, lock->svid); 2753460f29aSChuck Lever encode_netobj(xdr, lock->oh.data, lock->oh.len); 2763460f29aSChuck Lever 2773460f29aSChuck Lever p = xdr_reserve_space(xdr, 4 + 4); 2783460f29aSChuck Lever nlm4_compute_offsets(lock, &l_offset, &l_len); 2793460f29aSChuck Lever p = xdr_encode_hyper(p, l_offset); 2803460f29aSChuck Lever xdr_encode_hyper(p, l_len); 2813460f29aSChuck Lever } 2823460f29aSChuck Lever 2833460f29aSChuck Lever static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result) 2843460f29aSChuck Lever { 2853460f29aSChuck Lever struct nlm_lock *lock = &result->lock; 2863460f29aSChuck Lever struct file_lock *fl = &lock->fl; 2873460f29aSChuck Lever u64 l_offset, l_len; 2883460f29aSChuck Lever u32 exclusive; 2893460f29aSChuck Lever int error; 2903460f29aSChuck Lever __be32 *p; 2913460f29aSChuck Lever s32 end; 2923460f29aSChuck Lever 2933460f29aSChuck Lever memset(lock, 0, sizeof(*lock)); 2943460f29aSChuck Lever locks_init_lock(fl); 2953460f29aSChuck Lever 2963460f29aSChuck Lever p = xdr_inline_decode(xdr, 4 + 4); 2973460f29aSChuck Lever if (unlikely(p == NULL)) 2983460f29aSChuck Lever goto out_overflow; 2993460f29aSChuck Lever exclusive = be32_to_cpup(p++); 3003460f29aSChuck Lever lock->svid = be32_to_cpup(p); 3013460f29aSChuck Lever fl->fl_pid = (pid_t)lock->svid; 3023460f29aSChuck Lever 3033460f29aSChuck Lever error = decode_netobj(xdr, &lock->oh); 3043460f29aSChuck Lever if (unlikely(error)) 3053460f29aSChuck Lever goto out; 3063460f29aSChuck Lever 3073460f29aSChuck Lever p = xdr_inline_decode(xdr, 8 + 8); 3083460f29aSChuck Lever if (unlikely(p == NULL)) 3093460f29aSChuck Lever goto out_overflow; 3103460f29aSChuck Lever 3113460f29aSChuck Lever fl->fl_flags = FL_POSIX; 3123460f29aSChuck Lever fl->fl_type = exclusive != 0 ? F_WRLCK : F_RDLCK; 3133460f29aSChuck Lever p = xdr_decode_hyper(p, &l_offset); 3143460f29aSChuck Lever xdr_decode_hyper(p, &l_len); 3153460f29aSChuck Lever end = l_offset + l_len - 1; 3163460f29aSChuck Lever 3173460f29aSChuck Lever fl->fl_start = (loff_t)l_offset; 3183460f29aSChuck Lever if (l_len == 0 || end < 0) 3193460f29aSChuck Lever fl->fl_end = OFFSET_MAX; 3203460f29aSChuck Lever else 3213460f29aSChuck Lever fl->fl_end = (loff_t)end; 3223460f29aSChuck Lever error = 0; 3233460f29aSChuck Lever out: 3243460f29aSChuck Lever return error; 3253460f29aSChuck Lever out_overflow: 3263460f29aSChuck Lever print_overflow_msg(__func__, xdr); 3273460f29aSChuck Lever return -EIO; 3283460f29aSChuck Lever } 3293460f29aSChuck Lever 3303460f29aSChuck Lever /* 3313460f29aSChuck Lever * string caller_name<LM_MAXSTRLEN>; 3323460f29aSChuck Lever */ 3333460f29aSChuck Lever static void encode_caller_name(struct xdr_stream *xdr, const char *name) 3343460f29aSChuck Lever { 3353460f29aSChuck Lever /* NB: client-side does not set lock->len */ 3363460f29aSChuck Lever u32 length = strlen(name); 3373460f29aSChuck Lever __be32 *p; 3383460f29aSChuck Lever 3393460f29aSChuck Lever BUG_ON(length > NLM_MAXSTRLEN); 3403460f29aSChuck Lever p = xdr_reserve_space(xdr, 4 + length); 3413460f29aSChuck Lever xdr_encode_opaque(p, name, length); 3423460f29aSChuck Lever } 3433460f29aSChuck Lever 3443460f29aSChuck Lever /* 3453460f29aSChuck Lever * struct nlm4_lock { 3463460f29aSChuck Lever * string caller_name<LM_MAXSTRLEN>; 3473460f29aSChuck Lever * netobj fh; 3483460f29aSChuck Lever * netobj oh; 3493460f29aSChuck Lever * int32 svid; 3503460f29aSChuck Lever * uint64 l_offset; 3513460f29aSChuck Lever * uint64 l_len; 3523460f29aSChuck Lever * }; 3533460f29aSChuck Lever */ 3543460f29aSChuck Lever static void encode_nlm4_lock(struct xdr_stream *xdr, 3553460f29aSChuck Lever const struct nlm_lock *lock) 3563460f29aSChuck Lever { 3573460f29aSChuck Lever u64 l_offset, l_len; 3583460f29aSChuck Lever __be32 *p; 3593460f29aSChuck Lever 3603460f29aSChuck Lever encode_caller_name(xdr, lock->caller); 3613460f29aSChuck Lever encode_fh(xdr, &lock->fh); 3623460f29aSChuck Lever encode_netobj(xdr, lock->oh.data, lock->oh.len); 3633460f29aSChuck Lever 3643460f29aSChuck Lever p = xdr_reserve_space(xdr, 4 + 8 + 8); 3653460f29aSChuck Lever *p++ = cpu_to_be32(lock->svid); 3663460f29aSChuck Lever 3673460f29aSChuck Lever nlm4_compute_offsets(lock, &l_offset, &l_len); 3683460f29aSChuck Lever p = xdr_encode_hyper(p, l_offset); 3693460f29aSChuck Lever xdr_encode_hyper(p, l_len); 3703460f29aSChuck Lever } 3713460f29aSChuck Lever 3723460f29aSChuck Lever 3733460f29aSChuck Lever /* 3743460f29aSChuck Lever * NLMv4 XDR encode functions 3753460f29aSChuck Lever * 3763460f29aSChuck Lever * NLMv4 argument types are defined in Appendix II of RFC 1813: 3773460f29aSChuck Lever * "NFS Version 3 Protocol Specification" and Chapter 10 of X/Open's 3783460f29aSChuck Lever * "Protocols for Interworking: XNFS, Version 3W". 3793460f29aSChuck Lever */ 3803460f29aSChuck Lever 3813460f29aSChuck Lever /* 3823460f29aSChuck Lever * struct nlm4_testargs { 3833460f29aSChuck Lever * netobj cookie; 3843460f29aSChuck Lever * bool exclusive; 3853460f29aSChuck Lever * struct nlm4_lock alock; 3863460f29aSChuck Lever * }; 3873460f29aSChuck Lever */ 388*9f06c719SChuck Lever static void nlm4_xdr_enc_testargs(struct rpc_rqst *req, 389*9f06c719SChuck Lever struct xdr_stream *xdr, 3903460f29aSChuck Lever const struct nlm_args *args) 3913460f29aSChuck Lever { 3923460f29aSChuck Lever const struct nlm_lock *lock = &args->lock; 3933460f29aSChuck Lever 394*9f06c719SChuck Lever encode_cookie(xdr, &args->cookie); 395*9f06c719SChuck Lever encode_bool(xdr, lock->fl.fl_type == F_WRLCK); 396*9f06c719SChuck Lever encode_nlm4_lock(xdr, lock); 3973460f29aSChuck Lever } 3983460f29aSChuck Lever 3993460f29aSChuck Lever /* 4003460f29aSChuck Lever * struct nlm4_lockargs { 4013460f29aSChuck Lever * netobj cookie; 4023460f29aSChuck Lever * bool block; 4033460f29aSChuck Lever * bool exclusive; 4043460f29aSChuck Lever * struct nlm4_lock alock; 4053460f29aSChuck Lever * bool reclaim; 4063460f29aSChuck Lever * int state; 4073460f29aSChuck Lever * }; 4083460f29aSChuck Lever */ 409*9f06c719SChuck Lever static void nlm4_xdr_enc_lockargs(struct rpc_rqst *req, 410*9f06c719SChuck Lever struct xdr_stream *xdr, 4113460f29aSChuck Lever const struct nlm_args *args) 4123460f29aSChuck Lever { 4133460f29aSChuck Lever const struct nlm_lock *lock = &args->lock; 4143460f29aSChuck Lever 415*9f06c719SChuck Lever encode_cookie(xdr, &args->cookie); 416*9f06c719SChuck Lever encode_bool(xdr, args->block); 417*9f06c719SChuck Lever encode_bool(xdr, lock->fl.fl_type == F_WRLCK); 418*9f06c719SChuck Lever encode_nlm4_lock(xdr, lock); 419*9f06c719SChuck Lever encode_bool(xdr, args->reclaim); 420*9f06c719SChuck Lever encode_int32(xdr, args->state); 4213460f29aSChuck Lever } 4223460f29aSChuck Lever 4233460f29aSChuck Lever /* 4243460f29aSChuck Lever * struct nlm4_cancargs { 4253460f29aSChuck Lever * netobj cookie; 4263460f29aSChuck Lever * bool block; 4273460f29aSChuck Lever * bool exclusive; 4283460f29aSChuck Lever * struct nlm4_lock alock; 4293460f29aSChuck Lever * }; 4303460f29aSChuck Lever */ 431*9f06c719SChuck Lever static void nlm4_xdr_enc_cancargs(struct rpc_rqst *req, 432*9f06c719SChuck Lever struct xdr_stream *xdr, 4333460f29aSChuck Lever const struct nlm_args *args) 4343460f29aSChuck Lever { 4353460f29aSChuck Lever const struct nlm_lock *lock = &args->lock; 4363460f29aSChuck Lever 437*9f06c719SChuck Lever encode_cookie(xdr, &args->cookie); 438*9f06c719SChuck Lever encode_bool(xdr, args->block); 439*9f06c719SChuck Lever encode_bool(xdr, lock->fl.fl_type == F_WRLCK); 440*9f06c719SChuck Lever encode_nlm4_lock(xdr, lock); 4413460f29aSChuck Lever } 4423460f29aSChuck Lever 4433460f29aSChuck Lever /* 4443460f29aSChuck Lever * struct nlm4_unlockargs { 4453460f29aSChuck Lever * netobj cookie; 4463460f29aSChuck Lever * struct nlm4_lock alock; 4473460f29aSChuck Lever * }; 4483460f29aSChuck Lever */ 449*9f06c719SChuck Lever static void nlm4_xdr_enc_unlockargs(struct rpc_rqst *req, 450*9f06c719SChuck Lever struct xdr_stream *xdr, 4513460f29aSChuck Lever const struct nlm_args *args) 4523460f29aSChuck Lever { 4533460f29aSChuck Lever const struct nlm_lock *lock = &args->lock; 4543460f29aSChuck Lever 455*9f06c719SChuck Lever encode_cookie(xdr, &args->cookie); 456*9f06c719SChuck Lever encode_nlm4_lock(xdr, lock); 4573460f29aSChuck Lever } 4583460f29aSChuck Lever 4593460f29aSChuck Lever /* 4603460f29aSChuck Lever * struct nlm4_res { 4613460f29aSChuck Lever * netobj cookie; 4623460f29aSChuck Lever * nlm4_stat stat; 4633460f29aSChuck Lever * }; 4643460f29aSChuck Lever */ 465*9f06c719SChuck Lever static void nlm4_xdr_enc_res(struct rpc_rqst *req, 466*9f06c719SChuck Lever struct xdr_stream *xdr, 4673460f29aSChuck Lever const struct nlm_res *result) 4683460f29aSChuck Lever { 469*9f06c719SChuck Lever encode_cookie(xdr, &result->cookie); 470*9f06c719SChuck 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 */ 486*9f06c719SChuck Lever static void nlm4_xdr_enc_testres(struct rpc_rqst *req, 487*9f06c719SChuck Lever struct xdr_stream *xdr, 4883460f29aSChuck Lever const struct nlm_res *result) 4893460f29aSChuck Lever { 490*9f06c719SChuck Lever encode_cookie(xdr, &result->cookie); 491*9f06c719SChuck Lever encode_nlm4_stat(xdr, result->status); 4923460f29aSChuck Lever if (result->status == nlm_lck_denied) 493*9f06c719SChuck Lever encode_nlm4_holder(xdr, result); 4943460f29aSChuck Lever } 4953460f29aSChuck Lever 4963460f29aSChuck Lever 4973460f29aSChuck Lever /* 4983460f29aSChuck Lever * NLMv4 XDR decode functions 4993460f29aSChuck Lever * 5003460f29aSChuck Lever * NLMv4 argument types are defined in Appendix II of RFC 1813: 5013460f29aSChuck Lever * "NFS Version 3 Protocol Specification" and Chapter 10 of X/Open's 5023460f29aSChuck Lever * "Protocols for Interworking: XNFS, Version 3W". 5033460f29aSChuck Lever */ 5043460f29aSChuck Lever 5053460f29aSChuck Lever /* 5063460f29aSChuck Lever * union nlm4_testrply switch (nlm4_stats stat) { 5073460f29aSChuck Lever * case NLM4_DENIED: 5083460f29aSChuck Lever * struct nlm4_holder holder; 5093460f29aSChuck Lever * default: 5103460f29aSChuck Lever * void; 5113460f29aSChuck Lever * }; 5123460f29aSChuck Lever * 5133460f29aSChuck Lever * struct nlm4_testres { 5143460f29aSChuck Lever * netobj cookie; 5153460f29aSChuck Lever * nlm4_testrply test_stat; 5163460f29aSChuck Lever * }; 5173460f29aSChuck Lever */ 5183460f29aSChuck Lever static int decode_nlm4_testrply(struct xdr_stream *xdr, 5193460f29aSChuck Lever struct nlm_res *result) 5203460f29aSChuck Lever { 5213460f29aSChuck Lever int error; 5223460f29aSChuck Lever 5233460f29aSChuck Lever error = decode_nlm4_stat(xdr, &result->status); 5243460f29aSChuck Lever if (unlikely(error)) 5253460f29aSChuck Lever goto out; 5263460f29aSChuck Lever if (result->status == nlm_lck_denied) 5273460f29aSChuck Lever error = decode_nlm4_holder(xdr, result); 5283460f29aSChuck Lever out: 5293460f29aSChuck Lever return error; 5303460f29aSChuck Lever } 5313460f29aSChuck Lever 5323460f29aSChuck Lever static int nlm4_xdr_dec_testres(struct rpc_rqst *req, __be32 *p, 5333460f29aSChuck Lever struct nlm_res *result) 5343460f29aSChuck Lever { 5353460f29aSChuck Lever struct xdr_stream xdr; 5363460f29aSChuck Lever int error; 5373460f29aSChuck Lever 5383460f29aSChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 5393460f29aSChuck Lever error = decode_cookie(&xdr, &result->cookie); 5403460f29aSChuck Lever if (unlikely(error)) 5413460f29aSChuck Lever goto out; 5423460f29aSChuck Lever error = decode_nlm4_testrply(&xdr, result); 5433460f29aSChuck Lever out: 5443460f29aSChuck Lever return error; 5453460f29aSChuck Lever } 5463460f29aSChuck Lever 5473460f29aSChuck Lever /* 5483460f29aSChuck Lever * struct nlm4_res { 5493460f29aSChuck Lever * netobj cookie; 5503460f29aSChuck Lever * nlm4_stat stat; 5513460f29aSChuck Lever * }; 5523460f29aSChuck Lever */ 5533460f29aSChuck Lever static int nlm4_xdr_dec_res(struct rpc_rqst *req, __be32 *p, 5543460f29aSChuck Lever struct nlm_res *result) 5553460f29aSChuck Lever { 5563460f29aSChuck Lever struct xdr_stream xdr; 5573460f29aSChuck Lever int error; 5583460f29aSChuck Lever 5593460f29aSChuck Lever xdr_init_decode(&xdr, &req->rq_rcv_buf, p); 5603460f29aSChuck Lever error = decode_cookie(&xdr, &result->cookie); 5613460f29aSChuck Lever if (unlikely(error)) 5623460f29aSChuck Lever goto out; 5633460f29aSChuck Lever error = decode_nlm4_stat(&xdr, &result->status); 5643460f29aSChuck Lever out: 5653460f29aSChuck Lever return error; 5663460f29aSChuck Lever } 5673460f29aSChuck Lever 5683460f29aSChuck Lever 5693460f29aSChuck Lever /* 5703460f29aSChuck Lever * For NLM, a void procedure really returns nothing 5713460f29aSChuck Lever */ 5723460f29aSChuck Lever #define nlm4_xdr_dec_norep NULL 5733460f29aSChuck Lever 5743460f29aSChuck Lever #define PROC(proc, argtype, restype) \ 5753460f29aSChuck Lever [NLMPROC_##proc] = { \ 5763460f29aSChuck Lever .p_proc = NLMPROC_##proc, \ 577*9f06c719SChuck Lever .p_encode = (kxdreproc_t)nlm4_xdr_enc_##argtype, \ 5783460f29aSChuck Lever .p_decode = (kxdrproc_t)nlm4_xdr_dec_##restype, \ 5793460f29aSChuck Lever .p_arglen = NLM4_##argtype##_sz, \ 5803460f29aSChuck Lever .p_replen = NLM4_##restype##_sz, \ 5813460f29aSChuck Lever .p_statidx = NLMPROC_##proc, \ 5823460f29aSChuck Lever .p_name = #proc, \ 5833460f29aSChuck Lever } 5843460f29aSChuck Lever 5853460f29aSChuck Lever static struct rpc_procinfo nlm4_procedures[] = { 5863460f29aSChuck Lever PROC(TEST, testargs, testres), 5873460f29aSChuck Lever PROC(LOCK, lockargs, res), 5883460f29aSChuck Lever PROC(CANCEL, cancargs, res), 5893460f29aSChuck Lever PROC(UNLOCK, unlockargs, res), 5903460f29aSChuck Lever PROC(GRANTED, testargs, res), 5913460f29aSChuck Lever PROC(TEST_MSG, testargs, norep), 5923460f29aSChuck Lever PROC(LOCK_MSG, lockargs, norep), 5933460f29aSChuck Lever PROC(CANCEL_MSG, cancargs, norep), 5943460f29aSChuck Lever PROC(UNLOCK_MSG, unlockargs, norep), 5953460f29aSChuck Lever PROC(GRANTED_MSG, testargs, norep), 5963460f29aSChuck Lever PROC(TEST_RES, testres, norep), 5973460f29aSChuck Lever PROC(LOCK_RES, res, norep), 5983460f29aSChuck Lever PROC(CANCEL_RES, res, norep), 5993460f29aSChuck Lever PROC(UNLOCK_RES, res, norep), 6003460f29aSChuck Lever PROC(GRANTED_RES, res, norep), 6013460f29aSChuck Lever }; 6023460f29aSChuck Lever 6033460f29aSChuck Lever struct rpc_version nlm_version4 = { 6043460f29aSChuck Lever .number = 4, 6053460f29aSChuck Lever .nrprocs = ARRAY_SIZE(nlm4_procedures), 6063460f29aSChuck Lever .procs = nlm4_procedures, 6073460f29aSChuck Lever }; 608