xref: /openbmc/linux/fs/nfs/nfs4xdr.c (revision daccbded)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  fs/nfs/nfs4xdr.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  Client-side XDR for NFSv4.
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  *  Copyright (c) 2002 The Regents of the University of Michigan.
71da177e4SLinus Torvalds  *  All rights reserved.
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *  Kendrick Smith <kmsmith@umich.edu>
101da177e4SLinus Torvalds  *  Andy Adamson   <andros@umich.edu>
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  *  Redistribution and use in source and binary forms, with or without
131da177e4SLinus Torvalds  *  modification, are permitted provided that the following conditions
141da177e4SLinus Torvalds  *  are met:
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  *  1. Redistributions of source code must retain the above copyright
171da177e4SLinus Torvalds  *     notice, this list of conditions and the following disclaimer.
181da177e4SLinus Torvalds  *  2. Redistributions in binary form must reproduce the above copyright
191da177e4SLinus Torvalds  *     notice, this list of conditions and the following disclaimer in the
201da177e4SLinus Torvalds  *     documentation and/or other materials provided with the distribution.
211da177e4SLinus Torvalds  *  3. Neither the name of the University nor the names of its
221da177e4SLinus Torvalds  *     contributors may be used to endorse or promote products derived
231da177e4SLinus Torvalds  *     from this software without specific prior written permission.
241da177e4SLinus Torvalds  *
251da177e4SLinus Torvalds  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
261da177e4SLinus Torvalds  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
271da177e4SLinus Torvalds  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
281da177e4SLinus Torvalds  *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
291da177e4SLinus Torvalds  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
301da177e4SLinus Torvalds  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
311da177e4SLinus Torvalds  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
321da177e4SLinus Torvalds  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
331da177e4SLinus Torvalds  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
341da177e4SLinus Torvalds  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
351da177e4SLinus Torvalds  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
361da177e4SLinus Torvalds  */
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds #include <linux/param.h>
391da177e4SLinus Torvalds #include <linux/time.h>
401da177e4SLinus Torvalds #include <linux/mm.h>
411da177e4SLinus Torvalds #include <linux/errno.h>
421da177e4SLinus Torvalds #include <linux/string.h>
431da177e4SLinus Torvalds #include <linux/in.h>
441da177e4SLinus Torvalds #include <linux/pagemap.h>
451da177e4SLinus Torvalds #include <linux/proc_fs.h>
461da177e4SLinus Torvalds #include <linux/kdev_t.h>
471da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
482449ea2eSAlexandros Batsakis #include <linux/sunrpc/msg_prot.h>
491da177e4SLinus Torvalds #include <linux/nfs.h>
501da177e4SLinus Torvalds #include <linux/nfs4.h>
511da177e4SLinus Torvalds #include <linux/nfs_fs.h>
521da177e4SLinus Torvalds #include <linux/nfs_idmap.h>
534ce79717STrond Myklebust #include "nfs4_fs.h"
544882ef72SAlexandros Batsakis #include "internal.h"
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds #define NFSDBG_FACILITY		NFSDBG_XDR
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds /* Mapping from NFS error code to "errno" error code. */
591da177e4SLinus Torvalds #define errno_NFSERR_IO		EIO
601da177e4SLinus Torvalds 
610a8ea437SDavid Howells static int nfs4_stat_to_errno(int);
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds /* NFSv4 COMPOUND tags are only wanted for debugging purposes */
641da177e4SLinus Torvalds #ifdef DEBUG
651da177e4SLinus Torvalds #define NFS4_MAXTAGLEN		20
661da177e4SLinus Torvalds #else
671da177e4SLinus Torvalds #define NFS4_MAXTAGLEN		0
681da177e4SLinus Torvalds #endif
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds /* lock,open owner id:
719f958ab8STrond Myklebust  * we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT  >> 2)
721da177e4SLinus Torvalds  */
739f958ab8STrond Myklebust #define open_owner_id_maxsz	(1 + 4)
749f958ab8STrond Myklebust #define lock_owner_id_maxsz	(1 + 4)
759104a55dSTrond Myklebust #define decode_lockowner_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
761da177e4SLinus Torvalds #define compound_encode_hdr_maxsz	(3 + (NFS4_MAXTAGLEN >> 2))
771da177e4SLinus Torvalds #define compound_decode_hdr_maxsz	(3 + (NFS4_MAXTAGLEN >> 2))
781da177e4SLinus Torvalds #define op_encode_hdr_maxsz	(1)
791da177e4SLinus Torvalds #define op_decode_hdr_maxsz	(2)
809104a55dSTrond Myklebust #define encode_stateid_maxsz	(XDR_QUADLEN(NFS4_STATEID_SIZE))
819104a55dSTrond Myklebust #define decode_stateid_maxsz	(XDR_QUADLEN(NFS4_STATEID_SIZE))
829104a55dSTrond Myklebust #define encode_verifier_maxsz	(XDR_QUADLEN(NFS4_VERIFIER_SIZE))
839104a55dSTrond Myklebust #define decode_verifier_maxsz	(XDR_QUADLEN(NFS4_VERIFIER_SIZE))
841da177e4SLinus Torvalds #define encode_putfh_maxsz	(op_encode_hdr_maxsz + 1 + \
851da177e4SLinus Torvalds 				(NFS4_FHSIZE >> 2))
861da177e4SLinus Torvalds #define decode_putfh_maxsz	(op_decode_hdr_maxsz)
871da177e4SLinus Torvalds #define encode_putrootfh_maxsz	(op_encode_hdr_maxsz)
881da177e4SLinus Torvalds #define decode_putrootfh_maxsz	(op_decode_hdr_maxsz)
891da177e4SLinus Torvalds #define encode_getfh_maxsz      (op_encode_hdr_maxsz)
901da177e4SLinus Torvalds #define decode_getfh_maxsz      (op_decode_hdr_maxsz + 1 + \
911da177e4SLinus Torvalds 				((3+NFS4_FHSIZE) >> 2))
9296928206SJ. Bruce Fields #define nfs4_fattr_bitmap_maxsz 3
9396928206SJ. Bruce Fields #define encode_getattr_maxsz    (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
941da177e4SLinus Torvalds #define nfs4_name_maxsz		(1 + ((3 + NFS4_MAXNAMLEN) >> 2))
951da177e4SLinus Torvalds #define nfs4_path_maxsz		(1 + ((3 + NFS4_MAXPATHLEN) >> 2))
96bd625ba8STrond Myklebust #define nfs4_owner_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
97bd625ba8STrond Myklebust #define nfs4_group_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
9896928206SJ. Bruce Fields /* This is based on getfattr, which uses the most attributes: */
9996928206SJ. Bruce Fields #define nfs4_fattr_value_maxsz	(1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \
100bd625ba8STrond Myklebust 				3 + 3 + 3 + nfs4_owner_maxsz + nfs4_group_maxsz))
10196928206SJ. Bruce Fields #define nfs4_fattr_maxsz	(nfs4_fattr_bitmap_maxsz + \
10296928206SJ. Bruce Fields 				nfs4_fattr_value_maxsz)
10396928206SJ. Bruce Fields #define decode_getattr_maxsz    (op_decode_hdr_maxsz + nfs4_fattr_maxsz)
1049104a55dSTrond Myklebust #define encode_attrs_maxsz	(nfs4_fattr_bitmap_maxsz + \
1059104a55dSTrond Myklebust 				 1 + 2 + 1 + \
1069104a55dSTrond Myklebust 				nfs4_owner_maxsz + \
1079104a55dSTrond Myklebust 				nfs4_group_maxsz + \
1089104a55dSTrond Myklebust 				4 + 4)
1091da177e4SLinus Torvalds #define encode_savefh_maxsz     (op_encode_hdr_maxsz)
1101da177e4SLinus Torvalds #define decode_savefh_maxsz     (op_decode_hdr_maxsz)
11156ae19f3STrond Myklebust #define encode_restorefh_maxsz  (op_encode_hdr_maxsz)
11256ae19f3STrond Myklebust #define decode_restorefh_maxsz  (op_decode_hdr_maxsz)
1132f42b5d0SFred Isaman #define encode_fsinfo_maxsz	(encode_getattr_maxsz)
1141da177e4SLinus Torvalds #define decode_fsinfo_maxsz	(op_decode_hdr_maxsz + 11)
1151da177e4SLinus Torvalds #define encode_renew_maxsz	(op_encode_hdr_maxsz + 3)
1161da177e4SLinus Torvalds #define decode_renew_maxsz	(op_decode_hdr_maxsz)
1171da177e4SLinus Torvalds #define encode_setclientid_maxsz \
1181da177e4SLinus Torvalds 				(op_encode_hdr_maxsz + \
119cc38bac3SChuck Lever 				XDR_QUADLEN(NFS4_VERIFIER_SIZE) + \
120cc38bac3SChuck Lever 				XDR_QUADLEN(NFS4_SETCLIENTID_NAMELEN) + \
121cc38bac3SChuck Lever 				1 /* sc_prog */ + \
122cc38bac3SChuck Lever 				XDR_QUADLEN(RPCBIND_MAXNETIDLEN) + \
123cc38bac3SChuck Lever 				XDR_QUADLEN(RPCBIND_MAXUADDRLEN) + \
124cc38bac3SChuck Lever 				1) /* sc_cb_ident */
1251da177e4SLinus Torvalds #define decode_setclientid_maxsz \
1261da177e4SLinus Torvalds 				(op_decode_hdr_maxsz + \
1271da177e4SLinus Torvalds 				2 + \
1281da177e4SLinus Torvalds 				1024) /* large value for CLID_INUSE */
1291da177e4SLinus Torvalds #define encode_setclientid_confirm_maxsz \
1301da177e4SLinus Torvalds 				(op_encode_hdr_maxsz + \
1311da177e4SLinus Torvalds 				3 + (NFS4_VERIFIER_SIZE >> 2))
1321da177e4SLinus Torvalds #define decode_setclientid_confirm_maxsz \
1331da177e4SLinus Torvalds 				(op_decode_hdr_maxsz)
134e6889620STrond Myklebust #define encode_lookup_maxsz	(op_encode_hdr_maxsz + nfs4_name_maxsz)
135e6889620STrond Myklebust #define decode_lookup_maxsz	(op_decode_hdr_maxsz)
1362cebf828STrond Myklebust #define encode_share_access_maxsz \
1372cebf828STrond Myklebust 				(2)
1384882ef72SAlexandros Batsakis #define encode_createmode_maxsz	(1 + encode_attrs_maxsz + encode_verifier_maxsz)
1392cebf828STrond Myklebust #define encode_opentype_maxsz	(1 + encode_createmode_maxsz)
1402cebf828STrond Myklebust #define encode_claim_null_maxsz	(1 + nfs4_name_maxsz)
1412cebf828STrond Myklebust #define encode_open_maxsz	(op_encode_hdr_maxsz + \
1422cebf828STrond Myklebust 				2 + encode_share_access_maxsz + 2 + \
1432cebf828STrond Myklebust 				open_owner_id_maxsz + \
1442cebf828STrond Myklebust 				encode_opentype_maxsz + \
1452cebf828STrond Myklebust 				encode_claim_null_maxsz)
1462cebf828STrond Myklebust #define decode_ace_maxsz	(3 + nfs4_owner_maxsz)
1479104a55dSTrond Myklebust #define decode_delegation_maxsz	(1 + decode_stateid_maxsz + 1 + \
1482cebf828STrond Myklebust 				decode_ace_maxsz)
1492cebf828STrond Myklebust #define decode_change_info_maxsz	(5)
1502cebf828STrond Myklebust #define decode_open_maxsz	(op_decode_hdr_maxsz + \
1519104a55dSTrond Myklebust 				decode_stateid_maxsz + \
1522cebf828STrond Myklebust 				decode_change_info_maxsz + 1 + \
1532cebf828STrond Myklebust 				nfs4_fattr_bitmap_maxsz + \
1542cebf828STrond Myklebust 				decode_delegation_maxsz)
1559104a55dSTrond Myklebust #define encode_open_confirm_maxsz \
1569104a55dSTrond Myklebust 				(op_encode_hdr_maxsz + \
1579104a55dSTrond Myklebust 				 encode_stateid_maxsz + 1)
1589104a55dSTrond Myklebust #define decode_open_confirm_maxsz \
1599104a55dSTrond Myklebust 				(op_decode_hdr_maxsz + \
1609104a55dSTrond Myklebust 				 decode_stateid_maxsz)
1619104a55dSTrond Myklebust #define encode_open_downgrade_maxsz \
1629104a55dSTrond Myklebust 				(op_encode_hdr_maxsz + \
1639104a55dSTrond Myklebust 				 encode_stateid_maxsz + 1 + \
1649104a55dSTrond Myklebust 				 encode_share_access_maxsz)
1659104a55dSTrond Myklebust #define decode_open_downgrade_maxsz \
1669104a55dSTrond Myklebust 				(op_decode_hdr_maxsz + \
1679104a55dSTrond Myklebust 				 decode_stateid_maxsz)
1689104a55dSTrond Myklebust #define encode_close_maxsz	(op_encode_hdr_maxsz + \
1699104a55dSTrond Myklebust 				 1 + encode_stateid_maxsz)
1709104a55dSTrond Myklebust #define decode_close_maxsz	(op_decode_hdr_maxsz + \
1719104a55dSTrond Myklebust 				 decode_stateid_maxsz)
1729104a55dSTrond Myklebust #define encode_setattr_maxsz	(op_encode_hdr_maxsz + \
1739104a55dSTrond Myklebust 				 encode_stateid_maxsz + \
1749104a55dSTrond Myklebust 				 encode_attrs_maxsz)
1759104a55dSTrond Myklebust #define decode_setattr_maxsz	(op_decode_hdr_maxsz + \
1769104a55dSTrond Myklebust 				 nfs4_fattr_bitmap_maxsz)
1779104a55dSTrond Myklebust #define encode_read_maxsz	(op_encode_hdr_maxsz + \
1789104a55dSTrond Myklebust 				 encode_stateid_maxsz + 3)
1799104a55dSTrond Myklebust #define decode_read_maxsz	(op_decode_hdr_maxsz + 2)
1809104a55dSTrond Myklebust #define encode_readdir_maxsz	(op_encode_hdr_maxsz + \
1819104a55dSTrond Myklebust 				 2 + encode_verifier_maxsz + 5)
1829104a55dSTrond Myklebust #define decode_readdir_maxsz	(op_decode_hdr_maxsz + \
1839104a55dSTrond Myklebust 				 decode_verifier_maxsz)
1849104a55dSTrond Myklebust #define encode_readlink_maxsz	(op_encode_hdr_maxsz)
1859104a55dSTrond Myklebust #define decode_readlink_maxsz	(op_decode_hdr_maxsz + 1)
1869104a55dSTrond Myklebust #define encode_write_maxsz	(op_encode_hdr_maxsz + \
1879104a55dSTrond Myklebust 				 encode_stateid_maxsz + 4)
1889104a55dSTrond Myklebust #define decode_write_maxsz	(op_decode_hdr_maxsz + \
1899104a55dSTrond Myklebust 				 2 + decode_verifier_maxsz)
1909104a55dSTrond Myklebust #define encode_commit_maxsz	(op_encode_hdr_maxsz + 3)
1919104a55dSTrond Myklebust #define decode_commit_maxsz	(op_decode_hdr_maxsz + \
1929104a55dSTrond Myklebust 				 decode_verifier_maxsz)
1931da177e4SLinus Torvalds #define encode_remove_maxsz	(op_encode_hdr_maxsz + \
1941da177e4SLinus Torvalds 				nfs4_name_maxsz)
1956ce18391SBenny Halevy #define decode_remove_maxsz	(op_decode_hdr_maxsz + \
1966ce18391SBenny Halevy 				 decode_change_info_maxsz)
1971da177e4SLinus Torvalds #define encode_rename_maxsz	(op_encode_hdr_maxsz + \
1981da177e4SLinus Torvalds 				2 * nfs4_name_maxsz)
1996ce18391SBenny Halevy #define decode_rename_maxsz	(op_decode_hdr_maxsz + \
2006ce18391SBenny Halevy 				 decode_change_info_maxsz + \
2016ce18391SBenny Halevy 				 decode_change_info_maxsz)
2021da177e4SLinus Torvalds #define encode_link_maxsz	(op_encode_hdr_maxsz + \
2031da177e4SLinus Torvalds 				nfs4_name_maxsz)
2046ce18391SBenny Halevy #define decode_link_maxsz	(op_decode_hdr_maxsz + decode_change_info_maxsz)
205daccbdedSTrond Myklebust #define encode_lockowner_maxsz	(7)
2069104a55dSTrond Myklebust #define encode_lock_maxsz	(op_encode_hdr_maxsz + \
2079104a55dSTrond Myklebust 				 7 + \
208daccbdedSTrond Myklebust 				 1 + encode_stateid_maxsz + 1 + \
209daccbdedSTrond Myklebust 				 encode_lockowner_maxsz)
2109104a55dSTrond Myklebust #define decode_lock_denied_maxsz \
2119104a55dSTrond Myklebust 				(8 + decode_lockowner_maxsz)
2129104a55dSTrond Myklebust #define decode_lock_maxsz	(op_decode_hdr_maxsz + \
2139104a55dSTrond Myklebust 				 decode_lock_denied_maxsz)
214daccbdedSTrond Myklebust #define encode_lockt_maxsz	(op_encode_hdr_maxsz + 5 + \
215daccbdedSTrond Myklebust 				encode_lockowner_maxsz)
2169104a55dSTrond Myklebust #define decode_lockt_maxsz	(op_decode_hdr_maxsz + \
2179104a55dSTrond Myklebust 				 decode_lock_denied_maxsz)
2189104a55dSTrond Myklebust #define encode_locku_maxsz	(op_encode_hdr_maxsz + 3 + \
2199104a55dSTrond Myklebust 				 encode_stateid_maxsz + \
2209104a55dSTrond Myklebust 				 4)
2219104a55dSTrond Myklebust #define decode_locku_maxsz	(op_decode_hdr_maxsz + \
2229104a55dSTrond Myklebust 				 decode_stateid_maxsz)
2239104a55dSTrond Myklebust #define encode_access_maxsz	(op_encode_hdr_maxsz + 1)
2249104a55dSTrond Myklebust #define decode_access_maxsz	(op_decode_hdr_maxsz + 2)
2251da177e4SLinus Torvalds #define encode_symlink_maxsz	(op_encode_hdr_maxsz + \
2261da177e4SLinus Torvalds 				1 + nfs4_name_maxsz + \
22794a6d753SChuck Lever 				1 + \
22896928206SJ. Bruce Fields 				nfs4_fattr_maxsz)
2291da177e4SLinus Torvalds #define decode_symlink_maxsz	(op_decode_hdr_maxsz + 8)
2301da177e4SLinus Torvalds #define encode_create_maxsz	(op_encode_hdr_maxsz + \
2319104a55dSTrond Myklebust 				1 + 2 + nfs4_name_maxsz + \
2329104a55dSTrond Myklebust 				encode_attrs_maxsz)
2332cebf828STrond Myklebust #define decode_create_maxsz	(op_decode_hdr_maxsz + \
2342cebf828STrond Myklebust 				decode_change_info_maxsz + \
2352cebf828STrond Myklebust 				nfs4_fattr_bitmap_maxsz)
2369104a55dSTrond Myklebust #define encode_statfs_maxsz	(encode_getattr_maxsz)
2379104a55dSTrond Myklebust #define decode_statfs_maxsz	(decode_getattr_maxsz)
2381da177e4SLinus Torvalds #define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4)
2391da177e4SLinus Torvalds #define decode_delegreturn_maxsz (op_decode_hdr_maxsz)
2409104a55dSTrond Myklebust #define encode_getacl_maxsz	(encode_getattr_maxsz)
2419104a55dSTrond Myklebust #define decode_getacl_maxsz	(op_decode_hdr_maxsz + \
2429104a55dSTrond Myklebust 				 nfs4_fattr_bitmap_maxsz + 1)
2439104a55dSTrond Myklebust #define encode_setacl_maxsz	(op_encode_hdr_maxsz + \
2449104a55dSTrond Myklebust 				 encode_stateid_maxsz + 3)
2459104a55dSTrond Myklebust #define decode_setacl_maxsz	(decode_setattr_maxsz)
246e6889620STrond Myklebust #define encode_fs_locations_maxsz \
247e6889620STrond Myklebust 				(encode_getattr_maxsz)
248e6889620STrond Myklebust #define decode_fs_locations_maxsz \
249e6889620STrond Myklebust 				(0)
2509b7b9fccSAndy Adamson 
2519b7b9fccSAndy Adamson #if defined(CONFIG_NFS_V4_1)
252fc931582SAndy Adamson #define NFS4_MAX_MACHINE_NAME_LEN (64)
253fc931582SAndy Adamson 
25499fe60d0SBenny Halevy #define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \
25599fe60d0SBenny Halevy 				encode_verifier_maxsz + \
25699fe60d0SBenny Halevy 				1 /* co_ownerid.len */ + \
25799fe60d0SBenny Halevy 				XDR_QUADLEN(NFS4_EXCHANGE_ID_LEN) + \
25899fe60d0SBenny Halevy 				1 /* flags */ + \
25999fe60d0SBenny Halevy 				1 /* spa_how */ + \
26099fe60d0SBenny Halevy 				0 /* SP4_NONE (for now) */ + \
26199fe60d0SBenny Halevy 				1 /* zero implemetation id array */)
26299fe60d0SBenny Halevy #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \
26399fe60d0SBenny Halevy 				2 /* eir_clientid */ + \
26499fe60d0SBenny Halevy 				1 /* eir_sequenceid */ + \
26599fe60d0SBenny Halevy 				1 /* eir_flags */ + \
26699fe60d0SBenny Halevy 				1 /* spr_how */ + \
26799fe60d0SBenny Halevy 				0 /* SP4_NONE (for now) */ + \
26899fe60d0SBenny Halevy 				2 /* eir_server_owner.so_minor_id */ + \
26999fe60d0SBenny Halevy 				/* eir_server_owner.so_major_id<> */ \
27099fe60d0SBenny Halevy 				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \
27199fe60d0SBenny Halevy 				/* eir_server_scope<> */ \
27299fe60d0SBenny Halevy 				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \
27399fe60d0SBenny Halevy 				1 /* eir_server_impl_id array length */ + \
27499fe60d0SBenny Halevy 				0 /* ignored eir_server_impl_id contents */)
275fc931582SAndy Adamson #define encode_channel_attrs_maxsz  (6 + 1 /* ca_rdma_ird.len (0) */)
276fc931582SAndy Adamson #define decode_channel_attrs_maxsz  (6 + \
277fc931582SAndy Adamson 				     1 /* ca_rdma_ird.len */ + \
278fc931582SAndy Adamson 				     1 /* ca_rdma_ird */)
279fc931582SAndy Adamson #define encode_create_session_maxsz  (op_encode_hdr_maxsz + \
280fc931582SAndy Adamson 				     2 /* csa_clientid */ + \
281fc931582SAndy Adamson 				     1 /* csa_sequence */ + \
282fc931582SAndy Adamson 				     1 /* csa_flags */ + \
283fc931582SAndy Adamson 				     encode_channel_attrs_maxsz + \
284fc931582SAndy Adamson 				     encode_channel_attrs_maxsz + \
285fc931582SAndy Adamson 				     1 /* csa_cb_program */ + \
286fc931582SAndy Adamson 				     1 /* csa_sec_parms.len (1) */ + \
287fc931582SAndy Adamson 				     1 /* cb_secflavor (AUTH_SYS) */ + \
288fc931582SAndy Adamson 				     1 /* stamp */ + \
289fc931582SAndy Adamson 				     1 /* machinename.len */ + \
290fc931582SAndy Adamson 				     XDR_QUADLEN(NFS4_MAX_MACHINE_NAME_LEN) + \
291fc931582SAndy Adamson 				     1 /* uid */ + \
292fc931582SAndy Adamson 				     1 /* gid */ + \
293fc931582SAndy Adamson 				     1 /* gids.len (0) */)
294fc931582SAndy Adamson #define decode_create_session_maxsz  (op_decode_hdr_maxsz +	\
295fc931582SAndy Adamson 				     XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
296fc931582SAndy Adamson 				     1 /* csr_sequence */ + \
297fc931582SAndy Adamson 				     1 /* csr_flags */ + \
298fc931582SAndy Adamson 				     decode_channel_attrs_maxsz + \
299fc931582SAndy Adamson 				     decode_channel_attrs_maxsz)
3000f3e66c6SAndy Adamson #define encode_destroy_session_maxsz    (op_encode_hdr_maxsz + 4)
3010f3e66c6SAndy Adamson #define decode_destroy_session_maxsz    (op_decode_hdr_maxsz)
302fc01cea9SAndy Adamson #define encode_sequence_maxsz	(op_encode_hdr_maxsz + \
303fc01cea9SAndy Adamson 				XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 4)
304fc01cea9SAndy Adamson #define decode_sequence_maxsz	(op_decode_hdr_maxsz + \
305fc01cea9SAndy Adamson 				XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5)
30618019753SRicardo Labiaga #define encode_reclaim_complete_maxsz	(op_encode_hdr_maxsz + 4)
30718019753SRicardo Labiaga #define decode_reclaim_complete_maxsz	(op_decode_hdr_maxsz + 4)
3089b7b9fccSAndy Adamson #else /* CONFIG_NFS_V4_1 */
3099b7b9fccSAndy Adamson #define encode_sequence_maxsz	0
3109b7b9fccSAndy Adamson #define decode_sequence_maxsz	0
3119b7b9fccSAndy Adamson #endif /* CONFIG_NFS_V4_1 */
3129b7b9fccSAndy Adamson 
3131da177e4SLinus Torvalds #define NFS4_enc_compound_sz	(1024)  /* XXX: large enough? */
3141da177e4SLinus Torvalds #define NFS4_dec_compound_sz	(1024)  /* XXX: large enough? */
3151da177e4SLinus Torvalds #define NFS4_enc_read_sz	(compound_encode_hdr_maxsz + \
3169b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
3171da177e4SLinus Torvalds 				encode_putfh_maxsz + \
3189104a55dSTrond Myklebust 				encode_read_maxsz)
3191da177e4SLinus Torvalds #define NFS4_dec_read_sz	(compound_decode_hdr_maxsz + \
3209b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
3211da177e4SLinus Torvalds 				decode_putfh_maxsz + \
3229104a55dSTrond Myklebust 				decode_read_maxsz)
3231da177e4SLinus Torvalds #define NFS4_enc_readlink_sz	(compound_encode_hdr_maxsz + \
3249b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
3251da177e4SLinus Torvalds 				encode_putfh_maxsz + \
3269104a55dSTrond Myklebust 				encode_readlink_maxsz)
3271da177e4SLinus Torvalds #define NFS4_dec_readlink_sz	(compound_decode_hdr_maxsz + \
3289b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
3291da177e4SLinus Torvalds 				decode_putfh_maxsz + \
3309104a55dSTrond Myklebust 				decode_readlink_maxsz)
3311da177e4SLinus Torvalds #define NFS4_enc_readdir_sz	(compound_encode_hdr_maxsz + \
3329b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
3331da177e4SLinus Torvalds 				encode_putfh_maxsz + \
3349104a55dSTrond Myklebust 				encode_readdir_maxsz)
3351da177e4SLinus Torvalds #define NFS4_dec_readdir_sz	(compound_decode_hdr_maxsz + \
3369b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
3371da177e4SLinus Torvalds 				decode_putfh_maxsz + \
3389104a55dSTrond Myklebust 				decode_readdir_maxsz)
3391da177e4SLinus Torvalds #define NFS4_enc_write_sz	(compound_encode_hdr_maxsz + \
3409b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
3411da177e4SLinus Torvalds 				encode_putfh_maxsz + \
3429104a55dSTrond Myklebust 				encode_write_maxsz + \
3434f9838c7STrond Myklebust 				encode_getattr_maxsz)
3441da177e4SLinus Torvalds #define NFS4_dec_write_sz	(compound_decode_hdr_maxsz + \
3459b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
3461da177e4SLinus Torvalds 				decode_putfh_maxsz + \
3479104a55dSTrond Myklebust 				decode_write_maxsz + \
3484f9838c7STrond Myklebust 				decode_getattr_maxsz)
3491da177e4SLinus Torvalds #define NFS4_enc_commit_sz	(compound_encode_hdr_maxsz + \
3509b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
3511da177e4SLinus Torvalds 				encode_putfh_maxsz + \
3529104a55dSTrond Myklebust 				encode_commit_maxsz + \
3534f9838c7STrond Myklebust 				encode_getattr_maxsz)
3541da177e4SLinus Torvalds #define NFS4_dec_commit_sz	(compound_decode_hdr_maxsz + \
3559b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
3561da177e4SLinus Torvalds 				decode_putfh_maxsz + \
3579104a55dSTrond Myklebust 				decode_commit_maxsz + \
3584f9838c7STrond Myklebust 				decode_getattr_maxsz)
3591da177e4SLinus Torvalds #define NFS4_enc_open_sz        (compound_encode_hdr_maxsz + \
3609b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
3611da177e4SLinus Torvalds 				encode_putfh_maxsz + \
3622cebf828STrond Myklebust 				encode_savefh_maxsz + \
3632cebf828STrond Myklebust 				encode_open_maxsz + \
3642cebf828STrond Myklebust 				encode_getfh_maxsz + \
3651da177e4SLinus Torvalds 				encode_getattr_maxsz + \
3662cebf828STrond Myklebust 				encode_restorefh_maxsz + \
3672cebf828STrond Myklebust 				encode_getattr_maxsz)
3681da177e4SLinus Torvalds #define NFS4_dec_open_sz        (compound_decode_hdr_maxsz + \
3699b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
3701da177e4SLinus Torvalds 				decode_putfh_maxsz + \
3712cebf828STrond Myklebust 				decode_savefh_maxsz + \
3722cebf828STrond Myklebust 				decode_open_maxsz + \
3732cebf828STrond Myklebust 				decode_getfh_maxsz + \
3741da177e4SLinus Torvalds 				decode_getattr_maxsz + \
3752cebf828STrond Myklebust 				decode_restorefh_maxsz + \
3762cebf828STrond Myklebust 				decode_getattr_maxsz)
3771da177e4SLinus Torvalds #define NFS4_enc_open_confirm_sz \
3781da177e4SLinus Torvalds 				(compound_encode_hdr_maxsz + \
3791da177e4SLinus Torvalds 				 encode_putfh_maxsz + \
3809104a55dSTrond Myklebust 				 encode_open_confirm_maxsz)
3819104a55dSTrond Myklebust #define NFS4_dec_open_confirm_sz \
3829104a55dSTrond Myklebust 				(compound_decode_hdr_maxsz + \
3831da177e4SLinus Torvalds 				 decode_putfh_maxsz + \
3849104a55dSTrond Myklebust 				 decode_open_confirm_maxsz)
3851da177e4SLinus Torvalds #define NFS4_enc_open_noattr_sz	(compound_encode_hdr_maxsz + \
3869b7b9fccSAndy Adamson 					encode_sequence_maxsz + \
3871da177e4SLinus Torvalds 					encode_putfh_maxsz + \
3882cebf828STrond Myklebust 					encode_open_maxsz + \
3892cebf828STrond Myklebust 					encode_getattr_maxsz)
3901da177e4SLinus Torvalds #define NFS4_dec_open_noattr_sz	(compound_decode_hdr_maxsz + \
3919b7b9fccSAndy Adamson 					decode_sequence_maxsz + \
3921da177e4SLinus Torvalds 					decode_putfh_maxsz + \
3932cebf828STrond Myklebust 					decode_open_maxsz + \
3942cebf828STrond Myklebust 					decode_getattr_maxsz)
3951da177e4SLinus Torvalds #define NFS4_enc_open_downgrade_sz \
3961da177e4SLinus Torvalds 				(compound_encode_hdr_maxsz + \
3979b7b9fccSAndy Adamson 				 encode_sequence_maxsz + \
3981da177e4SLinus Torvalds 				 encode_putfh_maxsz + \
3999104a55dSTrond Myklebust 				 encode_open_downgrade_maxsz + \
400516a6af6STrond Myklebust 				 encode_getattr_maxsz)
4011da177e4SLinus Torvalds #define NFS4_dec_open_downgrade_sz \
4021da177e4SLinus Torvalds 				(compound_decode_hdr_maxsz + \
4039b7b9fccSAndy Adamson 				 decode_sequence_maxsz + \
4041da177e4SLinus Torvalds 				 decode_putfh_maxsz + \
4059104a55dSTrond Myklebust 				 decode_open_downgrade_maxsz + \
406516a6af6STrond Myklebust 				 decode_getattr_maxsz)
4071da177e4SLinus Torvalds #define NFS4_enc_close_sz	(compound_encode_hdr_maxsz + \
4089b7b9fccSAndy Adamson 				 encode_sequence_maxsz + \
4091da177e4SLinus Torvalds 				 encode_putfh_maxsz + \
4109104a55dSTrond Myklebust 				 encode_close_maxsz + \
411516a6af6STrond Myklebust 				 encode_getattr_maxsz)
4121da177e4SLinus Torvalds #define NFS4_dec_close_sz	(compound_decode_hdr_maxsz + \
4139b7b9fccSAndy Adamson 				 decode_sequence_maxsz + \
4141da177e4SLinus Torvalds 				 decode_putfh_maxsz + \
4159104a55dSTrond Myklebust 				 decode_close_maxsz + \
416516a6af6STrond Myklebust 				 decode_getattr_maxsz)
4171da177e4SLinus Torvalds #define NFS4_enc_setattr_sz	(compound_encode_hdr_maxsz + \
4189b7b9fccSAndy Adamson 				 encode_sequence_maxsz + \
4191da177e4SLinus Torvalds 				 encode_putfh_maxsz + \
4209104a55dSTrond Myklebust 				 encode_setattr_maxsz + \
4211da177e4SLinus Torvalds 				 encode_getattr_maxsz)
4221da177e4SLinus Torvalds #define NFS4_dec_setattr_sz	(compound_decode_hdr_maxsz + \
4239b7b9fccSAndy Adamson 				 decode_sequence_maxsz + \
4241da177e4SLinus Torvalds 				 decode_putfh_maxsz + \
4259104a55dSTrond Myklebust 				 decode_setattr_maxsz + \
4269104a55dSTrond Myklebust 				 decode_getattr_maxsz)
4271da177e4SLinus Torvalds #define NFS4_enc_fsinfo_sz	(compound_encode_hdr_maxsz + \
4289b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
4291da177e4SLinus Torvalds 				encode_putfh_maxsz + \
4301da177e4SLinus Torvalds 				encode_fsinfo_maxsz)
4311da177e4SLinus Torvalds #define NFS4_dec_fsinfo_sz	(compound_decode_hdr_maxsz + \
4329b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
4331da177e4SLinus Torvalds 				decode_putfh_maxsz + \
4341da177e4SLinus Torvalds 				decode_fsinfo_maxsz)
4351da177e4SLinus Torvalds #define NFS4_enc_renew_sz	(compound_encode_hdr_maxsz + \
4361da177e4SLinus Torvalds 				encode_renew_maxsz)
4371da177e4SLinus Torvalds #define NFS4_dec_renew_sz	(compound_decode_hdr_maxsz + \
4381da177e4SLinus Torvalds 				decode_renew_maxsz)
4391da177e4SLinus Torvalds #define NFS4_enc_setclientid_sz	(compound_encode_hdr_maxsz + \
4401da177e4SLinus Torvalds 				encode_setclientid_maxsz)
4411da177e4SLinus Torvalds #define NFS4_dec_setclientid_sz	(compound_decode_hdr_maxsz + \
4421da177e4SLinus Torvalds 				decode_setclientid_maxsz)
4431da177e4SLinus Torvalds #define NFS4_enc_setclientid_confirm_sz \
4441da177e4SLinus Torvalds 				(compound_encode_hdr_maxsz + \
4451da177e4SLinus Torvalds 				encode_setclientid_confirm_maxsz + \
4461da177e4SLinus Torvalds 				encode_putrootfh_maxsz + \
4471da177e4SLinus Torvalds 				encode_fsinfo_maxsz)
4481da177e4SLinus Torvalds #define NFS4_dec_setclientid_confirm_sz \
4491da177e4SLinus Torvalds 				(compound_decode_hdr_maxsz + \
4501da177e4SLinus Torvalds 				decode_setclientid_confirm_maxsz + \
4511da177e4SLinus Torvalds 				decode_putrootfh_maxsz + \
4521da177e4SLinus Torvalds 				decode_fsinfo_maxsz)
4531da177e4SLinus Torvalds #define NFS4_enc_lock_sz        (compound_encode_hdr_maxsz + \
4549b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
4551da177e4SLinus Torvalds 				encode_putfh_maxsz + \
4569104a55dSTrond Myklebust 				encode_lock_maxsz)
4571da177e4SLinus Torvalds #define NFS4_dec_lock_sz        (compound_decode_hdr_maxsz + \
4589b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
4591da177e4SLinus Torvalds 				decode_putfh_maxsz + \
4609104a55dSTrond Myklebust 				decode_lock_maxsz)
4611da177e4SLinus Torvalds #define NFS4_enc_lockt_sz       (compound_encode_hdr_maxsz + \
4629b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
4631da177e4SLinus Torvalds 				encode_putfh_maxsz + \
4649104a55dSTrond Myklebust 				encode_lockt_maxsz)
4659104a55dSTrond Myklebust #define NFS4_dec_lockt_sz       (compound_decode_hdr_maxsz + \
4669b7b9fccSAndy Adamson 				 decode_sequence_maxsz + \
4679104a55dSTrond Myklebust 				 decode_putfh_maxsz + \
4689104a55dSTrond Myklebust 				 decode_lockt_maxsz)
4691da177e4SLinus Torvalds #define NFS4_enc_locku_sz       (compound_encode_hdr_maxsz + \
4709b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
4711da177e4SLinus Torvalds 				encode_putfh_maxsz + \
4729104a55dSTrond Myklebust 				encode_locku_maxsz)
4731da177e4SLinus Torvalds #define NFS4_dec_locku_sz       (compound_decode_hdr_maxsz + \
4749b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
4751da177e4SLinus Torvalds 				decode_putfh_maxsz + \
4769104a55dSTrond Myklebust 				decode_locku_maxsz)
4771da177e4SLinus Torvalds #define NFS4_enc_access_sz	(compound_encode_hdr_maxsz + \
4789b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
4791da177e4SLinus Torvalds 				encode_putfh_maxsz + \
48076b32999STrond Myklebust 				encode_access_maxsz + \
48176b32999STrond Myklebust 				encode_getattr_maxsz)
4821da177e4SLinus Torvalds #define NFS4_dec_access_sz	(compound_decode_hdr_maxsz + \
4839b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
4841da177e4SLinus Torvalds 				decode_putfh_maxsz + \
48576b32999STrond Myklebust 				decode_access_maxsz + \
48676b32999STrond Myklebust 				decode_getattr_maxsz)
4871da177e4SLinus Torvalds #define NFS4_enc_getattr_sz	(compound_encode_hdr_maxsz + \
4889b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
4891da177e4SLinus Torvalds 				encode_putfh_maxsz + \
4901da177e4SLinus Torvalds 				encode_getattr_maxsz)
4911da177e4SLinus Torvalds #define NFS4_dec_getattr_sz	(compound_decode_hdr_maxsz + \
4929b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
4931da177e4SLinus Torvalds 				decode_putfh_maxsz + \
4941da177e4SLinus Torvalds 				decode_getattr_maxsz)
4951da177e4SLinus Torvalds #define NFS4_enc_lookup_sz	(compound_encode_hdr_maxsz + \
4969b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
4971da177e4SLinus Torvalds 				encode_putfh_maxsz + \
4981da177e4SLinus Torvalds 				encode_lookup_maxsz + \
4991da177e4SLinus Torvalds 				encode_getattr_maxsz + \
5001da177e4SLinus Torvalds 				encode_getfh_maxsz)
5011da177e4SLinus Torvalds #define NFS4_dec_lookup_sz	(compound_decode_hdr_maxsz + \
5029b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
5031da177e4SLinus Torvalds 				decode_putfh_maxsz + \
504e6889620STrond Myklebust 				decode_lookup_maxsz + \
5051da177e4SLinus Torvalds 				decode_getattr_maxsz + \
5061da177e4SLinus Torvalds 				decode_getfh_maxsz)
5071da177e4SLinus Torvalds #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \
5089b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
5091da177e4SLinus Torvalds 				encode_putrootfh_maxsz + \
5101da177e4SLinus Torvalds 				encode_getattr_maxsz + \
5111da177e4SLinus Torvalds 				encode_getfh_maxsz)
5121da177e4SLinus Torvalds #define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \
5139b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
5141da177e4SLinus Torvalds 				decode_putrootfh_maxsz + \
5151da177e4SLinus Torvalds 				decode_getattr_maxsz + \
5161da177e4SLinus Torvalds 				decode_getfh_maxsz)
5171da177e4SLinus Torvalds #define NFS4_enc_remove_sz	(compound_encode_hdr_maxsz + \
5189b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
5191da177e4SLinus Torvalds 				encode_putfh_maxsz + \
52016e42959STrond Myklebust 				encode_remove_maxsz + \
52116e42959STrond Myklebust 				encode_getattr_maxsz)
5221da177e4SLinus Torvalds #define NFS4_dec_remove_sz	(compound_decode_hdr_maxsz + \
5239b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
5241da177e4SLinus Torvalds 				decode_putfh_maxsz + \
5256ce18391SBenny Halevy 				decode_remove_maxsz + \
52616e42959STrond Myklebust 				decode_getattr_maxsz)
5271da177e4SLinus Torvalds #define NFS4_enc_rename_sz	(compound_encode_hdr_maxsz + \
5289b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
5291da177e4SLinus Torvalds 				encode_putfh_maxsz + \
5301da177e4SLinus Torvalds 				encode_savefh_maxsz + \
5311da177e4SLinus Torvalds 				encode_putfh_maxsz + \
5326caf2c82STrond Myklebust 				encode_rename_maxsz + \
5336caf2c82STrond Myklebust 				encode_getattr_maxsz + \
5346caf2c82STrond Myklebust 				encode_restorefh_maxsz + \
5356caf2c82STrond Myklebust 				encode_getattr_maxsz)
5361da177e4SLinus Torvalds #define NFS4_dec_rename_sz	(compound_decode_hdr_maxsz + \
5379b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
5381da177e4SLinus Torvalds 				decode_putfh_maxsz + \
5391da177e4SLinus Torvalds 				decode_savefh_maxsz + \
5401da177e4SLinus Torvalds 				decode_putfh_maxsz + \
5416caf2c82STrond Myklebust 				decode_rename_maxsz + \
5426caf2c82STrond Myklebust 				decode_getattr_maxsz + \
5436caf2c82STrond Myklebust 				decode_restorefh_maxsz + \
5446caf2c82STrond Myklebust 				decode_getattr_maxsz)
5451da177e4SLinus Torvalds #define NFS4_enc_link_sz	(compound_encode_hdr_maxsz + \
5469b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
5471da177e4SLinus Torvalds 				encode_putfh_maxsz + \
5481da177e4SLinus Torvalds 				encode_savefh_maxsz + \
5491da177e4SLinus Torvalds 				encode_putfh_maxsz + \
55091ba2eeeSTrond Myklebust 				encode_link_maxsz + \
55191ba2eeeSTrond Myklebust 				decode_getattr_maxsz + \
55291ba2eeeSTrond Myklebust 				encode_restorefh_maxsz + \
55391ba2eeeSTrond Myklebust 				decode_getattr_maxsz)
5541da177e4SLinus Torvalds #define NFS4_dec_link_sz	(compound_decode_hdr_maxsz + \
5559b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
5561da177e4SLinus Torvalds 				decode_putfh_maxsz + \
5571da177e4SLinus Torvalds 				decode_savefh_maxsz + \
5581da177e4SLinus Torvalds 				decode_putfh_maxsz + \
55991ba2eeeSTrond Myklebust 				decode_link_maxsz + \
56091ba2eeeSTrond Myklebust 				decode_getattr_maxsz + \
56191ba2eeeSTrond Myklebust 				decode_restorefh_maxsz + \
56291ba2eeeSTrond Myklebust 				decode_getattr_maxsz)
5631da177e4SLinus Torvalds #define NFS4_enc_symlink_sz	(compound_encode_hdr_maxsz + \
5649b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
5651da177e4SLinus Torvalds 				encode_putfh_maxsz + \
5661da177e4SLinus Torvalds 				encode_symlink_maxsz + \
5671da177e4SLinus Torvalds 				encode_getattr_maxsz + \
5681da177e4SLinus Torvalds 				encode_getfh_maxsz)
5691da177e4SLinus Torvalds #define NFS4_dec_symlink_sz	(compound_decode_hdr_maxsz + \
5709b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
5711da177e4SLinus Torvalds 				decode_putfh_maxsz + \
5721da177e4SLinus Torvalds 				decode_symlink_maxsz + \
5731da177e4SLinus Torvalds 				decode_getattr_maxsz + \
5741da177e4SLinus Torvalds 				decode_getfh_maxsz)
5751da177e4SLinus Torvalds #define NFS4_enc_create_sz	(compound_encode_hdr_maxsz + \
5769b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
5771da177e4SLinus Torvalds 				encode_putfh_maxsz + \
57856ae19f3STrond Myklebust 				encode_savefh_maxsz + \
5791da177e4SLinus Torvalds 				encode_create_maxsz + \
58056ae19f3STrond Myklebust 				encode_getfh_maxsz + \
5811da177e4SLinus Torvalds 				encode_getattr_maxsz + \
58256ae19f3STrond Myklebust 				encode_restorefh_maxsz + \
58356ae19f3STrond Myklebust 				encode_getattr_maxsz)
5841da177e4SLinus Torvalds #define NFS4_dec_create_sz	(compound_decode_hdr_maxsz + \
5859b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
5861da177e4SLinus Torvalds 				decode_putfh_maxsz + \
58756ae19f3STrond Myklebust 				decode_savefh_maxsz + \
5881da177e4SLinus Torvalds 				decode_create_maxsz + \
58956ae19f3STrond Myklebust 				decode_getfh_maxsz + \
5901da177e4SLinus Torvalds 				decode_getattr_maxsz + \
59156ae19f3STrond Myklebust 				decode_restorefh_maxsz + \
59256ae19f3STrond Myklebust 				decode_getattr_maxsz)
5931da177e4SLinus Torvalds #define NFS4_enc_pathconf_sz	(compound_encode_hdr_maxsz + \
5949b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
5951da177e4SLinus Torvalds 				encode_putfh_maxsz + \
5961da177e4SLinus Torvalds 				encode_getattr_maxsz)
5971da177e4SLinus Torvalds #define NFS4_dec_pathconf_sz	(compound_decode_hdr_maxsz + \
5989b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
5991da177e4SLinus Torvalds 				decode_putfh_maxsz + \
6001da177e4SLinus Torvalds 				decode_getattr_maxsz)
6011da177e4SLinus Torvalds #define NFS4_enc_statfs_sz	(compound_encode_hdr_maxsz + \
6029b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
6031da177e4SLinus Torvalds 				encode_putfh_maxsz + \
6049104a55dSTrond Myklebust 				encode_statfs_maxsz)
6051da177e4SLinus Torvalds #define NFS4_dec_statfs_sz	(compound_decode_hdr_maxsz + \
6069b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
6071da177e4SLinus Torvalds 				decode_putfh_maxsz + \
6089104a55dSTrond Myklebust 				decode_statfs_maxsz)
6091da177e4SLinus Torvalds #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \
6109b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
611ab91f264STrond Myklebust 				encode_putfh_maxsz + \
6121da177e4SLinus Torvalds 				encode_getattr_maxsz)
6131da177e4SLinus Torvalds #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \
6149b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
615ab91f264STrond Myklebust 				decode_putfh_maxsz + \
6161da177e4SLinus Torvalds 				decode_getattr_maxsz)
6171da177e4SLinus Torvalds #define NFS4_enc_delegreturn_sz	(compound_encode_hdr_maxsz + \
6189b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
6191da177e4SLinus Torvalds 				encode_putfh_maxsz + \
620fa178f29STrond Myklebust 				encode_delegreturn_maxsz + \
621fa178f29STrond Myklebust 				encode_getattr_maxsz)
6221da177e4SLinus Torvalds #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
6239b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
624fa178f29STrond Myklebust 				decode_delegreturn_maxsz + \
625fa178f29STrond Myklebust 				decode_getattr_maxsz)
626029d105eSJ. Bruce Fields #define NFS4_enc_getacl_sz	(compound_encode_hdr_maxsz + \
6279b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
628029d105eSJ. Bruce Fields 				encode_putfh_maxsz + \
6299104a55dSTrond Myklebust 				encode_getacl_maxsz)
630029d105eSJ. Bruce Fields #define NFS4_dec_getacl_sz	(compound_decode_hdr_maxsz + \
6319b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
632029d105eSJ. Bruce Fields 				decode_putfh_maxsz + \
6339104a55dSTrond Myklebust 				decode_getacl_maxsz)
63423ec6965SJ. Bruce Fields #define NFS4_enc_setacl_sz	(compound_encode_hdr_maxsz + \
6359b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
63623ec6965SJ. Bruce Fields 				encode_putfh_maxsz + \
6379104a55dSTrond Myklebust 				encode_setacl_maxsz)
63823ec6965SJ. Bruce Fields #define NFS4_dec_setacl_sz	(compound_decode_hdr_maxsz + \
6399b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
64023ec6965SJ. Bruce Fields 				decode_putfh_maxsz + \
6419104a55dSTrond Myklebust 				decode_setacl_maxsz)
642683b57b4STrond Myklebust #define NFS4_enc_fs_locations_sz \
643683b57b4STrond Myklebust 				(compound_encode_hdr_maxsz + \
6449b7b9fccSAndy Adamson 				 encode_sequence_maxsz + \
645683b57b4STrond Myklebust 				 encode_putfh_maxsz + \
646e6889620STrond Myklebust 				 encode_lookup_maxsz + \
647e6889620STrond Myklebust 				 encode_fs_locations_maxsz)
648683b57b4STrond Myklebust #define NFS4_dec_fs_locations_sz \
649683b57b4STrond Myklebust 				(compound_decode_hdr_maxsz + \
6509b7b9fccSAndy Adamson 				 decode_sequence_maxsz + \
651683b57b4STrond Myklebust 				 decode_putfh_maxsz + \
652e6889620STrond Myklebust 				 decode_lookup_maxsz + \
653e6889620STrond Myklebust 				 decode_fs_locations_maxsz)
65499fe60d0SBenny Halevy #if defined(CONFIG_NFS_V4_1)
65599fe60d0SBenny Halevy #define NFS4_enc_exchange_id_sz \
65699fe60d0SBenny Halevy 				(compound_encode_hdr_maxsz + \
65799fe60d0SBenny Halevy 				 encode_exchange_id_maxsz)
65899fe60d0SBenny Halevy #define NFS4_dec_exchange_id_sz \
65999fe60d0SBenny Halevy 				(compound_decode_hdr_maxsz + \
66099fe60d0SBenny Halevy 				 decode_exchange_id_maxsz)
661fc931582SAndy Adamson #define NFS4_enc_create_session_sz \
662fc931582SAndy Adamson 				(compound_encode_hdr_maxsz + \
663fc931582SAndy Adamson 				 encode_create_session_maxsz)
664fc931582SAndy Adamson #define NFS4_dec_create_session_sz \
665fc931582SAndy Adamson 				(compound_decode_hdr_maxsz + \
666fc931582SAndy Adamson 				 decode_create_session_maxsz)
6670f3e66c6SAndy Adamson #define NFS4_enc_destroy_session_sz	(compound_encode_hdr_maxsz + \
6680f3e66c6SAndy Adamson 					 encode_destroy_session_maxsz)
6690f3e66c6SAndy Adamson #define NFS4_dec_destroy_session_sz	(compound_decode_hdr_maxsz + \
6700f3e66c6SAndy Adamson 					 decode_destroy_session_maxsz)
671fc01cea9SAndy Adamson #define NFS4_enc_sequence_sz \
672fc01cea9SAndy Adamson 				(compound_decode_hdr_maxsz + \
673fc01cea9SAndy Adamson 				 encode_sequence_maxsz)
674fc01cea9SAndy Adamson #define NFS4_dec_sequence_sz \
675fc01cea9SAndy Adamson 				(compound_decode_hdr_maxsz + \
676fc01cea9SAndy Adamson 				 decode_sequence_maxsz)
6772050f0ccSAndy Adamson #define NFS4_enc_get_lease_time_sz	(compound_encode_hdr_maxsz + \
6782050f0ccSAndy Adamson 					 encode_sequence_maxsz + \
6792050f0ccSAndy Adamson 					 encode_putrootfh_maxsz + \
6802050f0ccSAndy Adamson 					 encode_fsinfo_maxsz)
6812050f0ccSAndy Adamson #define NFS4_dec_get_lease_time_sz	(compound_decode_hdr_maxsz + \
6822050f0ccSAndy Adamson 					 decode_sequence_maxsz + \
6832050f0ccSAndy Adamson 					 decode_putrootfh_maxsz + \
6842050f0ccSAndy Adamson 					 decode_fsinfo_maxsz)
68518019753SRicardo Labiaga #define NFS4_enc_reclaim_complete_sz	(compound_encode_hdr_maxsz + \
68618019753SRicardo Labiaga 					 encode_sequence_maxsz + \
68718019753SRicardo Labiaga 					 encode_reclaim_complete_maxsz)
68818019753SRicardo Labiaga #define NFS4_dec_reclaim_complete_sz	(compound_decode_hdr_maxsz + \
68918019753SRicardo Labiaga 					 decode_sequence_maxsz + \
69018019753SRicardo Labiaga 					 decode_reclaim_complete_maxsz)
6912449ea2eSAlexandros Batsakis 
6922449ea2eSAlexandros Batsakis const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
6932449ea2eSAlexandros Batsakis 				      compound_encode_hdr_maxsz +
6942449ea2eSAlexandros Batsakis 				      encode_sequence_maxsz +
6952449ea2eSAlexandros Batsakis 				      encode_putfh_maxsz +
6962449ea2eSAlexandros Batsakis 				      encode_getattr_maxsz) *
6972449ea2eSAlexandros Batsakis 				     XDR_UNIT);
6982449ea2eSAlexandros Batsakis 
6992449ea2eSAlexandros Batsakis const u32 nfs41_maxread_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
7002449ea2eSAlexandros Batsakis 				     compound_decode_hdr_maxsz +
7012449ea2eSAlexandros Batsakis 				     decode_sequence_maxsz +
7022449ea2eSAlexandros Batsakis 				     decode_putfh_maxsz) *
7032449ea2eSAlexandros Batsakis 				    XDR_UNIT);
70499fe60d0SBenny Halevy #endif /* CONFIG_NFS_V4_1 */
7051da177e4SLinus Torvalds 
706bca79478STrond Myklebust static const umode_t nfs_type2fmt[] = {
707bca79478STrond Myklebust 	[NF4BAD] = 0,
708bca79478STrond Myklebust 	[NF4REG] = S_IFREG,
709bca79478STrond Myklebust 	[NF4DIR] = S_IFDIR,
710bca79478STrond Myklebust 	[NF4BLK] = S_IFBLK,
711bca79478STrond Myklebust 	[NF4CHR] = S_IFCHR,
712bca79478STrond Myklebust 	[NF4LNK] = S_IFLNK,
713bca79478STrond Myklebust 	[NF4SOCK] = S_IFSOCK,
714bca79478STrond Myklebust 	[NF4FIFO] = S_IFIFO,
715bca79478STrond Myklebust 	[NF4ATTRDIR] = 0,
716bca79478STrond Myklebust 	[NF4NAMEDATTR] = 0,
7171da177e4SLinus Torvalds };
7181da177e4SLinus Torvalds 
7191da177e4SLinus Torvalds struct compound_hdr {
7201da177e4SLinus Torvalds 	int32_t		status;
7211da177e4SLinus Torvalds 	uint32_t	nops;
722d017931cSAndy Adamson 	__be32 *	nops_p;
7231da177e4SLinus Torvalds 	uint32_t	taglen;
7241da177e4SLinus Torvalds 	char *		tag;
7250c4e8c18SBenny Halevy 	uint32_t	replen;		/* expected reply words */
72666cc0429SBenny Halevy 	u32		minorversion;
7271da177e4SLinus Torvalds };
7281da177e4SLinus Torvalds 
72913c65ce9SBenny Halevy static __be32 *reserve_space(struct xdr_stream *xdr, size_t nbytes)
73013c65ce9SBenny Halevy {
73113c65ce9SBenny Halevy 	__be32 *p = xdr_reserve_space(xdr, nbytes);
73213c65ce9SBenny Halevy 	BUG_ON(!p);
73313c65ce9SBenny Halevy 	return p;
73413c65ce9SBenny Halevy }
7351da177e4SLinus Torvalds 
7361da177e4SLinus Torvalds static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
7371da177e4SLinus Torvalds {
7388687b63aSAl Viro 	__be32 *p;
7391da177e4SLinus Torvalds 
7401da177e4SLinus Torvalds 	p = xdr_reserve_space(xdr, 4 + len);
7411da177e4SLinus Torvalds 	BUG_ON(p == NULL);
7421da177e4SLinus Torvalds 	xdr_encode_opaque(p, str, len);
7431da177e4SLinus Torvalds }
7441da177e4SLinus Torvalds 
7450c4e8c18SBenny Halevy static void encode_compound_hdr(struct xdr_stream *xdr,
7460c4e8c18SBenny Halevy 				struct rpc_rqst *req,
7470c4e8c18SBenny Halevy 				struct compound_hdr *hdr)
7481da177e4SLinus Torvalds {
7498687b63aSAl Viro 	__be32 *p;
7500c4e8c18SBenny Halevy 	struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
7510c4e8c18SBenny Halevy 
7520c4e8c18SBenny Halevy 	/* initialize running count of expected bytes in reply.
7530c4e8c18SBenny Halevy 	 * NOTE: the replied tag SHOULD be the same is the one sent,
7540c4e8c18SBenny Halevy 	 * but this is not required as a MUST for the server to do so. */
7550c4e8c18SBenny Halevy 	hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen;
7561da177e4SLinus Torvalds 
7571da177e4SLinus Torvalds 	dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
7581da177e4SLinus Torvalds 	BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
759811652bdSBenny Halevy 	p = reserve_space(xdr, 4 + hdr->taglen + 8);
760811652bdSBenny Halevy 	p = xdr_encode_opaque(p, hdr->tag, hdr->taglen);
761e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(hdr->minorversion);
762d017931cSAndy Adamson 	hdr->nops_p = p;
76334558513SBenny Halevy 	*p = cpu_to_be32(hdr->nops);
764d017931cSAndy Adamson }
765d017931cSAndy Adamson 
766d017931cSAndy Adamson static void encode_nops(struct compound_hdr *hdr)
767d017931cSAndy Adamson {
768fc931582SAndy Adamson 	BUG_ON(hdr->nops > NFS4_MAX_OPS);
769d017931cSAndy Adamson 	*hdr->nops_p = htonl(hdr->nops);
7701da177e4SLinus Torvalds }
7711da177e4SLinus Torvalds 
7721da177e4SLinus Torvalds static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
7731da177e4SLinus Torvalds {
7748687b63aSAl Viro 	__be32 *p;
7751da177e4SLinus Torvalds 
7761da177e4SLinus Torvalds 	p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
7771da177e4SLinus Torvalds 	BUG_ON(p == NULL);
7781da177e4SLinus Torvalds 	xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE);
7791da177e4SLinus Torvalds }
7801da177e4SLinus Torvalds 
781cf8cdbe5SAndy Adamson static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
7821da177e4SLinus Torvalds {
7831da177e4SLinus Torvalds 	char owner_name[IDMAP_NAMESZ];
7841da177e4SLinus Torvalds 	char owner_group[IDMAP_NAMESZ];
7851da177e4SLinus Torvalds 	int owner_namelen = 0;
7861da177e4SLinus Torvalds 	int owner_grouplen = 0;
7878687b63aSAl Viro 	__be32 *p;
7888687b63aSAl Viro 	__be32 *q;
7891da177e4SLinus Torvalds 	int len;
7901da177e4SLinus Torvalds 	uint32_t bmval0 = 0;
7911da177e4SLinus Torvalds 	uint32_t bmval1 = 0;
7921da177e4SLinus Torvalds 
7931da177e4SLinus Torvalds 	/*
7941da177e4SLinus Torvalds 	 * We reserve enough space to write the entire attribute buffer at once.
7951da177e4SLinus Torvalds 	 * In the worst-case, this would be
7961da177e4SLinus Torvalds 	 *   12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
7971da177e4SLinus Torvalds 	 *          = 36 bytes, plus any contribution from variable-length fields
79823ec6965SJ. Bruce Fields 	 *            such as owner/group.
7991da177e4SLinus Torvalds 	 */
8001da177e4SLinus Torvalds 	len = 16;
8011da177e4SLinus Torvalds 
8021da177e4SLinus Torvalds 	/* Sigh */
8031da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_SIZE)
8041da177e4SLinus Torvalds 		len += 8;
8051da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_MODE)
8061da177e4SLinus Torvalds 		len += 4;
8071da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_UID) {
8087539bbabSDavid Howells 		owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
8091da177e4SLinus Torvalds 		if (owner_namelen < 0) {
810fe82a183SChuck Lever 			dprintk("nfs: couldn't resolve uid %d to string\n",
8111da177e4SLinus Torvalds 					iap->ia_uid);
8121da177e4SLinus Torvalds 			/* XXX */
8131da177e4SLinus Torvalds 			strcpy(owner_name, "nobody");
8141da177e4SLinus Torvalds 			owner_namelen = sizeof("nobody") - 1;
8151da177e4SLinus Torvalds 			/* goto out; */
8161da177e4SLinus Torvalds 		}
8171da177e4SLinus Torvalds 		len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
8181da177e4SLinus Torvalds 	}
8191da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_GID) {
8207539bbabSDavid Howells 		owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group);
8211da177e4SLinus Torvalds 		if (owner_grouplen < 0) {
822fe82a183SChuck Lever 			dprintk("nfs: couldn't resolve gid %d to string\n",
8231da177e4SLinus Torvalds 					iap->ia_gid);
8241da177e4SLinus Torvalds 			strcpy(owner_group, "nobody");
8251da177e4SLinus Torvalds 			owner_grouplen = sizeof("nobody") - 1;
8261da177e4SLinus Torvalds 			/* goto out; */
8271da177e4SLinus Torvalds 		}
8281da177e4SLinus Torvalds 		len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
8291da177e4SLinus Torvalds 	}
8301da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_ATIME_SET)
8311da177e4SLinus Torvalds 		len += 16;
8321da177e4SLinus Torvalds 	else if (iap->ia_valid & ATTR_ATIME)
8331da177e4SLinus Torvalds 		len += 4;
8341da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_MTIME_SET)
8351da177e4SLinus Torvalds 		len += 16;
8361da177e4SLinus Torvalds 	else if (iap->ia_valid & ATTR_MTIME)
8371da177e4SLinus Torvalds 		len += 4;
83813c65ce9SBenny Halevy 	p = reserve_space(xdr, len);
8391da177e4SLinus Torvalds 
8401da177e4SLinus Torvalds 	/*
8411da177e4SLinus Torvalds 	 * We write the bitmap length now, but leave the bitmap and the attribute
8421da177e4SLinus Torvalds 	 * buffer length to be backfilled at the end of this routine.
8431da177e4SLinus Torvalds 	 */
844e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(2);
8451da177e4SLinus Torvalds 	q = p;
8461da177e4SLinus Torvalds 	p += 3;
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_SIZE) {
8491da177e4SLinus Torvalds 		bmval0 |= FATTR4_WORD0_SIZE;
850b95be5a9SBenny Halevy 		p = xdr_encode_hyper(p, iap->ia_size);
8511da177e4SLinus Torvalds 	}
8521da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_MODE) {
8531da177e4SLinus Torvalds 		bmval1 |= FATTR4_WORD1_MODE;
854e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO);
8551da177e4SLinus Torvalds 	}
8561da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_UID) {
8571da177e4SLinus Torvalds 		bmval1 |= FATTR4_WORD1_OWNER;
858811652bdSBenny Halevy 		p = xdr_encode_opaque(p, owner_name, owner_namelen);
8591da177e4SLinus Torvalds 	}
8601da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_GID) {
8611da177e4SLinus Torvalds 		bmval1 |= FATTR4_WORD1_OWNER_GROUP;
862811652bdSBenny Halevy 		p = xdr_encode_opaque(p, owner_group, owner_grouplen);
8631da177e4SLinus Torvalds 	}
8641da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_ATIME_SET) {
8651da177e4SLinus Torvalds 		bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
866e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
867e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(0);
868d3f6baaaSTrond Myklebust 		*p++ = cpu_to_be32(iap->ia_atime.tv_sec);
869d3f6baaaSTrond Myklebust 		*p++ = cpu_to_be32(iap->ia_atime.tv_nsec);
8701da177e4SLinus Torvalds 	}
8711da177e4SLinus Torvalds 	else if (iap->ia_valid & ATTR_ATIME) {
8721da177e4SLinus Torvalds 		bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
873e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
8741da177e4SLinus Torvalds 	}
8751da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_MTIME_SET) {
8761da177e4SLinus Torvalds 		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
877e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
878e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(0);
879e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(iap->ia_mtime.tv_sec);
880e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(iap->ia_mtime.tv_nsec);
8811da177e4SLinus Torvalds 	}
8821da177e4SLinus Torvalds 	else if (iap->ia_valid & ATTR_MTIME) {
8831da177e4SLinus Torvalds 		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
884e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
8851da177e4SLinus Torvalds 	}
8861da177e4SLinus Torvalds 
8871da177e4SLinus Torvalds 	/*
8881da177e4SLinus Torvalds 	 * Now we backfill the bitmap and the attribute buffer length.
8891da177e4SLinus Torvalds 	 */
8901da177e4SLinus Torvalds 	if (len != ((char *)p - (char *)q) + 4) {
891fe82a183SChuck Lever 		printk(KERN_ERR "nfs: Attr length error, %u != %Zu\n",
8921da177e4SLinus Torvalds 				len, ((char *)p - (char *)q) + 4);
8931da177e4SLinus Torvalds 		BUG();
8941da177e4SLinus Torvalds 	}
8951da177e4SLinus Torvalds 	len = (char *)p - (char *)q - 12;
8961da177e4SLinus Torvalds 	*q++ = htonl(bmval0);
8971da177e4SLinus Torvalds 	*q++ = htonl(bmval1);
89834558513SBenny Halevy 	*q = htonl(len);
8991da177e4SLinus Torvalds 
9001da177e4SLinus Torvalds /* out: */
9011da177e4SLinus Torvalds }
9021da177e4SLinus Torvalds 
903cf8cdbe5SAndy Adamson static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hdr *hdr)
9041da177e4SLinus Torvalds {
9058687b63aSAl Viro 	__be32 *p;
9061da177e4SLinus Torvalds 
90713c65ce9SBenny Halevy 	p = reserve_space(xdr, 8);
908e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_ACCESS);
90934558513SBenny Halevy 	*p = cpu_to_be32(access);
910d017931cSAndy Adamson 	hdr->nops++;
911dadf0c27SBenny Halevy 	hdr->replen += decode_access_maxsz;
9121da177e4SLinus Torvalds }
9131da177e4SLinus Torvalds 
914cf8cdbe5SAndy Adamson static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
9151da177e4SLinus Torvalds {
9168687b63aSAl Viro 	__be32 *p;
9171da177e4SLinus Torvalds 
91813c65ce9SBenny Halevy 	p = reserve_space(xdr, 8+NFS4_STATEID_SIZE);
919e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_CLOSE);
920e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(arg->seqid->sequence->counter);
92134558513SBenny Halevy 	xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
922d017931cSAndy Adamson 	hdr->nops++;
923dadf0c27SBenny Halevy 	hdr->replen += decode_close_maxsz;
9241da177e4SLinus Torvalds }
9251da177e4SLinus Torvalds 
926cf8cdbe5SAndy Adamson static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
9271da177e4SLinus Torvalds {
9288687b63aSAl Viro 	__be32 *p;
9291da177e4SLinus Torvalds 
93013c65ce9SBenny Halevy 	p = reserve_space(xdr, 16);
931e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_COMMIT);
932b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, args->offset);
93334558513SBenny Halevy 	*p = cpu_to_be32(args->count);
934d017931cSAndy Adamson 	hdr->nops++;
935dadf0c27SBenny Halevy 	hdr->replen += decode_commit_maxsz;
9361da177e4SLinus Torvalds }
9371da177e4SLinus Torvalds 
938cf8cdbe5SAndy Adamson static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr)
9391da177e4SLinus Torvalds {
9408687b63aSAl Viro 	__be32 *p;
9411da177e4SLinus Torvalds 
94213c65ce9SBenny Halevy 	p = reserve_space(xdr, 8);
943e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_CREATE);
94434558513SBenny Halevy 	*p = cpu_to_be32(create->ftype);
9451da177e4SLinus Torvalds 
9461da177e4SLinus Torvalds 	switch (create->ftype) {
9471da177e4SLinus Torvalds 	case NF4LNK:
94813c65ce9SBenny Halevy 		p = reserve_space(xdr, 4);
94934558513SBenny Halevy 		*p = cpu_to_be32(create->u.symlink.len);
95094a6d753SChuck Lever 		xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len);
9511da177e4SLinus Torvalds 		break;
9521da177e4SLinus Torvalds 
9531da177e4SLinus Torvalds 	case NF4BLK: case NF4CHR:
95413c65ce9SBenny Halevy 		p = reserve_space(xdr, 8);
955e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(create->u.device.specdata1);
95634558513SBenny Halevy 		*p = cpu_to_be32(create->u.device.specdata2);
9571da177e4SLinus Torvalds 		break;
9581da177e4SLinus Torvalds 
9591da177e4SLinus Torvalds 	default:
9601da177e4SLinus Torvalds 		break;
9611da177e4SLinus Torvalds 	}
9621da177e4SLinus Torvalds 
963811652bdSBenny Halevy 	encode_string(xdr, create->name->len, create->name->name);
964d017931cSAndy Adamson 	hdr->nops++;
965dadf0c27SBenny Halevy 	hdr->replen += decode_create_maxsz;
9661da177e4SLinus Torvalds 
967cf8cdbe5SAndy Adamson 	encode_attrs(xdr, create->attrs, create->server);
9681da177e4SLinus Torvalds }
9691da177e4SLinus Torvalds 
970cf8cdbe5SAndy Adamson static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr)
9711da177e4SLinus Torvalds {
9728687b63aSAl Viro 	__be32 *p;
9731da177e4SLinus Torvalds 
97413c65ce9SBenny Halevy 	p = reserve_space(xdr, 12);
975e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_GETATTR);
976e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(1);
97734558513SBenny Halevy 	*p = cpu_to_be32(bitmap);
978d017931cSAndy Adamson 	hdr->nops++;
979dadf0c27SBenny Halevy 	hdr->replen += decode_getattr_maxsz;
9801da177e4SLinus Torvalds }
9811da177e4SLinus Torvalds 
982cf8cdbe5SAndy Adamson static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr)
9831da177e4SLinus Torvalds {
9848687b63aSAl Viro 	__be32 *p;
9851da177e4SLinus Torvalds 
98613c65ce9SBenny Halevy 	p = reserve_space(xdr, 16);
987e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_GETATTR);
988e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(2);
989e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(bm0);
99034558513SBenny Halevy 	*p = cpu_to_be32(bm1);
991d017931cSAndy Adamson 	hdr->nops++;
992dadf0c27SBenny Halevy 	hdr->replen += decode_getattr_maxsz;
9931da177e4SLinus Torvalds }
9941da177e4SLinus Torvalds 
995cf8cdbe5SAndy Adamson static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
9961da177e4SLinus Torvalds {
997cf8cdbe5SAndy Adamson 	encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
998d017931cSAndy Adamson 			   bitmask[1] & nfs4_fattr_bitmap[1], hdr);
9991da177e4SLinus Torvalds }
10001da177e4SLinus Torvalds 
1001cf8cdbe5SAndy Adamson static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
10021da177e4SLinus Torvalds {
1003cf8cdbe5SAndy Adamson 	encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
1004d017931cSAndy Adamson 			   bitmask[1] & nfs4_fsinfo_bitmap[1], hdr);
10051da177e4SLinus Torvalds }
10061da177e4SLinus Torvalds 
1007cf8cdbe5SAndy Adamson static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
1008830b8e33SManoj Naik {
1009cf8cdbe5SAndy Adamson 	encode_getattr_two(xdr, bitmask[0] & nfs4_fs_locations_bitmap[0],
1010cf8cdbe5SAndy Adamson 			   bitmask[1] & nfs4_fs_locations_bitmap[1], hdr);
1011830b8e33SManoj Naik }
1012830b8e33SManoj Naik 
1013cf8cdbe5SAndy Adamson static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
10141da177e4SLinus Torvalds {
10158687b63aSAl Viro 	__be32 *p;
10161da177e4SLinus Torvalds 
101713c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
101834558513SBenny Halevy 	*p = cpu_to_be32(OP_GETFH);
1019d017931cSAndy Adamson 	hdr->nops++;
1020dadf0c27SBenny Halevy 	hdr->replen += decode_getfh_maxsz;
10211da177e4SLinus Torvalds }
10221da177e4SLinus Torvalds 
1023cf8cdbe5SAndy Adamson static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
10241da177e4SLinus Torvalds {
10258687b63aSAl Viro 	__be32 *p;
10261da177e4SLinus Torvalds 
102713c65ce9SBenny Halevy 	p = reserve_space(xdr, 8 + name->len);
1028e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_LINK);
1029811652bdSBenny Halevy 	xdr_encode_opaque(p, name->name, name->len);
1030d017931cSAndy Adamson 	hdr->nops++;
1031dadf0c27SBenny Halevy 	hdr->replen += decode_link_maxsz;
10321da177e4SLinus Torvalds }
10331da177e4SLinus Torvalds 
1034911d1aafSTrond Myklebust static inline int nfs4_lock_type(struct file_lock *fl, int block)
1035911d1aafSTrond Myklebust {
1036911d1aafSTrond Myklebust 	if ((fl->fl_type & (F_RDLCK|F_WRLCK|F_UNLCK)) == F_RDLCK)
1037911d1aafSTrond Myklebust 		return block ? NFS4_READW_LT : NFS4_READ_LT;
1038911d1aafSTrond Myklebust 	return block ? NFS4_WRITEW_LT : NFS4_WRITE_LT;
1039911d1aafSTrond Myklebust }
1040911d1aafSTrond Myklebust 
1041911d1aafSTrond Myklebust static inline uint64_t nfs4_lock_length(struct file_lock *fl)
1042911d1aafSTrond Myklebust {
1043911d1aafSTrond Myklebust 	if (fl->fl_end == OFFSET_MAX)
1044911d1aafSTrond Myklebust 		return ~(uint64_t)0;
1045911d1aafSTrond Myklebust 	return fl->fl_end - fl->fl_start + 1;
1046911d1aafSTrond Myklebust }
1047911d1aafSTrond Myklebust 
1048daccbdedSTrond Myklebust static void encode_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner)
1049daccbdedSTrond Myklebust {
1050daccbdedSTrond Myklebust 	__be32 *p;
1051daccbdedSTrond Myklebust 
1052daccbdedSTrond Myklebust 	p = reserve_space(xdr, 28);
1053daccbdedSTrond Myklebust 	p = xdr_encode_hyper(p, lowner->clientid);
1054daccbdedSTrond Myklebust 	*p++ = cpu_to_be32(16);
1055daccbdedSTrond Myklebust 	p = xdr_encode_opaque_fixed(p, "lock id:", 8);
1056daccbdedSTrond Myklebust 	xdr_encode_hyper(p, lowner->id);
1057daccbdedSTrond Myklebust }
1058daccbdedSTrond Myklebust 
10591da177e4SLinus Torvalds /*
10601da177e4SLinus Torvalds  * opcode,type,reclaim,offset,length,new_lock_owner = 32
10611da177e4SLinus Torvalds  * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
10621da177e4SLinus Torvalds  */
1063cf8cdbe5SAndy Adamson static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args, struct compound_hdr *hdr)
10641da177e4SLinus Torvalds {
10658687b63aSAl Viro 	__be32 *p;
10661da177e4SLinus Torvalds 
106713c65ce9SBenny Halevy 	p = reserve_space(xdr, 32);
1068e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_LOCK);
1069e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, args->block));
1070e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->reclaim);
1071b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, args->fl->fl_start);
1072b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
107334558513SBenny Halevy 	*p = cpu_to_be32(args->new_lock_owner);
1074911d1aafSTrond Myklebust 	if (args->new_lock_owner){
1075daccbdedSTrond Myklebust 		p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
1076e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(args->open_seqid->sequence->counter);
107793f0cf25SBenny Halevy 		p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE);
1078e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(args->lock_seqid->sequence->counter);
1079daccbdedSTrond Myklebust 		encode_lockowner(xdr, &args->lock_owner);
10801da177e4SLinus Torvalds 	}
10811da177e4SLinus Torvalds 	else {
108213c65ce9SBenny Halevy 		p = reserve_space(xdr, NFS4_STATEID_SIZE+4);
108393f0cf25SBenny Halevy 		p = xdr_encode_opaque_fixed(p, args->lock_stateid->data, NFS4_STATEID_SIZE);
108434558513SBenny Halevy 		*p = cpu_to_be32(args->lock_seqid->sequence->counter);
10851da177e4SLinus Torvalds 	}
1086d017931cSAndy Adamson 	hdr->nops++;
1087dadf0c27SBenny Halevy 	hdr->replen += decode_lock_maxsz;
10881da177e4SLinus Torvalds }
10891da177e4SLinus Torvalds 
1090cf8cdbe5SAndy Adamson static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr)
10911da177e4SLinus Torvalds {
10928687b63aSAl Viro 	__be32 *p;
10931da177e4SLinus Torvalds 
1094daccbdedSTrond Myklebust 	p = reserve_space(xdr, 24);
1095e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_LOCKT);
1096e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
1097b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, args->fl->fl_start);
1098b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
1099daccbdedSTrond Myklebust 	encode_lockowner(xdr, &args->lock_owner);
1100d017931cSAndy Adamson 	hdr->nops++;
1101dadf0c27SBenny Halevy 	hdr->replen += decode_lockt_maxsz;
11021da177e4SLinus Torvalds }
11031da177e4SLinus Torvalds 
1104cf8cdbe5SAndy Adamson static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr)
11051da177e4SLinus Torvalds {
11068687b63aSAl Viro 	__be32 *p;
11071da177e4SLinus Torvalds 
110813c65ce9SBenny Halevy 	p = reserve_space(xdr, 12+NFS4_STATEID_SIZE+16);
1109e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_LOCKU);
1110e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
1111e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->seqid->sequence->counter);
111293f0cf25SBenny Halevy 	p = xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
1113b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, args->fl->fl_start);
111434558513SBenny Halevy 	xdr_encode_hyper(p, nfs4_lock_length(args->fl));
1115d017931cSAndy Adamson 	hdr->nops++;
1116dadf0c27SBenny Halevy 	hdr->replen += decode_locku_maxsz;
11171da177e4SLinus Torvalds }
11181da177e4SLinus Torvalds 
1119cf8cdbe5SAndy Adamson static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
11201da177e4SLinus Torvalds {
11211da177e4SLinus Torvalds 	int len = name->len;
11228687b63aSAl Viro 	__be32 *p;
11231da177e4SLinus Torvalds 
112413c65ce9SBenny Halevy 	p = reserve_space(xdr, 8 + len);
1125e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_LOOKUP);
1126811652bdSBenny Halevy 	xdr_encode_opaque(p, name->name, len);
1127d017931cSAndy Adamson 	hdr->nops++;
1128dadf0c27SBenny Halevy 	hdr->replen += decode_lookup_maxsz;
11291da177e4SLinus Torvalds }
11301da177e4SLinus Torvalds 
1131dc0b027dSTrond Myklebust static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode)
11321da177e4SLinus Torvalds {
11338687b63aSAl Viro 	__be32 *p;
11341da177e4SLinus Torvalds 
113513c65ce9SBenny Halevy 	p = reserve_space(xdr, 8);
1136dc0b027dSTrond Myklebust 	switch (fmode & (FMODE_READ|FMODE_WRITE)) {
11371da177e4SLinus Torvalds 	case FMODE_READ:
1138e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_READ);
11391da177e4SLinus Torvalds 		break;
11401da177e4SLinus Torvalds 	case FMODE_WRITE:
1141e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_WRITE);
11421da177e4SLinus Torvalds 		break;
11431da177e4SLinus Torvalds 	case FMODE_READ|FMODE_WRITE:
1144e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_BOTH);
11451da177e4SLinus Torvalds 		break;
11461da177e4SLinus Torvalds 	default:
1147e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(0);
11481da177e4SLinus Torvalds 	}
114934558513SBenny Halevy 	*p = cpu_to_be32(0);		/* for linux, share_deny = 0 always */
11501da177e4SLinus Torvalds }
11511da177e4SLinus Torvalds 
11521da177e4SLinus Torvalds static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg)
11531da177e4SLinus Torvalds {
11548687b63aSAl Viro 	__be32 *p;
11551da177e4SLinus Torvalds  /*
11561da177e4SLinus Torvalds  * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
11571da177e4SLinus Torvalds  * owner 4 = 32
11581da177e4SLinus Torvalds  */
115913c65ce9SBenny Halevy 	p = reserve_space(xdr, 8);
1160e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_OPEN);
116134558513SBenny Halevy 	*p = cpu_to_be32(arg->seqid->sequence->counter);
1162dc0b027dSTrond Myklebust 	encode_share_access(xdr, arg->fmode);
116313c65ce9SBenny Halevy 	p = reserve_space(xdr, 28);
1164b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, arg->clientid);
1165e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(16);
116693f0cf25SBenny Halevy 	p = xdr_encode_opaque_fixed(p, "open id:", 8);
116734558513SBenny Halevy 	xdr_encode_hyper(p, arg->id);
11681da177e4SLinus Torvalds }
11691da177e4SLinus Torvalds 
11701da177e4SLinus Torvalds static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
11711da177e4SLinus Torvalds {
11728687b63aSAl Viro 	__be32 *p;
11734882ef72SAlexandros Batsakis 	struct nfs_client *clp;
11741da177e4SLinus Torvalds 
117513c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
11761da177e4SLinus Torvalds 	switch(arg->open_flags & O_EXCL) {
11771da177e4SLinus Torvalds 	case 0:
117834558513SBenny Halevy 		*p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
11791da177e4SLinus Torvalds 		encode_attrs(xdr, arg->u.attrs, arg->server);
11801da177e4SLinus Torvalds 		break;
11811da177e4SLinus Torvalds 	default:
11824882ef72SAlexandros Batsakis 		clp = arg->server->nfs_client;
1183a4432345STrond Myklebust 		if (clp->cl_mvops->minor_version > 0) {
11844882ef72SAlexandros Batsakis 			if (nfs4_has_persistent_session(clp)) {
11854882ef72SAlexandros Batsakis 				*p = cpu_to_be32(NFS4_CREATE_GUARDED);
11864882ef72SAlexandros Batsakis 				encode_attrs(xdr, arg->u.attrs, arg->server);
11874882ef72SAlexandros Batsakis 			} else {
11884882ef72SAlexandros Batsakis 				struct iattr dummy;
11894882ef72SAlexandros Batsakis 
11904882ef72SAlexandros Batsakis 				*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
11914882ef72SAlexandros Batsakis 				encode_nfs4_verifier(xdr, &arg->u.verifier);
11924882ef72SAlexandros Batsakis 				dummy.ia_valid = 0;
11934882ef72SAlexandros Batsakis 				encode_attrs(xdr, &dummy, arg->server);
11944882ef72SAlexandros Batsakis 			}
11954882ef72SAlexandros Batsakis 		} else {
119634558513SBenny Halevy 			*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
11971da177e4SLinus Torvalds 			encode_nfs4_verifier(xdr, &arg->u.verifier);
11981da177e4SLinus Torvalds 		}
11991da177e4SLinus Torvalds 	}
12004882ef72SAlexandros Batsakis }
12011da177e4SLinus Torvalds 
12021da177e4SLinus Torvalds static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *arg)
12031da177e4SLinus Torvalds {
12048687b63aSAl Viro 	__be32 *p;
12051da177e4SLinus Torvalds 
120613c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
12071da177e4SLinus Torvalds 	switch (arg->open_flags & O_CREAT) {
12081da177e4SLinus Torvalds 	case 0:
120934558513SBenny Halevy 		*p = cpu_to_be32(NFS4_OPEN_NOCREATE);
12101da177e4SLinus Torvalds 		break;
12111da177e4SLinus Torvalds 	default:
12121da177e4SLinus Torvalds 		BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL);
121334558513SBenny Halevy 		*p = cpu_to_be32(NFS4_OPEN_CREATE);
12141da177e4SLinus Torvalds 		encode_createmode(xdr, arg);
12151da177e4SLinus Torvalds 	}
12161da177e4SLinus Torvalds }
12171da177e4SLinus Torvalds 
1218bd7bf9d5STrond Myklebust static inline void encode_delegation_type(struct xdr_stream *xdr, fmode_t delegation_type)
12191da177e4SLinus Torvalds {
12208687b63aSAl Viro 	__be32 *p;
12211da177e4SLinus Torvalds 
122213c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
12231da177e4SLinus Torvalds 	switch (delegation_type) {
12241da177e4SLinus Torvalds 	case 0:
122534558513SBenny Halevy 		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_NONE);
12261da177e4SLinus Torvalds 		break;
12271da177e4SLinus Torvalds 	case FMODE_READ:
122834558513SBenny Halevy 		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_READ);
12291da177e4SLinus Torvalds 		break;
12301da177e4SLinus Torvalds 	case FMODE_WRITE|FMODE_READ:
123134558513SBenny Halevy 		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_WRITE);
12321da177e4SLinus Torvalds 		break;
12331da177e4SLinus Torvalds 	default:
12341da177e4SLinus Torvalds 		BUG();
12351da177e4SLinus Torvalds 	}
12361da177e4SLinus Torvalds }
12371da177e4SLinus Torvalds 
12381da177e4SLinus Torvalds static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr *name)
12391da177e4SLinus Torvalds {
12408687b63aSAl Viro 	__be32 *p;
12411da177e4SLinus Torvalds 
124213c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
124334558513SBenny Halevy 	*p = cpu_to_be32(NFS4_OPEN_CLAIM_NULL);
12441da177e4SLinus Torvalds 	encode_string(xdr, name->len, name->name);
12451da177e4SLinus Torvalds }
12461da177e4SLinus Torvalds 
1247bd7bf9d5STrond Myklebust static inline void encode_claim_previous(struct xdr_stream *xdr, fmode_t type)
12481da177e4SLinus Torvalds {
12498687b63aSAl Viro 	__be32 *p;
12501da177e4SLinus Torvalds 
125113c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
125234558513SBenny Halevy 	*p = cpu_to_be32(NFS4_OPEN_CLAIM_PREVIOUS);
12531da177e4SLinus Torvalds 	encode_delegation_type(xdr, type);
12541da177e4SLinus Torvalds }
12551da177e4SLinus Torvalds 
12561da177e4SLinus Torvalds static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struct qstr *name, const nfs4_stateid *stateid)
12571da177e4SLinus Torvalds {
12588687b63aSAl Viro 	__be32 *p;
12591da177e4SLinus Torvalds 
126013c65ce9SBenny Halevy 	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
1261e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
126234558513SBenny Halevy 	xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
12631da177e4SLinus Torvalds 	encode_string(xdr, name->len, name->name);
12641da177e4SLinus Torvalds }
12651da177e4SLinus Torvalds 
1266cf8cdbe5SAndy Adamson static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr)
12671da177e4SLinus Torvalds {
12681da177e4SLinus Torvalds 	encode_openhdr(xdr, arg);
12691da177e4SLinus Torvalds 	encode_opentype(xdr, arg);
12701da177e4SLinus Torvalds 	switch (arg->claim) {
12711da177e4SLinus Torvalds 	case NFS4_OPEN_CLAIM_NULL:
12721da177e4SLinus Torvalds 		encode_claim_null(xdr, arg->name);
12731da177e4SLinus Torvalds 		break;
12741da177e4SLinus Torvalds 	case NFS4_OPEN_CLAIM_PREVIOUS:
12751da177e4SLinus Torvalds 		encode_claim_previous(xdr, arg->u.delegation_type);
12761da177e4SLinus Torvalds 		break;
12771da177e4SLinus Torvalds 	case NFS4_OPEN_CLAIM_DELEGATE_CUR:
12781da177e4SLinus Torvalds 		encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation);
12791da177e4SLinus Torvalds 		break;
12801da177e4SLinus Torvalds 	default:
12811da177e4SLinus Torvalds 		BUG();
12821da177e4SLinus Torvalds 	}
1283d017931cSAndy Adamson 	hdr->nops++;
1284dadf0c27SBenny Halevy 	hdr->replen += decode_open_maxsz;
12851da177e4SLinus Torvalds }
12861da177e4SLinus Torvalds 
1287cf8cdbe5SAndy Adamson static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr)
12881da177e4SLinus Torvalds {
12898687b63aSAl Viro 	__be32 *p;
12901da177e4SLinus Torvalds 
129113c65ce9SBenny Halevy 	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
1292e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_OPEN_CONFIRM);
129393f0cf25SBenny Halevy 	p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
129434558513SBenny Halevy 	*p = cpu_to_be32(arg->seqid->sequence->counter);
1295d017931cSAndy Adamson 	hdr->nops++;
1296dadf0c27SBenny Halevy 	hdr->replen += decode_open_confirm_maxsz;
12971da177e4SLinus Torvalds }
12981da177e4SLinus Torvalds 
1299cf8cdbe5SAndy Adamson static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
13001da177e4SLinus Torvalds {
13018687b63aSAl Viro 	__be32 *p;
13021da177e4SLinus Torvalds 
130313c65ce9SBenny Halevy 	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
1304e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_OPEN_DOWNGRADE);
130593f0cf25SBenny Halevy 	p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
130634558513SBenny Halevy 	*p = cpu_to_be32(arg->seqid->sequence->counter);
1307dc0b027dSTrond Myklebust 	encode_share_access(xdr, arg->fmode);
1308d017931cSAndy Adamson 	hdr->nops++;
1309dadf0c27SBenny Halevy 	hdr->replen += decode_open_downgrade_maxsz;
13101da177e4SLinus Torvalds }
13111da177e4SLinus Torvalds 
1312cf8cdbe5SAndy Adamson static void
1313d017931cSAndy Adamson encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hdr *hdr)
13141da177e4SLinus Torvalds {
13151da177e4SLinus Torvalds 	int len = fh->size;
13168687b63aSAl Viro 	__be32 *p;
13171da177e4SLinus Torvalds 
131813c65ce9SBenny Halevy 	p = reserve_space(xdr, 8 + len);
1319e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_PUTFH);
1320811652bdSBenny Halevy 	xdr_encode_opaque(p, fh->data, len);
1321d017931cSAndy Adamson 	hdr->nops++;
1322dadf0c27SBenny Halevy 	hdr->replen += decode_putfh_maxsz;
13231da177e4SLinus Torvalds }
13241da177e4SLinus Torvalds 
1325cf8cdbe5SAndy Adamson static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
13261da177e4SLinus Torvalds {
13278687b63aSAl Viro 	__be32 *p;
13281da177e4SLinus Torvalds 
132913c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
133034558513SBenny Halevy 	*p = cpu_to_be32(OP_PUTROOTFH);
1331d017931cSAndy Adamson 	hdr->nops++;
1332dadf0c27SBenny Halevy 	hdr->replen += decode_putrootfh_maxsz;
13331da177e4SLinus Torvalds }
13341da177e4SLinus Torvalds 
1335f11ac8dbSTrond Myklebust static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx, const struct nfs_lock_context *l_ctx)
13361da177e4SLinus Torvalds {
13371da177e4SLinus Torvalds 	nfs4_stateid stateid;
13388687b63aSAl Viro 	__be32 *p;
13391da177e4SLinus Torvalds 
134013c65ce9SBenny Halevy 	p = reserve_space(xdr, NFS4_STATEID_SIZE);
13411da177e4SLinus Torvalds 	if (ctx->state != NULL) {
1342f11ac8dbSTrond Myklebust 		nfs4_copy_stateid(&stateid, ctx->state, l_ctx->lockowner);
134334558513SBenny Halevy 		xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE);
13441da177e4SLinus Torvalds 	} else
134534558513SBenny Halevy 		xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
13461da177e4SLinus Torvalds }
13471da177e4SLinus Torvalds 
1348cf8cdbe5SAndy Adamson static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr)
13491da177e4SLinus Torvalds {
13508687b63aSAl Viro 	__be32 *p;
13511da177e4SLinus Torvalds 
135213c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
135334558513SBenny Halevy 	*p = cpu_to_be32(OP_READ);
13541da177e4SLinus Torvalds 
1355f11ac8dbSTrond Myklebust 	encode_stateid(xdr, args->context, args->lock_context);
13561da177e4SLinus Torvalds 
135713c65ce9SBenny Halevy 	p = reserve_space(xdr, 12);
1358b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, args->offset);
135934558513SBenny Halevy 	*p = cpu_to_be32(args->count);
1360d017931cSAndy Adamson 	hdr->nops++;
1361dadf0c27SBenny Halevy 	hdr->replen += decode_read_maxsz;
13621da177e4SLinus Torvalds }
13631da177e4SLinus Torvalds 
1364cf8cdbe5SAndy Adamson static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
13651da177e4SLinus Torvalds {
136697d312d0SManoj Naik 	uint32_t attrs[2] = {
136797d312d0SManoj Naik 		FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID,
136897d312d0SManoj Naik 		FATTR4_WORD1_MOUNTED_ON_FILEID,
136997d312d0SManoj Naik 	};
13708687b63aSAl Viro 	__be32 *p;
13711da177e4SLinus Torvalds 
137213c65ce9SBenny Halevy 	p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
1373e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_READDIR);
1374b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, readdir->cookie);
137593f0cf25SBenny Halevy 	p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE);
1376e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(readdir->count >> 1);  /* We're not doing readdirplus */
1377e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(readdir->count);
1378e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(2);
137997d312d0SManoj Naik 	/* Switch to mounted_on_fileid if the server supports it */
138097d312d0SManoj Naik 	if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
138197d312d0SManoj Naik 		attrs[0] &= ~FATTR4_WORD0_FILEID;
138297d312d0SManoj Naik 	else
138397d312d0SManoj Naik 		attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
1384e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]);
138534558513SBenny Halevy 	*p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
1386d017931cSAndy Adamson 	hdr->nops++;
1387dadf0c27SBenny Halevy 	hdr->replen += decode_readdir_maxsz;
138844109241SFred Isaman 	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
138944109241SFred Isaman 			__func__,
1390eadf4598STrond Myklebust 			(unsigned long long)readdir->cookie,
1391eadf4598STrond Myklebust 			((u32 *)readdir->verifier.data)[0],
1392eadf4598STrond Myklebust 			((u32 *)readdir->verifier.data)[1],
1393eadf4598STrond Myklebust 			attrs[0] & readdir->bitmask[0],
1394eadf4598STrond Myklebust 			attrs[1] & readdir->bitmask[1]);
13951da177e4SLinus Torvalds }
13961da177e4SLinus Torvalds 
1397cf8cdbe5SAndy Adamson static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
13981da177e4SLinus Torvalds {
13998687b63aSAl Viro 	__be32 *p;
14001da177e4SLinus Torvalds 
140113c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
140234558513SBenny Halevy 	*p = cpu_to_be32(OP_READLINK);
1403d017931cSAndy Adamson 	hdr->nops++;
1404dadf0c27SBenny Halevy 	hdr->replen += decode_readlink_maxsz;
14051da177e4SLinus Torvalds }
14061da177e4SLinus Torvalds 
1407cf8cdbe5SAndy Adamson static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
14081da177e4SLinus Torvalds {
14098687b63aSAl Viro 	__be32 *p;
14101da177e4SLinus Torvalds 
141113c65ce9SBenny Halevy 	p = reserve_space(xdr, 8 + name->len);
1412e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_REMOVE);
1413811652bdSBenny Halevy 	xdr_encode_opaque(p, name->name, name->len);
1414d017931cSAndy Adamson 	hdr->nops++;
1415dadf0c27SBenny Halevy 	hdr->replen += decode_remove_maxsz;
14161da177e4SLinus Torvalds }
14171da177e4SLinus Torvalds 
1418cf8cdbe5SAndy Adamson static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr)
14191da177e4SLinus Torvalds {
14208687b63aSAl Viro 	__be32 *p;
14211da177e4SLinus Torvalds 
1422811652bdSBenny Halevy 	p = reserve_space(xdr, 4);
1423811652bdSBenny Halevy 	*p = cpu_to_be32(OP_RENAME);
1424811652bdSBenny Halevy 	encode_string(xdr, oldname->len, oldname->name);
1425811652bdSBenny Halevy 	encode_string(xdr, newname->len, newname->name);
1426d017931cSAndy Adamson 	hdr->nops++;
1427dadf0c27SBenny Halevy 	hdr->replen += decode_rename_maxsz;
14281da177e4SLinus Torvalds }
14291da177e4SLinus Torvalds 
1430cf8cdbe5SAndy Adamson static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr)
14311da177e4SLinus Torvalds {
14328687b63aSAl Viro 	__be32 *p;
14331da177e4SLinus Torvalds 
143413c65ce9SBenny Halevy 	p = reserve_space(xdr, 12);
1435e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_RENEW);
143634558513SBenny Halevy 	xdr_encode_hyper(p, client_stateid->cl_clientid);
1437d017931cSAndy Adamson 	hdr->nops++;
1438dadf0c27SBenny Halevy 	hdr->replen += decode_renew_maxsz;
14391da177e4SLinus Torvalds }
14401da177e4SLinus Torvalds 
1441cf8cdbe5SAndy Adamson static void
1442d017931cSAndy Adamson encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
144356ae19f3STrond Myklebust {
14448687b63aSAl Viro 	__be32 *p;
144556ae19f3STrond Myklebust 
144613c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
144734558513SBenny Halevy 	*p = cpu_to_be32(OP_RESTOREFH);
1448d017931cSAndy Adamson 	hdr->nops++;
1449dadf0c27SBenny Halevy 	hdr->replen += decode_restorefh_maxsz;
145056ae19f3STrond Myklebust }
145156ae19f3STrond Myklebust 
145256ae19f3STrond Myklebust static int
1453d017931cSAndy Adamson encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compound_hdr *hdr)
145423ec6965SJ. Bruce Fields {
14558687b63aSAl Viro 	__be32 *p;
145623ec6965SJ. Bruce Fields 
145713c65ce9SBenny Halevy 	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
1458e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_SETATTR);
145934558513SBenny Halevy 	xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
146013c65ce9SBenny Halevy 	p = reserve_space(xdr, 2*4);
1461e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(1);
146234558513SBenny Halevy 	*p = cpu_to_be32(FATTR4_WORD0_ACL);
146323ec6965SJ. Bruce Fields 	if (arg->acl_len % 4)
146423ec6965SJ. Bruce Fields 		return -EINVAL;
146513c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
146634558513SBenny Halevy 	*p = cpu_to_be32(arg->acl_len);
146723ec6965SJ. Bruce Fields 	xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
1468d017931cSAndy Adamson 	hdr->nops++;
1469dadf0c27SBenny Halevy 	hdr->replen += decode_setacl_maxsz;
147023ec6965SJ. Bruce Fields 	return 0;
147123ec6965SJ. Bruce Fields }
147223ec6965SJ. Bruce Fields 
1473cf8cdbe5SAndy Adamson static void
1474d017931cSAndy Adamson encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
14751da177e4SLinus Torvalds {
14768687b63aSAl Viro 	__be32 *p;
14771da177e4SLinus Torvalds 
147813c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
147934558513SBenny Halevy 	*p = cpu_to_be32(OP_SAVEFH);
1480d017931cSAndy Adamson 	hdr->nops++;
1481dadf0c27SBenny Halevy 	hdr->replen += decode_savefh_maxsz;
14821da177e4SLinus Torvalds }
14831da177e4SLinus Torvalds 
1484cf8cdbe5SAndy Adamson static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr)
14851da177e4SLinus Torvalds {
14868687b63aSAl Viro 	__be32 *p;
14871da177e4SLinus Torvalds 
148813c65ce9SBenny Halevy 	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
1489e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_SETATTR);
149034558513SBenny Halevy 	xdr_encode_opaque_fixed(p, arg->stateid.data, NFS4_STATEID_SIZE);
1491d017931cSAndy Adamson 	hdr->nops++;
1492dadf0c27SBenny Halevy 	hdr->replen += decode_setattr_maxsz;
1493cf8cdbe5SAndy Adamson 	encode_attrs(xdr, arg->iap, server);
14941da177e4SLinus Torvalds }
14951da177e4SLinus Torvalds 
1496cf8cdbe5SAndy Adamson static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)
14971da177e4SLinus Torvalds {
14988687b63aSAl Viro 	__be32 *p;
14991da177e4SLinus Torvalds 
150013c65ce9SBenny Halevy 	p = reserve_space(xdr, 4 + NFS4_VERIFIER_SIZE);
1501e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_SETCLIENTID);
150234558513SBenny Halevy 	xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE);
15031da177e4SLinus Torvalds 
15041da177e4SLinus Torvalds 	encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
150513c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
150634558513SBenny Halevy 	*p = cpu_to_be32(setclientid->sc_prog);
15071da177e4SLinus Torvalds 	encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid);
15081da177e4SLinus Torvalds 	encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
150913c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
151034558513SBenny Halevy 	*p = cpu_to_be32(setclientid->sc_cb_ident);
1511d017931cSAndy Adamson 	hdr->nops++;
1512dadf0c27SBenny Halevy 	hdr->replen += decode_setclientid_maxsz;
15131da177e4SLinus Torvalds }
15141da177e4SLinus Torvalds 
1515bb8b27e5STrond Myklebust static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_setclientid_res *arg, struct compound_hdr *hdr)
15161da177e4SLinus Torvalds {
15178687b63aSAl Viro 	__be32 *p;
15181da177e4SLinus Torvalds 
151913c65ce9SBenny Halevy 	p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE);
1520e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM);
1521bb8b27e5STrond Myklebust 	p = xdr_encode_hyper(p, arg->clientid);
1522bb8b27e5STrond Myklebust 	xdr_encode_opaque_fixed(p, arg->confirm.data, NFS4_VERIFIER_SIZE);
1523d017931cSAndy Adamson 	hdr->nops++;
1524dadf0c27SBenny Halevy 	hdr->replen += decode_setclientid_confirm_maxsz;
15251da177e4SLinus Torvalds }
15261da177e4SLinus Torvalds 
1527cf8cdbe5SAndy Adamson static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
15281da177e4SLinus Torvalds {
15298687b63aSAl Viro 	__be32 *p;
15301da177e4SLinus Torvalds 
153113c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
153234558513SBenny Halevy 	*p = cpu_to_be32(OP_WRITE);
15331da177e4SLinus Torvalds 
1534f11ac8dbSTrond Myklebust 	encode_stateid(xdr, args->context, args->lock_context);
15351da177e4SLinus Torvalds 
153613c65ce9SBenny Halevy 	p = reserve_space(xdr, 16);
1537b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, args->offset);
1538e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->stable);
153934558513SBenny Halevy 	*p = cpu_to_be32(args->count);
15401da177e4SLinus Torvalds 
15411da177e4SLinus Torvalds 	xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
1542d017931cSAndy Adamson 	hdr->nops++;
1543dadf0c27SBenny Halevy 	hdr->replen += decode_write_maxsz;
15441da177e4SLinus Torvalds }
15451da177e4SLinus Torvalds 
1546cf8cdbe5SAndy Adamson static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr)
15471da177e4SLinus Torvalds {
15488687b63aSAl Viro 	__be32 *p;
15491da177e4SLinus Torvalds 
155013c65ce9SBenny Halevy 	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
15511da177e4SLinus Torvalds 
1552e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_DELEGRETURN);
155334558513SBenny Halevy 	xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
1554d017931cSAndy Adamson 	hdr->nops++;
1555dadf0c27SBenny Halevy 	hdr->replen += decode_delegreturn_maxsz;
15561da177e4SLinus Torvalds }
15579b7b9fccSAndy Adamson 
155899fe60d0SBenny Halevy #if defined(CONFIG_NFS_V4_1)
15599b7b9fccSAndy Adamson /* NFSv4.1 operations */
156099fe60d0SBenny Halevy static void encode_exchange_id(struct xdr_stream *xdr,
156199fe60d0SBenny Halevy 			       struct nfs41_exchange_id_args *args,
156299fe60d0SBenny Halevy 			       struct compound_hdr *hdr)
156399fe60d0SBenny Halevy {
156499fe60d0SBenny Halevy 	__be32 *p;
156599fe60d0SBenny Halevy 
156613c65ce9SBenny Halevy 	p = reserve_space(xdr, 4 + sizeof(args->verifier->data));
1567e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_EXCHANGE_ID);
156834558513SBenny Halevy 	xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data));
156999fe60d0SBenny Halevy 
157099fe60d0SBenny Halevy 	encode_string(xdr, args->id_len, args->id);
157199fe60d0SBenny Halevy 
157213c65ce9SBenny Halevy 	p = reserve_space(xdr, 12);
1573e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->flags);
1574e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(0);	/* zero length state_protect4_a */
157534558513SBenny Halevy 	*p = cpu_to_be32(0);	/* zero length implementation id array */
157699fe60d0SBenny Halevy 	hdr->nops++;
157799fe60d0SBenny Halevy 	hdr->replen += decode_exchange_id_maxsz;
157899fe60d0SBenny Halevy }
1579fc931582SAndy Adamson 
1580fc931582SAndy Adamson static void encode_create_session(struct xdr_stream *xdr,
1581fc931582SAndy Adamson 				  struct nfs41_create_session_args *args,
1582fc931582SAndy Adamson 				  struct compound_hdr *hdr)
1583fc931582SAndy Adamson {
1584fc931582SAndy Adamson 	__be32 *p;
1585fc931582SAndy Adamson 	char machine_name[NFS4_MAX_MACHINE_NAME_LEN];
1586fc931582SAndy Adamson 	uint32_t len;
1587fc931582SAndy Adamson 	struct nfs_client *clp = args->client;
15888e0d46e1SMike Sager 	u32 max_resp_sz_cached;
15898e0d46e1SMike Sager 
15908e0d46e1SMike Sager 	/*
15918e0d46e1SMike Sager 	 * Assumes OPEN is the biggest non-idempotent compound.
15928e0d46e1SMike Sager 	 * 2 is the verifier.
15938e0d46e1SMike Sager 	 */
15948e0d46e1SMike Sager 	max_resp_sz_cached = (NFS4_dec_open_sz + RPC_REPHDRSIZE +
15958e0d46e1SMike Sager 			      RPC_MAX_AUTH_SIZE + 2) * XDR_UNIT;
1596fc931582SAndy Adamson 
1597fc931582SAndy Adamson 	len = scnprintf(machine_name, sizeof(machine_name), "%s",
1598fc931582SAndy Adamson 			clp->cl_ipaddr);
159942edd698SBenny Halevy 
160013c65ce9SBenny Halevy 	p = reserve_space(xdr, 20 + 2*28 + 20 + len + 12);
1601e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_CREATE_SESSION);
1602b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, clp->cl_ex_clid);
1603e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(clp->cl_seqid);			/*Sequence id */
1604e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->flags);			/*flags */
1605fc931582SAndy Adamson 
1606fc931582SAndy Adamson 	/* Fore Channel */
1607e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->fc_attrs.headerpadsz);	/* header padding size */
1608e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->fc_attrs.max_rqst_sz);	/* max req size */
1609e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->fc_attrs.max_resp_sz);	/* max resp size */
16108e0d46e1SMike Sager 	*p++ = cpu_to_be32(max_resp_sz_cached);		/* Max resp sz cached */
1611e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->fc_attrs.max_ops);	/* max operations */
1612e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->fc_attrs.max_reqs);	/* max requests */
1613e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(0);				/* rdmachannel_attrs */
1614fc931582SAndy Adamson 
1615fc931582SAndy Adamson 	/* Back Channel */
1616e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->fc_attrs.headerpadsz);	/* header padding size */
1617e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->bc_attrs.max_rqst_sz);	/* max req size */
1618e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->bc_attrs.max_resp_sz);	/* max resp size */
1619e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->bc_attrs.max_resp_sz_cached);	/* Max resp sz cached */
1620e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->bc_attrs.max_ops);	/* max operations */
1621e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->bc_attrs.max_reqs);	/* max requests */
1622e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(0);				/* rdmachannel_attrs */
1623fc931582SAndy Adamson 
1624e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->cb_program);		/* cb_program */
1625e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(1);
1626e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(RPC_AUTH_UNIX);			/* auth_sys */
1627fc931582SAndy Adamson 
1628fc931582SAndy Adamson 	/* authsys_parms rfc1831 */
1629e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32((u32)clp->cl_boot_time.tv_nsec);	/* stamp */
1630811652bdSBenny Halevy 	p = xdr_encode_opaque(p, machine_name, len);
1631e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(0);				/* UID */
1632e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(0);				/* GID */
163334558513SBenny Halevy 	*p = cpu_to_be32(0);				/* No more gids */
1634fc931582SAndy Adamson 	hdr->nops++;
1635fc931582SAndy Adamson 	hdr->replen += decode_create_session_maxsz;
1636fc931582SAndy Adamson }
16370f3e66c6SAndy Adamson 
16380f3e66c6SAndy Adamson static void encode_destroy_session(struct xdr_stream *xdr,
16390f3e66c6SAndy Adamson 				   struct nfs4_session *session,
16400f3e66c6SAndy Adamson 				   struct compound_hdr *hdr)
16410f3e66c6SAndy Adamson {
16420f3e66c6SAndy Adamson 	__be32 *p;
164313c65ce9SBenny Halevy 	p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN);
1644e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_DESTROY_SESSION);
164534558513SBenny Halevy 	xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
16460f3e66c6SAndy Adamson 	hdr->nops++;
16470f3e66c6SAndy Adamson 	hdr->replen += decode_destroy_session_maxsz;
16480f3e66c6SAndy Adamson }
164918019753SRicardo Labiaga 
165018019753SRicardo Labiaga static void encode_reclaim_complete(struct xdr_stream *xdr,
165118019753SRicardo Labiaga 				    struct nfs41_reclaim_complete_args *args,
165218019753SRicardo Labiaga 				    struct compound_hdr *hdr)
165318019753SRicardo Labiaga {
165418019753SRicardo Labiaga 	__be32 *p;
165518019753SRicardo Labiaga 
165618019753SRicardo Labiaga 	p = reserve_space(xdr, 8);
165718019753SRicardo Labiaga 	*p++ = cpu_to_be32(OP_RECLAIM_COMPLETE);
165818019753SRicardo Labiaga 	*p++ = cpu_to_be32(args->one_fs);
165918019753SRicardo Labiaga 	hdr->nops++;
166018019753SRicardo Labiaga 	hdr->replen += decode_reclaim_complete_maxsz;
166118019753SRicardo Labiaga }
166299fe60d0SBenny Halevy #endif /* CONFIG_NFS_V4_1 */
166399fe60d0SBenny Halevy 
16649b7b9fccSAndy Adamson static void encode_sequence(struct xdr_stream *xdr,
16659b7b9fccSAndy Adamson 			    const struct nfs4_sequence_args *args,
16669b7b9fccSAndy Adamson 			    struct compound_hdr *hdr)
16679b7b9fccSAndy Adamson {
16689b7b9fccSAndy Adamson #if defined(CONFIG_NFS_V4_1)
16699b7b9fccSAndy Adamson 	struct nfs4_session *session = args->sa_session;
1670fc01cea9SAndy Adamson 	struct nfs4_slot_table *tp;
1671fc01cea9SAndy Adamson 	struct nfs4_slot *slot;
1672fc01cea9SAndy Adamson 	__be32 *p;
16739b7b9fccSAndy Adamson 
16749b7b9fccSAndy Adamson 	if (!session)
16759b7b9fccSAndy Adamson 		return;
16769b7b9fccSAndy Adamson 
1677fc01cea9SAndy Adamson 	tp = &session->fc_slot_table;
1678fc01cea9SAndy Adamson 
1679fc01cea9SAndy Adamson 	WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE);
1680fc01cea9SAndy Adamson 	slot = tp->slots + args->sa_slotid;
1681fc01cea9SAndy Adamson 
168213c65ce9SBenny Halevy 	p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN + 16);
1683e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_SEQUENCE);
1684fc01cea9SAndy Adamson 
1685fc01cea9SAndy Adamson 	/*
1686fc01cea9SAndy Adamson 	 * Sessionid + seqid + slotid + max slotid + cache_this
1687fc01cea9SAndy Adamson 	 */
1688fc01cea9SAndy Adamson 	dprintk("%s: sessionid=%u:%u:%u:%u seqid=%d slotid=%d "
1689fc01cea9SAndy Adamson 		"max_slotid=%d cache_this=%d\n",
1690fc01cea9SAndy Adamson 		__func__,
1691fc01cea9SAndy Adamson 		((u32 *)session->sess_id.data)[0],
1692fc01cea9SAndy Adamson 		((u32 *)session->sess_id.data)[1],
1693fc01cea9SAndy Adamson 		((u32 *)session->sess_id.data)[2],
1694fc01cea9SAndy Adamson 		((u32 *)session->sess_id.data)[3],
1695fc01cea9SAndy Adamson 		slot->seq_nr, args->sa_slotid,
1696fc01cea9SAndy Adamson 		tp->highest_used_slotid, args->sa_cache_this);
169793f0cf25SBenny Halevy 	p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
1698e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(slot->seq_nr);
1699e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->sa_slotid);
1700e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(tp->highest_used_slotid);
170134558513SBenny Halevy 	*p = cpu_to_be32(args->sa_cache_this);
17029b7b9fccSAndy Adamson 	hdr->nops++;
17039b7b9fccSAndy Adamson 	hdr->replen += decode_sequence_maxsz;
17049b7b9fccSAndy Adamson #endif /* CONFIG_NFS_V4_1 */
17059b7b9fccSAndy Adamson }
17069b7b9fccSAndy Adamson 
17071da177e4SLinus Torvalds /*
17081da177e4SLinus Torvalds  * END OF "GENERIC" ENCODE ROUTINES.
17091da177e4SLinus Torvalds  */
17101da177e4SLinus Torvalds 
171166cc0429SBenny Halevy static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args)
171266cc0429SBenny Halevy {
171366cc0429SBenny Halevy #if defined(CONFIG_NFS_V4_1)
171466cc0429SBenny Halevy 	if (args->sa_session)
1715a4432345STrond Myklebust 		return args->sa_session->clp->cl_mvops->minor_version;
171666cc0429SBenny Halevy #endif /* CONFIG_NFS_V4_1 */
171766cc0429SBenny Halevy 	return 0;
171866cc0429SBenny Halevy }
171966cc0429SBenny Halevy 
17201da177e4SLinus Torvalds /*
17211da177e4SLinus Torvalds  * Encode an ACCESS request
17221da177e4SLinus Torvalds  */
17238687b63aSAl Viro static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs4_accessargs *args)
17241da177e4SLinus Torvalds {
17251da177e4SLinus Torvalds 	struct xdr_stream xdr;
17261da177e4SLinus Torvalds 	struct compound_hdr hdr = {
172766cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
17281da177e4SLinus Torvalds 	};
17291da177e4SLinus Torvalds 
17301da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
17310c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
17329b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1733cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1734cf8cdbe5SAndy Adamson 	encode_access(&xdr, args->access, &hdr);
1735cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1736d017931cSAndy Adamson 	encode_nops(&hdr);
1737cf8cdbe5SAndy Adamson 	return 0;
17381da177e4SLinus Torvalds }
17391da177e4SLinus Torvalds 
17401da177e4SLinus Torvalds /*
17411da177e4SLinus Torvalds  * Encode LOOKUP request
17421da177e4SLinus Torvalds  */
17438687b63aSAl Viro static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_arg *args)
17441da177e4SLinus Torvalds {
17451da177e4SLinus Torvalds 	struct xdr_stream xdr;
17461da177e4SLinus Torvalds 	struct compound_hdr hdr = {
174766cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
17481da177e4SLinus Torvalds 	};
17491da177e4SLinus Torvalds 
17501da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
17510c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
17529b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1753cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->dir_fh, &hdr);
1754cf8cdbe5SAndy Adamson 	encode_lookup(&xdr, args->name, &hdr);
1755cf8cdbe5SAndy Adamson 	encode_getfh(&xdr, &hdr);
1756cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1757d017931cSAndy Adamson 	encode_nops(&hdr);
1758cf8cdbe5SAndy Adamson 	return 0;
17591da177e4SLinus Torvalds }
17601da177e4SLinus Torvalds 
17611da177e4SLinus Torvalds /*
17621da177e4SLinus Torvalds  * Encode LOOKUP_ROOT request
17631da177e4SLinus Torvalds  */
17648687b63aSAl Viro static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_root_arg *args)
17651da177e4SLinus Torvalds {
17661da177e4SLinus Torvalds 	struct xdr_stream xdr;
17671da177e4SLinus Torvalds 	struct compound_hdr hdr = {
176866cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
17691da177e4SLinus Torvalds 	};
17701da177e4SLinus Torvalds 
17711da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
17720c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
17739b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1774cf8cdbe5SAndy Adamson 	encode_putrootfh(&xdr, &hdr);
1775cf8cdbe5SAndy Adamson 	encode_getfh(&xdr, &hdr);
1776cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1777d017931cSAndy Adamson 	encode_nops(&hdr);
1778cf8cdbe5SAndy Adamson 	return 0;
17791da177e4SLinus Torvalds }
17801da177e4SLinus Torvalds 
17811da177e4SLinus Torvalds /*
17821da177e4SLinus Torvalds  * Encode REMOVE request
17831da177e4SLinus Torvalds  */
17844fdc17b2STrond Myklebust static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
17851da177e4SLinus Torvalds {
17861da177e4SLinus Torvalds 	struct xdr_stream xdr;
17871da177e4SLinus Torvalds 	struct compound_hdr hdr = {
178866cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
17891da177e4SLinus Torvalds 	};
17901da177e4SLinus Torvalds 
17911da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
17920c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
17939b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1794cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1795cf8cdbe5SAndy Adamson 	encode_remove(&xdr, &args->name, &hdr);
1796cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1797d017931cSAndy Adamson 	encode_nops(&hdr);
1798cf8cdbe5SAndy Adamson 	return 0;
17991da177e4SLinus Torvalds }
18001da177e4SLinus Torvalds 
18011da177e4SLinus Torvalds /*
18021da177e4SLinus Torvalds  * Encode RENAME request
18031da177e4SLinus Torvalds  */
18048687b63aSAl Viro static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs4_rename_arg *args)
18051da177e4SLinus Torvalds {
18061da177e4SLinus Torvalds 	struct xdr_stream xdr;
18071da177e4SLinus Torvalds 	struct compound_hdr hdr = {
180866cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
18091da177e4SLinus Torvalds 	};
18101da177e4SLinus Torvalds 
18111da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
18120c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
18139b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1814cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->old_dir, &hdr);
1815cf8cdbe5SAndy Adamson 	encode_savefh(&xdr, &hdr);
1816cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->new_dir, &hdr);
1817cf8cdbe5SAndy Adamson 	encode_rename(&xdr, args->old_name, args->new_name, &hdr);
1818cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1819cf8cdbe5SAndy Adamson 	encode_restorefh(&xdr, &hdr);
1820cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1821d017931cSAndy Adamson 	encode_nops(&hdr);
1822cf8cdbe5SAndy Adamson 	return 0;
18231da177e4SLinus Torvalds }
18241da177e4SLinus Torvalds 
18251da177e4SLinus Torvalds /*
18261da177e4SLinus Torvalds  * Encode LINK request
18271da177e4SLinus Torvalds  */
18288687b63aSAl Viro static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_link_arg *args)
18291da177e4SLinus Torvalds {
18301da177e4SLinus Torvalds 	struct xdr_stream xdr;
18311da177e4SLinus Torvalds 	struct compound_hdr hdr = {
183266cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
18331da177e4SLinus Torvalds 	};
18341da177e4SLinus Torvalds 
18351da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
18360c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
18379b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1838cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1839cf8cdbe5SAndy Adamson 	encode_savefh(&xdr, &hdr);
1840cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->dir_fh, &hdr);
1841cf8cdbe5SAndy Adamson 	encode_link(&xdr, args->name, &hdr);
1842cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1843cf8cdbe5SAndy Adamson 	encode_restorefh(&xdr, &hdr);
1844cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1845d017931cSAndy Adamson 	encode_nops(&hdr);
1846cf8cdbe5SAndy Adamson 	return 0;
18471da177e4SLinus Torvalds }
18481da177e4SLinus Torvalds 
18491da177e4SLinus Torvalds /*
18501da177e4SLinus Torvalds  * Encode CREATE request
18511da177e4SLinus Torvalds  */
18528687b63aSAl Viro static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
18531da177e4SLinus Torvalds {
18541da177e4SLinus Torvalds 	struct xdr_stream xdr;
18551da177e4SLinus Torvalds 	struct compound_hdr hdr = {
185666cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
18571da177e4SLinus Torvalds 	};
18581da177e4SLinus Torvalds 
18591da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
18600c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
18619b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1862cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->dir_fh, &hdr);
1863cf8cdbe5SAndy Adamson 	encode_savefh(&xdr, &hdr);
1864cf8cdbe5SAndy Adamson 	encode_create(&xdr, args, &hdr);
1865cf8cdbe5SAndy Adamson 	encode_getfh(&xdr, &hdr);
1866cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1867cf8cdbe5SAndy Adamson 	encode_restorefh(&xdr, &hdr);
1868cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1869d017931cSAndy Adamson 	encode_nops(&hdr);
1870cf8cdbe5SAndy Adamson 	return 0;
18711da177e4SLinus Torvalds }
18721da177e4SLinus Torvalds 
18731da177e4SLinus Torvalds /*
18741da177e4SLinus Torvalds  * Encode SYMLINK request
18751da177e4SLinus Torvalds  */
18768687b63aSAl Viro static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
18771da177e4SLinus Torvalds {
18781da177e4SLinus Torvalds 	return nfs4_xdr_enc_create(req, p, args);
18791da177e4SLinus Torvalds }
18801da177e4SLinus Torvalds 
18811da177e4SLinus Torvalds /*
18821da177e4SLinus Torvalds  * Encode GETATTR request
18831da177e4SLinus Torvalds  */
18848687b63aSAl Viro static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nfs4_getattr_arg *args)
18851da177e4SLinus Torvalds {
18861da177e4SLinus Torvalds 	struct xdr_stream xdr;
18871da177e4SLinus Torvalds 	struct compound_hdr hdr = {
188866cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
18891da177e4SLinus Torvalds 	};
18901da177e4SLinus Torvalds 
18911da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
18920c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
18939b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1894cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1895cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1896d017931cSAndy Adamson 	encode_nops(&hdr);
1897cf8cdbe5SAndy Adamson 	return 0;
18981da177e4SLinus Torvalds }
18991da177e4SLinus Torvalds 
19001da177e4SLinus Torvalds /*
19011da177e4SLinus Torvalds  * Encode a CLOSE request
19021da177e4SLinus Torvalds  */
19038687b63aSAl Viro static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
19041da177e4SLinus Torvalds {
19051da177e4SLinus Torvalds 	struct xdr_stream xdr;
19061da177e4SLinus Torvalds 	struct compound_hdr hdr = {
190766cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
19081da177e4SLinus Torvalds 	};
19091da177e4SLinus Torvalds 
19101da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
19110c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
19129b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1913cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1914cf8cdbe5SAndy Adamson 	encode_close(&xdr, args, &hdr);
1915cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1916d017931cSAndy Adamson 	encode_nops(&hdr);
1917cf8cdbe5SAndy Adamson 	return 0;
19181da177e4SLinus Torvalds }
19191da177e4SLinus Torvalds 
19201da177e4SLinus Torvalds /*
19211da177e4SLinus Torvalds  * Encode an OPEN request
19221da177e4SLinus Torvalds  */
19238687b63aSAl Viro static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
19241da177e4SLinus Torvalds {
19251da177e4SLinus Torvalds 	struct xdr_stream xdr;
19261da177e4SLinus Torvalds 	struct compound_hdr hdr = {
192766cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
19281da177e4SLinus Torvalds 	};
19291da177e4SLinus Torvalds 
19301da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
19310c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
19329b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1933cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1934cf8cdbe5SAndy Adamson 	encode_savefh(&xdr, &hdr);
1935cf8cdbe5SAndy Adamson 	encode_open(&xdr, args, &hdr);
1936cf8cdbe5SAndy Adamson 	encode_getfh(&xdr, &hdr);
1937cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1938cf8cdbe5SAndy Adamson 	encode_restorefh(&xdr, &hdr);
1939cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1940d017931cSAndy Adamson 	encode_nops(&hdr);
1941cf8cdbe5SAndy Adamson 	return 0;
19421da177e4SLinus Torvalds }
19431da177e4SLinus Torvalds 
19441da177e4SLinus Torvalds /*
19451da177e4SLinus Torvalds  * Encode an OPEN_CONFIRM request
19461da177e4SLinus Torvalds  */
19478687b63aSAl Viro static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_open_confirmargs *args)
19481da177e4SLinus Torvalds {
19491da177e4SLinus Torvalds 	struct xdr_stream xdr;
19501da177e4SLinus Torvalds 	struct compound_hdr hdr = {
1951d017931cSAndy Adamson 		.nops   = 0,
19521da177e4SLinus Torvalds 	};
19531da177e4SLinus Torvalds 
19541da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
19550c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
1956cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1957cf8cdbe5SAndy Adamson 	encode_open_confirm(&xdr, args, &hdr);
1958d017931cSAndy Adamson 	encode_nops(&hdr);
1959cf8cdbe5SAndy Adamson 	return 0;
19601da177e4SLinus Torvalds }
19611da177e4SLinus Torvalds 
19621da177e4SLinus Torvalds /*
19631da177e4SLinus Torvalds  * Encode an OPEN request with no attributes.
19641da177e4SLinus Torvalds  */
19658687b63aSAl Viro static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
19661da177e4SLinus Torvalds {
19671da177e4SLinus Torvalds 	struct xdr_stream xdr;
19681da177e4SLinus Torvalds 	struct compound_hdr hdr = {
196966cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
19701da177e4SLinus Torvalds 	};
19711da177e4SLinus Torvalds 
19721da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
19730c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
19749b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1975cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1976cf8cdbe5SAndy Adamson 	encode_open(&xdr, args, &hdr);
1977cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1978d017931cSAndy Adamson 	encode_nops(&hdr);
1979cf8cdbe5SAndy Adamson 	return 0;
19801da177e4SLinus Torvalds }
19811da177e4SLinus Torvalds 
19821da177e4SLinus Torvalds /*
19831da177e4SLinus Torvalds  * Encode an OPEN_DOWNGRADE request
19841da177e4SLinus Torvalds  */
19858687b63aSAl Viro static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
19861da177e4SLinus Torvalds {
19871da177e4SLinus Torvalds 	struct xdr_stream xdr;
19881da177e4SLinus Torvalds 	struct compound_hdr hdr = {
198966cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
19901da177e4SLinus Torvalds 	};
19911da177e4SLinus Torvalds 
19921da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
19930c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
19949b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1995cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1996cf8cdbe5SAndy Adamson 	encode_open_downgrade(&xdr, args, &hdr);
1997cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1998d017931cSAndy Adamson 	encode_nops(&hdr);
1999cf8cdbe5SAndy Adamson 	return 0;
20001da177e4SLinus Torvalds }
20011da177e4SLinus Torvalds 
20021da177e4SLinus Torvalds /*
20031da177e4SLinus Torvalds  * Encode a LOCK request
20041da177e4SLinus Torvalds  */
20058687b63aSAl Viro static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_args *args)
20061da177e4SLinus Torvalds {
20071da177e4SLinus Torvalds 	struct xdr_stream xdr;
20081da177e4SLinus Torvalds 	struct compound_hdr hdr = {
200966cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
20101da177e4SLinus Torvalds 	};
20111da177e4SLinus Torvalds 
20121da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
20130c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
20149b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2015cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2016cf8cdbe5SAndy Adamson 	encode_lock(&xdr, args, &hdr);
2017d017931cSAndy Adamson 	encode_nops(&hdr);
2018cf8cdbe5SAndy Adamson 	return 0;
20191da177e4SLinus Torvalds }
20201da177e4SLinus Torvalds 
20211da177e4SLinus Torvalds /*
20221da177e4SLinus Torvalds  * Encode a LOCKT request
20231da177e4SLinus Torvalds  */
20248687b63aSAl Viro static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_args *args)
20251da177e4SLinus Torvalds {
20261da177e4SLinus Torvalds 	struct xdr_stream xdr;
20271da177e4SLinus Torvalds 	struct compound_hdr hdr = {
202866cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
20291da177e4SLinus Torvalds 	};
20301da177e4SLinus Torvalds 
20311da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
20320c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
20339b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2034cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2035cf8cdbe5SAndy Adamson 	encode_lockt(&xdr, args, &hdr);
2036d017931cSAndy Adamson 	encode_nops(&hdr);
2037cf8cdbe5SAndy Adamson 	return 0;
20381da177e4SLinus Torvalds }
20391da177e4SLinus Torvalds 
20401da177e4SLinus Torvalds /*
20411da177e4SLinus Torvalds  * Encode a LOCKU request
20421da177e4SLinus Torvalds  */
20438687b63aSAl Viro static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_args *args)
20441da177e4SLinus Torvalds {
20451da177e4SLinus Torvalds 	struct xdr_stream xdr;
20461da177e4SLinus Torvalds 	struct compound_hdr hdr = {
204766cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
20481da177e4SLinus Torvalds 	};
20491da177e4SLinus Torvalds 
20501da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
20510c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
20529b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2053cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2054cf8cdbe5SAndy Adamson 	encode_locku(&xdr, args, &hdr);
2055d017931cSAndy Adamson 	encode_nops(&hdr);
2056cf8cdbe5SAndy Adamson 	return 0;
20571da177e4SLinus Torvalds }
20581da177e4SLinus Torvalds 
20591da177e4SLinus Torvalds /*
20601da177e4SLinus Torvalds  * Encode a READLINK request
20611da177e4SLinus Torvalds  */
20628687b63aSAl Viro static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_readlink *args)
20631da177e4SLinus Torvalds {
20641da177e4SLinus Torvalds 	struct xdr_stream xdr;
20651da177e4SLinus Torvalds 	struct compound_hdr hdr = {
206666cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
20671da177e4SLinus Torvalds 	};
20681da177e4SLinus Torvalds 
20691da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
20700c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
20719b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2072cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2073cf8cdbe5SAndy Adamson 	encode_readlink(&xdr, args, req, &hdr);
2074e3a535e1STrond Myklebust 
207528f56694SBenny Halevy 	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
2076e3a535e1STrond Myklebust 			args->pgbase, args->pglen);
2077d017931cSAndy Adamson 	encode_nops(&hdr);
2078cf8cdbe5SAndy Adamson 	return 0;
20791da177e4SLinus Torvalds }
20801da177e4SLinus Torvalds 
20811da177e4SLinus Torvalds /*
20821da177e4SLinus Torvalds  * Encode a READDIR request
20831da177e4SLinus Torvalds  */
20848687b63aSAl Viro static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nfs4_readdir_arg *args)
20851da177e4SLinus Torvalds {
20861da177e4SLinus Torvalds 	struct xdr_stream xdr;
20871da177e4SLinus Torvalds 	struct compound_hdr hdr = {
208866cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
20891da177e4SLinus Torvalds 	};
20901da177e4SLinus Torvalds 
20911da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
20920c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
20939b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2094cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2095cf8cdbe5SAndy Adamson 	encode_readdir(&xdr, args, req, &hdr);
2096d6ac02dfSTrond Myklebust 
209728f56694SBenny Halevy 	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
2098d6ac02dfSTrond Myklebust 			 args->pgbase, args->count);
2099d6ac02dfSTrond Myklebust 	dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
210028f56694SBenny Halevy 			__func__, hdr.replen << 2, args->pages,
2101d6ac02dfSTrond Myklebust 			args->pgbase, args->count);
2102d017931cSAndy Adamson 	encode_nops(&hdr);
2103cf8cdbe5SAndy Adamson 	return 0;
21041da177e4SLinus Torvalds }
21051da177e4SLinus Torvalds 
21061da177e4SLinus Torvalds /*
21071da177e4SLinus Torvalds  * Encode a READ request
21081da177e4SLinus Torvalds  */
21098687b63aSAl Viro static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
21101da177e4SLinus Torvalds {
21111da177e4SLinus Torvalds 	struct xdr_stream xdr;
21121da177e4SLinus Torvalds 	struct compound_hdr hdr = {
211366cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
21141da177e4SLinus Torvalds 	};
21151da177e4SLinus Torvalds 
21161da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
21170c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
21189b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2119cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2120cf8cdbe5SAndy Adamson 	encode_read(&xdr, args, &hdr);
21211da177e4SLinus Torvalds 
212228f56694SBenny Halevy 	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2,
21231da177e4SLinus Torvalds 			 args->pages, args->pgbase, args->count);
21244f22ccc3S\"Talpey, Thomas\ 	req->rq_rcv_buf.flags |= XDRBUF_READ;
2125d017931cSAndy Adamson 	encode_nops(&hdr);
2126cf8cdbe5SAndy Adamson 	return 0;
21271da177e4SLinus Torvalds }
21281da177e4SLinus Torvalds 
21291da177e4SLinus Torvalds /*
21301da177e4SLinus Torvalds  * Encode an SETATTR request
21311da177e4SLinus Torvalds  */
21328687b63aSAl Viro static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args)
21331da177e4SLinus Torvalds {
21341da177e4SLinus Torvalds 	struct xdr_stream xdr;
21351da177e4SLinus Torvalds 	struct compound_hdr hdr = {
213666cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
21371da177e4SLinus Torvalds 	};
21381da177e4SLinus Torvalds 
21391da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
21400c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
21419b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2142cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2143cf8cdbe5SAndy Adamson 	encode_setattr(&xdr, args, args->server, &hdr);
2144cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
2145d017931cSAndy Adamson 	encode_nops(&hdr);
2146cf8cdbe5SAndy Adamson 	return 0;
21471da177e4SLinus Torvalds }
21481da177e4SLinus Torvalds 
21491da177e4SLinus Torvalds /*
2150029d105eSJ. Bruce Fields  * Encode a GETACL request
2151029d105eSJ. Bruce Fields  */
2152029d105eSJ. Bruce Fields static int
21538687b63aSAl Viro nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
2154029d105eSJ. Bruce Fields 		struct nfs_getaclargs *args)
2155029d105eSJ. Bruce Fields {
2156029d105eSJ. Bruce Fields 	struct xdr_stream xdr;
2157029d105eSJ. Bruce Fields 	struct compound_hdr hdr = {
215866cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
2159029d105eSJ. Bruce Fields 	};
216028f56694SBenny Halevy 	uint32_t replen;
2161029d105eSJ. Bruce Fields 
2162029d105eSJ. Bruce Fields 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
21630c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
21649b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2165cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2166d327cf74SJ. Bruce Fields 	replen = hdr.replen + op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz + 1;
2167cf8cdbe5SAndy Adamson 	encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr);
2168cf8cdbe5SAndy Adamson 
216928f56694SBenny Halevy 	xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
2170029d105eSJ. Bruce Fields 		args->acl_pages, args->acl_pgbase, args->acl_len);
2171d017931cSAndy Adamson 	encode_nops(&hdr);
2172cf8cdbe5SAndy Adamson 	return 0;
2173029d105eSJ. Bruce Fields }
2174029d105eSJ. Bruce Fields 
2175029d105eSJ. Bruce Fields /*
21761da177e4SLinus Torvalds  * Encode a WRITE request
21771da177e4SLinus Torvalds  */
21788687b63aSAl Viro static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
21791da177e4SLinus Torvalds {
21801da177e4SLinus Torvalds 	struct xdr_stream xdr;
21811da177e4SLinus Torvalds 	struct compound_hdr hdr = {
218266cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
21831da177e4SLinus Torvalds 	};
21841da177e4SLinus Torvalds 
21851da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
21860c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
21879b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2188cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2189cf8cdbe5SAndy Adamson 	encode_write(&xdr, args, &hdr);
21904f22ccc3S\"Talpey, Thomas\ 	req->rq_snd_buf.flags |= XDRBUF_WRITE;
2191cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
2192d017931cSAndy Adamson 	encode_nops(&hdr);
2193cf8cdbe5SAndy Adamson 	return 0;
21941da177e4SLinus Torvalds }
21951da177e4SLinus Torvalds 
21961da177e4SLinus Torvalds /*
21971da177e4SLinus Torvalds  *  a COMMIT request
21981da177e4SLinus Torvalds  */
21998687b63aSAl Viro static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
22001da177e4SLinus Torvalds {
22011da177e4SLinus Torvalds 	struct xdr_stream xdr;
22021da177e4SLinus Torvalds 	struct compound_hdr hdr = {
220366cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
22041da177e4SLinus Torvalds 	};
22051da177e4SLinus Torvalds 
22061da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
22070c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
22089b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2209cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2210cf8cdbe5SAndy Adamson 	encode_commit(&xdr, args, &hdr);
2211cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
2212d017931cSAndy Adamson 	encode_nops(&hdr);
2213cf8cdbe5SAndy Adamson 	return 0;
22141da177e4SLinus Torvalds }
22151da177e4SLinus Torvalds 
22161da177e4SLinus Torvalds /*
22171da177e4SLinus Torvalds  * FSINFO request
22181da177e4SLinus Torvalds  */
22198687b63aSAl Viro static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsinfo_arg *args)
22201da177e4SLinus Torvalds {
22211da177e4SLinus Torvalds 	struct xdr_stream xdr;
22221da177e4SLinus Torvalds 	struct compound_hdr hdr = {
222366cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
22241da177e4SLinus Torvalds 	};
22251da177e4SLinus Torvalds 
22261da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
22270c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
22289b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2229cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2230cf8cdbe5SAndy Adamson 	encode_fsinfo(&xdr, args->bitmask, &hdr);
2231d017931cSAndy Adamson 	encode_nops(&hdr);
2232cf8cdbe5SAndy Adamson 	return 0;
22331da177e4SLinus Torvalds }
22341da177e4SLinus Torvalds 
22351da177e4SLinus Torvalds /*
22361da177e4SLinus Torvalds  * a PATHCONF request
22371da177e4SLinus Torvalds  */
22388687b63aSAl Viro static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct nfs4_pathconf_arg *args)
22391da177e4SLinus Torvalds {
22401da177e4SLinus Torvalds 	struct xdr_stream xdr;
22411da177e4SLinus Torvalds 	struct compound_hdr hdr = {
224266cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
22431da177e4SLinus Torvalds 	};
22441da177e4SLinus Torvalds 
22451da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
22460c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
22479b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2248cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2249cf8cdbe5SAndy Adamson 	encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0],
2250d017931cSAndy Adamson 			   &hdr);
2251d017931cSAndy Adamson 	encode_nops(&hdr);
2252cf8cdbe5SAndy Adamson 	return 0;
22531da177e4SLinus Torvalds }
22541da177e4SLinus Torvalds 
22551da177e4SLinus Torvalds /*
22561da177e4SLinus Torvalds  * a STATFS request
22571da177e4SLinus Torvalds  */
22588687b63aSAl Viro static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs4_statfs_arg *args)
22591da177e4SLinus Torvalds {
22601da177e4SLinus Torvalds 	struct xdr_stream xdr;
22611da177e4SLinus Torvalds 	struct compound_hdr hdr = {
226266cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
22631da177e4SLinus Torvalds 	};
22641da177e4SLinus Torvalds 
22651da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
22660c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
22679b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2268cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2269cf8cdbe5SAndy Adamson 	encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0],
2270d017931cSAndy Adamson 			   args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr);
2271d017931cSAndy Adamson 	encode_nops(&hdr);
2272cf8cdbe5SAndy Adamson 	return 0;
22731da177e4SLinus Torvalds }
22741da177e4SLinus Torvalds 
22751da177e4SLinus Torvalds /*
22761da177e4SLinus Torvalds  * GETATTR_BITMAP request
22771da177e4SLinus Torvalds  */
227843652ad5SBenny Halevy static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p,
227943652ad5SBenny Halevy 				    struct nfs4_server_caps_arg *args)
22801da177e4SLinus Torvalds {
22811da177e4SLinus Torvalds 	struct xdr_stream xdr;
22821da177e4SLinus Torvalds 	struct compound_hdr hdr = {
228366cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
22841da177e4SLinus Torvalds 	};
22851da177e4SLinus Torvalds 
22861da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
22870c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
22889b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
228943652ad5SBenny Halevy 	encode_putfh(&xdr, args->fhandle, &hdr);
2290cf8cdbe5SAndy Adamson 	encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
22911da177e4SLinus Torvalds 			   FATTR4_WORD0_LINK_SUPPORT|
22921da177e4SLinus Torvalds 			   FATTR4_WORD0_SYMLINK_SUPPORT|
2293d017931cSAndy Adamson 			   FATTR4_WORD0_ACLSUPPORT, &hdr);
2294d017931cSAndy Adamson 	encode_nops(&hdr);
2295cf8cdbe5SAndy Adamson 	return 0;
22961da177e4SLinus Torvalds }
22971da177e4SLinus Torvalds 
22981da177e4SLinus Torvalds /*
22991da177e4SLinus Torvalds  * a RENEW request
23001da177e4SLinus Torvalds  */
23018687b63aSAl Viro static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
23021da177e4SLinus Torvalds {
23031da177e4SLinus Torvalds 	struct xdr_stream xdr;
23041da177e4SLinus Torvalds 	struct compound_hdr hdr = {
2305d017931cSAndy Adamson 		.nops	= 0,
23061da177e4SLinus Torvalds 	};
23071da177e4SLinus Torvalds 
23081da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
23090c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
2310cf8cdbe5SAndy Adamson 	encode_renew(&xdr, clp, &hdr);
2311d017931cSAndy Adamson 	encode_nops(&hdr);
2312cf8cdbe5SAndy Adamson 	return 0;
23131da177e4SLinus Torvalds }
23141da177e4SLinus Torvalds 
23151da177e4SLinus Torvalds /*
23161da177e4SLinus Torvalds  * a SETCLIENTID request
23171da177e4SLinus Torvalds  */
23188687b63aSAl Viro static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid *sc)
23191da177e4SLinus Torvalds {
23201da177e4SLinus Torvalds 	struct xdr_stream xdr;
23211da177e4SLinus Torvalds 	struct compound_hdr hdr = {
2322d017931cSAndy Adamson 		.nops	= 0,
23231da177e4SLinus Torvalds 	};
23241da177e4SLinus Torvalds 
23251da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
23260c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
2327cf8cdbe5SAndy Adamson 	encode_setclientid(&xdr, sc, &hdr);
2328d017931cSAndy Adamson 	encode_nops(&hdr);
2329cf8cdbe5SAndy Adamson 	return 0;
23301da177e4SLinus Torvalds }
23311da177e4SLinus Torvalds 
23321da177e4SLinus Torvalds /*
23331da177e4SLinus Torvalds  * a SETCLIENTID_CONFIRM request
23341da177e4SLinus Torvalds  */
2335bb8b27e5STrond Myklebust static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid_res *arg)
23361da177e4SLinus Torvalds {
23371da177e4SLinus Torvalds 	struct xdr_stream xdr;
23381da177e4SLinus Torvalds 	struct compound_hdr hdr = {
2339d017931cSAndy Adamson 		.nops	= 0,
23401da177e4SLinus Torvalds 	};
23411da177e4SLinus Torvalds 	const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
23421da177e4SLinus Torvalds 
23431da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
23440c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
2345bb8b27e5STrond Myklebust 	encode_setclientid_confirm(&xdr, arg, &hdr);
2346cf8cdbe5SAndy Adamson 	encode_putrootfh(&xdr, &hdr);
2347cf8cdbe5SAndy Adamson 	encode_fsinfo(&xdr, lease_bitmap, &hdr);
2348d017931cSAndy Adamson 	encode_nops(&hdr);
2349cf8cdbe5SAndy Adamson 	return 0;
23501da177e4SLinus Torvalds }
23511da177e4SLinus Torvalds 
23521da177e4SLinus Torvalds /*
23531da177e4SLinus Torvalds  * DELEGRETURN request
23541da177e4SLinus Torvalds  */
23558687b63aSAl Viro static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struct nfs4_delegreturnargs *args)
23561da177e4SLinus Torvalds {
23571da177e4SLinus Torvalds 	struct xdr_stream xdr;
23581da177e4SLinus Torvalds 	struct compound_hdr hdr = {
235966cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
23601da177e4SLinus Torvalds 	};
23611da177e4SLinus Torvalds 
23621da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
23630c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
23649b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2365cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fhandle, &hdr);
2366cf8cdbe5SAndy Adamson 	encode_delegreturn(&xdr, args->stateid, &hdr);
2367cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
2368d017931cSAndy Adamson 	encode_nops(&hdr);
2369cf8cdbe5SAndy Adamson 	return 0;
23701da177e4SLinus Torvalds }
23711da177e4SLinus Torvalds 
23721da177e4SLinus Torvalds /*
2373683b57b4STrond Myklebust  * Encode FS_LOCATIONS request
2374683b57b4STrond Myklebust  */
23758687b63aSAl Viro static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations_arg *args)
2376683b57b4STrond Myklebust {
2377683b57b4STrond Myklebust 	struct xdr_stream xdr;
2378683b57b4STrond Myklebust 	struct compound_hdr hdr = {
237966cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
2380683b57b4STrond Myklebust 	};
238128f56694SBenny Halevy 	uint32_t replen;
2382683b57b4STrond Myklebust 
2383683b57b4STrond Myklebust 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
23840c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
23859b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2386cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->dir_fh, &hdr);
2387cf8cdbe5SAndy Adamson 	encode_lookup(&xdr, args->name, &hdr);
238828f56694SBenny Halevy 	replen = hdr.replen;	/* get the attribute into args->page */
2389cf8cdbe5SAndy Adamson 	encode_fs_locations(&xdr, args->bitmask, &hdr);
2390cf8cdbe5SAndy Adamson 
239128f56694SBenny Halevy 	xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page,
2392683b57b4STrond Myklebust 			0, PAGE_SIZE);
2393d017931cSAndy Adamson 	encode_nops(&hdr);
2394cf8cdbe5SAndy Adamson 	return 0;
2395683b57b4STrond Myklebust }
2396683b57b4STrond Myklebust 
239799fe60d0SBenny Halevy #if defined(CONFIG_NFS_V4_1)
239899fe60d0SBenny Halevy /*
239999fe60d0SBenny Halevy  * EXCHANGE_ID request
240099fe60d0SBenny Halevy  */
240199fe60d0SBenny Halevy static int nfs4_xdr_enc_exchange_id(struct rpc_rqst *req, uint32_t *p,
240299fe60d0SBenny Halevy 				    struct nfs41_exchange_id_args *args)
240399fe60d0SBenny Halevy {
240499fe60d0SBenny Halevy 	struct xdr_stream xdr;
240599fe60d0SBenny Halevy 	struct compound_hdr hdr = {
2406a4432345STrond Myklebust 		.minorversion = args->client->cl_mvops->minor_version,
240799fe60d0SBenny Halevy 	};
240899fe60d0SBenny Halevy 
240999fe60d0SBenny Halevy 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
241099fe60d0SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
241199fe60d0SBenny Halevy 	encode_exchange_id(&xdr, args, &hdr);
241299fe60d0SBenny Halevy 	encode_nops(&hdr);
241399fe60d0SBenny Halevy 	return 0;
241499fe60d0SBenny Halevy }
24152050f0ccSAndy Adamson 
24162050f0ccSAndy Adamson /*
2417fc931582SAndy Adamson  * a CREATE_SESSION request
2418fc931582SAndy Adamson  */
2419fc931582SAndy Adamson static int nfs4_xdr_enc_create_session(struct rpc_rqst *req, uint32_t *p,
2420fc931582SAndy Adamson 				       struct nfs41_create_session_args *args)
2421fc931582SAndy Adamson {
2422fc931582SAndy Adamson 	struct xdr_stream xdr;
2423fc931582SAndy Adamson 	struct compound_hdr hdr = {
2424a4432345STrond Myklebust 		.minorversion = args->client->cl_mvops->minor_version,
2425fc931582SAndy Adamson 	};
2426fc931582SAndy Adamson 
2427fc931582SAndy Adamson 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2428fc931582SAndy Adamson 	encode_compound_hdr(&xdr, req, &hdr);
2429fc931582SAndy Adamson 	encode_create_session(&xdr, args, &hdr);
2430fc931582SAndy Adamson 	encode_nops(&hdr);
2431fc931582SAndy Adamson 	return 0;
2432fc931582SAndy Adamson }
2433fc931582SAndy Adamson 
2434fc931582SAndy Adamson /*
24350f3e66c6SAndy Adamson  * a DESTROY_SESSION request
24360f3e66c6SAndy Adamson  */
24370f3e66c6SAndy Adamson static int nfs4_xdr_enc_destroy_session(struct rpc_rqst *req, uint32_t *p,
24380f3e66c6SAndy Adamson 					struct nfs4_session *session)
24390f3e66c6SAndy Adamson {
24400f3e66c6SAndy Adamson 	struct xdr_stream xdr;
24410f3e66c6SAndy Adamson 	struct compound_hdr hdr = {
2442a4432345STrond Myklebust 		.minorversion = session->clp->cl_mvops->minor_version,
24430f3e66c6SAndy Adamson 	};
24440f3e66c6SAndy Adamson 
24450f3e66c6SAndy Adamson 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
24460f3e66c6SAndy Adamson 	encode_compound_hdr(&xdr, req, &hdr);
24470f3e66c6SAndy Adamson 	encode_destroy_session(&xdr, session, &hdr);
24480f3e66c6SAndy Adamson 	encode_nops(&hdr);
24490f3e66c6SAndy Adamson 	return 0;
24500f3e66c6SAndy Adamson }
24510f3e66c6SAndy Adamson 
24520f3e66c6SAndy Adamson /*
2453fc01cea9SAndy Adamson  * a SEQUENCE request
2454fc01cea9SAndy Adamson  */
2455fc01cea9SAndy Adamson static int nfs4_xdr_enc_sequence(struct rpc_rqst *req, uint32_t *p,
2456fc01cea9SAndy Adamson 				 struct nfs4_sequence_args *args)
2457fc01cea9SAndy Adamson {
2458fc01cea9SAndy Adamson 	struct xdr_stream xdr;
2459fc01cea9SAndy Adamson 	struct compound_hdr hdr = {
2460fc01cea9SAndy Adamson 		.minorversion = nfs4_xdr_minorversion(args),
2461fc01cea9SAndy Adamson 	};
2462fc01cea9SAndy Adamson 
2463fc01cea9SAndy Adamson 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2464fc01cea9SAndy Adamson 	encode_compound_hdr(&xdr, req, &hdr);
2465fc01cea9SAndy Adamson 	encode_sequence(&xdr, args, &hdr);
2466fc01cea9SAndy Adamson 	encode_nops(&hdr);
2467fc01cea9SAndy Adamson 	return 0;
2468fc01cea9SAndy Adamson }
2469fc01cea9SAndy Adamson 
2470fc01cea9SAndy Adamson /*
24712050f0ccSAndy Adamson  * a GET_LEASE_TIME request
24722050f0ccSAndy Adamson  */
24732050f0ccSAndy Adamson static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p,
24742050f0ccSAndy Adamson 				       struct nfs4_get_lease_time_args *args)
24752050f0ccSAndy Adamson {
24762050f0ccSAndy Adamson 	struct xdr_stream xdr;
24772050f0ccSAndy Adamson 	struct compound_hdr hdr = {
24782050f0ccSAndy Adamson 		.minorversion = nfs4_xdr_minorversion(&args->la_seq_args),
24792050f0ccSAndy Adamson 	};
24802050f0ccSAndy Adamson 	const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
24812050f0ccSAndy Adamson 
24822050f0ccSAndy Adamson 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
24832050f0ccSAndy Adamson 	encode_compound_hdr(&xdr, req, &hdr);
24842050f0ccSAndy Adamson 	encode_sequence(&xdr, &args->la_seq_args, &hdr);
24852050f0ccSAndy Adamson 	encode_putrootfh(&xdr, &hdr);
24862050f0ccSAndy Adamson 	encode_fsinfo(&xdr, lease_bitmap, &hdr);
24872050f0ccSAndy Adamson 	encode_nops(&hdr);
24882050f0ccSAndy Adamson 	return 0;
24892050f0ccSAndy Adamson }
249018019753SRicardo Labiaga 
249118019753SRicardo Labiaga /*
249218019753SRicardo Labiaga  * a RECLAIM_COMPLETE request
249318019753SRicardo Labiaga  */
249418019753SRicardo Labiaga static int nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req, uint32_t *p,
249518019753SRicardo Labiaga 				     struct nfs41_reclaim_complete_args *args)
249618019753SRicardo Labiaga {
249718019753SRicardo Labiaga 	struct xdr_stream xdr;
249818019753SRicardo Labiaga 	struct compound_hdr hdr = {
249918019753SRicardo Labiaga 		.minorversion = nfs4_xdr_minorversion(&args->seq_args)
250018019753SRicardo Labiaga 	};
250118019753SRicardo Labiaga 
250218019753SRicardo Labiaga 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
250318019753SRicardo Labiaga 	encode_compound_hdr(&xdr, req, &hdr);
250418019753SRicardo Labiaga 	encode_sequence(&xdr, &args->seq_args, &hdr);
250518019753SRicardo Labiaga 	encode_reclaim_complete(&xdr, args, &hdr);
250618019753SRicardo Labiaga 	encode_nops(&hdr);
250718019753SRicardo Labiaga 	return 0;
250818019753SRicardo Labiaga }
250918019753SRicardo Labiaga 
251099fe60d0SBenny Halevy #endif /* CONFIG_NFS_V4_1 */
251199fe60d0SBenny Halevy 
2512686841b3SBenny Halevy static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
2513686841b3SBenny Halevy {
2514686841b3SBenny Halevy 	dprintk("nfs: %s: prematurely hit end of receive buffer. "
2515686841b3SBenny Halevy 		"Remaining buffer length is %tu words.\n",
2516686841b3SBenny Halevy 		func, xdr->end - xdr->p);
2517686841b3SBenny Halevy }
25181da177e4SLinus Torvalds 
2519683b57b4STrond Myklebust static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
25201da177e4SLinus Torvalds {
25218687b63aSAl Viro 	__be32 *p;
25221da177e4SLinus Torvalds 
2523c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
2524c0eae66eSBenny Halevy 	if (unlikely(!p))
2525c0eae66eSBenny Halevy 		goto out_overflow;
2526cccddf4fSBenny Halevy 	*len = be32_to_cpup(p);
2527c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, *len);
2528c0eae66eSBenny Halevy 	if (unlikely(!p))
2529c0eae66eSBenny Halevy 		goto out_overflow;
25301da177e4SLinus Torvalds 	*string = (char *)p;
25311da177e4SLinus Torvalds 	return 0;
2532c0eae66eSBenny Halevy out_overflow:
2533c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2534c0eae66eSBenny Halevy 	return -EIO;
25351da177e4SLinus Torvalds }
25361da177e4SLinus Torvalds 
25371da177e4SLinus Torvalds static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
25381da177e4SLinus Torvalds {
25398687b63aSAl Viro 	__be32 *p;
25401da177e4SLinus Torvalds 
2541c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
2542c0eae66eSBenny Halevy 	if (unlikely(!p))
2543c0eae66eSBenny Halevy 		goto out_overflow;
25446f723f77SBenny Halevy 	hdr->status = be32_to_cpup(p++);
2545cccddf4fSBenny Halevy 	hdr->taglen = be32_to_cpup(p);
25461da177e4SLinus Torvalds 
2547c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, hdr->taglen + 4);
2548c0eae66eSBenny Halevy 	if (unlikely(!p))
2549c0eae66eSBenny Halevy 		goto out_overflow;
25501da177e4SLinus Torvalds 	hdr->tag = (char *)p;
25511da177e4SLinus Torvalds 	p += XDR_QUADLEN(hdr->taglen);
2552cccddf4fSBenny Halevy 	hdr->nops = be32_to_cpup(p);
2553aadf6152SBenny Halevy 	if (unlikely(hdr->nops < 1))
2554aadf6152SBenny Halevy 		return nfs4_stat_to_errno(hdr->status);
25551da177e4SLinus Torvalds 	return 0;
2556c0eae66eSBenny Halevy out_overflow:
2557c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2558c0eae66eSBenny Halevy 	return -EIO;
25591da177e4SLinus Torvalds }
25601da177e4SLinus Torvalds 
25611da177e4SLinus Torvalds static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
25621da177e4SLinus Torvalds {
25638687b63aSAl Viro 	__be32 *p;
25641da177e4SLinus Torvalds 	uint32_t opnum;
25651da177e4SLinus Torvalds 	int32_t nfserr;
25661da177e4SLinus Torvalds 
2567c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
2568c0eae66eSBenny Halevy 	if (unlikely(!p))
2569c0eae66eSBenny Halevy 		goto out_overflow;
25706f723f77SBenny Halevy 	opnum = be32_to_cpup(p++);
25711da177e4SLinus Torvalds 	if (opnum != expected) {
2572fe82a183SChuck Lever 		dprintk("nfs: Server returned operation"
25731da177e4SLinus Torvalds 			" %d but we issued a request for %d\n",
25741da177e4SLinus Torvalds 				opnum, expected);
25751da177e4SLinus Torvalds 		return -EIO;
25761da177e4SLinus Torvalds 	}
2577cccddf4fSBenny Halevy 	nfserr = be32_to_cpup(p);
25781da177e4SLinus Torvalds 	if (nfserr != NFS_OK)
2579856dff3dSBenny Halevy 		return nfs4_stat_to_errno(nfserr);
25801da177e4SLinus Torvalds 	return 0;
2581c0eae66eSBenny Halevy out_overflow:
2582c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2583c0eae66eSBenny Halevy 	return -EIO;
25841da177e4SLinus Torvalds }
25851da177e4SLinus Torvalds 
25861da177e4SLinus Torvalds /* Dummy routine */
2587adfa6f98SDavid Howells static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp)
25881da177e4SLinus Torvalds {
25898687b63aSAl Viro 	__be32 *p;
2590683b57b4STrond Myklebust 	unsigned int strlen;
25911da177e4SLinus Torvalds 	char *str;
25921da177e4SLinus Torvalds 
2593c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 12);
2594c0eae66eSBenny Halevy 	if (likely(p))
25951da177e4SLinus Torvalds 		return decode_opaque_inline(xdr, &strlen, &str);
2596c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2597c0eae66eSBenny Halevy 	return -EIO;
25981da177e4SLinus Torvalds }
25991da177e4SLinus Torvalds 
26001da177e4SLinus Torvalds static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
26011da177e4SLinus Torvalds {
26028687b63aSAl Viro 	uint32_t bmlen;
26038687b63aSAl Viro 	__be32 *p;
26041da177e4SLinus Torvalds 
2605c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
2606c0eae66eSBenny Halevy 	if (unlikely(!p))
2607c0eae66eSBenny Halevy 		goto out_overflow;
2608cccddf4fSBenny Halevy 	bmlen = be32_to_cpup(p);
26091da177e4SLinus Torvalds 
26101da177e4SLinus Torvalds 	bitmap[0] = bitmap[1] = 0;
2611c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, (bmlen << 2));
2612c0eae66eSBenny Halevy 	if (unlikely(!p))
2613c0eae66eSBenny Halevy 		goto out_overflow;
26141da177e4SLinus Torvalds 	if (bmlen > 0) {
26156f723f77SBenny Halevy 		bitmap[0] = be32_to_cpup(p++);
26161da177e4SLinus Torvalds 		if (bmlen > 1)
2617cccddf4fSBenny Halevy 			bitmap[1] = be32_to_cpup(p);
26181da177e4SLinus Torvalds 	}
26191da177e4SLinus Torvalds 	return 0;
2620c0eae66eSBenny Halevy out_overflow:
2621c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2622c0eae66eSBenny Halevy 	return -EIO;
26231da177e4SLinus Torvalds }
26241da177e4SLinus Torvalds 
26258687b63aSAl Viro static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep)
26261da177e4SLinus Torvalds {
26278687b63aSAl Viro 	__be32 *p;
26281da177e4SLinus Torvalds 
2629c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
2630c0eae66eSBenny Halevy 	if (unlikely(!p))
2631c0eae66eSBenny Halevy 		goto out_overflow;
2632cccddf4fSBenny Halevy 	*attrlen = be32_to_cpup(p);
26331da177e4SLinus Torvalds 	*savep = xdr->p;
26341da177e4SLinus Torvalds 	return 0;
2635c0eae66eSBenny Halevy out_overflow:
2636c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2637c0eae66eSBenny Halevy 	return -EIO;
26381da177e4SLinus Torvalds }
26391da177e4SLinus Torvalds 
26401da177e4SLinus Torvalds static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask)
26411da177e4SLinus Torvalds {
26421da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_SUPPORTED_ATTRS)) {
26431da177e4SLinus Torvalds 		decode_attr_bitmap(xdr, bitmask);
26441da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS;
26451da177e4SLinus Torvalds 	} else
26461da177e4SLinus Torvalds 		bitmask[0] = bitmask[1] = 0;
264744109241SFred Isaman 	dprintk("%s: bitmask=%08x:%08x\n", __func__, bitmask[0], bitmask[1]);
26481da177e4SLinus Torvalds 	return 0;
26491da177e4SLinus Torvalds }
26501da177e4SLinus Torvalds 
26511da177e4SLinus Torvalds static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
26521da177e4SLinus Torvalds {
26538687b63aSAl Viro 	__be32 *p;
2654409924e4STrond Myklebust 	int ret = 0;
26551da177e4SLinus Torvalds 
26561da177e4SLinus Torvalds 	*type = 0;
26571da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
26581da177e4SLinus Torvalds 		return -EIO;
26591da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_TYPE)) {
2660c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
2661c0eae66eSBenny Halevy 		if (unlikely(!p))
2662c0eae66eSBenny Halevy 			goto out_overflow;
2663cccddf4fSBenny Halevy 		*type = be32_to_cpup(p);
26641da177e4SLinus Torvalds 		if (*type < NF4REG || *type > NF4NAMEDATTR) {
26653110ff80SHarvey Harrison 			dprintk("%s: bad type %d\n", __func__, *type);
26661da177e4SLinus Torvalds 			return -EIO;
26671da177e4SLinus Torvalds 		}
26681da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_TYPE;
2669409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_TYPE;
26701da177e4SLinus Torvalds 	}
2671bca79478STrond Myklebust 	dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type]);
2672409924e4STrond Myklebust 	return ret;
2673c0eae66eSBenny Halevy out_overflow:
2674c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2675c0eae66eSBenny Halevy 	return -EIO;
26761da177e4SLinus Torvalds }
26771da177e4SLinus Torvalds 
26781da177e4SLinus Torvalds static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
26791da177e4SLinus Torvalds {
26808687b63aSAl Viro 	__be32 *p;
2681409924e4STrond Myklebust 	int ret = 0;
26821da177e4SLinus Torvalds 
26831da177e4SLinus Torvalds 	*change = 0;
26841da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
26851da177e4SLinus Torvalds 		return -EIO;
26861da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) {
2687c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
2688c0eae66eSBenny Halevy 		if (unlikely(!p))
2689c0eae66eSBenny Halevy 			goto out_overflow;
2690cccddf4fSBenny Halevy 		xdr_decode_hyper(p, change);
26911da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_CHANGE;
2692409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_CHANGE;
26931da177e4SLinus Torvalds 	}
26943110ff80SHarvey Harrison 	dprintk("%s: change attribute=%Lu\n", __func__,
26951da177e4SLinus Torvalds 			(unsigned long long)*change);
2696409924e4STrond Myklebust 	return ret;
2697c0eae66eSBenny Halevy out_overflow:
2698c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2699c0eae66eSBenny Halevy 	return -EIO;
27001da177e4SLinus Torvalds }
27011da177e4SLinus Torvalds 
27021da177e4SLinus Torvalds static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
27031da177e4SLinus Torvalds {
27048687b63aSAl Viro 	__be32 *p;
2705409924e4STrond Myklebust 	int ret = 0;
27061da177e4SLinus Torvalds 
27071da177e4SLinus Torvalds 	*size = 0;
27081da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
27091da177e4SLinus Torvalds 		return -EIO;
27101da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) {
2711c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
2712c0eae66eSBenny Halevy 		if (unlikely(!p))
2713c0eae66eSBenny Halevy 			goto out_overflow;
2714cccddf4fSBenny Halevy 		xdr_decode_hyper(p, size);
27151da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_SIZE;
2716409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_SIZE;
27171da177e4SLinus Torvalds 	}
27183110ff80SHarvey Harrison 	dprintk("%s: file size=%Lu\n", __func__, (unsigned long long)*size);
2719409924e4STrond Myklebust 	return ret;
2720c0eae66eSBenny Halevy out_overflow:
2721c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2722c0eae66eSBenny Halevy 	return -EIO;
27231da177e4SLinus Torvalds }
27241da177e4SLinus Torvalds 
27251da177e4SLinus Torvalds static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
27261da177e4SLinus Torvalds {
27278687b63aSAl Viro 	__be32 *p;
27281da177e4SLinus Torvalds 
27291da177e4SLinus Torvalds 	*res = 0;
27301da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U)))
27311da177e4SLinus Torvalds 		return -EIO;
27321da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) {
2733c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
2734c0eae66eSBenny Halevy 		if (unlikely(!p))
2735c0eae66eSBenny Halevy 			goto out_overflow;
2736cccddf4fSBenny Halevy 		*res = be32_to_cpup(p);
27371da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT;
27381da177e4SLinus Torvalds 	}
27393110ff80SHarvey Harrison 	dprintk("%s: link support=%s\n", __func__, *res == 0 ? "false" : "true");
27401da177e4SLinus Torvalds 	return 0;
2741c0eae66eSBenny Halevy out_overflow:
2742c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2743c0eae66eSBenny Halevy 	return -EIO;
27441da177e4SLinus Torvalds }
27451da177e4SLinus Torvalds 
27461da177e4SLinus Torvalds static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
27471da177e4SLinus Torvalds {
27488687b63aSAl Viro 	__be32 *p;
27491da177e4SLinus Torvalds 
27501da177e4SLinus Torvalds 	*res = 0;
27511da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U)))
27521da177e4SLinus Torvalds 		return -EIO;
27531da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) {
2754c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
2755c0eae66eSBenny Halevy 		if (unlikely(!p))
2756c0eae66eSBenny Halevy 			goto out_overflow;
2757cccddf4fSBenny Halevy 		*res = be32_to_cpup(p);
27581da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT;
27591da177e4SLinus Torvalds 	}
27603110ff80SHarvey Harrison 	dprintk("%s: symlink support=%s\n", __func__, *res == 0 ? "false" : "true");
27611da177e4SLinus Torvalds 	return 0;
2762c0eae66eSBenny Halevy out_overflow:
2763c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2764c0eae66eSBenny Halevy 	return -EIO;
27651da177e4SLinus Torvalds }
27661da177e4SLinus Torvalds 
27678b4bdcf8STrond Myklebust static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
27681da177e4SLinus Torvalds {
27698687b63aSAl Viro 	__be32 *p;
2770409924e4STrond Myklebust 	int ret = 0;
27711da177e4SLinus Torvalds 
27721da177e4SLinus Torvalds 	fsid->major = 0;
27731da177e4SLinus Torvalds 	fsid->minor = 0;
27741da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_FSID - 1U)))
27751da177e4SLinus Torvalds 		return -EIO;
27761da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_FSID)) {
2777c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 16);
2778c0eae66eSBenny Halevy 		if (unlikely(!p))
2779c0eae66eSBenny Halevy 			goto out_overflow;
27803ceb4dbbSBenny Halevy 		p = xdr_decode_hyper(p, &fsid->major);
2781cccddf4fSBenny Halevy 		xdr_decode_hyper(p, &fsid->minor);
27821da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_FSID;
2783409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_FSID;
27841da177e4SLinus Torvalds 	}
27853110ff80SHarvey Harrison 	dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __func__,
27861da177e4SLinus Torvalds 			(unsigned long long)fsid->major,
27871da177e4SLinus Torvalds 			(unsigned long long)fsid->minor);
2788409924e4STrond Myklebust 	return ret;
2789c0eae66eSBenny Halevy out_overflow:
2790c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2791c0eae66eSBenny Halevy 	return -EIO;
27921da177e4SLinus Torvalds }
27931da177e4SLinus Torvalds 
27941da177e4SLinus Torvalds static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
27951da177e4SLinus Torvalds {
27968687b63aSAl Viro 	__be32 *p;
27971da177e4SLinus Torvalds 
27981da177e4SLinus Torvalds 	*res = 60;
27991da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U)))
28001da177e4SLinus Torvalds 		return -EIO;
28011da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) {
2802c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
2803c0eae66eSBenny Halevy 		if (unlikely(!p))
2804c0eae66eSBenny Halevy 			goto out_overflow;
2805cccddf4fSBenny Halevy 		*res = be32_to_cpup(p);
28061da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME;
28071da177e4SLinus Torvalds 	}
28083110ff80SHarvey Harrison 	dprintk("%s: file size=%u\n", __func__, (unsigned int)*res);
28091da177e4SLinus Torvalds 	return 0;
2810c0eae66eSBenny Halevy out_overflow:
2811c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2812c0eae66eSBenny Halevy 	return -EIO;
28131da177e4SLinus Torvalds }
28141da177e4SLinus Torvalds 
28151da177e4SLinus Torvalds static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
28161da177e4SLinus Torvalds {
28178687b63aSAl Viro 	__be32 *p;
28181da177e4SLinus Torvalds 
28191da177e4SLinus Torvalds 	*res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL;
28201da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
28211da177e4SLinus Torvalds 		return -EIO;
28221da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) {
2823c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
2824c0eae66eSBenny Halevy 		if (unlikely(!p))
2825c0eae66eSBenny Halevy 			goto out_overflow;
2826cccddf4fSBenny Halevy 		*res = be32_to_cpup(p);
28271da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT;
28281da177e4SLinus Torvalds 	}
28293110ff80SHarvey Harrison 	dprintk("%s: ACLs supported=%u\n", __func__, (unsigned int)*res);
28301da177e4SLinus Torvalds 	return 0;
2831c0eae66eSBenny Halevy out_overflow:
2832c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2833c0eae66eSBenny Halevy 	return -EIO;
28341da177e4SLinus Torvalds }
28351da177e4SLinus Torvalds 
28361da177e4SLinus Torvalds static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
28371da177e4SLinus Torvalds {
28388687b63aSAl Viro 	__be32 *p;
2839409924e4STrond Myklebust 	int ret = 0;
28401da177e4SLinus Torvalds 
28411da177e4SLinus Torvalds 	*fileid = 0;
28421da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
28431da177e4SLinus Torvalds 		return -EIO;
28441da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) {
2845c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
2846c0eae66eSBenny Halevy 		if (unlikely(!p))
2847c0eae66eSBenny Halevy 			goto out_overflow;
2848cccddf4fSBenny Halevy 		xdr_decode_hyper(p, fileid);
28491da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_FILEID;
2850409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_FILEID;
28511da177e4SLinus Torvalds 	}
28523110ff80SHarvey Harrison 	dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
2853409924e4STrond Myklebust 	return ret;
2854c0eae66eSBenny Halevy out_overflow:
2855c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2856c0eae66eSBenny Halevy 	return -EIO;
28571da177e4SLinus Torvalds }
28581da177e4SLinus Torvalds 
285999baf625SManoj Naik static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
286099baf625SManoj Naik {
28618687b63aSAl Viro 	__be32 *p;
2862409924e4STrond Myklebust 	int ret = 0;
286399baf625SManoj Naik 
286499baf625SManoj Naik 	*fileid = 0;
286599baf625SManoj Naik 	if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
286699baf625SManoj Naik 		return -EIO;
286799baf625SManoj Naik 	if (likely(bitmap[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) {
2868c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
2869c0eae66eSBenny Halevy 		if (unlikely(!p))
2870c0eae66eSBenny Halevy 			goto out_overflow;
2871cccddf4fSBenny Halevy 		xdr_decode_hyper(p, fileid);
287299baf625SManoj Naik 		bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
2873409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_FILEID;
287499baf625SManoj Naik 	}
28753110ff80SHarvey Harrison 	dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
2876409924e4STrond Myklebust 	return ret;
2877c0eae66eSBenny Halevy out_overflow:
2878c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2879c0eae66eSBenny Halevy 	return -EIO;
288099baf625SManoj Naik }
288199baf625SManoj Naik 
28821da177e4SLinus Torvalds static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
28831da177e4SLinus Torvalds {
28848687b63aSAl Viro 	__be32 *p;
28851da177e4SLinus Torvalds 	int status = 0;
28861da177e4SLinus Torvalds 
28871da177e4SLinus Torvalds 	*res = 0;
28881da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_AVAIL - 1U)))
28891da177e4SLinus Torvalds 		return -EIO;
28901da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_FILES_AVAIL)) {
2891c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
2892c0eae66eSBenny Halevy 		if (unlikely(!p))
2893c0eae66eSBenny Halevy 			goto out_overflow;
2894cccddf4fSBenny Halevy 		xdr_decode_hyper(p, res);
28951da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL;
28961da177e4SLinus Torvalds 	}
28973110ff80SHarvey Harrison 	dprintk("%s: files avail=%Lu\n", __func__, (unsigned long long)*res);
28981da177e4SLinus Torvalds 	return status;
2899c0eae66eSBenny Halevy out_overflow:
2900c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2901c0eae66eSBenny Halevy 	return -EIO;
29021da177e4SLinus Torvalds }
29031da177e4SLinus Torvalds 
29041da177e4SLinus Torvalds static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
29051da177e4SLinus Torvalds {
29068687b63aSAl Viro 	__be32 *p;
29071da177e4SLinus Torvalds 	int status = 0;
29081da177e4SLinus Torvalds 
29091da177e4SLinus Torvalds 	*res = 0;
29101da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_FREE - 1U)))
29111da177e4SLinus Torvalds 		return -EIO;
29121da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_FILES_FREE)) {
2913c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
2914c0eae66eSBenny Halevy 		if (unlikely(!p))
2915c0eae66eSBenny Halevy 			goto out_overflow;
2916cccddf4fSBenny Halevy 		xdr_decode_hyper(p, res);
29171da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_FILES_FREE;
29181da177e4SLinus Torvalds 	}
29193110ff80SHarvey Harrison 	dprintk("%s: files free=%Lu\n", __func__, (unsigned long long)*res);
29201da177e4SLinus Torvalds 	return status;
2921c0eae66eSBenny Halevy out_overflow:
2922c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2923c0eae66eSBenny Halevy 	return -EIO;
29241da177e4SLinus Torvalds }
29251da177e4SLinus Torvalds 
29261da177e4SLinus Torvalds static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
29271da177e4SLinus Torvalds {
29288687b63aSAl Viro 	__be32 *p;
29291da177e4SLinus Torvalds 	int status = 0;
29301da177e4SLinus Torvalds 
29311da177e4SLinus Torvalds 	*res = 0;
29321da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_TOTAL - 1U)))
29331da177e4SLinus Torvalds 		return -EIO;
29341da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_FILES_TOTAL)) {
2935c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
2936c0eae66eSBenny Halevy 		if (unlikely(!p))
2937c0eae66eSBenny Halevy 			goto out_overflow;
2938cccddf4fSBenny Halevy 		xdr_decode_hyper(p, res);
29391da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL;
29401da177e4SLinus Torvalds 	}
29413110ff80SHarvey Harrison 	dprintk("%s: files total=%Lu\n", __func__, (unsigned long long)*res);
29421da177e4SLinus Torvalds 	return status;
2943c0eae66eSBenny Halevy out_overflow:
2944c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2945c0eae66eSBenny Halevy 	return -EIO;
29461da177e4SLinus Torvalds }
29471da177e4SLinus Torvalds 
29487aaa0b3bSManoj Naik static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
29497aaa0b3bSManoj Naik {
2950464ad6b1SChuck Lever 	u32 n;
29518687b63aSAl Viro 	__be32 *p;
29527aaa0b3bSManoj Naik 	int status = 0;
29537aaa0b3bSManoj Naik 
2954c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
2955c0eae66eSBenny Halevy 	if (unlikely(!p))
2956c0eae66eSBenny Halevy 		goto out_overflow;
2957cccddf4fSBenny Halevy 	n = be32_to_cpup(p);
295833a43f28SAndy Adamson 	if (n == 0)
295933a43f28SAndy Adamson 		goto root_path;
29607aaa0b3bSManoj Naik 	dprintk("path ");
29617aaa0b3bSManoj Naik 	path->ncomponents = 0;
29627aaa0b3bSManoj Naik 	while (path->ncomponents < n) {
29637aaa0b3bSManoj Naik 		struct nfs4_string *component = &path->components[path->ncomponents];
29647aaa0b3bSManoj Naik 		status = decode_opaque_inline(xdr, &component->len, &component->data);
29657aaa0b3bSManoj Naik 		if (unlikely(status != 0))
29667aaa0b3bSManoj Naik 			goto out_eio;
29677aaa0b3bSManoj Naik 		if (path->ncomponents != n)
29687aaa0b3bSManoj Naik 			dprintk("/");
29697aaa0b3bSManoj Naik 		dprintk("%s", component->data);
29707aaa0b3bSManoj Naik 		if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS)
29717aaa0b3bSManoj Naik 			path->ncomponents++;
29727aaa0b3bSManoj Naik 		else {
29737aaa0b3bSManoj Naik 			dprintk("cannot parse %d components in path\n", n);
29747aaa0b3bSManoj Naik 			goto out_eio;
29757aaa0b3bSManoj Naik 		}
29767aaa0b3bSManoj Naik 	}
29777aaa0b3bSManoj Naik out:
29787aaa0b3bSManoj Naik 	dprintk("\n");
29797aaa0b3bSManoj Naik 	return status;
298033a43f28SAndy Adamson root_path:
298133a43f28SAndy Adamson /* a root pathname is sent as a zero component4 */
298233a43f28SAndy Adamson 	path->ncomponents = 1;
298333a43f28SAndy Adamson 	path->components[0].len=0;
298433a43f28SAndy Adamson 	path->components[0].data=NULL;
298533a43f28SAndy Adamson 	dprintk("path /\n");
298633a43f28SAndy Adamson 	goto out;
29877aaa0b3bSManoj Naik out_eio:
29887aaa0b3bSManoj Naik 	dprintk(" status %d", status);
29897aaa0b3bSManoj Naik 	status = -EIO;
29907aaa0b3bSManoj Naik 	goto out;
2991c0eae66eSBenny Halevy out_overflow:
2992c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2993c0eae66eSBenny Halevy 	return -EIO;
29947aaa0b3bSManoj Naik }
29957aaa0b3bSManoj Naik 
29967aaa0b3bSManoj Naik static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res)
2997683b57b4STrond Myklebust {
2998683b57b4STrond Myklebust 	int n;
29998687b63aSAl Viro 	__be32 *p;
3000683b57b4STrond Myklebust 	int status = -EIO;
3001683b57b4STrond Myklebust 
3002683b57b4STrond Myklebust 	if (unlikely(bitmap[0] & (FATTR4_WORD0_FS_LOCATIONS -1U)))
3003683b57b4STrond Myklebust 		goto out;
3004683b57b4STrond Myklebust 	status = 0;
3005683b57b4STrond Myklebust 	if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
3006683b57b4STrond Myklebust 		goto out;
30073110ff80SHarvey Harrison 	dprintk("%s: fsroot ", __func__);
30087aaa0b3bSManoj Naik 	status = decode_pathname(xdr, &res->fs_path);
3009683b57b4STrond Myklebust 	if (unlikely(status != 0))
3010683b57b4STrond Myklebust 		goto out;
3011c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
3012c0eae66eSBenny Halevy 	if (unlikely(!p))
3013c0eae66eSBenny Halevy 		goto out_overflow;
3014cccddf4fSBenny Halevy 	n = be32_to_cpup(p);
3015683b57b4STrond Myklebust 	if (n <= 0)
3016683b57b4STrond Myklebust 		goto out_eio;
3017683b57b4STrond Myklebust 	res->nlocations = 0;
3018683b57b4STrond Myklebust 	while (res->nlocations < n) {
3019464ad6b1SChuck Lever 		u32 m;
30207aaa0b3bSManoj Naik 		struct nfs4_fs_location *loc = &res->locations[res->nlocations];
3021683b57b4STrond Myklebust 
3022c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
3023c0eae66eSBenny Halevy 		if (unlikely(!p))
3024c0eae66eSBenny Halevy 			goto out_overflow;
3025cccddf4fSBenny Halevy 		m = be32_to_cpup(p);
30267aaa0b3bSManoj Naik 
30277aaa0b3bSManoj Naik 		loc->nservers = 0;
30283110ff80SHarvey Harrison 		dprintk("%s: servers ", __func__);
30297aaa0b3bSManoj Naik 		while (loc->nservers < m) {
30307aaa0b3bSManoj Naik 			struct nfs4_string *server = &loc->servers[loc->nservers];
30317aaa0b3bSManoj Naik 			status = decode_opaque_inline(xdr, &server->len, &server->data);
3032683b57b4STrond Myklebust 			if (unlikely(status != 0))
3033683b57b4STrond Myklebust 				goto out_eio;
30347aaa0b3bSManoj Naik 			dprintk("%s ", server->data);
30357aaa0b3bSManoj Naik 			if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS)
30367aaa0b3bSManoj Naik 				loc->nservers++;
30377aaa0b3bSManoj Naik 			else {
3038464ad6b1SChuck Lever 				unsigned int i;
3039464ad6b1SChuck Lever 				dprintk("%s: using first %u of %u servers "
3040464ad6b1SChuck Lever 					"returned for location %u\n",
30413110ff80SHarvey Harrison 						__func__,
3042464ad6b1SChuck Lever 						NFS4_FS_LOCATION_MAXSERVERS,
3043464ad6b1SChuck Lever 						m, res->nlocations);
30447aaa0b3bSManoj Naik 				for (i = loc->nservers; i < m; i++) {
30452e42c3e2STrond Myklebust 					unsigned int len;
30467aaa0b3bSManoj Naik 					char *data;
30477aaa0b3bSManoj Naik 					status = decode_opaque_inline(xdr, &len, &data);
3048683b57b4STrond Myklebust 					if (unlikely(status != 0))
3049683b57b4STrond Myklebust 						goto out_eio;
30507aaa0b3bSManoj Naik 				}
30517aaa0b3bSManoj Naik 			}
30527aaa0b3bSManoj Naik 		}
30537aaa0b3bSManoj Naik 		status = decode_pathname(xdr, &loc->rootpath);
30547aaa0b3bSManoj Naik 		if (unlikely(status != 0))
30557aaa0b3bSManoj Naik 			goto out_eio;
30567aaa0b3bSManoj Naik 		if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
3057683b57b4STrond Myklebust 			res->nlocations++;
3058683b57b4STrond Myklebust 	}
3059409924e4STrond Myklebust 	if (res->nlocations != 0)
3060409924e4STrond Myklebust 		status = NFS_ATTR_FATTR_V4_REFERRAL;
3061683b57b4STrond Myklebust out:
30623110ff80SHarvey Harrison 	dprintk("%s: fs_locations done, error = %d\n", __func__, status);
3063683b57b4STrond Myklebust 	return status;
3064c0eae66eSBenny Halevy out_overflow:
3065c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3066683b57b4STrond Myklebust out_eio:
3067683b57b4STrond Myklebust 	status = -EIO;
3068683b57b4STrond Myklebust 	goto out;
3069683b57b4STrond Myklebust }
3070683b57b4STrond Myklebust 
30711da177e4SLinus Torvalds static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
30721da177e4SLinus Torvalds {
30738687b63aSAl Viro 	__be32 *p;
30741da177e4SLinus Torvalds 	int status = 0;
30751da177e4SLinus Torvalds 
30761da177e4SLinus Torvalds 	*res = 0;
30771da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXFILESIZE - 1U)))
30781da177e4SLinus Torvalds 		return -EIO;
30791da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_MAXFILESIZE)) {
3080c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
3081c0eae66eSBenny Halevy 		if (unlikely(!p))
3082c0eae66eSBenny Halevy 			goto out_overflow;
3083cccddf4fSBenny Halevy 		xdr_decode_hyper(p, res);
30841da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE;
30851da177e4SLinus Torvalds 	}
30863110ff80SHarvey Harrison 	dprintk("%s: maxfilesize=%Lu\n", __func__, (unsigned long long)*res);
30871da177e4SLinus Torvalds 	return status;
3088c0eae66eSBenny Halevy out_overflow:
3089c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3090c0eae66eSBenny Halevy 	return -EIO;
30911da177e4SLinus Torvalds }
30921da177e4SLinus Torvalds 
30931da177e4SLinus Torvalds static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink)
30941da177e4SLinus Torvalds {
30958687b63aSAl Viro 	__be32 *p;
30961da177e4SLinus Torvalds 	int status = 0;
30971da177e4SLinus Torvalds 
30981da177e4SLinus Torvalds 	*maxlink = 1;
30991da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXLINK - 1U)))
31001da177e4SLinus Torvalds 		return -EIO;
31011da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_MAXLINK)) {
3102c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
3103c0eae66eSBenny Halevy 		if (unlikely(!p))
3104c0eae66eSBenny Halevy 			goto out_overflow;
3105cccddf4fSBenny Halevy 		*maxlink = be32_to_cpup(p);
31061da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_MAXLINK;
31071da177e4SLinus Torvalds 	}
31083110ff80SHarvey Harrison 	dprintk("%s: maxlink=%u\n", __func__, *maxlink);
31091da177e4SLinus Torvalds 	return status;
3110c0eae66eSBenny Halevy out_overflow:
3111c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3112c0eae66eSBenny Halevy 	return -EIO;
31131da177e4SLinus Torvalds }
31141da177e4SLinus Torvalds 
31151da177e4SLinus Torvalds static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname)
31161da177e4SLinus Torvalds {
31178687b63aSAl Viro 	__be32 *p;
31181da177e4SLinus Torvalds 	int status = 0;
31191da177e4SLinus Torvalds 
31201da177e4SLinus Torvalds 	*maxname = 1024;
31211da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXNAME - 1U)))
31221da177e4SLinus Torvalds 		return -EIO;
31231da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_MAXNAME)) {
3124c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
3125c0eae66eSBenny Halevy 		if (unlikely(!p))
3126c0eae66eSBenny Halevy 			goto out_overflow;
3127cccddf4fSBenny Halevy 		*maxname = be32_to_cpup(p);
31281da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_MAXNAME;
31291da177e4SLinus Torvalds 	}
31303110ff80SHarvey Harrison 	dprintk("%s: maxname=%u\n", __func__, *maxname);
31311da177e4SLinus Torvalds 	return status;
3132c0eae66eSBenny Halevy out_overflow:
3133c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3134c0eae66eSBenny Halevy 	return -EIO;
31351da177e4SLinus Torvalds }
31361da177e4SLinus Torvalds 
31371da177e4SLinus Torvalds static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
31381da177e4SLinus Torvalds {
31398687b63aSAl Viro 	__be32 *p;
31401da177e4SLinus Torvalds 	int status = 0;
31411da177e4SLinus Torvalds 
31421da177e4SLinus Torvalds 	*res = 1024;
31431da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXREAD - 1U)))
31441da177e4SLinus Torvalds 		return -EIO;
31451da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_MAXREAD)) {
31461da177e4SLinus Torvalds 		uint64_t maxread;
3147c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
3148c0eae66eSBenny Halevy 		if (unlikely(!p))
3149c0eae66eSBenny Halevy 			goto out_overflow;
3150cccddf4fSBenny Halevy 		xdr_decode_hyper(p, &maxread);
31511da177e4SLinus Torvalds 		if (maxread > 0x7FFFFFFF)
31521da177e4SLinus Torvalds 			maxread = 0x7FFFFFFF;
31531da177e4SLinus Torvalds 		*res = (uint32_t)maxread;
31541da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_MAXREAD;
31551da177e4SLinus Torvalds 	}
31563110ff80SHarvey Harrison 	dprintk("%s: maxread=%lu\n", __func__, (unsigned long)*res);
31571da177e4SLinus Torvalds 	return status;
3158c0eae66eSBenny Halevy out_overflow:
3159c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3160c0eae66eSBenny Halevy 	return -EIO;
31611da177e4SLinus Torvalds }
31621da177e4SLinus Torvalds 
31631da177e4SLinus Torvalds static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
31641da177e4SLinus Torvalds {
31658687b63aSAl Viro 	__be32 *p;
31661da177e4SLinus Torvalds 	int status = 0;
31671da177e4SLinus Torvalds 
31681da177e4SLinus Torvalds 	*res = 1024;
31691da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXWRITE - 1U)))
31701da177e4SLinus Torvalds 		return -EIO;
31711da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_MAXWRITE)) {
31721da177e4SLinus Torvalds 		uint64_t maxwrite;
3173c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
3174c0eae66eSBenny Halevy 		if (unlikely(!p))
3175c0eae66eSBenny Halevy 			goto out_overflow;
3176cccddf4fSBenny Halevy 		xdr_decode_hyper(p, &maxwrite);
31771da177e4SLinus Torvalds 		if (maxwrite > 0x7FFFFFFF)
31781da177e4SLinus Torvalds 			maxwrite = 0x7FFFFFFF;
31791da177e4SLinus Torvalds 		*res = (uint32_t)maxwrite;
31801da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_MAXWRITE;
31811da177e4SLinus Torvalds 	}
31823110ff80SHarvey Harrison 	dprintk("%s: maxwrite=%lu\n", __func__, (unsigned long)*res);
31831da177e4SLinus Torvalds 	return status;
3184c0eae66eSBenny Halevy out_overflow:
3185c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3186c0eae66eSBenny Halevy 	return -EIO;
31871da177e4SLinus Torvalds }
31881da177e4SLinus Torvalds 
3189bca79478STrond Myklebust static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *mode)
31901da177e4SLinus Torvalds {
3191bca79478STrond Myklebust 	uint32_t tmp;
31928687b63aSAl Viro 	__be32 *p;
3193409924e4STrond Myklebust 	int ret = 0;
31941da177e4SLinus Torvalds 
31951da177e4SLinus Torvalds 	*mode = 0;
31961da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
31971da177e4SLinus Torvalds 		return -EIO;
31981da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_MODE)) {
3199c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
3200c0eae66eSBenny Halevy 		if (unlikely(!p))
3201c0eae66eSBenny Halevy 			goto out_overflow;
3202cccddf4fSBenny Halevy 		tmp = be32_to_cpup(p);
3203bca79478STrond Myklebust 		*mode = tmp & ~S_IFMT;
32041da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_MODE;
3205409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_MODE;
32061da177e4SLinus Torvalds 	}
32073110ff80SHarvey Harrison 	dprintk("%s: file mode=0%o\n", __func__, (unsigned int)*mode);
3208409924e4STrond Myklebust 	return ret;
3209c0eae66eSBenny Halevy out_overflow:
3210c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3211c0eae66eSBenny Halevy 	return -EIO;
32121da177e4SLinus Torvalds }
32131da177e4SLinus Torvalds 
32141da177e4SLinus Torvalds static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
32151da177e4SLinus Torvalds {
32168687b63aSAl Viro 	__be32 *p;
3217409924e4STrond Myklebust 	int ret = 0;
32181da177e4SLinus Torvalds 
32191da177e4SLinus Torvalds 	*nlink = 1;
32201da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
32211da177e4SLinus Torvalds 		return -EIO;
32221da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) {
3223c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
3224c0eae66eSBenny Halevy 		if (unlikely(!p))
3225c0eae66eSBenny Halevy 			goto out_overflow;
3226cccddf4fSBenny Halevy 		*nlink = be32_to_cpup(p);
32271da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_NUMLINKS;
3228409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_NLINK;
32291da177e4SLinus Torvalds 	}
32303110ff80SHarvey Harrison 	dprintk("%s: nlink=%u\n", __func__, (unsigned int)*nlink);
3231409924e4STrond Myklebust 	return ret;
3232c0eae66eSBenny Halevy out_overflow:
3233c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3234c0eae66eSBenny Halevy 	return -EIO;
32351da177e4SLinus Torvalds }
32361da177e4SLinus Torvalds 
323780e52aceSTrond Myklebust static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap,
323880e52aceSTrond Myklebust 		struct nfs_client *clp, uint32_t *uid, int may_sleep)
32391da177e4SLinus Torvalds {
32408687b63aSAl Viro 	uint32_t len;
32418687b63aSAl Viro 	__be32 *p;
3242409924e4STrond Myklebust 	int ret = 0;
32431da177e4SLinus Torvalds 
32441da177e4SLinus Torvalds 	*uid = -2;
32451da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
32461da177e4SLinus Torvalds 		return -EIO;
32471da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) {
3248c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
3249c0eae66eSBenny Halevy 		if (unlikely(!p))
3250c0eae66eSBenny Halevy 			goto out_overflow;
3251cccddf4fSBenny Halevy 		len = be32_to_cpup(p);
3252c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, len);
3253c0eae66eSBenny Halevy 		if (unlikely(!p))
3254c0eae66eSBenny Halevy 			goto out_overflow;
325580e52aceSTrond Myklebust 		if (!may_sleep) {
325680e52aceSTrond Myklebust 			/* do nothing */
325780e52aceSTrond Myklebust 		} else if (len < XDR_MAX_NETOBJ) {
3258409924e4STrond Myklebust 			if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0)
3259409924e4STrond Myklebust 				ret = NFS_ATTR_FATTR_OWNER;
3260409924e4STrond Myklebust 			else
32611da177e4SLinus Torvalds 				dprintk("%s: nfs_map_name_to_uid failed!\n",
32623110ff80SHarvey Harrison 						__func__);
32631da177e4SLinus Torvalds 		} else
3264fe82a183SChuck Lever 			dprintk("%s: name too long (%u)!\n",
32653110ff80SHarvey Harrison 					__func__, len);
32661da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_OWNER;
32671da177e4SLinus Torvalds 	}
32683110ff80SHarvey Harrison 	dprintk("%s: uid=%d\n", __func__, (int)*uid);
3269409924e4STrond Myklebust 	return ret;
3270c0eae66eSBenny Halevy out_overflow:
3271c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3272c0eae66eSBenny Halevy 	return -EIO;
32731da177e4SLinus Torvalds }
32741da177e4SLinus Torvalds 
327580e52aceSTrond Myklebust static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap,
327680e52aceSTrond Myklebust 		struct nfs_client *clp, uint32_t *gid, int may_sleep)
32771da177e4SLinus Torvalds {
32788687b63aSAl Viro 	uint32_t len;
32798687b63aSAl Viro 	__be32 *p;
3280409924e4STrond Myklebust 	int ret = 0;
32811da177e4SLinus Torvalds 
32821da177e4SLinus Torvalds 	*gid = -2;
32831da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
32841da177e4SLinus Torvalds 		return -EIO;
32851da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) {
3286c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
3287c0eae66eSBenny Halevy 		if (unlikely(!p))
3288c0eae66eSBenny Halevy 			goto out_overflow;
3289cccddf4fSBenny Halevy 		len = be32_to_cpup(p);
3290c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, len);
3291c0eae66eSBenny Halevy 		if (unlikely(!p))
3292c0eae66eSBenny Halevy 			goto out_overflow;
329380e52aceSTrond Myklebust 		if (!may_sleep) {
329480e52aceSTrond Myklebust 			/* do nothing */
329580e52aceSTrond Myklebust 		} else if (len < XDR_MAX_NETOBJ) {
3296409924e4STrond Myklebust 			if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0)
3297409924e4STrond Myklebust 				ret = NFS_ATTR_FATTR_GROUP;
3298409924e4STrond Myklebust 			else
32991da177e4SLinus Torvalds 				dprintk("%s: nfs_map_group_to_gid failed!\n",
33003110ff80SHarvey Harrison 						__func__);
33011da177e4SLinus Torvalds 		} else
3302fe82a183SChuck Lever 			dprintk("%s: name too long (%u)!\n",
33033110ff80SHarvey Harrison 					__func__, len);
33041da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
33051da177e4SLinus Torvalds 	}
33063110ff80SHarvey Harrison 	dprintk("%s: gid=%d\n", __func__, (int)*gid);
3307409924e4STrond Myklebust 	return ret;
3308c0eae66eSBenny Halevy out_overflow:
3309c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3310c0eae66eSBenny Halevy 	return -EIO;
33111da177e4SLinus Torvalds }
33121da177e4SLinus Torvalds 
33131da177e4SLinus Torvalds static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
33141da177e4SLinus Torvalds {
33158687b63aSAl Viro 	uint32_t major = 0, minor = 0;
33168687b63aSAl Viro 	__be32 *p;
3317409924e4STrond Myklebust 	int ret = 0;
33181da177e4SLinus Torvalds 
33191da177e4SLinus Torvalds 	*rdev = MKDEV(0,0);
33201da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U)))
33211da177e4SLinus Torvalds 		return -EIO;
33221da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_RAWDEV)) {
33231da177e4SLinus Torvalds 		dev_t tmp;
33241da177e4SLinus Torvalds 
3325c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
3326c0eae66eSBenny Halevy 		if (unlikely(!p))
3327c0eae66eSBenny Halevy 			goto out_overflow;
33286f723f77SBenny Halevy 		major = be32_to_cpup(p++);
3329cccddf4fSBenny Halevy 		minor = be32_to_cpup(p);
33301da177e4SLinus Torvalds 		tmp = MKDEV(major, minor);
33311da177e4SLinus Torvalds 		if (MAJOR(tmp) == major && MINOR(tmp) == minor)
33321da177e4SLinus Torvalds 			*rdev = tmp;
33331da177e4SLinus Torvalds 		bitmap[1] &= ~ FATTR4_WORD1_RAWDEV;
3334409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_RDEV;
33351da177e4SLinus Torvalds 	}
33363110ff80SHarvey Harrison 	dprintk("%s: rdev=(0x%x:0x%x)\n", __func__, major, minor);
3337409924e4STrond Myklebust 	return ret;
3338c0eae66eSBenny Halevy out_overflow:
3339c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3340c0eae66eSBenny Halevy 	return -EIO;
33411da177e4SLinus Torvalds }
33421da177e4SLinus Torvalds 
33431da177e4SLinus Torvalds static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
33441da177e4SLinus Torvalds {
33458687b63aSAl Viro 	__be32 *p;
33461da177e4SLinus Torvalds 	int status = 0;
33471da177e4SLinus Torvalds 
33481da177e4SLinus Torvalds 	*res = 0;
33491da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_AVAIL - 1U)))
33501da177e4SLinus Torvalds 		return -EIO;
33511da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_AVAIL)) {
3352c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
3353c0eae66eSBenny Halevy 		if (unlikely(!p))
3354c0eae66eSBenny Halevy 			goto out_overflow;
3355cccddf4fSBenny Halevy 		xdr_decode_hyper(p, res);
33561da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL;
33571da177e4SLinus Torvalds 	}
33583110ff80SHarvey Harrison 	dprintk("%s: space avail=%Lu\n", __func__, (unsigned long long)*res);
33591da177e4SLinus Torvalds 	return status;
3360c0eae66eSBenny Halevy out_overflow:
3361c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3362c0eae66eSBenny Halevy 	return -EIO;
33631da177e4SLinus Torvalds }
33641da177e4SLinus Torvalds 
33651da177e4SLinus Torvalds static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
33661da177e4SLinus Torvalds {
33678687b63aSAl Viro 	__be32 *p;
33681da177e4SLinus Torvalds 	int status = 0;
33691da177e4SLinus Torvalds 
33701da177e4SLinus Torvalds 	*res = 0;
33711da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_FREE - 1U)))
33721da177e4SLinus Torvalds 		return -EIO;
33731da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_FREE)) {
3374c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
3375c0eae66eSBenny Halevy 		if (unlikely(!p))
3376c0eae66eSBenny Halevy 			goto out_overflow;
3377cccddf4fSBenny Halevy 		xdr_decode_hyper(p, res);
33781da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE;
33791da177e4SLinus Torvalds 	}
33803110ff80SHarvey Harrison 	dprintk("%s: space free=%Lu\n", __func__, (unsigned long long)*res);
33811da177e4SLinus Torvalds 	return status;
3382c0eae66eSBenny Halevy out_overflow:
3383c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3384c0eae66eSBenny Halevy 	return -EIO;
33851da177e4SLinus Torvalds }
33861da177e4SLinus Torvalds 
33871da177e4SLinus Torvalds static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
33881da177e4SLinus Torvalds {
33898687b63aSAl Viro 	__be32 *p;
33901da177e4SLinus Torvalds 	int status = 0;
33911da177e4SLinus Torvalds 
33921da177e4SLinus Torvalds 	*res = 0;
33931da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_TOTAL - 1U)))
33941da177e4SLinus Torvalds 		return -EIO;
33951da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_TOTAL)) {
3396c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
3397c0eae66eSBenny Halevy 		if (unlikely(!p))
3398c0eae66eSBenny Halevy 			goto out_overflow;
3399cccddf4fSBenny Halevy 		xdr_decode_hyper(p, res);
34001da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL;
34011da177e4SLinus Torvalds 	}
34023110ff80SHarvey Harrison 	dprintk("%s: space total=%Lu\n", __func__, (unsigned long long)*res);
34031da177e4SLinus Torvalds 	return status;
3404c0eae66eSBenny Halevy out_overflow:
3405c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3406c0eae66eSBenny Halevy 	return -EIO;
34071da177e4SLinus Torvalds }
34081da177e4SLinus Torvalds 
34091da177e4SLinus Torvalds static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
34101da177e4SLinus Torvalds {
34118687b63aSAl Viro 	__be32 *p;
3412409924e4STrond Myklebust 	int ret = 0;
34131da177e4SLinus Torvalds 
34141da177e4SLinus Torvalds 	*used = 0;
34151da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
34161da177e4SLinus Torvalds 		return -EIO;
34171da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) {
3418c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
3419c0eae66eSBenny Halevy 		if (unlikely(!p))
3420c0eae66eSBenny Halevy 			goto out_overflow;
3421cccddf4fSBenny Halevy 		xdr_decode_hyper(p, used);
34221da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_SPACE_USED;
3423409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_SPACE_USED;
34241da177e4SLinus Torvalds 	}
34253110ff80SHarvey Harrison 	dprintk("%s: space used=%Lu\n", __func__,
34261da177e4SLinus Torvalds 			(unsigned long long)*used);
3427409924e4STrond Myklebust 	return ret;
3428c0eae66eSBenny Halevy out_overflow:
3429c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3430c0eae66eSBenny Halevy 	return -EIO;
34311da177e4SLinus Torvalds }
34321da177e4SLinus Torvalds 
34331da177e4SLinus Torvalds static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
34341da177e4SLinus Torvalds {
34358687b63aSAl Viro 	__be32 *p;
34361da177e4SLinus Torvalds 	uint64_t sec;
34371da177e4SLinus Torvalds 	uint32_t nsec;
34381da177e4SLinus Torvalds 
3439c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 12);
3440c0eae66eSBenny Halevy 	if (unlikely(!p))
3441c0eae66eSBenny Halevy 		goto out_overflow;
34423ceb4dbbSBenny Halevy 	p = xdr_decode_hyper(p, &sec);
3443cccddf4fSBenny Halevy 	nsec = be32_to_cpup(p);
34441da177e4SLinus Torvalds 	time->tv_sec = (time_t)sec;
34451da177e4SLinus Torvalds 	time->tv_nsec = (long)nsec;
34461da177e4SLinus Torvalds 	return 0;
3447c0eae66eSBenny Halevy out_overflow:
3448c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3449c0eae66eSBenny Halevy 	return -EIO;
34501da177e4SLinus Torvalds }
34511da177e4SLinus Torvalds 
34521da177e4SLinus Torvalds static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
34531da177e4SLinus Torvalds {
34541da177e4SLinus Torvalds 	int status = 0;
34551da177e4SLinus Torvalds 
34561da177e4SLinus Torvalds 	time->tv_sec = 0;
34571da177e4SLinus Torvalds 	time->tv_nsec = 0;
34581da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_ACCESS - 1U)))
34591da177e4SLinus Torvalds 		return -EIO;
34601da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_TIME_ACCESS)) {
34611da177e4SLinus Torvalds 		status = decode_attr_time(xdr, time);
3462409924e4STrond Myklebust 		if (status == 0)
3463409924e4STrond Myklebust 			status = NFS_ATTR_FATTR_ATIME;
34641da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS;
34651da177e4SLinus Torvalds 	}
34663110ff80SHarvey Harrison 	dprintk("%s: atime=%ld\n", __func__, (long)time->tv_sec);
34671da177e4SLinus Torvalds 	return status;
34681da177e4SLinus Torvalds }
34691da177e4SLinus Torvalds 
34701da177e4SLinus Torvalds static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
34711da177e4SLinus Torvalds {
34721da177e4SLinus Torvalds 	int status = 0;
34731da177e4SLinus Torvalds 
34741da177e4SLinus Torvalds 	time->tv_sec = 0;
34751da177e4SLinus Torvalds 	time->tv_nsec = 0;
34761da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_METADATA - 1U)))
34771da177e4SLinus Torvalds 		return -EIO;
34781da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) {
34791da177e4SLinus Torvalds 		status = decode_attr_time(xdr, time);
3480409924e4STrond Myklebust 		if (status == 0)
3481409924e4STrond Myklebust 			status = NFS_ATTR_FATTR_CTIME;
34821da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
34831da177e4SLinus Torvalds 	}
34843110ff80SHarvey Harrison 	dprintk("%s: ctime=%ld\n", __func__, (long)time->tv_sec);
34851da177e4SLinus Torvalds 	return status;
34861da177e4SLinus Torvalds }
34871da177e4SLinus Torvalds 
34881da177e4SLinus Torvalds static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
34891da177e4SLinus Torvalds {
34901da177e4SLinus Torvalds 	int status = 0;
34911da177e4SLinus Torvalds 
34921da177e4SLinus Torvalds 	time->tv_sec = 0;
34931da177e4SLinus Torvalds 	time->tv_nsec = 0;
34941da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_MODIFY - 1U)))
34951da177e4SLinus Torvalds 		return -EIO;
34961da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) {
34971da177e4SLinus Torvalds 		status = decode_attr_time(xdr, time);
3498409924e4STrond Myklebust 		if (status == 0)
3499409924e4STrond Myklebust 			status = NFS_ATTR_FATTR_MTIME;
35001da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
35011da177e4SLinus Torvalds 	}
35023110ff80SHarvey Harrison 	dprintk("%s: mtime=%ld\n", __func__, (long)time->tv_sec);
35031da177e4SLinus Torvalds 	return status;
35041da177e4SLinus Torvalds }
35051da177e4SLinus Torvalds 
35068687b63aSAl Viro static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
35071da177e4SLinus Torvalds {
35081da177e4SLinus Torvalds 	unsigned int attrwords = XDR_QUADLEN(attrlen);
35091da177e4SLinus Torvalds 	unsigned int nwords = xdr->p - savep;
35101da177e4SLinus Torvalds 
35111da177e4SLinus Torvalds 	if (unlikely(attrwords != nwords)) {
3512fe82a183SChuck Lever 		dprintk("%s: server returned incorrect attribute length: "
3513fe82a183SChuck Lever 			"%u %c %u\n",
35143110ff80SHarvey Harrison 				__func__,
35151da177e4SLinus Torvalds 				attrwords << 2,
35161da177e4SLinus Torvalds 				(attrwords < nwords) ? '<' : '>',
35171da177e4SLinus Torvalds 				nwords << 2);
35181da177e4SLinus Torvalds 		return -EIO;
35191da177e4SLinus Torvalds 	}
35201da177e4SLinus Torvalds 	return 0;
35211da177e4SLinus Torvalds }
35221da177e4SLinus Torvalds 
35231da177e4SLinus Torvalds static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
35241da177e4SLinus Torvalds {
35258687b63aSAl Viro 	__be32 *p;
35261da177e4SLinus Torvalds 
3527c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 20);
3528c0eae66eSBenny Halevy 	if (unlikely(!p))
3529c0eae66eSBenny Halevy 		goto out_overflow;
35306f723f77SBenny Halevy 	cinfo->atomic = be32_to_cpup(p++);
35313ceb4dbbSBenny Halevy 	p = xdr_decode_hyper(p, &cinfo->before);
3532cccddf4fSBenny Halevy 	xdr_decode_hyper(p, &cinfo->after);
35331da177e4SLinus Torvalds 	return 0;
3534c0eae66eSBenny Halevy out_overflow:
3535c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3536c0eae66eSBenny Halevy 	return -EIO;
35371da177e4SLinus Torvalds }
35381da177e4SLinus Torvalds 
35391da177e4SLinus Torvalds static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
35401da177e4SLinus Torvalds {
35418687b63aSAl Viro 	__be32 *p;
35421da177e4SLinus Torvalds 	uint32_t supp, acc;
35431da177e4SLinus Torvalds 	int status;
35441da177e4SLinus Torvalds 
35451da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_ACCESS);
35461da177e4SLinus Torvalds 	if (status)
35471da177e4SLinus Torvalds 		return status;
3548c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
3549c0eae66eSBenny Halevy 	if (unlikely(!p))
3550c0eae66eSBenny Halevy 		goto out_overflow;
35516f723f77SBenny Halevy 	supp = be32_to_cpup(p++);
3552cccddf4fSBenny Halevy 	acc = be32_to_cpup(p);
35531da177e4SLinus Torvalds 	access->supported = supp;
35541da177e4SLinus Torvalds 	access->access = acc;
35551da177e4SLinus Torvalds 	return 0;
3556c0eae66eSBenny Halevy out_overflow:
3557c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3558c0eae66eSBenny Halevy 	return -EIO;
35591da177e4SLinus Torvalds }
35601da177e4SLinus Torvalds 
356107d30434SBenny Halevy static int decode_opaque_fixed(struct xdr_stream *xdr, void *buf, size_t len)
35621da177e4SLinus Torvalds {
35638687b63aSAl Viro 	__be32 *p;
356407d30434SBenny Halevy 
356507d30434SBenny Halevy 	p = xdr_inline_decode(xdr, len);
356607d30434SBenny Halevy 	if (likely(p)) {
356707d30434SBenny Halevy 		memcpy(buf, p, len);
356807d30434SBenny Halevy 		return 0;
356907d30434SBenny Halevy 	}
357007d30434SBenny Halevy 	print_overflow_msg(__func__, xdr);
357107d30434SBenny Halevy 	return -EIO;
357207d30434SBenny Halevy }
357307d30434SBenny Halevy 
357407d30434SBenny Halevy static int decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
357507d30434SBenny Halevy {
357607d30434SBenny Halevy 	return decode_opaque_fixed(xdr, stateid->data, NFS4_STATEID_SIZE);
35771da177e4SLinus Torvalds }
35781da177e4SLinus Torvalds 
35791da177e4SLinus Torvalds static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
35801da177e4SLinus Torvalds {
35811da177e4SLinus Torvalds 	int status;
35821da177e4SLinus Torvalds 
35831da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_CLOSE);
3584c1d51931STrond Myklebust 	if (status != -EIO)
3585c1d51931STrond Myklebust 		nfs_increment_open_seqid(status, res->seqid);
358607d30434SBenny Halevy 	if (!status)
358707d30434SBenny Halevy 		status = decode_stateid(xdr, &res->stateid);
35881da177e4SLinus Torvalds 	return status;
35891da177e4SLinus Torvalds }
35901da177e4SLinus Torvalds 
3591db942bbdSBenny Halevy static int decode_verifier(struct xdr_stream *xdr, void *verifier)
3592db942bbdSBenny Halevy {
3593db942bbdSBenny Halevy 	return decode_opaque_fixed(xdr, verifier, 8);
35941da177e4SLinus Torvalds }
35951da177e4SLinus Torvalds 
35961da177e4SLinus Torvalds static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
35971da177e4SLinus Torvalds {
35981da177e4SLinus Torvalds 	int status;
35991da177e4SLinus Torvalds 
36001da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_COMMIT);
3601db942bbdSBenny Halevy 	if (!status)
3602db942bbdSBenny Halevy 		status = decode_verifier(xdr, res->verf->verifier);
36031da177e4SLinus Torvalds 	return status;
36041da177e4SLinus Torvalds }
36051da177e4SLinus Torvalds 
36061da177e4SLinus Torvalds static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
36071da177e4SLinus Torvalds {
36088687b63aSAl Viro 	__be32 *p;
36091da177e4SLinus Torvalds 	uint32_t bmlen;
36101da177e4SLinus Torvalds 	int status;
36111da177e4SLinus Torvalds 
36121da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_CREATE);
36131da177e4SLinus Torvalds 	if (status)
36141da177e4SLinus Torvalds 		return status;
36151da177e4SLinus Torvalds 	if ((status = decode_change_info(xdr, cinfo)))
36161da177e4SLinus Torvalds 		return status;
3617c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
3618c0eae66eSBenny Halevy 	if (unlikely(!p))
3619c0eae66eSBenny Halevy 		goto out_overflow;
3620cccddf4fSBenny Halevy 	bmlen = be32_to_cpup(p);
3621c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, bmlen << 2);
3622c0eae66eSBenny Halevy 	if (likely(p))
36231da177e4SLinus Torvalds 		return 0;
3624c0eae66eSBenny Halevy out_overflow:
3625c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3626c0eae66eSBenny Halevy 	return -EIO;
36271da177e4SLinus Torvalds }
36281da177e4SLinus Torvalds 
36291da177e4SLinus Torvalds static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
36301da177e4SLinus Torvalds {
36318687b63aSAl Viro 	__be32 *savep;
36326c0195a4SAndy Adamson 	uint32_t attrlen, bitmap[2] = {0};
36331da177e4SLinus Torvalds 	int status;
36341da177e4SLinus Torvalds 
36351da177e4SLinus Torvalds 	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
36361da177e4SLinus Torvalds 		goto xdr_error;
36371da177e4SLinus Torvalds 	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
36381da177e4SLinus Torvalds 		goto xdr_error;
36391da177e4SLinus Torvalds 	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
36401da177e4SLinus Torvalds 		goto xdr_error;
36411da177e4SLinus Torvalds 	if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0)
36421da177e4SLinus Torvalds 		goto xdr_error;
36431da177e4SLinus Torvalds 	if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0)
36441da177e4SLinus Torvalds 		goto xdr_error;
36451da177e4SLinus Torvalds 	if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0)
36461da177e4SLinus Torvalds 		goto xdr_error;
36471da177e4SLinus Torvalds 	if ((status = decode_attr_aclsupport(xdr, bitmap, &res->acl_bitmask)) != 0)
36481da177e4SLinus Torvalds 		goto xdr_error;
36491da177e4SLinus Torvalds 	status = verify_attr_len(xdr, savep, attrlen);
36501da177e4SLinus Torvalds xdr_error:
36513110ff80SHarvey Harrison 	dprintk("%s: xdr returned %d!\n", __func__, -status);
36521da177e4SLinus Torvalds 	return status;
36531da177e4SLinus Torvalds }
36541da177e4SLinus Torvalds 
36551da177e4SLinus Torvalds static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
36561da177e4SLinus Torvalds {
36578687b63aSAl Viro 	__be32 *savep;
36586c0195a4SAndy Adamson 	uint32_t attrlen, bitmap[2] = {0};
36591da177e4SLinus Torvalds 	int status;
36601da177e4SLinus Torvalds 
36611da177e4SLinus Torvalds 	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
36621da177e4SLinus Torvalds 		goto xdr_error;
36631da177e4SLinus Torvalds 	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
36641da177e4SLinus Torvalds 		goto xdr_error;
36651da177e4SLinus Torvalds 	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
36661da177e4SLinus Torvalds 		goto xdr_error;
36671da177e4SLinus Torvalds 
36681da177e4SLinus Torvalds 	if ((status = decode_attr_files_avail(xdr, bitmap, &fsstat->afiles)) != 0)
36691da177e4SLinus Torvalds 		goto xdr_error;
36701da177e4SLinus Torvalds 	if ((status = decode_attr_files_free(xdr, bitmap, &fsstat->ffiles)) != 0)
36711da177e4SLinus Torvalds 		goto xdr_error;
36721da177e4SLinus Torvalds 	if ((status = decode_attr_files_total(xdr, bitmap, &fsstat->tfiles)) != 0)
36731da177e4SLinus Torvalds 		goto xdr_error;
36741da177e4SLinus Torvalds 	if ((status = decode_attr_space_avail(xdr, bitmap, &fsstat->abytes)) != 0)
36751da177e4SLinus Torvalds 		goto xdr_error;
36761da177e4SLinus Torvalds 	if ((status = decode_attr_space_free(xdr, bitmap, &fsstat->fbytes)) != 0)
36771da177e4SLinus Torvalds 		goto xdr_error;
36781da177e4SLinus Torvalds 	if ((status = decode_attr_space_total(xdr, bitmap, &fsstat->tbytes)) != 0)
36791da177e4SLinus Torvalds 		goto xdr_error;
36801da177e4SLinus Torvalds 
36811da177e4SLinus Torvalds 	status = verify_attr_len(xdr, savep, attrlen);
36821da177e4SLinus Torvalds xdr_error:
36833110ff80SHarvey Harrison 	dprintk("%s: xdr returned %d!\n", __func__, -status);
36841da177e4SLinus Torvalds 	return status;
36851da177e4SLinus Torvalds }
36861da177e4SLinus Torvalds 
36871da177e4SLinus Torvalds static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
36881da177e4SLinus Torvalds {
36898687b63aSAl Viro 	__be32 *savep;
36906c0195a4SAndy Adamson 	uint32_t attrlen, bitmap[2] = {0};
36911da177e4SLinus Torvalds 	int status;
36921da177e4SLinus Torvalds 
36931da177e4SLinus Torvalds 	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
36941da177e4SLinus Torvalds 		goto xdr_error;
36951da177e4SLinus Torvalds 	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
36961da177e4SLinus Torvalds 		goto xdr_error;
36971da177e4SLinus Torvalds 	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
36981da177e4SLinus Torvalds 		goto xdr_error;
36991da177e4SLinus Torvalds 
37001da177e4SLinus Torvalds 	if ((status = decode_attr_maxlink(xdr, bitmap, &pathconf->max_link)) != 0)
37011da177e4SLinus Torvalds 		goto xdr_error;
37021da177e4SLinus Torvalds 	if ((status = decode_attr_maxname(xdr, bitmap, &pathconf->max_namelen)) != 0)
37031da177e4SLinus Torvalds 		goto xdr_error;
37041da177e4SLinus Torvalds 
37051da177e4SLinus Torvalds 	status = verify_attr_len(xdr, savep, attrlen);
37061da177e4SLinus Torvalds xdr_error:
37073110ff80SHarvey Harrison 	dprintk("%s: xdr returned %d!\n", __func__, -status);
37081da177e4SLinus Torvalds 	return status;
37091da177e4SLinus Torvalds }
37101da177e4SLinus Torvalds 
371180e52aceSTrond Myklebust static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
371280e52aceSTrond Myklebust 		const struct nfs_server *server, int may_sleep)
37131da177e4SLinus Torvalds {
37148687b63aSAl Viro 	__be32 *savep;
37151da177e4SLinus Torvalds 	uint32_t attrlen,
37161da177e4SLinus Torvalds 		 bitmap[2] = {0},
37171da177e4SLinus Torvalds 		 type;
3718bca79478STrond Myklebust 	int status;
3719bca79478STrond Myklebust 	umode_t fmode = 0;
372099baf625SManoj Naik 	uint64_t fileid;
37211da177e4SLinus Torvalds 
3722f26c7a78STrond Myklebust 	status = decode_op_hdr(xdr, OP_GETATTR);
3723f26c7a78STrond Myklebust 	if (status < 0)
37241da177e4SLinus Torvalds 		goto xdr_error;
37251da177e4SLinus Torvalds 
3726f26c7a78STrond Myklebust 	status = decode_attr_bitmap(xdr, bitmap);
3727f26c7a78STrond Myklebust 	if (status < 0)
3728f26c7a78STrond Myklebust 		goto xdr_error;
3729f26c7a78STrond Myklebust 
3730f26c7a78STrond Myklebust 	status = decode_attr_length(xdr, &attrlen, &savep);
3731f26c7a78STrond Myklebust 	if (status < 0)
37321da177e4SLinus Torvalds 		goto xdr_error;
37331da177e4SLinus Torvalds 
37341da177e4SLinus Torvalds 
3735f26c7a78STrond Myklebust 	status = decode_attr_type(xdr, bitmap, &type);
3736f26c7a78STrond Myklebust 	if (status < 0)
37371da177e4SLinus Torvalds 		goto xdr_error;
3738409924e4STrond Myklebust 	fattr->mode = 0;
3739409924e4STrond Myklebust 	if (status != 0) {
3740409924e4STrond Myklebust 		fattr->mode |= nfs_type2fmt[type];
3741409924e4STrond Myklebust 		fattr->valid |= status;
3742409924e4STrond Myklebust 	}
37431da177e4SLinus Torvalds 
3744f26c7a78STrond Myklebust 	status = decode_attr_change(xdr, bitmap, &fattr->change_attr);
3745f26c7a78STrond Myklebust 	if (status < 0)
37461da177e4SLinus Torvalds 		goto xdr_error;
3747409924e4STrond Myklebust 	fattr->valid |= status;
3748f26c7a78STrond Myklebust 
3749f26c7a78STrond Myklebust 	status = decode_attr_size(xdr, bitmap, &fattr->size);
3750f26c7a78STrond Myklebust 	if (status < 0)
37511da177e4SLinus Torvalds 		goto xdr_error;
3752409924e4STrond Myklebust 	fattr->valid |= status;
3753f26c7a78STrond Myklebust 
3754f26c7a78STrond Myklebust 	status = decode_attr_fsid(xdr, bitmap, &fattr->fsid);
3755f26c7a78STrond Myklebust 	if (status < 0)
37561da177e4SLinus Torvalds 		goto xdr_error;
3757409924e4STrond Myklebust 	fattr->valid |= status;
3758f26c7a78STrond Myklebust 
3759f26c7a78STrond Myklebust 	status = decode_attr_fileid(xdr, bitmap, &fattr->fileid);
3760f26c7a78STrond Myklebust 	if (status < 0)
37611da177e4SLinus Torvalds 		goto xdr_error;
3762409924e4STrond Myklebust 	fattr->valid |= status;
3763f26c7a78STrond Myklebust 
3764f26c7a78STrond Myklebust 	status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
37657aaa0b3bSManoj Naik 						struct nfs4_fs_locations,
3766f26c7a78STrond Myklebust 						fattr));
3767f26c7a78STrond Myklebust 	if (status < 0)
3768683b57b4STrond Myklebust 		goto xdr_error;
3769409924e4STrond Myklebust 	fattr->valid |= status;
3770f26c7a78STrond Myklebust 
3771f26c7a78STrond Myklebust 	status = decode_attr_mode(xdr, bitmap, &fmode);
3772f26c7a78STrond Myklebust 	if (status < 0)
37731da177e4SLinus Torvalds 		goto xdr_error;
3774409924e4STrond Myklebust 	if (status != 0) {
37751da177e4SLinus Torvalds 		fattr->mode |= fmode;
3776409924e4STrond Myklebust 		fattr->valid |= status;
3777409924e4STrond Myklebust 	}
3778f26c7a78STrond Myklebust 
3779f26c7a78STrond Myklebust 	status = decode_attr_nlink(xdr, bitmap, &fattr->nlink);
3780f26c7a78STrond Myklebust 	if (status < 0)
37811da177e4SLinus Torvalds 		goto xdr_error;
3782409924e4STrond Myklebust 	fattr->valid |= status;
3783f26c7a78STrond Myklebust 
378480e52aceSTrond Myklebust 	status = decode_attr_owner(xdr, bitmap, server->nfs_client,
378580e52aceSTrond Myklebust 			&fattr->uid, may_sleep);
3786f26c7a78STrond Myklebust 	if (status < 0)
37871da177e4SLinus Torvalds 		goto xdr_error;
3788409924e4STrond Myklebust 	fattr->valid |= status;
3789f26c7a78STrond Myklebust 
379080e52aceSTrond Myklebust 	status = decode_attr_group(xdr, bitmap, server->nfs_client,
379180e52aceSTrond Myklebust 			&fattr->gid, may_sleep);
3792f26c7a78STrond Myklebust 	if (status < 0)
37931da177e4SLinus Torvalds 		goto xdr_error;
3794409924e4STrond Myklebust 	fattr->valid |= status;
3795f26c7a78STrond Myklebust 
3796f26c7a78STrond Myklebust 	status = decode_attr_rdev(xdr, bitmap, &fattr->rdev);
3797f26c7a78STrond Myklebust 	if (status < 0)
37981da177e4SLinus Torvalds 		goto xdr_error;
3799409924e4STrond Myklebust 	fattr->valid |= status;
3800f26c7a78STrond Myklebust 
3801f26c7a78STrond Myklebust 	status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used);
3802f26c7a78STrond Myklebust 	if (status < 0)
38031da177e4SLinus Torvalds 		goto xdr_error;
3804409924e4STrond Myklebust 	fattr->valid |= status;
3805f26c7a78STrond Myklebust 
3806f26c7a78STrond Myklebust 	status = decode_attr_time_access(xdr, bitmap, &fattr->atime);
3807f26c7a78STrond Myklebust 	if (status < 0)
38081da177e4SLinus Torvalds 		goto xdr_error;
3809409924e4STrond Myklebust 	fattr->valid |= status;
3810f26c7a78STrond Myklebust 
3811f26c7a78STrond Myklebust 	status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
3812f26c7a78STrond Myklebust 	if (status < 0)
38131da177e4SLinus Torvalds 		goto xdr_error;
3814409924e4STrond Myklebust 	fattr->valid |= status;
3815f26c7a78STrond Myklebust 
3816f26c7a78STrond Myklebust 	status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime);
3817f26c7a78STrond Myklebust 	if (status < 0)
38181da177e4SLinus Torvalds 		goto xdr_error;
3819409924e4STrond Myklebust 	fattr->valid |= status;
3820f26c7a78STrond Myklebust 
3821f26c7a78STrond Myklebust 	status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid);
3822f26c7a78STrond Myklebust 	if (status < 0)
382399baf625SManoj Naik 		goto xdr_error;
3824409924e4STrond Myklebust 	if (status != 0 && !(fattr->valid & status)) {
382599baf625SManoj Naik 		fattr->fileid = fileid;
3826409924e4STrond Myklebust 		fattr->valid |= status;
3827409924e4STrond Myklebust 	}
3828f26c7a78STrond Myklebust 
3829f26c7a78STrond Myklebust 	status = verify_attr_len(xdr, savep, attrlen);
38301da177e4SLinus Torvalds xdr_error:
38313110ff80SHarvey Harrison 	dprintk("%s: xdr returned %d\n", __func__, -status);
38321da177e4SLinus Torvalds 	return status;
38331da177e4SLinus Torvalds }
38341da177e4SLinus Torvalds 
38351da177e4SLinus Torvalds 
38361da177e4SLinus Torvalds static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
38371da177e4SLinus Torvalds {
38388687b63aSAl Viro 	__be32 *savep;
38391da177e4SLinus Torvalds 	uint32_t attrlen, bitmap[2];
38401da177e4SLinus Torvalds 	int status;
38411da177e4SLinus Torvalds 
38421da177e4SLinus Torvalds 	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
38431da177e4SLinus Torvalds 		goto xdr_error;
38441da177e4SLinus Torvalds 	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
38451da177e4SLinus Torvalds 		goto xdr_error;
38461da177e4SLinus Torvalds 	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
38471da177e4SLinus Torvalds 		goto xdr_error;
38481da177e4SLinus Torvalds 
38491da177e4SLinus Torvalds 	fsinfo->rtmult = fsinfo->wtmult = 512;	/* ??? */
38501da177e4SLinus Torvalds 
38511da177e4SLinus Torvalds 	if ((status = decode_attr_lease_time(xdr, bitmap, &fsinfo->lease_time)) != 0)
38521da177e4SLinus Torvalds 		goto xdr_error;
38531da177e4SLinus Torvalds 	if ((status = decode_attr_maxfilesize(xdr, bitmap, &fsinfo->maxfilesize)) != 0)
38541da177e4SLinus Torvalds 		goto xdr_error;
38551da177e4SLinus Torvalds 	if ((status = decode_attr_maxread(xdr, bitmap, &fsinfo->rtmax)) != 0)
38561da177e4SLinus Torvalds 		goto xdr_error;
38571da177e4SLinus Torvalds 	fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax;
38581da177e4SLinus Torvalds 	if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0)
38591da177e4SLinus Torvalds 		goto xdr_error;
38601da177e4SLinus Torvalds 	fsinfo->wtpref = fsinfo->wtmax;
38611da177e4SLinus Torvalds 
38621da177e4SLinus Torvalds 	status = verify_attr_len(xdr, savep, attrlen);
38631da177e4SLinus Torvalds xdr_error:
38643110ff80SHarvey Harrison 	dprintk("%s: xdr returned %d!\n", __func__, -status);
38651da177e4SLinus Torvalds 	return status;
38661da177e4SLinus Torvalds }
38671da177e4SLinus Torvalds 
38681da177e4SLinus Torvalds static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
38691da177e4SLinus Torvalds {
38708687b63aSAl Viro 	__be32 *p;
38711da177e4SLinus Torvalds 	uint32_t len;
38721da177e4SLinus Torvalds 	int status;
38731da177e4SLinus Torvalds 
38749936781dSTrond Myklebust 	/* Zero handle first to allow comparisons */
38759936781dSTrond Myklebust 	memset(fh, 0, sizeof(*fh));
38769936781dSTrond Myklebust 
38771da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_GETFH);
38781da177e4SLinus Torvalds 	if (status)
38791da177e4SLinus Torvalds 		return status;
38801da177e4SLinus Torvalds 
3881c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
3882c0eae66eSBenny Halevy 	if (unlikely(!p))
3883c0eae66eSBenny Halevy 		goto out_overflow;
3884cccddf4fSBenny Halevy 	len = be32_to_cpup(p);
38851da177e4SLinus Torvalds 	if (len > NFS4_FHSIZE)
38861da177e4SLinus Torvalds 		return -EIO;
38871da177e4SLinus Torvalds 	fh->size = len;
3888c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, len);
3889c0eae66eSBenny Halevy 	if (unlikely(!p))
3890c0eae66eSBenny Halevy 		goto out_overflow;
389199398d06SBenny Halevy 	memcpy(fh->data, p, len);
38921da177e4SLinus Torvalds 	return 0;
3893c0eae66eSBenny Halevy out_overflow:
3894c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3895c0eae66eSBenny Halevy 	return -EIO;
38961da177e4SLinus Torvalds }
38971da177e4SLinus Torvalds 
38981da177e4SLinus Torvalds static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
38991da177e4SLinus Torvalds {
39001da177e4SLinus Torvalds 	int status;
39011da177e4SLinus Torvalds 
39021da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_LINK);
39031da177e4SLinus Torvalds 	if (status)
39041da177e4SLinus Torvalds 		return status;
39051da177e4SLinus Torvalds 	return decode_change_info(xdr, cinfo);
39061da177e4SLinus Torvalds }
39071da177e4SLinus Torvalds 
39081da177e4SLinus Torvalds /*
39091da177e4SLinus Torvalds  * We create the owner, so we know a proper owner.id length is 4.
39101da177e4SLinus Torvalds  */
3911911d1aafSTrond Myklebust static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
39121da177e4SLinus Torvalds {
3913911d1aafSTrond Myklebust 	uint64_t offset, length, clientid;
39148687b63aSAl Viro 	__be32 *p;
3915911d1aafSTrond Myklebust 	uint32_t namelen, type;
39161da177e4SLinus Torvalds 
3917c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 32);
3918c0eae66eSBenny Halevy 	if (unlikely(!p))
3919c0eae66eSBenny Halevy 		goto out_overflow;
39203ceb4dbbSBenny Halevy 	p = xdr_decode_hyper(p, &offset);
39213ceb4dbbSBenny Halevy 	p = xdr_decode_hyper(p, &length);
39226f723f77SBenny Halevy 	type = be32_to_cpup(p++);
3923911d1aafSTrond Myklebust 	if (fl != NULL) {
3924911d1aafSTrond Myklebust 		fl->fl_start = (loff_t)offset;
3925911d1aafSTrond Myklebust 		fl->fl_end = fl->fl_start + (loff_t)length - 1;
3926911d1aafSTrond Myklebust 		if (length == ~(uint64_t)0)
3927911d1aafSTrond Myklebust 			fl->fl_end = OFFSET_MAX;
3928911d1aafSTrond Myklebust 		fl->fl_type = F_WRLCK;
3929911d1aafSTrond Myklebust 		if (type & 1)
3930911d1aafSTrond Myklebust 			fl->fl_type = F_RDLCK;
3931911d1aafSTrond Myklebust 		fl->fl_pid = 0;
3932911d1aafSTrond Myklebust 	}
39333ceb4dbbSBenny Halevy 	p = xdr_decode_hyper(p, &clientid);
3934cccddf4fSBenny Halevy 	namelen = be32_to_cpup(p);
3935c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, namelen);
3936c0eae66eSBenny Halevy 	if (likely(p))
39371da177e4SLinus Torvalds 		return -NFS4ERR_DENIED;
3938c0eae66eSBenny Halevy out_overflow:
3939c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3940c0eae66eSBenny Halevy 	return -EIO;
39411da177e4SLinus Torvalds }
39421da177e4SLinus Torvalds 
3943911d1aafSTrond Myklebust static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
39441da177e4SLinus Torvalds {
39451da177e4SLinus Torvalds 	int status;
39461da177e4SLinus Torvalds 
39471da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_LOCK);
3948c1d51931STrond Myklebust 	if (status == -EIO)
3949c1d51931STrond Myklebust 		goto out;
39501da177e4SLinus Torvalds 	if (status == 0) {
395107d30434SBenny Halevy 		status = decode_stateid(xdr, &res->stateid);
395207d30434SBenny Halevy 		if (unlikely(status))
395307d30434SBenny Halevy 			goto out;
39541da177e4SLinus Torvalds 	} else if (status == -NFS4ERR_DENIED)
3955c1d51931STrond Myklebust 		status = decode_lock_denied(xdr, NULL);
3956c1d51931STrond Myklebust 	if (res->open_seqid != NULL)
3957c1d51931STrond Myklebust 		nfs_increment_open_seqid(status, res->open_seqid);
3958c1d51931STrond Myklebust 	nfs_increment_lock_seqid(status, res->lock_seqid);
3959c1d51931STrond Myklebust out:
39601da177e4SLinus Torvalds 	return status;
39611da177e4SLinus Torvalds }
39621da177e4SLinus Torvalds 
3963911d1aafSTrond Myklebust static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res)
39641da177e4SLinus Torvalds {
39651da177e4SLinus Torvalds 	int status;
39661da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_LOCKT);
39671da177e4SLinus Torvalds 	if (status == -NFS4ERR_DENIED)
3968911d1aafSTrond Myklebust 		return decode_lock_denied(xdr, res->denied);
39691da177e4SLinus Torvalds 	return status;
39701da177e4SLinus Torvalds }
39711da177e4SLinus Torvalds 
3972911d1aafSTrond Myklebust static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
39731da177e4SLinus Torvalds {
39741da177e4SLinus Torvalds 	int status;
39751da177e4SLinus Torvalds 
39761da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_LOCKU);
3977c1d51931STrond Myklebust 	if (status != -EIO)
3978c1d51931STrond Myklebust 		nfs_increment_lock_seqid(status, res->seqid);
397907d30434SBenny Halevy 	if (status == 0)
398007d30434SBenny Halevy 		status = decode_stateid(xdr, &res->stateid);
39811da177e4SLinus Torvalds 	return status;
39821da177e4SLinus Torvalds }
39831da177e4SLinus Torvalds 
39841da177e4SLinus Torvalds static int decode_lookup(struct xdr_stream *xdr)
39851da177e4SLinus Torvalds {
39861da177e4SLinus Torvalds 	return decode_op_hdr(xdr, OP_LOOKUP);
39871da177e4SLinus Torvalds }
39881da177e4SLinus Torvalds 
39891da177e4SLinus Torvalds /* This is too sick! */
39901da177e4SLinus Torvalds static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
39911da177e4SLinus Torvalds {
39928687b63aSAl Viro 	__be32 *p;
39931da177e4SLinus Torvalds 	uint32_t limit_type, nblocks, blocksize;
39941da177e4SLinus Torvalds 
3995c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 12);
3996c0eae66eSBenny Halevy 	if (unlikely(!p))
3997c0eae66eSBenny Halevy 		goto out_overflow;
39986f723f77SBenny Halevy 	limit_type = be32_to_cpup(p++);
39991da177e4SLinus Torvalds 	switch (limit_type) {
40001da177e4SLinus Torvalds 	case 1:
4001cccddf4fSBenny Halevy 		xdr_decode_hyper(p, maxsize);
40021da177e4SLinus Torvalds 		break;
40031da177e4SLinus Torvalds 	case 2:
40046f723f77SBenny Halevy 		nblocks = be32_to_cpup(p++);
4005cccddf4fSBenny Halevy 		blocksize = be32_to_cpup(p);
40061da177e4SLinus Torvalds 		*maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
40071da177e4SLinus Torvalds 	}
40081da177e4SLinus Torvalds 	return 0;
4009c0eae66eSBenny Halevy out_overflow:
4010c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4011c0eae66eSBenny Halevy 	return -EIO;
40121da177e4SLinus Torvalds }
40131da177e4SLinus Torvalds 
40141da177e4SLinus Torvalds static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
40151da177e4SLinus Torvalds {
40168687b63aSAl Viro 	__be32 *p;
40171da177e4SLinus Torvalds 	uint32_t delegation_type;
401807d30434SBenny Halevy 	int status;
40191da177e4SLinus Torvalds 
4020c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
4021c0eae66eSBenny Halevy 	if (unlikely(!p))
4022c0eae66eSBenny Halevy 		goto out_overflow;
4023cccddf4fSBenny Halevy 	delegation_type = be32_to_cpup(p);
40241da177e4SLinus Torvalds 	if (delegation_type == NFS4_OPEN_DELEGATE_NONE) {
40251da177e4SLinus Torvalds 		res->delegation_type = 0;
40261da177e4SLinus Torvalds 		return 0;
40271da177e4SLinus Torvalds 	}
402807d30434SBenny Halevy 	status = decode_stateid(xdr, &res->delegation);
402907d30434SBenny Halevy 	if (unlikely(status))
403007d30434SBenny Halevy 		return status;
4031c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
4032c0eae66eSBenny Halevy 	if (unlikely(!p))
4033c0eae66eSBenny Halevy 		goto out_overflow;
4034cccddf4fSBenny Halevy 	res->do_recall = be32_to_cpup(p);
403505d564feSAndy Adamson 
40361da177e4SLinus Torvalds 	switch (delegation_type) {
40371da177e4SLinus Torvalds 	case NFS4_OPEN_DELEGATE_READ:
40381da177e4SLinus Torvalds 		res->delegation_type = FMODE_READ;
40391da177e4SLinus Torvalds 		break;
40401da177e4SLinus Torvalds 	case NFS4_OPEN_DELEGATE_WRITE:
40411da177e4SLinus Torvalds 		res->delegation_type = FMODE_WRITE|FMODE_READ;
40421da177e4SLinus Torvalds 		if (decode_space_limit(xdr, &res->maxsize) < 0)
40431da177e4SLinus Torvalds 				return -EIO;
40441da177e4SLinus Torvalds 	}
40457539bbabSDavid Howells 	return decode_ace(xdr, NULL, res->server->nfs_client);
4046c0eae66eSBenny Halevy out_overflow:
4047c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4048c0eae66eSBenny Halevy 	return -EIO;
40491da177e4SLinus Torvalds }
40501da177e4SLinus Torvalds 
40511da177e4SLinus Torvalds static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
40521da177e4SLinus Torvalds {
40538687b63aSAl Viro 	__be32 *p;
4054aa53ed54SJeff Layton 	uint32_t savewords, bmlen, i;
40551da177e4SLinus Torvalds 	int status;
40561da177e4SLinus Torvalds 
40571da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_OPEN);
4058c1d51931STrond Myklebust 	if (status != -EIO)
4059c1d51931STrond Myklebust 		nfs_increment_open_seqid(status, res->seqid);
406007d30434SBenny Halevy 	if (!status)
406107d30434SBenny Halevy 		status = decode_stateid(xdr, &res->stateid);
406207d30434SBenny Halevy 	if (unlikely(status))
40631da177e4SLinus Torvalds 		return status;
40641da177e4SLinus Torvalds 
40651da177e4SLinus Torvalds 	decode_change_info(xdr, &res->cinfo);
40661da177e4SLinus Torvalds 
4067c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
4068c0eae66eSBenny Halevy 	if (unlikely(!p))
4069c0eae66eSBenny Halevy 		goto out_overflow;
40706f723f77SBenny Halevy 	res->rflags = be32_to_cpup(p++);
4071cccddf4fSBenny Halevy 	bmlen = be32_to_cpup(p);
40721da177e4SLinus Torvalds 	if (bmlen > 10)
40731da177e4SLinus Torvalds 		goto xdr_error;
40741da177e4SLinus Torvalds 
4075c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, bmlen << 2);
4076c0eae66eSBenny Halevy 	if (unlikely(!p))
4077c0eae66eSBenny Halevy 		goto out_overflow;
4078aa53ed54SJeff Layton 	savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE);
4079aa53ed54SJeff Layton 	for (i = 0; i < savewords; ++i)
40806f723f77SBenny Halevy 		res->attrset[i] = be32_to_cpup(p++);
4081aa53ed54SJeff Layton 	for (; i < NFS4_BITMAP_SIZE; i++)
4082aa53ed54SJeff Layton 		res->attrset[i] = 0;
4083aa53ed54SJeff Layton 
40841da177e4SLinus Torvalds 	return decode_delegation(xdr, res);
40851da177e4SLinus Torvalds xdr_error:
40863110ff80SHarvey Harrison 	dprintk("%s: Bitmap too large! Length = %u\n", __func__, bmlen);
40871da177e4SLinus Torvalds 	return -EIO;
4088c0eae66eSBenny Halevy out_overflow:
4089c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4090c0eae66eSBenny Halevy 	return -EIO;
40911da177e4SLinus Torvalds }
40921da177e4SLinus Torvalds 
40931da177e4SLinus Torvalds static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
40941da177e4SLinus Torvalds {
40951da177e4SLinus Torvalds 	int status;
40961da177e4SLinus Torvalds 
40971da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
4098c1d51931STrond Myklebust 	if (status != -EIO)
4099c1d51931STrond Myklebust 		nfs_increment_open_seqid(status, res->seqid);
410007d30434SBenny Halevy 	if (!status)
410107d30434SBenny Halevy 		status = decode_stateid(xdr, &res->stateid);
41021da177e4SLinus Torvalds 	return status;
41031da177e4SLinus Torvalds }
41041da177e4SLinus Torvalds 
41051da177e4SLinus Torvalds static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
41061da177e4SLinus Torvalds {
41071da177e4SLinus Torvalds 	int status;
41081da177e4SLinus Torvalds 
41091da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE);
4110c1d51931STrond Myklebust 	if (status != -EIO)
4111c1d51931STrond Myklebust 		nfs_increment_open_seqid(status, res->seqid);
411207d30434SBenny Halevy 	if (!status)
411307d30434SBenny Halevy 		status = decode_stateid(xdr, &res->stateid);
41141da177e4SLinus Torvalds 	return status;
41151da177e4SLinus Torvalds }
41161da177e4SLinus Torvalds 
41171da177e4SLinus Torvalds static int decode_putfh(struct xdr_stream *xdr)
41181da177e4SLinus Torvalds {
41191da177e4SLinus Torvalds 	return decode_op_hdr(xdr, OP_PUTFH);
41201da177e4SLinus Torvalds }
41211da177e4SLinus Torvalds 
41221da177e4SLinus Torvalds static int decode_putrootfh(struct xdr_stream *xdr)
41231da177e4SLinus Torvalds {
41241da177e4SLinus Torvalds 	return decode_op_hdr(xdr, OP_PUTROOTFH);
41251da177e4SLinus Torvalds }
41261da177e4SLinus Torvalds 
41271da177e4SLinus Torvalds static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
41281da177e4SLinus Torvalds {
41291da177e4SLinus Torvalds 	struct kvec *iov = req->rq_rcv_buf.head;
41308687b63aSAl Viro 	__be32 *p;
41311da177e4SLinus Torvalds 	uint32_t count, eof, recvd, hdrlen;
41321da177e4SLinus Torvalds 	int status;
41331da177e4SLinus Torvalds 
41341da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_READ);
41351da177e4SLinus Torvalds 	if (status)
41361da177e4SLinus Torvalds 		return status;
4137c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
4138c0eae66eSBenny Halevy 	if (unlikely(!p))
4139c0eae66eSBenny Halevy 		goto out_overflow;
41406f723f77SBenny Halevy 	eof = be32_to_cpup(p++);
4141cccddf4fSBenny Halevy 	count = be32_to_cpup(p);
41421da177e4SLinus Torvalds 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
41431da177e4SLinus Torvalds 	recvd = req->rq_rcv_buf.len - hdrlen;
41441da177e4SLinus Torvalds 	if (count > recvd) {
4145fe82a183SChuck Lever 		dprintk("NFS: server cheating in read reply: "
41461da177e4SLinus Torvalds 				"count %u > recvd %u\n", count, recvd);
41471da177e4SLinus Torvalds 		count = recvd;
41481da177e4SLinus Torvalds 		eof = 0;
41491da177e4SLinus Torvalds 	}
41501da177e4SLinus Torvalds 	xdr_read_pages(xdr, count);
41511da177e4SLinus Torvalds 	res->eof = eof;
41521da177e4SLinus Torvalds 	res->count = count;
41531da177e4SLinus Torvalds 	return 0;
4154c0eae66eSBenny Halevy out_overflow:
4155c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4156c0eae66eSBenny Halevy 	return -EIO;
41571da177e4SLinus Torvalds }
41581da177e4SLinus Torvalds 
41591da177e4SLinus Torvalds static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
41601da177e4SLinus Torvalds {
41611da177e4SLinus Torvalds 	struct xdr_buf	*rcvbuf = &req->rq_rcv_buf;
41621da177e4SLinus Torvalds 	struct page	*page = *rcvbuf->pages;
41631da177e4SLinus Torvalds 	struct kvec	*iov = rcvbuf->head;
4164bcecff77SChuck Lever 	size_t		hdrlen;
4165bcecff77SChuck Lever 	u32		recvd, pglen = rcvbuf->page_len;
41668687b63aSAl Viro 	__be32		*end, *entry, *p, *kaddr;
41677bda2cdfSJeff Layton 	unsigned int	nr = 0;
4168bcecff77SChuck Lever 	int		status;
41691da177e4SLinus Torvalds 
41701da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_READDIR);
4171db942bbdSBenny Halevy 	if (!status)
4172db942bbdSBenny Halevy 		status = decode_verifier(xdr, readdir->verifier.data);
4173db942bbdSBenny Halevy 	if (unlikely(status))
41741da177e4SLinus Torvalds 		return status;
417544109241SFred Isaman 	dprintk("%s: verifier = %08x:%08x\n",
417644109241SFred Isaman 			__func__,
4177eadf4598STrond Myklebust 			((u32 *)readdir->verifier.data)[0],
4178eadf4598STrond Myklebust 			((u32 *)readdir->verifier.data)[1]);
4179eadf4598STrond Myklebust 
41801da177e4SLinus Torvalds 
4181db942bbdSBenny Halevy 	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
41821da177e4SLinus Torvalds 	recvd = rcvbuf->len - hdrlen;
41831da177e4SLinus Torvalds 	if (pglen > recvd)
41841da177e4SLinus Torvalds 		pglen = recvd;
41851da177e4SLinus Torvalds 	xdr_read_pages(xdr, pglen);
41861da177e4SLinus Torvalds 
41871da177e4SLinus Torvalds 	BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
41888687b63aSAl Viro 	kaddr = p = kmap_atomic(page, KM_USER0);
4189e8896495SDavid Howells 	end = p + ((pglen + readdir->pgbase) >> 2);
41901da177e4SLinus Torvalds 	entry = p;
41917bda2cdfSJeff Layton 
41927bda2cdfSJeff Layton 	/* Make sure the packet actually has a value_follows and EOF entry */
41937bda2cdfSJeff Layton 	if ((entry + 1) > end)
41947bda2cdfSJeff Layton 		goto short_pkt;
41957bda2cdfSJeff Layton 
41967bda2cdfSJeff Layton 	for (; *p++; nr++) {
4197bcecff77SChuck Lever 		u32 len, attrlen, xlen;
4198e8896495SDavid Howells 		if (end - p < 3)
41991da177e4SLinus Torvalds 			goto short_pkt;
4200eadf4598STrond Myklebust 		dprintk("cookie = %Lu, ", *((unsigned long long *)p));
42011da177e4SLinus Torvalds 		p += 2;			/* cookie */
42021da177e4SLinus Torvalds 		len = ntohl(*p++);	/* filename length */
42031da177e4SLinus Torvalds 		if (len > NFS4_MAXNAMLEN) {
4204fe82a183SChuck Lever 			dprintk("NFS: giant filename in readdir (len 0x%x)\n",
4205fe82a183SChuck Lever 					len);
42061da177e4SLinus Torvalds 			goto err_unmap;
42071da177e4SLinus Torvalds 		}
4208e8896495SDavid Howells 		xlen = XDR_QUADLEN(len);
4209e8896495SDavid Howells 		if (end - p < xlen + 1)
4210e8896495SDavid Howells 			goto short_pkt;
4211eadf4598STrond Myklebust 		dprintk("filename = %*s\n", len, (char *)p);
4212e8896495SDavid Howells 		p += xlen;
42131da177e4SLinus Torvalds 		len = ntohl(*p++);	/* bitmap length */
4214e8896495SDavid Howells 		if (end - p < len + 1)
4215e8896495SDavid Howells 			goto short_pkt;
42161da177e4SLinus Torvalds 		p += len;
42171da177e4SLinus Torvalds 		attrlen = XDR_QUADLEN(ntohl(*p++));
4218e8896495SDavid Howells 		if (end - p < attrlen + 2)
42191da177e4SLinus Torvalds 			goto short_pkt;
4220e8896495SDavid Howells 		p += attrlen;		/* attributes */
42211da177e4SLinus Torvalds 		entry = p;
42221da177e4SLinus Torvalds 	}
42237bda2cdfSJeff Layton 	/*
42247bda2cdfSJeff Layton 	 * Apparently some server sends responses that are a valid size, but
42257bda2cdfSJeff Layton 	 * contain no entries, and have value_follows==0 and EOF==0. For
42267bda2cdfSJeff Layton 	 * those, just set the EOF marker.
42277bda2cdfSJeff Layton 	 */
42287bda2cdfSJeff Layton 	if (!nr && entry[1] == 0) {
42297bda2cdfSJeff Layton 		dprintk("NFS: readdir reply truncated!\n");
42307bda2cdfSJeff Layton 		entry[1] = 1;
42317bda2cdfSJeff Layton 	}
42321da177e4SLinus Torvalds out:
42331da177e4SLinus Torvalds 	kunmap_atomic(kaddr, KM_USER0);
42341da177e4SLinus Torvalds 	return 0;
42351da177e4SLinus Torvalds short_pkt:
42367bda2cdfSJeff Layton 	/*
42377bda2cdfSJeff Layton 	 * When we get a short packet there are 2 possibilities. We can
42387bda2cdfSJeff Layton 	 * return an error, or fix up the response to look like a valid
42397bda2cdfSJeff Layton 	 * response and return what we have so far. If there are no
42407bda2cdfSJeff Layton 	 * entries and the packet was short, then return -EIO. If there
42417bda2cdfSJeff Layton 	 * are valid entries in the response, return them and pretend that
42427bda2cdfSJeff Layton 	 * the call was successful, but incomplete. The caller can retry the
42437bda2cdfSJeff Layton 	 * readdir starting at the last cookie.
42447bda2cdfSJeff Layton 	 */
42453110ff80SHarvey Harrison 	dprintk("%s: short packet at entry %d\n", __func__, nr);
42461da177e4SLinus Torvalds 	entry[0] = entry[1] = 0;
42477bda2cdfSJeff Layton 	if (nr)
42481da177e4SLinus Torvalds 		goto out;
42491da177e4SLinus Torvalds err_unmap:
42501da177e4SLinus Torvalds 	kunmap_atomic(kaddr, KM_USER0);
42511da177e4SLinus Torvalds 	return -errno_NFSERR_IO;
42521da177e4SLinus Torvalds }
42531da177e4SLinus Torvalds 
42541da177e4SLinus Torvalds static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
42551da177e4SLinus Torvalds {
42561da177e4SLinus Torvalds 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
42571da177e4SLinus Torvalds 	struct kvec *iov = rcvbuf->head;
4258bcecff77SChuck Lever 	size_t hdrlen;
4259bcecff77SChuck Lever 	u32 len, recvd;
42608687b63aSAl Viro 	__be32 *p;
42611da177e4SLinus Torvalds 	char *kaddr;
42621da177e4SLinus Torvalds 	int status;
42631da177e4SLinus Torvalds 
42641da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_READLINK);
42651da177e4SLinus Torvalds 	if (status)
42661da177e4SLinus Torvalds 		return status;
42671da177e4SLinus Torvalds 
42681da177e4SLinus Torvalds 	/* Convert length of symlink */
4269c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
4270c0eae66eSBenny Halevy 	if (unlikely(!p))
4271c0eae66eSBenny Halevy 		goto out_overflow;
4272cccddf4fSBenny Halevy 	len = be32_to_cpup(p);
42731da177e4SLinus Torvalds 	if (len >= rcvbuf->page_len || len <= 0) {
4274fe82a183SChuck Lever 		dprintk("nfs: server returned giant symlink!\n");
42751da177e4SLinus Torvalds 		return -ENAMETOOLONG;
42761da177e4SLinus Torvalds 	}
42771da177e4SLinus Torvalds 	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
42781da177e4SLinus Torvalds 	recvd = req->rq_rcv_buf.len - hdrlen;
42791da177e4SLinus Torvalds 	if (recvd < len) {
4280fe82a183SChuck Lever 		dprintk("NFS: server cheating in readlink reply: "
42811da177e4SLinus Torvalds 				"count %u > recvd %u\n", len, recvd);
42821da177e4SLinus Torvalds 		return -EIO;
42831da177e4SLinus Torvalds 	}
42841da177e4SLinus Torvalds 	xdr_read_pages(xdr, len);
42851da177e4SLinus Torvalds 	/*
42861da177e4SLinus Torvalds 	 * The XDR encode routine has set things up so that
42871da177e4SLinus Torvalds 	 * the link text will be copied directly into the
42881da177e4SLinus Torvalds 	 * buffer.  We just have to do overflow-checking,
42891da177e4SLinus Torvalds 	 * and and null-terminate the text (the VFS expects
42901da177e4SLinus Torvalds 	 * null-termination).
42911da177e4SLinus Torvalds 	 */
42921da177e4SLinus Torvalds 	kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
42931da177e4SLinus Torvalds 	kaddr[len+rcvbuf->page_base] = '\0';
42941da177e4SLinus Torvalds 	kunmap_atomic(kaddr, KM_USER0);
42951da177e4SLinus Torvalds 	return 0;
4296c0eae66eSBenny Halevy out_overflow:
4297c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4298c0eae66eSBenny Halevy 	return -EIO;
42991da177e4SLinus Torvalds }
43001da177e4SLinus Torvalds 
43011da177e4SLinus Torvalds static int decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
43021da177e4SLinus Torvalds {
43031da177e4SLinus Torvalds 	int status;
43041da177e4SLinus Torvalds 
43051da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_REMOVE);
43061da177e4SLinus Torvalds 	if (status)
43071da177e4SLinus Torvalds 		goto out;
43081da177e4SLinus Torvalds 	status = decode_change_info(xdr, cinfo);
43091da177e4SLinus Torvalds out:
43101da177e4SLinus Torvalds 	return status;
43111da177e4SLinus Torvalds }
43121da177e4SLinus Torvalds 
43131da177e4SLinus Torvalds static int decode_rename(struct xdr_stream *xdr, struct nfs4_change_info *old_cinfo,
43141da177e4SLinus Torvalds 	      struct nfs4_change_info *new_cinfo)
43151da177e4SLinus Torvalds {
43161da177e4SLinus Torvalds 	int status;
43171da177e4SLinus Torvalds 
43181da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_RENAME);
43191da177e4SLinus Torvalds 	if (status)
43201da177e4SLinus Torvalds 		goto out;
43211da177e4SLinus Torvalds 	if ((status = decode_change_info(xdr, old_cinfo)))
43221da177e4SLinus Torvalds 		goto out;
43231da177e4SLinus Torvalds 	status = decode_change_info(xdr, new_cinfo);
43241da177e4SLinus Torvalds out:
43251da177e4SLinus Torvalds 	return status;
43261da177e4SLinus Torvalds }
43271da177e4SLinus Torvalds 
43281da177e4SLinus Torvalds static int decode_renew(struct xdr_stream *xdr)
43291da177e4SLinus Torvalds {
43301da177e4SLinus Torvalds 	return decode_op_hdr(xdr, OP_RENEW);
43311da177e4SLinus Torvalds }
43321da177e4SLinus Torvalds 
433356ae19f3STrond Myklebust static int
433456ae19f3STrond Myklebust decode_restorefh(struct xdr_stream *xdr)
433556ae19f3STrond Myklebust {
433656ae19f3STrond Myklebust 	return decode_op_hdr(xdr, OP_RESTOREFH);
433756ae19f3STrond Myklebust }
433856ae19f3STrond Myklebust 
4339029d105eSJ. Bruce Fields static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
4340029d105eSJ. Bruce Fields 		size_t *acl_len)
4341029d105eSJ. Bruce Fields {
43428687b63aSAl Viro 	__be32 *savep;
4343029d105eSJ. Bruce Fields 	uint32_t attrlen,
4344029d105eSJ. Bruce Fields 		 bitmap[2] = {0};
4345029d105eSJ. Bruce Fields 	struct kvec *iov = req->rq_rcv_buf.head;
4346029d105eSJ. Bruce Fields 	int status;
4347029d105eSJ. Bruce Fields 
4348029d105eSJ. Bruce Fields 	*acl_len = 0;
4349029d105eSJ. Bruce Fields 	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
4350029d105eSJ. Bruce Fields 		goto out;
4351029d105eSJ. Bruce Fields 	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
4352029d105eSJ. Bruce Fields 		goto out;
4353029d105eSJ. Bruce Fields 	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
4354029d105eSJ. Bruce Fields 		goto out;
4355029d105eSJ. Bruce Fields 
4356029d105eSJ. Bruce Fields 	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
4357029d105eSJ. Bruce Fields 		return -EIO;
4358029d105eSJ. Bruce Fields 	if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
4359bcecff77SChuck Lever 		size_t hdrlen;
4360bcecff77SChuck Lever 		u32 recvd;
4361029d105eSJ. Bruce Fields 
4362029d105eSJ. Bruce Fields 		/* We ignore &savep and don't do consistency checks on
4363029d105eSJ. Bruce Fields 		 * the attr length.  Let userspace figure it out.... */
4364029d105eSJ. Bruce Fields 		hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
4365029d105eSJ. Bruce Fields 		recvd = req->rq_rcv_buf.len - hdrlen;
4366029d105eSJ. Bruce Fields 		if (attrlen > recvd) {
4367fe82a183SChuck Lever 			dprintk("NFS: server cheating in getattr"
4368029d105eSJ. Bruce Fields 					" acl reply: attrlen %u > recvd %u\n",
4369029d105eSJ. Bruce Fields 					attrlen, recvd);
4370029d105eSJ. Bruce Fields 			return -EINVAL;
4371029d105eSJ. Bruce Fields 		}
4372029d105eSJ. Bruce Fields 		xdr_read_pages(xdr, attrlen);
4373029d105eSJ. Bruce Fields 		*acl_len = attrlen;
43748c233cf9SJ. Bruce Fields 	} else
43758c233cf9SJ. Bruce Fields 		status = -EOPNOTSUPP;
4376029d105eSJ. Bruce Fields 
4377029d105eSJ. Bruce Fields out:
4378029d105eSJ. Bruce Fields 	return status;
4379029d105eSJ. Bruce Fields }
4380029d105eSJ. Bruce Fields 
43811da177e4SLinus Torvalds static int
43821da177e4SLinus Torvalds decode_savefh(struct xdr_stream *xdr)
43831da177e4SLinus Torvalds {
43841da177e4SLinus Torvalds 	return decode_op_hdr(xdr, OP_SAVEFH);
43851da177e4SLinus Torvalds }
43861da177e4SLinus Torvalds 
43879e9ecc03SBenny Halevy static int decode_setattr(struct xdr_stream *xdr)
43881da177e4SLinus Torvalds {
43898687b63aSAl Viro 	__be32 *p;
43901da177e4SLinus Torvalds 	uint32_t bmlen;
43911da177e4SLinus Torvalds 	int status;
43921da177e4SLinus Torvalds 
43931da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_SETATTR);
43941da177e4SLinus Torvalds 	if (status)
43951da177e4SLinus Torvalds 		return status;
4396c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
4397c0eae66eSBenny Halevy 	if (unlikely(!p))
4398c0eae66eSBenny Halevy 		goto out_overflow;
4399cccddf4fSBenny Halevy 	bmlen = be32_to_cpup(p);
4400c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, bmlen << 2);
4401c0eae66eSBenny Halevy 	if (likely(p))
44021da177e4SLinus Torvalds 		return 0;
4403c0eae66eSBenny Halevy out_overflow:
4404c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4405c0eae66eSBenny Halevy 	return -EIO;
44061da177e4SLinus Torvalds }
44071da177e4SLinus Torvalds 
4408bb8b27e5STrond Myklebust static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid_res *res)
44091da177e4SLinus Torvalds {
44108687b63aSAl Viro 	__be32 *p;
44111da177e4SLinus Torvalds 	uint32_t opnum;
44121da177e4SLinus Torvalds 	int32_t nfserr;
44131da177e4SLinus Torvalds 
4414c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
4415c0eae66eSBenny Halevy 	if (unlikely(!p))
4416c0eae66eSBenny Halevy 		goto out_overflow;
44176f723f77SBenny Halevy 	opnum = be32_to_cpup(p++);
44181da177e4SLinus Torvalds 	if (opnum != OP_SETCLIENTID) {
4419fe82a183SChuck Lever 		dprintk("nfs: decode_setclientid: Server returned operation"
44201da177e4SLinus Torvalds 			" %d\n", opnum);
44211da177e4SLinus Torvalds 		return -EIO;
44221da177e4SLinus Torvalds 	}
4423cccddf4fSBenny Halevy 	nfserr = be32_to_cpup(p);
44241da177e4SLinus Torvalds 	if (nfserr == NFS_OK) {
4425c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE);
4426c0eae66eSBenny Halevy 		if (unlikely(!p))
4427c0eae66eSBenny Halevy 			goto out_overflow;
4428bb8b27e5STrond Myklebust 		p = xdr_decode_hyper(p, &res->clientid);
4429bb8b27e5STrond Myklebust 		memcpy(res->confirm.data, p, NFS4_VERIFIER_SIZE);
44301da177e4SLinus Torvalds 	} else if (nfserr == NFSERR_CLID_INUSE) {
44311da177e4SLinus Torvalds 		uint32_t len;
44321da177e4SLinus Torvalds 
44331da177e4SLinus Torvalds 		/* skip netid string */
4434c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
4435c0eae66eSBenny Halevy 		if (unlikely(!p))
4436c0eae66eSBenny Halevy 			goto out_overflow;
4437cccddf4fSBenny Halevy 		len = be32_to_cpup(p);
4438c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, len);
4439c0eae66eSBenny Halevy 		if (unlikely(!p))
4440c0eae66eSBenny Halevy 			goto out_overflow;
44411da177e4SLinus Torvalds 
44421da177e4SLinus Torvalds 		/* skip uaddr string */
4443c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
4444c0eae66eSBenny Halevy 		if (unlikely(!p))
4445c0eae66eSBenny Halevy 			goto out_overflow;
4446cccddf4fSBenny Halevy 		len = be32_to_cpup(p);
4447c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, len);
4448c0eae66eSBenny Halevy 		if (unlikely(!p))
4449c0eae66eSBenny Halevy 			goto out_overflow;
44501da177e4SLinus Torvalds 		return -NFSERR_CLID_INUSE;
44511da177e4SLinus Torvalds 	} else
4452856dff3dSBenny Halevy 		return nfs4_stat_to_errno(nfserr);
44531da177e4SLinus Torvalds 
44541da177e4SLinus Torvalds 	return 0;
4455c0eae66eSBenny Halevy out_overflow:
4456c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4457c0eae66eSBenny Halevy 	return -EIO;
44581da177e4SLinus Torvalds }
44591da177e4SLinus Torvalds 
44601da177e4SLinus Torvalds static int decode_setclientid_confirm(struct xdr_stream *xdr)
44611da177e4SLinus Torvalds {
44621da177e4SLinus Torvalds 	return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM);
44631da177e4SLinus Torvalds }
44641da177e4SLinus Torvalds 
44651da177e4SLinus Torvalds static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
44661da177e4SLinus Torvalds {
44678687b63aSAl Viro 	__be32 *p;
44681da177e4SLinus Torvalds 	int status;
44691da177e4SLinus Torvalds 
44701da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_WRITE);
44711da177e4SLinus Torvalds 	if (status)
44721da177e4SLinus Torvalds 		return status;
44731da177e4SLinus Torvalds 
4474c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 16);
4475c0eae66eSBenny Halevy 	if (unlikely(!p))
4476c0eae66eSBenny Halevy 		goto out_overflow;
44776f723f77SBenny Halevy 	res->count = be32_to_cpup(p++);
44786f723f77SBenny Halevy 	res->verf->committed = be32_to_cpup(p++);
447999398d06SBenny Halevy 	memcpy(res->verf->verifier, p, 8);
44801da177e4SLinus Torvalds 	return 0;
4481c0eae66eSBenny Halevy out_overflow:
4482c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4483c0eae66eSBenny Halevy 	return -EIO;
44841da177e4SLinus Torvalds }
44851da177e4SLinus Torvalds 
44861da177e4SLinus Torvalds static int decode_delegreturn(struct xdr_stream *xdr)
44871da177e4SLinus Torvalds {
44881da177e4SLinus Torvalds 	return decode_op_hdr(xdr, OP_DELEGRETURN);
44891da177e4SLinus Torvalds }
44901da177e4SLinus Torvalds 
449199fe60d0SBenny Halevy #if defined(CONFIG_NFS_V4_1)
449299fe60d0SBenny Halevy static int decode_exchange_id(struct xdr_stream *xdr,
449399fe60d0SBenny Halevy 			      struct nfs41_exchange_id_res *res)
449499fe60d0SBenny Halevy {
449599fe60d0SBenny Halevy 	__be32 *p;
449699fe60d0SBenny Halevy 	uint32_t dummy;
44972460ba57SBenny Halevy 	char *dummy_str;
449899fe60d0SBenny Halevy 	int status;
449999fe60d0SBenny Halevy 	struct nfs_client *clp = res->client;
450099fe60d0SBenny Halevy 
450199fe60d0SBenny Halevy 	status = decode_op_hdr(xdr, OP_EXCHANGE_ID);
450299fe60d0SBenny Halevy 	if (status)
450399fe60d0SBenny Halevy 		return status;
450499fe60d0SBenny Halevy 
4505c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
4506c0eae66eSBenny Halevy 	if (unlikely(!p))
4507c0eae66eSBenny Halevy 		goto out_overflow;
4508cccddf4fSBenny Halevy 	xdr_decode_hyper(p, &clp->cl_ex_clid);
4509c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 12);
4510c0eae66eSBenny Halevy 	if (unlikely(!p))
4511c0eae66eSBenny Halevy 		goto out_overflow;
45126f723f77SBenny Halevy 	clp->cl_seqid = be32_to_cpup(p++);
45136f723f77SBenny Halevy 	clp->cl_exchange_flags = be32_to_cpup(p++);
451499fe60d0SBenny Halevy 
451599fe60d0SBenny Halevy 	/* We ask for SP4_NONE */
4516cccddf4fSBenny Halevy 	dummy = be32_to_cpup(p);
451799fe60d0SBenny Halevy 	if (dummy != SP4_NONE)
451899fe60d0SBenny Halevy 		return -EIO;
451999fe60d0SBenny Halevy 
452099fe60d0SBenny Halevy 	/* Throw away minor_id */
4521c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
4522c0eae66eSBenny Halevy 	if (unlikely(!p))
4523c0eae66eSBenny Halevy 		goto out_overflow;
452499fe60d0SBenny Halevy 
452599fe60d0SBenny Halevy 	/* Throw away Major id */
45262460ba57SBenny Halevy 	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
45272460ba57SBenny Halevy 	if (unlikely(status))
45282460ba57SBenny Halevy 		return status;
452999fe60d0SBenny Halevy 
453099fe60d0SBenny Halevy 	/* Throw away server_scope */
45312460ba57SBenny Halevy 	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
45322460ba57SBenny Halevy 	if (unlikely(status))
45332460ba57SBenny Halevy 		return status;
453499fe60d0SBenny Halevy 
453599fe60d0SBenny Halevy 	/* Throw away Implementation id array */
45362460ba57SBenny Halevy 	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
45372460ba57SBenny Halevy 	if (unlikely(status))
45382460ba57SBenny Halevy 		return status;
453999fe60d0SBenny Halevy 
454099fe60d0SBenny Halevy 	return 0;
4541c0eae66eSBenny Halevy out_overflow:
4542c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4543c0eae66eSBenny Halevy 	return -EIO;
454499fe60d0SBenny Halevy }
4545fc931582SAndy Adamson 
4546fc931582SAndy Adamson static int decode_chan_attrs(struct xdr_stream *xdr,
4547fc931582SAndy Adamson 			     struct nfs4_channel_attrs *attrs)
4548fc931582SAndy Adamson {
4549fc931582SAndy Adamson 	__be32 *p;
4550fc931582SAndy Adamson 	u32 nr_attrs;
4551fc931582SAndy Adamson 
4552c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 28);
4553c0eae66eSBenny Halevy 	if (unlikely(!p))
4554c0eae66eSBenny Halevy 		goto out_overflow;
45556f723f77SBenny Halevy 	attrs->headerpadsz = be32_to_cpup(p++);
45566f723f77SBenny Halevy 	attrs->max_rqst_sz = be32_to_cpup(p++);
45576f723f77SBenny Halevy 	attrs->max_resp_sz = be32_to_cpup(p++);
45586f723f77SBenny Halevy 	attrs->max_resp_sz_cached = be32_to_cpup(p++);
45596f723f77SBenny Halevy 	attrs->max_ops = be32_to_cpup(p++);
45606f723f77SBenny Halevy 	attrs->max_reqs = be32_to_cpup(p++);
4561cccddf4fSBenny Halevy 	nr_attrs = be32_to_cpup(p);
4562fc931582SAndy Adamson 	if (unlikely(nr_attrs > 1)) {
4563fc931582SAndy Adamson 		printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n",
4564fc931582SAndy Adamson 			__func__, nr_attrs);
4565fc931582SAndy Adamson 		return -EINVAL;
4566fc931582SAndy Adamson 	}
4567c0eae66eSBenny Halevy 	if (nr_attrs == 1) {
4568c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4); /* skip rdma_attrs */
4569c0eae66eSBenny Halevy 		if (unlikely(!p))
4570c0eae66eSBenny Halevy 			goto out_overflow;
4571c0eae66eSBenny Halevy 	}
4572fc931582SAndy Adamson 	return 0;
4573c0eae66eSBenny Halevy out_overflow:
4574c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4575c0eae66eSBenny Halevy 	return -EIO;
4576fc931582SAndy Adamson }
4577fc931582SAndy Adamson 
4578e78291e4SBenny Halevy static int decode_sessionid(struct xdr_stream *xdr, struct nfs4_sessionid *sid)
4579e78291e4SBenny Halevy {
4580e78291e4SBenny Halevy 	return decode_opaque_fixed(xdr, sid->data, NFS4_MAX_SESSIONID_LEN);
4581fc931582SAndy Adamson }
4582fc931582SAndy Adamson 
4583fc931582SAndy Adamson static int decode_create_session(struct xdr_stream *xdr,
4584fc931582SAndy Adamson 				 struct nfs41_create_session_res *res)
4585fc931582SAndy Adamson {
4586fc931582SAndy Adamson 	__be32 *p;
4587fc931582SAndy Adamson 	int status;
4588fc931582SAndy Adamson 	struct nfs_client *clp = res->client;
4589fc931582SAndy Adamson 	struct nfs4_session *session = clp->cl_session;
4590fc931582SAndy Adamson 
4591fc931582SAndy Adamson 	status = decode_op_hdr(xdr, OP_CREATE_SESSION);
4592e78291e4SBenny Halevy 	if (!status)
4593e78291e4SBenny Halevy 		status = decode_sessionid(xdr, &session->sess_id);
4594e78291e4SBenny Halevy 	if (unlikely(status))
4595fc931582SAndy Adamson 		return status;
4596fc931582SAndy Adamson 
4597fc931582SAndy Adamson 	/* seqid, flags */
4598c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
4599c0eae66eSBenny Halevy 	if (unlikely(!p))
4600c0eae66eSBenny Halevy 		goto out_overflow;
46016f723f77SBenny Halevy 	clp->cl_seqid = be32_to_cpup(p++);
4602cccddf4fSBenny Halevy 	session->flags = be32_to_cpup(p);
4603fc931582SAndy Adamson 
4604fc931582SAndy Adamson 	/* Channel attributes */
4605fc931582SAndy Adamson 	status = decode_chan_attrs(xdr, &session->fc_attrs);
4606fc931582SAndy Adamson 	if (!status)
4607fc931582SAndy Adamson 		status = decode_chan_attrs(xdr, &session->bc_attrs);
4608fc931582SAndy Adamson 	return status;
4609c0eae66eSBenny Halevy out_overflow:
4610c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4611c0eae66eSBenny Halevy 	return -EIO;
4612fc931582SAndy Adamson }
46130f3e66c6SAndy Adamson 
46140f3e66c6SAndy Adamson static int decode_destroy_session(struct xdr_stream *xdr, void *dummy)
46150f3e66c6SAndy Adamson {
46160f3e66c6SAndy Adamson 	return decode_op_hdr(xdr, OP_DESTROY_SESSION);
46170f3e66c6SAndy Adamson }
461818019753SRicardo Labiaga 
461918019753SRicardo Labiaga static int decode_reclaim_complete(struct xdr_stream *xdr, void *dummy)
462018019753SRicardo Labiaga {
462118019753SRicardo Labiaga 	return decode_op_hdr(xdr, OP_RECLAIM_COMPLETE);
462218019753SRicardo Labiaga }
462399fe60d0SBenny Halevy #endif /* CONFIG_NFS_V4_1 */
462499fe60d0SBenny Halevy 
46259b7b9fccSAndy Adamson static int decode_sequence(struct xdr_stream *xdr,
46269b7b9fccSAndy Adamson 			   struct nfs4_sequence_res *res,
46279b7b9fccSAndy Adamson 			   struct rpc_rqst *rqstp)
46289b7b9fccSAndy Adamson {
46299b7b9fccSAndy Adamson #if defined(CONFIG_NFS_V4_1)
4630fc01cea9SAndy Adamson 	struct nfs4_slot *slot;
4631fc01cea9SAndy Adamson 	struct nfs4_sessionid id;
4632fc01cea9SAndy Adamson 	u32 dummy;
4633fc01cea9SAndy Adamson 	int status;
4634fc01cea9SAndy Adamson 	__be32 *p;
4635fc01cea9SAndy Adamson 
46369b7b9fccSAndy Adamson 	if (!res->sr_session)
46379b7b9fccSAndy Adamson 		return 0;
46389b7b9fccSAndy Adamson 
4639fc01cea9SAndy Adamson 	status = decode_op_hdr(xdr, OP_SEQUENCE);
4640e78291e4SBenny Halevy 	if (!status)
4641e78291e4SBenny Halevy 		status = decode_sessionid(xdr, &id);
4642e78291e4SBenny Halevy 	if (unlikely(status))
4643fc01cea9SAndy Adamson 		goto out_err;
46449b7b9fccSAndy Adamson 
4645fc01cea9SAndy Adamson 	/*
4646fc01cea9SAndy Adamson 	 * If the server returns different values for sessionID, slotID or
4647fc01cea9SAndy Adamson 	 * sequence number, the server is looney tunes.
4648fc01cea9SAndy Adamson 	 */
4649fdcb4577STrond Myklebust 	status = -EREMOTEIO;
4650fc01cea9SAndy Adamson 
4651fc01cea9SAndy Adamson 	if (memcmp(id.data, res->sr_session->sess_id.data,
4652fc01cea9SAndy Adamson 		   NFS4_MAX_SESSIONID_LEN)) {
4653fc01cea9SAndy Adamson 		dprintk("%s Invalid session id\n", __func__);
4654fc01cea9SAndy Adamson 		goto out_err;
4655fc01cea9SAndy Adamson 	}
4656e78291e4SBenny Halevy 
4657c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 20);
4658c0eae66eSBenny Halevy 	if (unlikely(!p))
4659c0eae66eSBenny Halevy 		goto out_overflow;
4660e78291e4SBenny Halevy 
4661fc01cea9SAndy Adamson 	/* seqid */
4662e78291e4SBenny Halevy 	slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid];
46636f723f77SBenny Halevy 	dummy = be32_to_cpup(p++);
4664fc01cea9SAndy Adamson 	if (dummy != slot->seq_nr) {
4665fc01cea9SAndy Adamson 		dprintk("%s Invalid sequence number\n", __func__);
4666fc01cea9SAndy Adamson 		goto out_err;
4667fc01cea9SAndy Adamson 	}
4668fc01cea9SAndy Adamson 	/* slot id */
46696f723f77SBenny Halevy 	dummy = be32_to_cpup(p++);
4670fc01cea9SAndy Adamson 	if (dummy != res->sr_slotid) {
4671fc01cea9SAndy Adamson 		dprintk("%s Invalid slot id\n", __func__);
4672fc01cea9SAndy Adamson 		goto out_err;
4673fc01cea9SAndy Adamson 	}
4674fc01cea9SAndy Adamson 	/* highest slot id - currently not processed */
46756f723f77SBenny Halevy 	dummy = be32_to_cpup(p++);
4676fc01cea9SAndy Adamson 	/* target highest slot id - currently not processed */
46776f723f77SBenny Halevy 	dummy = be32_to_cpup(p++);
46780629e370SAlexandros Batsakis 	/* result flags */
46790629e370SAlexandros Batsakis 	res->sr_status_flags = be32_to_cpup(p);
4680fc01cea9SAndy Adamson 	status = 0;
4681fc01cea9SAndy Adamson out_err:
4682fc01cea9SAndy Adamson 	res->sr_status = status;
4683fc01cea9SAndy Adamson 	return status;
4684c0eae66eSBenny Halevy out_overflow:
4685c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4686c0eae66eSBenny Halevy 	status = -EIO;
4687c0eae66eSBenny Halevy 	goto out_err;
4688fc01cea9SAndy Adamson #else  /* CONFIG_NFS_V4_1 */
46899b7b9fccSAndy Adamson 	return 0;
4690fc01cea9SAndy Adamson #endif /* CONFIG_NFS_V4_1 */
46919b7b9fccSAndy Adamson }
46929b7b9fccSAndy Adamson 
46931da177e4SLinus Torvalds /*
469449c2559eSBenny Halevy  * END OF "GENERIC" DECODE ROUTINES.
469549c2559eSBenny Halevy  */
469649c2559eSBenny Halevy 
469749c2559eSBenny Halevy /*
46981da177e4SLinus Torvalds  * Decode OPEN_DOWNGRADE response
46991da177e4SLinus Torvalds  */
47008687b63aSAl Viro static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
47011da177e4SLinus Torvalds {
47021da177e4SLinus Torvalds 	struct xdr_stream xdr;
47031da177e4SLinus Torvalds 	struct compound_hdr hdr;
47041da177e4SLinus Torvalds 	int status;
47051da177e4SLinus Torvalds 
47061da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
47071da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
47081da177e4SLinus Torvalds 	if (status)
47091da177e4SLinus Torvalds 		goto out;
47109b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
47119b7b9fccSAndy Adamson 	if (status)
47129b7b9fccSAndy Adamson 		goto out;
47131da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
47141da177e4SLinus Torvalds 	if (status)
47151da177e4SLinus Torvalds 		goto out;
47161da177e4SLinus Torvalds 	status = decode_open_downgrade(&xdr, res);
4717516a6af6STrond Myklebust 	if (status != 0)
4718516a6af6STrond Myklebust 		goto out;
471980e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->fattr, res->server,
472080e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
47211da177e4SLinus Torvalds out:
47221da177e4SLinus Torvalds 	return status;
47231da177e4SLinus Torvalds }
47241da177e4SLinus Torvalds 
47251da177e4SLinus Torvalds /*
47261da177e4SLinus Torvalds  * Decode ACCESS response
47271da177e4SLinus Torvalds  */
47288687b63aSAl Viro static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res)
47291da177e4SLinus Torvalds {
47301da177e4SLinus Torvalds 	struct xdr_stream xdr;
47311da177e4SLinus Torvalds 	struct compound_hdr hdr;
47321da177e4SLinus Torvalds 	int status;
47331da177e4SLinus Torvalds 
47341da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
47359b7b9fccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
47369b7b9fccSAndy Adamson 	if (status)
47379b7b9fccSAndy Adamson 		goto out;
47389b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
47399b7b9fccSAndy Adamson 	if (status)
47401da177e4SLinus Torvalds 		goto out;
474176b32999STrond Myklebust 	status = decode_putfh(&xdr);
474276b32999STrond Myklebust 	if (status != 0)
474376b32999STrond Myklebust 		goto out;
47441da177e4SLinus Torvalds 	status = decode_access(&xdr, res);
474576b32999STrond Myklebust 	if (status != 0)
474676b32999STrond Myklebust 		goto out;
474780e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->fattr, res->server,
474880e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
47491da177e4SLinus Torvalds out:
47501da177e4SLinus Torvalds 	return status;
47511da177e4SLinus Torvalds }
47521da177e4SLinus Torvalds 
47531da177e4SLinus Torvalds /*
47541da177e4SLinus Torvalds  * Decode LOOKUP response
47551da177e4SLinus Torvalds  */
47568687b63aSAl Viro static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
47571da177e4SLinus Torvalds {
47581da177e4SLinus Torvalds 	struct xdr_stream xdr;
47591da177e4SLinus Torvalds 	struct compound_hdr hdr;
47601da177e4SLinus Torvalds 	int status;
47611da177e4SLinus Torvalds 
47621da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
47639b7b9fccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
47649b7b9fccSAndy Adamson 	if (status)
47659b7b9fccSAndy Adamson 		goto out;
47669b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
47679b7b9fccSAndy Adamson 	if (status)
47681da177e4SLinus Torvalds 		goto out;
47691da177e4SLinus Torvalds 	if ((status = decode_putfh(&xdr)) != 0)
47701da177e4SLinus Torvalds 		goto out;
47711da177e4SLinus Torvalds 	if ((status = decode_lookup(&xdr)) != 0)
47721da177e4SLinus Torvalds 		goto out;
47731da177e4SLinus Torvalds 	if ((status = decode_getfh(&xdr, res->fh)) != 0)
47741da177e4SLinus Torvalds 		goto out;
477580e52aceSTrond Myklebust 	status = decode_getfattr(&xdr, res->fattr, res->server
477680e52aceSTrond Myklebust 			,!RPC_IS_ASYNC(rqstp->rq_task));
47771da177e4SLinus Torvalds out:
47781da177e4SLinus Torvalds 	return status;
47791da177e4SLinus Torvalds }
47801da177e4SLinus Torvalds 
47811da177e4SLinus Torvalds /*
47821da177e4SLinus Torvalds  * Decode LOOKUP_ROOT response
47831da177e4SLinus Torvalds  */
47848687b63aSAl Viro static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
47851da177e4SLinus Torvalds {
47861da177e4SLinus Torvalds 	struct xdr_stream xdr;
47871da177e4SLinus Torvalds 	struct compound_hdr hdr;
47881da177e4SLinus Torvalds 	int status;
47891da177e4SLinus Torvalds 
47901da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
47919b7b9fccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
47929b7b9fccSAndy Adamson 	if (status)
47939b7b9fccSAndy Adamson 		goto out;
47949b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
47959b7b9fccSAndy Adamson 	if (status)
47961da177e4SLinus Torvalds 		goto out;
47971da177e4SLinus Torvalds 	if ((status = decode_putrootfh(&xdr)) != 0)
47981da177e4SLinus Torvalds 		goto out;
47991da177e4SLinus Torvalds 	if ((status = decode_getfh(&xdr, res->fh)) == 0)
480080e52aceSTrond Myklebust 		status = decode_getfattr(&xdr, res->fattr, res->server,
480180e52aceSTrond Myklebust 				!RPC_IS_ASYNC(rqstp->rq_task));
48021da177e4SLinus Torvalds out:
48031da177e4SLinus Torvalds 	return status;
48041da177e4SLinus Torvalds }
48051da177e4SLinus Torvalds 
48061da177e4SLinus Torvalds /*
48071da177e4SLinus Torvalds  * Decode REMOVE response
48081da177e4SLinus Torvalds  */
48094fdc17b2STrond Myklebust static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_removeres *res)
48101da177e4SLinus Torvalds {
48111da177e4SLinus Torvalds 	struct xdr_stream xdr;
48121da177e4SLinus Torvalds 	struct compound_hdr hdr;
48131da177e4SLinus Torvalds 	int status;
48141da177e4SLinus Torvalds 
48151da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
48169b7b9fccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
48179b7b9fccSAndy Adamson 	if (status)
48189b7b9fccSAndy Adamson 		goto out;
48199b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
48209b7b9fccSAndy Adamson 	if (status)
48211da177e4SLinus Torvalds 		goto out;
482216e42959STrond Myklebust 	if ((status = decode_putfh(&xdr)) != 0)
482316e42959STrond Myklebust 		goto out;
482416e42959STrond Myklebust 	if ((status = decode_remove(&xdr, &res->cinfo)) != 0)
482516e42959STrond Myklebust 		goto out;
4826d346890bSTrond Myklebust 	decode_getfattr(&xdr, res->dir_attr, res->server,
482780e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
48281da177e4SLinus Torvalds out:
48291da177e4SLinus Torvalds 	return status;
48301da177e4SLinus Torvalds }
48311da177e4SLinus Torvalds 
48321da177e4SLinus Torvalds /*
48331da177e4SLinus Torvalds  * Decode RENAME response
48341da177e4SLinus Torvalds  */
48358687b63aSAl Viro static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res)
48361da177e4SLinus Torvalds {
48371da177e4SLinus Torvalds 	struct xdr_stream xdr;
48381da177e4SLinus Torvalds 	struct compound_hdr hdr;
48391da177e4SLinus Torvalds 	int status;
48401da177e4SLinus Torvalds 
48411da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
48429b7b9fccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
48439b7b9fccSAndy Adamson 	if (status)
48449b7b9fccSAndy Adamson 		goto out;
48459b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
48469b7b9fccSAndy Adamson 	if (status)
48471da177e4SLinus Torvalds 		goto out;
48481da177e4SLinus Torvalds 	if ((status = decode_putfh(&xdr)) != 0)
48491da177e4SLinus Torvalds 		goto out;
48501da177e4SLinus Torvalds 	if ((status = decode_savefh(&xdr)) != 0)
48511da177e4SLinus Torvalds 		goto out;
48521da177e4SLinus Torvalds 	if ((status = decode_putfh(&xdr)) != 0)
48531da177e4SLinus Torvalds 		goto out;
48546caf2c82STrond Myklebust 	if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0)
48556caf2c82STrond Myklebust 		goto out;
48566caf2c82STrond Myklebust 	/* Current FH is target directory */
485780e52aceSTrond Myklebust 	if (decode_getfattr(&xdr, res->new_fattr, res->server,
485880e52aceSTrond Myklebust 				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
48596caf2c82STrond Myklebust 		goto out;
48606caf2c82STrond Myklebust 	if ((status = decode_restorefh(&xdr)) != 0)
48616caf2c82STrond Myklebust 		goto out;
486280e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->old_fattr, res->server,
486380e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
48641da177e4SLinus Torvalds out:
48651da177e4SLinus Torvalds 	return status;
48661da177e4SLinus Torvalds }
48671da177e4SLinus Torvalds 
48681da177e4SLinus Torvalds /*
48691da177e4SLinus Torvalds  * Decode LINK response
48701da177e4SLinus Torvalds  */
48718687b63aSAl Viro static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link_res *res)
48721da177e4SLinus Torvalds {
48731da177e4SLinus Torvalds 	struct xdr_stream xdr;
48741da177e4SLinus Torvalds 	struct compound_hdr hdr;
48751da177e4SLinus Torvalds 	int status;
48761da177e4SLinus Torvalds 
48771da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
48789b7b9fccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
48799b7b9fccSAndy Adamson 	if (status)
48809b7b9fccSAndy Adamson 		goto out;
48819b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
48829b7b9fccSAndy Adamson 	if (status)
48831da177e4SLinus Torvalds 		goto out;
48841da177e4SLinus Torvalds 	if ((status = decode_putfh(&xdr)) != 0)
48851da177e4SLinus Torvalds 		goto out;
48861da177e4SLinus Torvalds 	if ((status = decode_savefh(&xdr)) != 0)
48871da177e4SLinus Torvalds 		goto out;
48881da177e4SLinus Torvalds 	if ((status = decode_putfh(&xdr)) != 0)
48891da177e4SLinus Torvalds 		goto out;
489091ba2eeeSTrond Myklebust 	if ((status = decode_link(&xdr, &res->cinfo)) != 0)
489191ba2eeeSTrond Myklebust 		goto out;
489291ba2eeeSTrond Myklebust 	/*
489391ba2eeeSTrond Myklebust 	 * Note order: OP_LINK leaves the directory as the current
489491ba2eeeSTrond Myklebust 	 *             filehandle.
489591ba2eeeSTrond Myklebust 	 */
489680e52aceSTrond Myklebust 	if (decode_getfattr(&xdr, res->dir_attr, res->server,
489780e52aceSTrond Myklebust 				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
489891ba2eeeSTrond Myklebust 		goto out;
489991ba2eeeSTrond Myklebust 	if ((status = decode_restorefh(&xdr)) != 0)
490091ba2eeeSTrond Myklebust 		goto out;
490180e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->fattr, res->server,
490280e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
49031da177e4SLinus Torvalds out:
49041da177e4SLinus Torvalds 	return status;
49051da177e4SLinus Torvalds }
49061da177e4SLinus Torvalds 
49071da177e4SLinus Torvalds /*
49081da177e4SLinus Torvalds  * Decode CREATE response
49091da177e4SLinus Torvalds  */
49108687b63aSAl Viro static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
49111da177e4SLinus Torvalds {
49121da177e4SLinus Torvalds 	struct xdr_stream xdr;
49131da177e4SLinus Torvalds 	struct compound_hdr hdr;
49141da177e4SLinus Torvalds 	int status;
49151da177e4SLinus Torvalds 
49161da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
49179b7b9fccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
49189b7b9fccSAndy Adamson 	if (status)
49199b7b9fccSAndy Adamson 		goto out;
49209b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
49219b7b9fccSAndy Adamson 	if (status)
49221da177e4SLinus Torvalds 		goto out;
49231da177e4SLinus Torvalds 	if ((status = decode_putfh(&xdr)) != 0)
49241da177e4SLinus Torvalds 		goto out;
492556ae19f3STrond Myklebust 	if ((status = decode_savefh(&xdr)) != 0)
492656ae19f3STrond Myklebust 		goto out;
49271da177e4SLinus Torvalds 	if ((status = decode_create(&xdr,&res->dir_cinfo)) != 0)
49281da177e4SLinus Torvalds 		goto out;
49291da177e4SLinus Torvalds 	if ((status = decode_getfh(&xdr, res->fh)) != 0)
49301da177e4SLinus Torvalds 		goto out;
493180e52aceSTrond Myklebust 	if (decode_getfattr(&xdr, res->fattr, res->server,
493280e52aceSTrond Myklebust 				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
493356ae19f3STrond Myklebust 		goto out;
493456ae19f3STrond Myklebust 	if ((status = decode_restorefh(&xdr)) != 0)
493556ae19f3STrond Myklebust 		goto out;
493680e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->dir_fattr, res->server,
493780e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
49381da177e4SLinus Torvalds out:
49391da177e4SLinus Torvalds 	return status;
49401da177e4SLinus Torvalds }
49411da177e4SLinus Torvalds 
49421da177e4SLinus Torvalds /*
49431da177e4SLinus Torvalds  * Decode SYMLINK response
49441da177e4SLinus Torvalds  */
49458687b63aSAl Viro static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
49461da177e4SLinus Torvalds {
49471da177e4SLinus Torvalds 	return nfs4_xdr_dec_create(rqstp, p, res);
49481da177e4SLinus Torvalds }
49491da177e4SLinus Torvalds 
49501da177e4SLinus Torvalds /*
49511da177e4SLinus Torvalds  * Decode GETATTR response
49521da177e4SLinus Torvalds  */
49538687b63aSAl Viro static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_getattr_res *res)
49541da177e4SLinus Torvalds {
49551da177e4SLinus Torvalds 	struct xdr_stream xdr;
49561da177e4SLinus Torvalds 	struct compound_hdr hdr;
49571da177e4SLinus Torvalds 	int status;
49581da177e4SLinus Torvalds 
49591da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
49601da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
49611da177e4SLinus Torvalds 	if (status)
49621da177e4SLinus Torvalds 		goto out;
49639b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
49649b7b9fccSAndy Adamson 	if (status)
49659b7b9fccSAndy Adamson 		goto out;
49661da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
49671da177e4SLinus Torvalds 	if (status)
49681da177e4SLinus Torvalds 		goto out;
496980e52aceSTrond Myklebust 	status = decode_getfattr(&xdr, res->fattr, res->server,
497080e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
49711da177e4SLinus Torvalds out:
49721da177e4SLinus Torvalds 	return status;
49731da177e4SLinus Torvalds }
49741da177e4SLinus Torvalds 
497523ec6965SJ. Bruce Fields /*
497623ec6965SJ. Bruce Fields  * Encode an SETACL request
497723ec6965SJ. Bruce Fields  */
497823ec6965SJ. Bruce Fields static int
49798687b63aSAl Viro nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args)
498023ec6965SJ. Bruce Fields {
498123ec6965SJ. Bruce Fields 	struct xdr_stream xdr;
498223ec6965SJ. Bruce Fields 	struct compound_hdr hdr = {
498366cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
498423ec6965SJ. Bruce Fields 	};
498523ec6965SJ. Bruce Fields 	int status;
498623ec6965SJ. Bruce Fields 
498723ec6965SJ. Bruce Fields 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
49880c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
49899b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
4990cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
4991d017931cSAndy Adamson 	status = encode_setacl(&xdr, args, &hdr);
4992d017931cSAndy Adamson 	encode_nops(&hdr);
499323ec6965SJ. Bruce Fields 	return status;
499423ec6965SJ. Bruce Fields }
499505d564feSAndy Adamson 
499623ec6965SJ. Bruce Fields /*
499723ec6965SJ. Bruce Fields  * Decode SETACL response
499823ec6965SJ. Bruce Fields  */
499923ec6965SJ. Bruce Fields static int
500073c403a9SBenny Halevy nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p,
500173c403a9SBenny Halevy 		    struct nfs_setaclres *res)
500223ec6965SJ. Bruce Fields {
500323ec6965SJ. Bruce Fields 	struct xdr_stream xdr;
500423ec6965SJ. Bruce Fields 	struct compound_hdr hdr;
500523ec6965SJ. Bruce Fields 	int status;
500623ec6965SJ. Bruce Fields 
500723ec6965SJ. Bruce Fields 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
500823ec6965SJ. Bruce Fields 	status = decode_compound_hdr(&xdr, &hdr);
500923ec6965SJ. Bruce Fields 	if (status)
501023ec6965SJ. Bruce Fields 		goto out;
50119b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
50129b7b9fccSAndy Adamson 	if (status)
50139b7b9fccSAndy Adamson 		goto out;
501423ec6965SJ. Bruce Fields 	status = decode_putfh(&xdr);
501523ec6965SJ. Bruce Fields 	if (status)
501623ec6965SJ. Bruce Fields 		goto out;
50179e9ecc03SBenny Halevy 	status = decode_setattr(&xdr);
501823ec6965SJ. Bruce Fields out:
501923ec6965SJ. Bruce Fields 	return status;
502023ec6965SJ. Bruce Fields }
50211da177e4SLinus Torvalds 
50221da177e4SLinus Torvalds /*
5023029d105eSJ. Bruce Fields  * Decode GETACL response
5024029d105eSJ. Bruce Fields  */
5025029d105eSJ. Bruce Fields static int
5026663c79b3SBenny Halevy nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p,
5027663c79b3SBenny Halevy 		    struct nfs_getaclres *res)
5028029d105eSJ. Bruce Fields {
5029029d105eSJ. Bruce Fields 	struct xdr_stream xdr;
5030029d105eSJ. Bruce Fields 	struct compound_hdr hdr;
5031029d105eSJ. Bruce Fields 	int status;
5032029d105eSJ. Bruce Fields 
5033029d105eSJ. Bruce Fields 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
5034029d105eSJ. Bruce Fields 	status = decode_compound_hdr(&xdr, &hdr);
5035029d105eSJ. Bruce Fields 	if (status)
5036029d105eSJ. Bruce Fields 		goto out;
50379b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
50389b7b9fccSAndy Adamson 	if (status)
50399b7b9fccSAndy Adamson 		goto out;
5040029d105eSJ. Bruce Fields 	status = decode_putfh(&xdr);
5041029d105eSJ. Bruce Fields 	if (status)
5042029d105eSJ. Bruce Fields 		goto out;
5043663c79b3SBenny Halevy 	status = decode_getacl(&xdr, rqstp, &res->acl_len);
5044029d105eSJ. Bruce Fields 
5045029d105eSJ. Bruce Fields out:
5046029d105eSJ. Bruce Fields 	return status;
5047029d105eSJ. Bruce Fields }
5048029d105eSJ. Bruce Fields 
5049029d105eSJ. Bruce Fields /*
50501da177e4SLinus Torvalds  * Decode CLOSE response
50511da177e4SLinus Torvalds  */
50528687b63aSAl Viro static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
50531da177e4SLinus Torvalds {
50541da177e4SLinus Torvalds 	struct xdr_stream xdr;
50551da177e4SLinus Torvalds 	struct compound_hdr hdr;
50561da177e4SLinus Torvalds 	int status;
50571da177e4SLinus Torvalds 
50581da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
50591da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
50601da177e4SLinus Torvalds 	if (status)
50611da177e4SLinus Torvalds 		goto out;
50629b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
50639b7b9fccSAndy Adamson 	if (status)
50649b7b9fccSAndy Adamson 		goto out;
50651da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
50661da177e4SLinus Torvalds 	if (status)
50671da177e4SLinus Torvalds 		goto out;
50681da177e4SLinus Torvalds 	status = decode_close(&xdr, res);
5069516a6af6STrond Myklebust 	if (status != 0)
5070516a6af6STrond Myklebust 		goto out;
5071516a6af6STrond Myklebust 	/*
5072516a6af6STrond Myklebust 	 * Note: Server may do delete on close for this file
5073516a6af6STrond Myklebust 	 * 	in which case the getattr call will fail with
5074516a6af6STrond Myklebust 	 * 	an ESTALE error. Shouldn't be a problem,
5075516a6af6STrond Myklebust 	 * 	though, since fattr->valid will remain unset.
5076516a6af6STrond Myklebust 	 */
507780e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->fattr, res->server,
507880e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
50791da177e4SLinus Torvalds out:
50801da177e4SLinus Torvalds 	return status;
50811da177e4SLinus Torvalds }
50821da177e4SLinus Torvalds 
50831da177e4SLinus Torvalds /*
50841da177e4SLinus Torvalds  * Decode OPEN response
50851da177e4SLinus Torvalds  */
50868687b63aSAl Viro static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
50871da177e4SLinus Torvalds {
50881da177e4SLinus Torvalds 	struct xdr_stream xdr;
50891da177e4SLinus Torvalds 	struct compound_hdr hdr;
50901da177e4SLinus Torvalds 	int status;
50911da177e4SLinus Torvalds 
50921da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
50931da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
50941da177e4SLinus Torvalds 	if (status)
50951da177e4SLinus Torvalds 		goto out;
50969b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
50979b7b9fccSAndy Adamson 	if (status)
50989b7b9fccSAndy Adamson 		goto out;
50991da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
51001da177e4SLinus Torvalds 	if (status)
51011da177e4SLinus Torvalds 		goto out;
510256ae19f3STrond Myklebust 	status = decode_savefh(&xdr);
510356ae19f3STrond Myklebust 	if (status)
510456ae19f3STrond Myklebust 		goto out;
51051da177e4SLinus Torvalds 	status = decode_open(&xdr, res);
51061da177e4SLinus Torvalds 	if (status)
51071da177e4SLinus Torvalds 		goto out;
51089936781dSTrond Myklebust 	if (decode_getfh(&xdr, &res->fh) != 0)
51091da177e4SLinus Torvalds 		goto out;
511080e52aceSTrond Myklebust 	if (decode_getfattr(&xdr, res->f_attr, res->server,
511180e52aceSTrond Myklebust 				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
511256ae19f3STrond Myklebust 		goto out;
5113365c8f58STrond Myklebust 	if (decode_restorefh(&xdr) != 0)
511456ae19f3STrond Myklebust 		goto out;
511580e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->dir_attr, res->server,
511680e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
51171da177e4SLinus Torvalds out:
51181da177e4SLinus Torvalds 	return status;
51191da177e4SLinus Torvalds }
51201da177e4SLinus Torvalds 
51211da177e4SLinus Torvalds /*
51221da177e4SLinus Torvalds  * Decode OPEN_CONFIRM response
51231da177e4SLinus Torvalds  */
51248687b63aSAl Viro static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, __be32 *p, struct nfs_open_confirmres *res)
51251da177e4SLinus Torvalds {
51261da177e4SLinus Torvalds 	struct xdr_stream xdr;
51271da177e4SLinus Torvalds 	struct compound_hdr hdr;
51281da177e4SLinus Torvalds 	int status;
51291da177e4SLinus Torvalds 
51301da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
51311da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
51321da177e4SLinus Torvalds 	if (status)
51331da177e4SLinus Torvalds 		goto out;
51341da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
51351da177e4SLinus Torvalds 	if (status)
51361da177e4SLinus Torvalds 		goto out;
51371da177e4SLinus Torvalds 	status = decode_open_confirm(&xdr, res);
51381da177e4SLinus Torvalds out:
51391da177e4SLinus Torvalds 	return status;
51401da177e4SLinus Torvalds }
51411da177e4SLinus Torvalds 
51421da177e4SLinus Torvalds /*
51431da177e4SLinus Torvalds  * Decode OPEN response
51441da177e4SLinus Torvalds  */
51458687b63aSAl Viro static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
51461da177e4SLinus Torvalds {
51471da177e4SLinus Torvalds 	struct xdr_stream xdr;
51481da177e4SLinus Torvalds 	struct compound_hdr hdr;
51491da177e4SLinus Torvalds 	int status;
51501da177e4SLinus Torvalds 
51511da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
51521da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
51531da177e4SLinus Torvalds 	if (status)
51541da177e4SLinus Torvalds 		goto out;
51559b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
51569b7b9fccSAndy Adamson 	if (status)
51579b7b9fccSAndy Adamson 		goto out;
51581da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
51591da177e4SLinus Torvalds 	if (status)
51601da177e4SLinus Torvalds 		goto out;
51611da177e4SLinus Torvalds 	status = decode_open(&xdr, res);
5162864472e9STrond Myklebust 	if (status)
5163864472e9STrond Myklebust 		goto out;
516480e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->f_attr, res->server,
516580e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
51661da177e4SLinus Torvalds out:
51671da177e4SLinus Torvalds 	return status;
51681da177e4SLinus Torvalds }
51691da177e4SLinus Torvalds 
51701da177e4SLinus Torvalds /*
51711da177e4SLinus Torvalds  * Decode SETATTR response
51721da177e4SLinus Torvalds  */
51738687b63aSAl Viro static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res)
51741da177e4SLinus Torvalds {
51751da177e4SLinus Torvalds 	struct xdr_stream xdr;
51761da177e4SLinus Torvalds 	struct compound_hdr hdr;
51771da177e4SLinus Torvalds 	int status;
51781da177e4SLinus Torvalds 
51791da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
51801da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
51811da177e4SLinus Torvalds 	if (status)
51821da177e4SLinus Torvalds 		goto out;
51839b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
51849b7b9fccSAndy Adamson 	if (status)
51859b7b9fccSAndy Adamson 		goto out;
51861da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
51871da177e4SLinus Torvalds 	if (status)
51881da177e4SLinus Torvalds 		goto out;
51899e9ecc03SBenny Halevy 	status = decode_setattr(&xdr);
51901da177e4SLinus Torvalds 	if (status)
51911da177e4SLinus Torvalds 		goto out;
519280e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->fattr, res->server,
519380e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
51941da177e4SLinus Torvalds out:
51951da177e4SLinus Torvalds 	return status;
51961da177e4SLinus Torvalds }
51971da177e4SLinus Torvalds 
51981da177e4SLinus Torvalds /*
51991da177e4SLinus Torvalds  * Decode LOCK response
52001da177e4SLinus Torvalds  */
52018687b63aSAl Viro static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_res *res)
52021da177e4SLinus Torvalds {
52031da177e4SLinus Torvalds 	struct xdr_stream xdr;
52041da177e4SLinus Torvalds 	struct compound_hdr hdr;
52051da177e4SLinus Torvalds 	int status;
52061da177e4SLinus Torvalds 
52071da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
52081da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
52091da177e4SLinus Torvalds 	if (status)
52101da177e4SLinus Torvalds 		goto out;
52119b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
52129b7b9fccSAndy Adamson 	if (status)
52139b7b9fccSAndy Adamson 		goto out;
52141da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
52151da177e4SLinus Torvalds 	if (status)
52161da177e4SLinus Torvalds 		goto out;
52171da177e4SLinus Torvalds 	status = decode_lock(&xdr, res);
52181da177e4SLinus Torvalds out:
52191da177e4SLinus Torvalds 	return status;
52201da177e4SLinus Torvalds }
52211da177e4SLinus Torvalds 
52221da177e4SLinus Torvalds /*
52231da177e4SLinus Torvalds  * Decode LOCKT response
52241da177e4SLinus Torvalds  */
52258687b63aSAl Viro static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lockt_res *res)
52261da177e4SLinus Torvalds {
52271da177e4SLinus Torvalds 	struct xdr_stream xdr;
52281da177e4SLinus Torvalds 	struct compound_hdr hdr;
52291da177e4SLinus Torvalds 	int status;
52301da177e4SLinus Torvalds 
52311da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
52321da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
52331da177e4SLinus Torvalds 	if (status)
52341da177e4SLinus Torvalds 		goto out;
52359b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
52369b7b9fccSAndy Adamson 	if (status)
52379b7b9fccSAndy Adamson 		goto out;
52381da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
52391da177e4SLinus Torvalds 	if (status)
52401da177e4SLinus Torvalds 		goto out;
52411da177e4SLinus Torvalds 	status = decode_lockt(&xdr, res);
52421da177e4SLinus Torvalds out:
52431da177e4SLinus Torvalds 	return status;
52441da177e4SLinus Torvalds }
52451da177e4SLinus Torvalds 
52461da177e4SLinus Torvalds /*
52471da177e4SLinus Torvalds  * Decode LOCKU response
52481da177e4SLinus Torvalds  */
52498687b63aSAl Viro static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_locku_res *res)
52501da177e4SLinus Torvalds {
52511da177e4SLinus Torvalds 	struct xdr_stream xdr;
52521da177e4SLinus Torvalds 	struct compound_hdr hdr;
52531da177e4SLinus Torvalds 	int status;
52541da177e4SLinus Torvalds 
52551da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
52561da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
52571da177e4SLinus Torvalds 	if (status)
52581da177e4SLinus Torvalds 		goto out;
52599b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
52609b7b9fccSAndy Adamson 	if (status)
52619b7b9fccSAndy Adamson 		goto out;
52621da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
52631da177e4SLinus Torvalds 	if (status)
52641da177e4SLinus Torvalds 		goto out;
52651da177e4SLinus Torvalds 	status = decode_locku(&xdr, res);
52661da177e4SLinus Torvalds out:
52671da177e4SLinus Torvalds 	return status;
52681da177e4SLinus Torvalds }
52691da177e4SLinus Torvalds 
52701da177e4SLinus Torvalds /*
52711da177e4SLinus Torvalds  * Decode READLINK response
52721da177e4SLinus Torvalds  */
5273f50c7000SBenny Halevy static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p,
5274f50c7000SBenny Halevy 				 struct nfs4_readlink_res *res)
52751da177e4SLinus Torvalds {
52761da177e4SLinus Torvalds 	struct xdr_stream xdr;
52771da177e4SLinus Torvalds 	struct compound_hdr hdr;
52781da177e4SLinus Torvalds 	int status;
52791da177e4SLinus Torvalds 
52801da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
52811da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
52821da177e4SLinus Torvalds 	if (status)
52831da177e4SLinus Torvalds 		goto out;
52849b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
52859b7b9fccSAndy Adamson 	if (status)
52869b7b9fccSAndy Adamson 		goto out;
52871da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
52881da177e4SLinus Torvalds 	if (status)
52891da177e4SLinus Torvalds 		goto out;
52901da177e4SLinus Torvalds 	status = decode_readlink(&xdr, rqstp);
52911da177e4SLinus Torvalds out:
52921da177e4SLinus Torvalds 	return status;
52931da177e4SLinus Torvalds }
52941da177e4SLinus Torvalds 
52951da177e4SLinus Torvalds /*
52961da177e4SLinus Torvalds  * Decode READDIR response
52971da177e4SLinus Torvalds  */
52988687b63aSAl Viro static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_readdir_res *res)
52991da177e4SLinus Torvalds {
53001da177e4SLinus Torvalds 	struct xdr_stream xdr;
53011da177e4SLinus Torvalds 	struct compound_hdr hdr;
53021da177e4SLinus Torvalds 	int status;
53031da177e4SLinus Torvalds 
53041da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
53051da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
53061da177e4SLinus Torvalds 	if (status)
53071da177e4SLinus Torvalds 		goto out;
53089b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
53099b7b9fccSAndy Adamson 	if (status)
53109b7b9fccSAndy Adamson 		goto out;
53111da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
53121da177e4SLinus Torvalds 	if (status)
53131da177e4SLinus Torvalds 		goto out;
53141da177e4SLinus Torvalds 	status = decode_readdir(&xdr, rqstp, res);
53151da177e4SLinus Torvalds out:
53161da177e4SLinus Torvalds 	return status;
53171da177e4SLinus Torvalds }
53181da177e4SLinus Torvalds 
53191da177e4SLinus Torvalds /*
53201da177e4SLinus Torvalds  * Decode Read response
53211da177e4SLinus Torvalds  */
53228687b63aSAl Viro static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readres *res)
53231da177e4SLinus Torvalds {
53241da177e4SLinus Torvalds 	struct xdr_stream xdr;
53251da177e4SLinus Torvalds 	struct compound_hdr hdr;
53261da177e4SLinus Torvalds 	int status;
53271da177e4SLinus Torvalds 
53281da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
53291da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
53301da177e4SLinus Torvalds 	if (status)
53311da177e4SLinus Torvalds 		goto out;
53329b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
53339b7b9fccSAndy Adamson 	if (status)
53349b7b9fccSAndy Adamson 		goto out;
53351da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
53361da177e4SLinus Torvalds 	if (status)
53371da177e4SLinus Torvalds 		goto out;
53381da177e4SLinus Torvalds 	status = decode_read(&xdr, rqstp, res);
53391da177e4SLinus Torvalds 	if (!status)
53401da177e4SLinus Torvalds 		status = res->count;
53411da177e4SLinus Torvalds out:
53421da177e4SLinus Torvalds 	return status;
53431da177e4SLinus Torvalds }
53441da177e4SLinus Torvalds 
53451da177e4SLinus Torvalds /*
53461da177e4SLinus Torvalds  * Decode WRITE response
53471da177e4SLinus Torvalds  */
53488687b63aSAl Viro static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
53491da177e4SLinus Torvalds {
53501da177e4SLinus Torvalds 	struct xdr_stream xdr;
53511da177e4SLinus Torvalds 	struct compound_hdr hdr;
53521da177e4SLinus Torvalds 	int status;
53531da177e4SLinus Torvalds 
53541da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
53551da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
53561da177e4SLinus Torvalds 	if (status)
53571da177e4SLinus Torvalds 		goto out;
53589b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
53599b7b9fccSAndy Adamson 	if (status)
53609b7b9fccSAndy Adamson 		goto out;
53611da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
53621da177e4SLinus Torvalds 	if (status)
53631da177e4SLinus Torvalds 		goto out;
53641da177e4SLinus Torvalds 	status = decode_write(&xdr, res);
53654f9838c7STrond Myklebust 	if (status)
53664f9838c7STrond Myklebust 		goto out;
536780e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->fattr, res->server,
536880e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
53691da177e4SLinus Torvalds 	if (!status)
53701da177e4SLinus Torvalds 		status = res->count;
53711da177e4SLinus Torvalds out:
53721da177e4SLinus Torvalds 	return status;
53731da177e4SLinus Torvalds }
53741da177e4SLinus Torvalds 
53751da177e4SLinus Torvalds /*
53761da177e4SLinus Torvalds  * Decode COMMIT response
53771da177e4SLinus Torvalds  */
53788687b63aSAl Viro static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
53791da177e4SLinus Torvalds {
53801da177e4SLinus Torvalds 	struct xdr_stream xdr;
53811da177e4SLinus Torvalds 	struct compound_hdr hdr;
53821da177e4SLinus Torvalds 	int status;
53831da177e4SLinus Torvalds 
53841da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
53851da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
53861da177e4SLinus Torvalds 	if (status)
53871da177e4SLinus Torvalds 		goto out;
53889b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
53899b7b9fccSAndy Adamson 	if (status)
53909b7b9fccSAndy Adamson 		goto out;
53911da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
53921da177e4SLinus Torvalds 	if (status)
53931da177e4SLinus Torvalds 		goto out;
53941da177e4SLinus Torvalds 	status = decode_commit(&xdr, res);
53954f9838c7STrond Myklebust 	if (status)
53964f9838c7STrond Myklebust 		goto out;
539780e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->fattr, res->server,
539880e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
53991da177e4SLinus Torvalds out:
54001da177e4SLinus Torvalds 	return status;
54011da177e4SLinus Torvalds }
54021da177e4SLinus Torvalds 
54031da177e4SLinus Torvalds /*
54048b173218SRicardo Labiaga  * Decode FSINFO response
54051da177e4SLinus Torvalds  */
54063dda5e43SBenny Halevy static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p,
54073dda5e43SBenny Halevy 			       struct nfs4_fsinfo_res *res)
54081da177e4SLinus Torvalds {
54091da177e4SLinus Torvalds 	struct xdr_stream xdr;
54101da177e4SLinus Torvalds 	struct compound_hdr hdr;
54111da177e4SLinus Torvalds 	int status;
54121da177e4SLinus Torvalds 
54131da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
54141da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
54151da177e4SLinus Torvalds 	if (!status)
54169b7b9fccSAndy Adamson 		status = decode_sequence(&xdr, &res->seq_res, req);
54179b7b9fccSAndy Adamson 	if (!status)
54181da177e4SLinus Torvalds 		status = decode_putfh(&xdr);
54191da177e4SLinus Torvalds 	if (!status)
54203dda5e43SBenny Halevy 		status = decode_fsinfo(&xdr, res->fsinfo);
54211da177e4SLinus Torvalds 	return status;
54221da177e4SLinus Torvalds }
54231da177e4SLinus Torvalds 
54241da177e4SLinus Torvalds /*
54258b173218SRicardo Labiaga  * Decode PATHCONF response
54261da177e4SLinus Torvalds  */
5427d45b2989SBenny Halevy static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p,
5428d45b2989SBenny Halevy 				 struct nfs4_pathconf_res *res)
54291da177e4SLinus Torvalds {
54301da177e4SLinus Torvalds 	struct xdr_stream xdr;
54311da177e4SLinus Torvalds 	struct compound_hdr hdr;
54321da177e4SLinus Torvalds 	int status;
54331da177e4SLinus Torvalds 
54341da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
54351da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
54361da177e4SLinus Torvalds 	if (!status)
54379b7b9fccSAndy Adamson 		status = decode_sequence(&xdr, &res->seq_res, req);
54389b7b9fccSAndy Adamson 	if (!status)
54391da177e4SLinus Torvalds 		status = decode_putfh(&xdr);
54401da177e4SLinus Torvalds 	if (!status)
5441d45b2989SBenny Halevy 		status = decode_pathconf(&xdr, res->pathconf);
54421da177e4SLinus Torvalds 	return status;
54431da177e4SLinus Torvalds }
54441da177e4SLinus Torvalds 
54451da177e4SLinus Torvalds /*
54468b173218SRicardo Labiaga  * Decode STATFS response
54471da177e4SLinus Torvalds  */
544824ad148aSBenny Halevy static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p,
544924ad148aSBenny Halevy 			       struct nfs4_statfs_res *res)
54501da177e4SLinus Torvalds {
54511da177e4SLinus Torvalds 	struct xdr_stream xdr;
54521da177e4SLinus Torvalds 	struct compound_hdr hdr;
54531da177e4SLinus Torvalds 	int status;
54541da177e4SLinus Torvalds 
54551da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
54561da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
54571da177e4SLinus Torvalds 	if (!status)
54589b7b9fccSAndy Adamson 		status = decode_sequence(&xdr, &res->seq_res, req);
54599b7b9fccSAndy Adamson 	if (!status)
54601da177e4SLinus Torvalds 		status = decode_putfh(&xdr);
54611da177e4SLinus Torvalds 	if (!status)
546224ad148aSBenny Halevy 		status = decode_statfs(&xdr, res->fsstat);
54631da177e4SLinus Torvalds 	return status;
54641da177e4SLinus Torvalds }
54651da177e4SLinus Torvalds 
54661da177e4SLinus Torvalds /*
54678b173218SRicardo Labiaga  * Decode GETATTR_BITMAP response
54681da177e4SLinus Torvalds  */
54698687b63aSAl Viro static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4_server_caps_res *res)
54701da177e4SLinus Torvalds {
54711da177e4SLinus Torvalds 	struct xdr_stream xdr;
54721da177e4SLinus Torvalds 	struct compound_hdr hdr;
54731da177e4SLinus Torvalds 	int status;
54741da177e4SLinus Torvalds 
54751da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
54769b7b9fccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
54779b7b9fccSAndy Adamson 	if (status)
54789b7b9fccSAndy Adamson 		goto out;
54799b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, req);
54809b7b9fccSAndy Adamson 	if (status)
54811da177e4SLinus Torvalds 		goto out;
54821da177e4SLinus Torvalds 	if ((status = decode_putfh(&xdr)) != 0)
54831da177e4SLinus Torvalds 		goto out;
54841da177e4SLinus Torvalds 	status = decode_server_caps(&xdr, res);
54851da177e4SLinus Torvalds out:
54861da177e4SLinus Torvalds 	return status;
54871da177e4SLinus Torvalds }
54881da177e4SLinus Torvalds 
54891da177e4SLinus Torvalds /*
54901da177e4SLinus Torvalds  * Decode RENEW response
54911da177e4SLinus Torvalds  */
54928687b63aSAl Viro static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy)
54931da177e4SLinus Torvalds {
54941da177e4SLinus Torvalds 	struct xdr_stream xdr;
54951da177e4SLinus Torvalds 	struct compound_hdr hdr;
54961da177e4SLinus Torvalds 	int status;
54971da177e4SLinus Torvalds 
54981da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
54991da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
55001da177e4SLinus Torvalds 	if (!status)
55011da177e4SLinus Torvalds 		status = decode_renew(&xdr);
55021da177e4SLinus Torvalds 	return status;
55031da177e4SLinus Torvalds }
55041da177e4SLinus Torvalds 
55051da177e4SLinus Torvalds /*
55068b173218SRicardo Labiaga  * Decode SETCLIENTID response
55071da177e4SLinus Torvalds  */
55088687b63aSAl Viro static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p,
5509bb8b27e5STrond Myklebust 		struct nfs4_setclientid_res *res)
55101da177e4SLinus Torvalds {
55111da177e4SLinus Torvalds 	struct xdr_stream xdr;
55121da177e4SLinus Torvalds 	struct compound_hdr hdr;
55131da177e4SLinus Torvalds 	int status;
55141da177e4SLinus Torvalds 
55151da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
55161da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
55171da177e4SLinus Torvalds 	if (!status)
5518bb8b27e5STrond Myklebust 		status = decode_setclientid(&xdr, res);
55191da177e4SLinus Torvalds 	return status;
55201da177e4SLinus Torvalds }
55211da177e4SLinus Torvalds 
55221da177e4SLinus Torvalds /*
55238b173218SRicardo Labiaga  * Decode SETCLIENTID_CONFIRM response
55241da177e4SLinus Torvalds  */
55258687b63aSAl Viro static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
55261da177e4SLinus Torvalds {
55271da177e4SLinus Torvalds 	struct xdr_stream xdr;
55281da177e4SLinus Torvalds 	struct compound_hdr hdr;
55291da177e4SLinus Torvalds 	int status;
55301da177e4SLinus Torvalds 
55311da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
55321da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
55331da177e4SLinus Torvalds 	if (!status)
55341da177e4SLinus Torvalds 		status = decode_setclientid_confirm(&xdr);
55351da177e4SLinus Torvalds 	if (!status)
55361da177e4SLinus Torvalds 		status = decode_putrootfh(&xdr);
55371da177e4SLinus Torvalds 	if (!status)
55381da177e4SLinus Torvalds 		status = decode_fsinfo(&xdr, fsinfo);
55391da177e4SLinus Torvalds 	return status;
55401da177e4SLinus Torvalds }
55411da177e4SLinus Torvalds 
55421da177e4SLinus Torvalds /*
55438b173218SRicardo Labiaga  * Decode DELEGRETURN response
55441da177e4SLinus Torvalds  */
55458687b63aSAl Viro static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_delegreturnres *res)
55461da177e4SLinus Torvalds {
55471da177e4SLinus Torvalds 	struct xdr_stream xdr;
55481da177e4SLinus Torvalds 	struct compound_hdr hdr;
55491da177e4SLinus Torvalds 	int status;
55501da177e4SLinus Torvalds 
55511da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
55521da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
55539b7b9fccSAndy Adamson 	if (status)
55549b7b9fccSAndy Adamson 		goto out;
55559b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
55569b7b9fccSAndy Adamson 	if (status)
5557fa178f29STrond Myklebust 		goto out;
55581da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
5559fa178f29STrond Myklebust 	if (status != 0)
5560fa178f29STrond Myklebust 		goto out;
55611da177e4SLinus Torvalds 	status = decode_delegreturn(&xdr);
5562556ae3bbSJeff Layton 	if (status != 0)
5563556ae3bbSJeff Layton 		goto out;
556480e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->fattr, res->server,
556580e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
5566fa178f29STrond Myklebust out:
55671da177e4SLinus Torvalds 	return status;
55681da177e4SLinus Torvalds }
55691da177e4SLinus Torvalds 
5570683b57b4STrond Myklebust /*
55718b173218SRicardo Labiaga  * Decode FS_LOCATIONS response
5572683b57b4STrond Myklebust  */
557322958463SBenny Halevy static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p,
557422958463SBenny Halevy 				     struct nfs4_fs_locations_res *res)
5575683b57b4STrond Myklebust {
5576683b57b4STrond Myklebust 	struct xdr_stream xdr;
5577683b57b4STrond Myklebust 	struct compound_hdr hdr;
5578683b57b4STrond Myklebust 	int status;
5579683b57b4STrond Myklebust 
5580683b57b4STrond Myklebust 	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
5581683b57b4STrond Myklebust 	status = decode_compound_hdr(&xdr, &hdr);
55829b7b9fccSAndy Adamson 	if (status)
55839b7b9fccSAndy Adamson 		goto out;
55849b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, req);
55859b7b9fccSAndy Adamson 	if (status)
5586683b57b4STrond Myklebust 		goto out;
5587683b57b4STrond Myklebust 	if ((status = decode_putfh(&xdr)) != 0)
5588683b57b4STrond Myklebust 		goto out;
5589683b57b4STrond Myklebust 	if ((status = decode_lookup(&xdr)) != 0)
5590683b57b4STrond Myklebust 		goto out;
5591683b57b4STrond Myklebust 	xdr_enter_page(&xdr, PAGE_SIZE);
559222958463SBenny Halevy 	status = decode_getfattr(&xdr, &res->fs_locations->fattr,
559380e52aceSTrond Myklebust 				 res->fs_locations->server,
559480e52aceSTrond Myklebust 				 !RPC_IS_ASYNC(req->rq_task));
5595683b57b4STrond Myklebust out:
5596683b57b4STrond Myklebust 	return status;
5597683b57b4STrond Myklebust }
5598683b57b4STrond Myklebust 
559999fe60d0SBenny Halevy #if defined(CONFIG_NFS_V4_1)
560099fe60d0SBenny Halevy /*
56018b173218SRicardo Labiaga  * Decode EXCHANGE_ID response
560299fe60d0SBenny Halevy  */
560399fe60d0SBenny Halevy static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp, uint32_t *p,
560499fe60d0SBenny Halevy 				    void *res)
560599fe60d0SBenny Halevy {
560699fe60d0SBenny Halevy 	struct xdr_stream xdr;
560799fe60d0SBenny Halevy 	struct compound_hdr hdr;
560899fe60d0SBenny Halevy 	int status;
560999fe60d0SBenny Halevy 
561099fe60d0SBenny Halevy 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
561199fe60d0SBenny Halevy 	status = decode_compound_hdr(&xdr, &hdr);
561299fe60d0SBenny Halevy 	if (!status)
561399fe60d0SBenny Halevy 		status = decode_exchange_id(&xdr, res);
561499fe60d0SBenny Halevy 	return status;
561599fe60d0SBenny Halevy }
56162050f0ccSAndy Adamson 
56172050f0ccSAndy Adamson /*
56188b173218SRicardo Labiaga  * Decode CREATE_SESSION response
5619fc931582SAndy Adamson  */
5620fc931582SAndy Adamson static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp, uint32_t *p,
5621fc931582SAndy Adamson 				       struct nfs41_create_session_res *res)
5622fc931582SAndy Adamson {
5623fc931582SAndy Adamson 	struct xdr_stream xdr;
5624fc931582SAndy Adamson 	struct compound_hdr hdr;
5625fc931582SAndy Adamson 	int status;
5626fc931582SAndy Adamson 
5627fc931582SAndy Adamson 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
5628fc931582SAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
5629fc931582SAndy Adamson 	if (!status)
5630fc931582SAndy Adamson 		status = decode_create_session(&xdr, res);
5631fc931582SAndy Adamson 	return status;
5632fc931582SAndy Adamson }
5633fc931582SAndy Adamson 
5634fc931582SAndy Adamson /*
56358b173218SRicardo Labiaga  * Decode DESTROY_SESSION response
56360f3e66c6SAndy Adamson  */
56370f3e66c6SAndy Adamson static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp, uint32_t *p,
56380f3e66c6SAndy Adamson 					void *dummy)
56390f3e66c6SAndy Adamson {
56400f3e66c6SAndy Adamson 	struct xdr_stream xdr;
56410f3e66c6SAndy Adamson 	struct compound_hdr hdr;
56420f3e66c6SAndy Adamson 	int status;
56430f3e66c6SAndy Adamson 
56440f3e66c6SAndy Adamson 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
56450f3e66c6SAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
56460f3e66c6SAndy Adamson 	if (!status)
56470f3e66c6SAndy Adamson 		status = decode_destroy_session(&xdr, dummy);
56480f3e66c6SAndy Adamson 	return status;
56490f3e66c6SAndy Adamson }
56500f3e66c6SAndy Adamson 
56510f3e66c6SAndy Adamson /*
56528b173218SRicardo Labiaga  * Decode SEQUENCE response
5653fc01cea9SAndy Adamson  */
5654fc01cea9SAndy Adamson static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp, uint32_t *p,
5655fc01cea9SAndy Adamson 				 struct nfs4_sequence_res *res)
5656fc01cea9SAndy Adamson {
5657fc01cea9SAndy Adamson 	struct xdr_stream xdr;
5658fc01cea9SAndy Adamson 	struct compound_hdr hdr;
5659fc01cea9SAndy Adamson 	int status;
5660fc01cea9SAndy Adamson 
5661fc01cea9SAndy Adamson 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
5662fc01cea9SAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
5663fc01cea9SAndy Adamson 	if (!status)
5664fc01cea9SAndy Adamson 		status = decode_sequence(&xdr, res, rqstp);
5665fc01cea9SAndy Adamson 	return status;
5666fc01cea9SAndy Adamson }
5667fc01cea9SAndy Adamson 
5668fc01cea9SAndy Adamson /*
56698b173218SRicardo Labiaga  * Decode GET_LEASE_TIME response
56702050f0ccSAndy Adamson  */
56712050f0ccSAndy Adamson static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p,
56722050f0ccSAndy Adamson 				       struct nfs4_get_lease_time_res *res)
56732050f0ccSAndy Adamson {
56742050f0ccSAndy Adamson 	struct xdr_stream xdr;
56752050f0ccSAndy Adamson 	struct compound_hdr hdr;
56762050f0ccSAndy Adamson 	int status;
56772050f0ccSAndy Adamson 
56782050f0ccSAndy Adamson 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
56792050f0ccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
56802050f0ccSAndy Adamson 	if (!status)
56812050f0ccSAndy Adamson 		status = decode_sequence(&xdr, &res->lr_seq_res, rqstp);
56822050f0ccSAndy Adamson 	if (!status)
56832050f0ccSAndy Adamson 		status = decode_putrootfh(&xdr);
56842050f0ccSAndy Adamson 	if (!status)
56852050f0ccSAndy Adamson 		status = decode_fsinfo(&xdr, res->lr_fsinfo);
56862050f0ccSAndy Adamson 	return status;
56872050f0ccSAndy Adamson }
568818019753SRicardo Labiaga 
568918019753SRicardo Labiaga /*
569018019753SRicardo Labiaga  * Decode RECLAIM_COMPLETE response
569118019753SRicardo Labiaga  */
569218019753SRicardo Labiaga static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp, uint32_t *p,
569318019753SRicardo Labiaga 					 struct nfs41_reclaim_complete_res *res)
569418019753SRicardo Labiaga {
569518019753SRicardo Labiaga 	struct xdr_stream xdr;
569618019753SRicardo Labiaga 	struct compound_hdr hdr;
569718019753SRicardo Labiaga 	int status;
569818019753SRicardo Labiaga 
569918019753SRicardo Labiaga 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
570018019753SRicardo Labiaga 	status = decode_compound_hdr(&xdr, &hdr);
570118019753SRicardo Labiaga 	if (!status)
570218019753SRicardo Labiaga 		status = decode_sequence(&xdr, &res->seq_res, rqstp);
570318019753SRicardo Labiaga 	if (!status)
570418019753SRicardo Labiaga 		status = decode_reclaim_complete(&xdr, (void *)NULL);
570518019753SRicardo Labiaga 	return status;
570618019753SRicardo Labiaga }
570799fe60d0SBenny Halevy #endif /* CONFIG_NFS_V4_1 */
570899fe60d0SBenny Halevy 
57090dbb4c67SAl Viro __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
57101da177e4SLinus Torvalds {
57111da177e4SLinus Torvalds 	uint32_t bitmap[2] = {0};
57121da177e4SLinus Torvalds 	uint32_t len;
57131da177e4SLinus Torvalds 
57141da177e4SLinus Torvalds 	if (!*p++) {
57151da177e4SLinus Torvalds 		if (!*p)
57161da177e4SLinus Torvalds 			return ERR_PTR(-EAGAIN);
57171da177e4SLinus Torvalds 		entry->eof = 1;
57181da177e4SLinus Torvalds 		return ERR_PTR(-EBADCOOKIE);
57191da177e4SLinus Torvalds 	}
57201da177e4SLinus Torvalds 
57211da177e4SLinus Torvalds 	entry->prev_cookie = entry->cookie;
57221da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &entry->cookie);
57231da177e4SLinus Torvalds 	entry->len = ntohl(*p++);
57241da177e4SLinus Torvalds 	entry->name = (const char *) p;
57251da177e4SLinus Torvalds 	p += XDR_QUADLEN(entry->len);
57261da177e4SLinus Torvalds 
57271da177e4SLinus Torvalds 	/*
57281da177e4SLinus Torvalds 	 * In case the server doesn't return an inode number,
57291da177e4SLinus Torvalds 	 * we fake one here.  (We don't use inode number 0,
57301da177e4SLinus Torvalds 	 * since glibc seems to choke on it...)
57311da177e4SLinus Torvalds 	 */
57321da177e4SLinus Torvalds 	entry->ino = 1;
57331da177e4SLinus Torvalds 
57341da177e4SLinus Torvalds 	len = ntohl(*p++);		/* bitmap length */
57351da177e4SLinus Torvalds 	if (len-- > 0) {
57361da177e4SLinus Torvalds 		bitmap[0] = ntohl(*p++);
57371da177e4SLinus Torvalds 		if (len-- > 0) {
57381da177e4SLinus Torvalds 			bitmap[1] = ntohl(*p++);
57391da177e4SLinus Torvalds 			p += len;
57401da177e4SLinus Torvalds 		}
57411da177e4SLinus Torvalds 	}
57421da177e4SLinus Torvalds 	len = XDR_QUADLEN(ntohl(*p++));	/* attribute buffer length */
57431da177e4SLinus Torvalds 	if (len > 0) {
574497d312d0SManoj Naik 		if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) {
574597d312d0SManoj Naik 			bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR;
574697d312d0SManoj Naik 			/* Ignore the return value of rdattr_error for now */
574797d312d0SManoj Naik 			p++;
574897d312d0SManoj Naik 			len--;
574997d312d0SManoj Naik 		}
57501da177e4SLinus Torvalds 		if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID)
57511da177e4SLinus Torvalds 			xdr_decode_hyper(p, &entry->ino);
57521da177e4SLinus Torvalds 		else if (bitmap[0] == FATTR4_WORD0_FILEID)
57531da177e4SLinus Torvalds 			xdr_decode_hyper(p, &entry->ino);
57541da177e4SLinus Torvalds 		p += len;
57551da177e4SLinus Torvalds 	}
57561da177e4SLinus Torvalds 
57571da177e4SLinus Torvalds 	entry->eof = !p[0] && p[1];
57581da177e4SLinus Torvalds 	return p;
57591da177e4SLinus Torvalds }
57601da177e4SLinus Torvalds 
57611da177e4SLinus Torvalds /*
57621da177e4SLinus Torvalds  * We need to translate between nfs status return values and
57631da177e4SLinus Torvalds  * the local errno values which may not be the same.
57641da177e4SLinus Torvalds  */
57651da177e4SLinus Torvalds static struct {
57661da177e4SLinus Torvalds 	int stat;
57671da177e4SLinus Torvalds 	int errno;
57681da177e4SLinus Torvalds } nfs_errtbl[] = {
57691da177e4SLinus Torvalds 	{ NFS4_OK,		0		},
5770856dff3dSBenny Halevy 	{ NFS4ERR_PERM,		-EPERM		},
5771856dff3dSBenny Halevy 	{ NFS4ERR_NOENT,	-ENOENT		},
5772856dff3dSBenny Halevy 	{ NFS4ERR_IO,		-errno_NFSERR_IO},
5773856dff3dSBenny Halevy 	{ NFS4ERR_NXIO,		-ENXIO		},
5774856dff3dSBenny Halevy 	{ NFS4ERR_ACCESS,	-EACCES		},
5775856dff3dSBenny Halevy 	{ NFS4ERR_EXIST,	-EEXIST		},
5776856dff3dSBenny Halevy 	{ NFS4ERR_XDEV,		-EXDEV		},
5777856dff3dSBenny Halevy 	{ NFS4ERR_NOTDIR,	-ENOTDIR	},
5778856dff3dSBenny Halevy 	{ NFS4ERR_ISDIR,	-EISDIR		},
5779856dff3dSBenny Halevy 	{ NFS4ERR_INVAL,	-EINVAL		},
5780856dff3dSBenny Halevy 	{ NFS4ERR_FBIG,		-EFBIG		},
5781856dff3dSBenny Halevy 	{ NFS4ERR_NOSPC,	-ENOSPC		},
5782856dff3dSBenny Halevy 	{ NFS4ERR_ROFS,		-EROFS		},
5783856dff3dSBenny Halevy 	{ NFS4ERR_MLINK,	-EMLINK		},
5784856dff3dSBenny Halevy 	{ NFS4ERR_NAMETOOLONG,	-ENAMETOOLONG	},
5785856dff3dSBenny Halevy 	{ NFS4ERR_NOTEMPTY,	-ENOTEMPTY	},
5786856dff3dSBenny Halevy 	{ NFS4ERR_DQUOT,	-EDQUOT		},
5787856dff3dSBenny Halevy 	{ NFS4ERR_STALE,	-ESTALE		},
5788856dff3dSBenny Halevy 	{ NFS4ERR_BADHANDLE,	-EBADHANDLE	},
5789856dff3dSBenny Halevy 	{ NFS4ERR_BADOWNER,	-EINVAL		},
5790856dff3dSBenny Halevy 	{ NFS4ERR_BADNAME,	-EINVAL		},
5791856dff3dSBenny Halevy 	{ NFS4ERR_BAD_COOKIE,	-EBADCOOKIE	},
5792856dff3dSBenny Halevy 	{ NFS4ERR_NOTSUPP,	-ENOTSUPP	},
5793856dff3dSBenny Halevy 	{ NFS4ERR_TOOSMALL,	-ETOOSMALL	},
5794fdcb4577STrond Myklebust 	{ NFS4ERR_SERVERFAULT,	-EREMOTEIO	},
5795856dff3dSBenny Halevy 	{ NFS4ERR_BADTYPE,	-EBADTYPE	},
5796856dff3dSBenny Halevy 	{ NFS4ERR_LOCKED,	-EAGAIN		},
5797856dff3dSBenny Halevy 	{ NFS4ERR_SYMLINK,	-ELOOP		},
5798856dff3dSBenny Halevy 	{ NFS4ERR_OP_ILLEGAL,	-EOPNOTSUPP	},
5799856dff3dSBenny Halevy 	{ NFS4ERR_DEADLOCK,	-EDEADLK	},
5800856dff3dSBenny Halevy 	{ NFS4ERR_WRONGSEC,	-EPERM		}, /* FIXME: this needs
58011da177e4SLinus Torvalds 						    * to be handled by a
58021da177e4SLinus Torvalds 						    * middle-layer.
58031da177e4SLinus Torvalds 						    */
5804856dff3dSBenny Halevy 	{ -1,			-EIO		}
58051da177e4SLinus Torvalds };
58061da177e4SLinus Torvalds 
58071da177e4SLinus Torvalds /*
58081da177e4SLinus Torvalds  * Convert an NFS error code to a local one.
58091da177e4SLinus Torvalds  * This one is used jointly by NFSv2 and NFSv3.
58101da177e4SLinus Torvalds  */
58111da177e4SLinus Torvalds static int
58120a8ea437SDavid Howells nfs4_stat_to_errno(int stat)
58131da177e4SLinus Torvalds {
58141da177e4SLinus Torvalds 	int i;
58151da177e4SLinus Torvalds 	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
58161da177e4SLinus Torvalds 		if (nfs_errtbl[i].stat == stat)
58171da177e4SLinus Torvalds 			return nfs_errtbl[i].errno;
58181da177e4SLinus Torvalds 	}
58191da177e4SLinus Torvalds 	if (stat <= 10000 || stat > 10100) {
58201da177e4SLinus Torvalds 		/* The server is looney tunes. */
5821fdcb4577STrond Myklebust 		return -EREMOTEIO;
58221da177e4SLinus Torvalds 	}
58231da177e4SLinus Torvalds 	/* If we cannot translate the error, the recovery routines should
58241da177e4SLinus Torvalds 	 * handle it.
58251da177e4SLinus Torvalds 	 * Note: remaining NFSv4 error codes have values > 10000, so should
58261da177e4SLinus Torvalds 	 * not conflict with native Linux error codes.
58271da177e4SLinus Torvalds 	 */
5828856dff3dSBenny Halevy 	return -stat;
58291da177e4SLinus Torvalds }
58301da177e4SLinus Torvalds 
58311da177e4SLinus Torvalds #define PROC(proc, argtype, restype)				\
58321da177e4SLinus Torvalds [NFSPROC4_CLNT_##proc] = {					\
58331da177e4SLinus Torvalds 	.p_proc   = NFSPROC4_COMPOUND,				\
58341da177e4SLinus Torvalds 	.p_encode = (kxdrproc_t) nfs4_xdr_##argtype,		\
58351da177e4SLinus Torvalds 	.p_decode = (kxdrproc_t) nfs4_xdr_##restype,		\
58362bea90d4SChuck Lever 	.p_arglen = NFS4_##argtype##_sz,			\
58372bea90d4SChuck Lever 	.p_replen = NFS4_##restype##_sz,			\
5838cc0175c1SChuck Lever 	.p_statidx = NFSPROC4_CLNT_##proc,			\
5839cc0175c1SChuck Lever 	.p_name   = #proc,					\
58401da177e4SLinus Torvalds }
58411da177e4SLinus Torvalds 
58421da177e4SLinus Torvalds struct rpc_procinfo	nfs4_procedures[] = {
58431da177e4SLinus Torvalds   PROC(READ,		enc_read,	dec_read),
58441da177e4SLinus Torvalds   PROC(WRITE,		enc_write,	dec_write),
58451da177e4SLinus Torvalds   PROC(COMMIT,		enc_commit,	dec_commit),
58461da177e4SLinus Torvalds   PROC(OPEN,		enc_open,	dec_open),
58471da177e4SLinus Torvalds   PROC(OPEN_CONFIRM,	enc_open_confirm,	dec_open_confirm),
58481da177e4SLinus Torvalds   PROC(OPEN_NOATTR,	enc_open_noattr,	dec_open_noattr),
58491da177e4SLinus Torvalds   PROC(OPEN_DOWNGRADE,	enc_open_downgrade,	dec_open_downgrade),
58501da177e4SLinus Torvalds   PROC(CLOSE,		enc_close,	dec_close),
58511da177e4SLinus Torvalds   PROC(SETATTR,		enc_setattr,	dec_setattr),
58521da177e4SLinus Torvalds   PROC(FSINFO,		enc_fsinfo,	dec_fsinfo),
58531da177e4SLinus Torvalds   PROC(RENEW,		enc_renew,	dec_renew),
58541da177e4SLinus Torvalds   PROC(SETCLIENTID,	enc_setclientid,	dec_setclientid),
58551da177e4SLinus Torvalds   PROC(SETCLIENTID_CONFIRM,	enc_setclientid_confirm,	dec_setclientid_confirm),
58561da177e4SLinus Torvalds   PROC(LOCK,            enc_lock,       dec_lock),
58571da177e4SLinus Torvalds   PROC(LOCKT,           enc_lockt,      dec_lockt),
58581da177e4SLinus Torvalds   PROC(LOCKU,           enc_locku,      dec_locku),
58591da177e4SLinus Torvalds   PROC(ACCESS,		enc_access,	dec_access),
58601da177e4SLinus Torvalds   PROC(GETATTR,		enc_getattr,	dec_getattr),
58611da177e4SLinus Torvalds   PROC(LOOKUP,		enc_lookup,	dec_lookup),
58621da177e4SLinus Torvalds   PROC(LOOKUP_ROOT,	enc_lookup_root,	dec_lookup_root),
58631da177e4SLinus Torvalds   PROC(REMOVE,		enc_remove,	dec_remove),
58641da177e4SLinus Torvalds   PROC(RENAME,		enc_rename,	dec_rename),
58651da177e4SLinus Torvalds   PROC(LINK,		enc_link,	dec_link),
58661da177e4SLinus Torvalds   PROC(SYMLINK,		enc_symlink,	dec_symlink),
58671da177e4SLinus Torvalds   PROC(CREATE,		enc_create,	dec_create),
58681da177e4SLinus Torvalds   PROC(PATHCONF,	enc_pathconf,	dec_pathconf),
58691da177e4SLinus Torvalds   PROC(STATFS,		enc_statfs,	dec_statfs),
58701da177e4SLinus Torvalds   PROC(READLINK,	enc_readlink,	dec_readlink),
58711da177e4SLinus Torvalds   PROC(READDIR,		enc_readdir,	dec_readdir),
58721da177e4SLinus Torvalds   PROC(SERVER_CAPS,	enc_server_caps, dec_server_caps),
58731da177e4SLinus Torvalds   PROC(DELEGRETURN,	enc_delegreturn, dec_delegreturn),
5874029d105eSJ. Bruce Fields   PROC(GETACL,		enc_getacl,	dec_getacl),
587523ec6965SJ. Bruce Fields   PROC(SETACL,		enc_setacl,	dec_setacl),
5876683b57b4STrond Myklebust   PROC(FS_LOCATIONS,	enc_fs_locations, dec_fs_locations),
587799fe60d0SBenny Halevy #if defined(CONFIG_NFS_V4_1)
587899fe60d0SBenny Halevy   PROC(EXCHANGE_ID,	enc_exchange_id,	dec_exchange_id),
5879fc931582SAndy Adamson   PROC(CREATE_SESSION,	enc_create_session,	dec_create_session),
58800f3e66c6SAndy Adamson   PROC(DESTROY_SESSION,	enc_destroy_session,	dec_destroy_session),
5881fc01cea9SAndy Adamson   PROC(SEQUENCE,	enc_sequence,	dec_sequence),
58822050f0ccSAndy Adamson   PROC(GET_LEASE_TIME,	enc_get_lease_time,	dec_get_lease_time),
588318019753SRicardo Labiaga   PROC(RECLAIM_COMPLETE, enc_reclaim_complete,  dec_reclaim_complete),
588499fe60d0SBenny Halevy #endif /* CONFIG_NFS_V4_1 */
58851da177e4SLinus Torvalds };
58861da177e4SLinus Torvalds 
58871da177e4SLinus Torvalds struct rpc_version		nfs_version4 = {
58881da177e4SLinus Torvalds 	.number			= 4,
5889e8c96f8cSTobias Klauser 	.nrprocs		= ARRAY_SIZE(nfs4_procedures),
58901da177e4SLinus Torvalds 	.procs			= nfs4_procedures
58911da177e4SLinus Torvalds };
58921da177e4SLinus Torvalds 
58931da177e4SLinus Torvalds /*
58941da177e4SLinus Torvalds  * Local variables:
58951da177e4SLinus Torvalds  *  c-basic-offset: 8
58961da177e4SLinus Torvalds  * End:
58971da177e4SLinus Torvalds  */
5898