xref: /openbmc/linux/fs/nfs/nfs4xdr.c (revision 556ae3bb)
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/slab.h>
421da177e4SLinus Torvalds #include <linux/errno.h>
431da177e4SLinus Torvalds #include <linux/string.h>
441da177e4SLinus Torvalds #include <linux/in.h>
451da177e4SLinus Torvalds #include <linux/pagemap.h>
461da177e4SLinus Torvalds #include <linux/proc_fs.h>
471da177e4SLinus Torvalds #include <linux/kdev_t.h>
481da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
492449ea2eSAlexandros Batsakis #include <linux/sunrpc/msg_prot.h>
501da177e4SLinus Torvalds #include <linux/nfs.h>
511da177e4SLinus Torvalds #include <linux/nfs4.h>
521da177e4SLinus Torvalds #include <linux/nfs_fs.h>
531da177e4SLinus Torvalds #include <linux/nfs_idmap.h>
544ce79717STrond Myklebust #include "nfs4_fs.h"
554882ef72SAlexandros Batsakis #include "internal.h"
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds #define NFSDBG_FACILITY		NFSDBG_XDR
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds /* Mapping from NFS error code to "errno" error code. */
601da177e4SLinus Torvalds #define errno_NFSERR_IO		EIO
611da177e4SLinus Torvalds 
620a8ea437SDavid Howells static int nfs4_stat_to_errno(int);
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds /* NFSv4 COMPOUND tags are only wanted for debugging purposes */
651da177e4SLinus Torvalds #ifdef DEBUG
661da177e4SLinus Torvalds #define NFS4_MAXTAGLEN		20
671da177e4SLinus Torvalds #else
681da177e4SLinus Torvalds #define NFS4_MAXTAGLEN		0
691da177e4SLinus Torvalds #endif
701da177e4SLinus Torvalds 
711da177e4SLinus Torvalds /* lock,open owner id:
729f958ab8STrond Myklebust  * we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT  >> 2)
731da177e4SLinus Torvalds  */
749f958ab8STrond Myklebust #define open_owner_id_maxsz	(1 + 4)
759f958ab8STrond Myklebust #define lock_owner_id_maxsz	(1 + 4)
769104a55dSTrond Myklebust #define decode_lockowner_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
771da177e4SLinus Torvalds #define compound_encode_hdr_maxsz	(3 + (NFS4_MAXTAGLEN >> 2))
781da177e4SLinus Torvalds #define compound_decode_hdr_maxsz	(3 + (NFS4_MAXTAGLEN >> 2))
791da177e4SLinus Torvalds #define op_encode_hdr_maxsz	(1)
801da177e4SLinus Torvalds #define op_decode_hdr_maxsz	(2)
819104a55dSTrond Myklebust #define encode_stateid_maxsz	(XDR_QUADLEN(NFS4_STATEID_SIZE))
829104a55dSTrond Myklebust #define decode_stateid_maxsz	(XDR_QUADLEN(NFS4_STATEID_SIZE))
839104a55dSTrond Myklebust #define encode_verifier_maxsz	(XDR_QUADLEN(NFS4_VERIFIER_SIZE))
849104a55dSTrond Myklebust #define decode_verifier_maxsz	(XDR_QUADLEN(NFS4_VERIFIER_SIZE))
851da177e4SLinus Torvalds #define encode_putfh_maxsz	(op_encode_hdr_maxsz + 1 + \
861da177e4SLinus Torvalds 				(NFS4_FHSIZE >> 2))
871da177e4SLinus Torvalds #define decode_putfh_maxsz	(op_decode_hdr_maxsz)
881da177e4SLinus Torvalds #define encode_putrootfh_maxsz	(op_encode_hdr_maxsz)
891da177e4SLinus Torvalds #define decode_putrootfh_maxsz	(op_decode_hdr_maxsz)
901da177e4SLinus Torvalds #define encode_getfh_maxsz      (op_encode_hdr_maxsz)
911da177e4SLinus Torvalds #define decode_getfh_maxsz      (op_decode_hdr_maxsz + 1 + \
921da177e4SLinus Torvalds 				((3+NFS4_FHSIZE) >> 2))
9396928206SJ. Bruce Fields #define nfs4_fattr_bitmap_maxsz 3
9496928206SJ. Bruce Fields #define encode_getattr_maxsz    (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
951da177e4SLinus Torvalds #define nfs4_name_maxsz		(1 + ((3 + NFS4_MAXNAMLEN) >> 2))
961da177e4SLinus Torvalds #define nfs4_path_maxsz		(1 + ((3 + NFS4_MAXPATHLEN) >> 2))
97bd625ba8STrond Myklebust #define nfs4_owner_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
98bd625ba8STrond Myklebust #define nfs4_group_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
9996928206SJ. Bruce Fields /* This is based on getfattr, which uses the most attributes: */
10096928206SJ. Bruce Fields #define nfs4_fattr_value_maxsz	(1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \
101bd625ba8STrond Myklebust 				3 + 3 + 3 + nfs4_owner_maxsz + nfs4_group_maxsz))
10296928206SJ. Bruce Fields #define nfs4_fattr_maxsz	(nfs4_fattr_bitmap_maxsz + \
10396928206SJ. Bruce Fields 				nfs4_fattr_value_maxsz)
10496928206SJ. Bruce Fields #define decode_getattr_maxsz    (op_decode_hdr_maxsz + nfs4_fattr_maxsz)
1059104a55dSTrond Myklebust #define encode_attrs_maxsz	(nfs4_fattr_bitmap_maxsz + \
1069104a55dSTrond Myklebust 				 1 + 2 + 1 + \
1079104a55dSTrond Myklebust 				nfs4_owner_maxsz + \
1089104a55dSTrond Myklebust 				nfs4_group_maxsz + \
1099104a55dSTrond Myklebust 				4 + 4)
1101da177e4SLinus Torvalds #define encode_savefh_maxsz     (op_encode_hdr_maxsz)
1111da177e4SLinus Torvalds #define decode_savefh_maxsz     (op_decode_hdr_maxsz)
11256ae19f3STrond Myklebust #define encode_restorefh_maxsz  (op_encode_hdr_maxsz)
11356ae19f3STrond Myklebust #define decode_restorefh_maxsz  (op_decode_hdr_maxsz)
1142f42b5d0SFred Isaman #define encode_fsinfo_maxsz	(encode_getattr_maxsz)
1151da177e4SLinus Torvalds #define decode_fsinfo_maxsz	(op_decode_hdr_maxsz + 11)
1161da177e4SLinus Torvalds #define encode_renew_maxsz	(op_encode_hdr_maxsz + 3)
1171da177e4SLinus Torvalds #define decode_renew_maxsz	(op_decode_hdr_maxsz)
1181da177e4SLinus Torvalds #define encode_setclientid_maxsz \
1191da177e4SLinus Torvalds 				(op_encode_hdr_maxsz + \
120cc38bac3SChuck Lever 				XDR_QUADLEN(NFS4_VERIFIER_SIZE) + \
121cc38bac3SChuck Lever 				XDR_QUADLEN(NFS4_SETCLIENTID_NAMELEN) + \
122cc38bac3SChuck Lever 				1 /* sc_prog */ + \
123cc38bac3SChuck Lever 				XDR_QUADLEN(RPCBIND_MAXNETIDLEN) + \
124cc38bac3SChuck Lever 				XDR_QUADLEN(RPCBIND_MAXUADDRLEN) + \
125cc38bac3SChuck Lever 				1) /* sc_cb_ident */
1261da177e4SLinus Torvalds #define decode_setclientid_maxsz \
1271da177e4SLinus Torvalds 				(op_decode_hdr_maxsz + \
1281da177e4SLinus Torvalds 				2 + \
1291da177e4SLinus Torvalds 				1024) /* large value for CLID_INUSE */
1301da177e4SLinus Torvalds #define encode_setclientid_confirm_maxsz \
1311da177e4SLinus Torvalds 				(op_encode_hdr_maxsz + \
1321da177e4SLinus Torvalds 				3 + (NFS4_VERIFIER_SIZE >> 2))
1331da177e4SLinus Torvalds #define decode_setclientid_confirm_maxsz \
1341da177e4SLinus Torvalds 				(op_decode_hdr_maxsz)
135e6889620STrond Myklebust #define encode_lookup_maxsz	(op_encode_hdr_maxsz + nfs4_name_maxsz)
136e6889620STrond Myklebust #define decode_lookup_maxsz	(op_decode_hdr_maxsz)
1372cebf828STrond Myklebust #define encode_share_access_maxsz \
1382cebf828STrond Myklebust 				(2)
1394882ef72SAlexandros Batsakis #define encode_createmode_maxsz	(1 + encode_attrs_maxsz + encode_verifier_maxsz)
1402cebf828STrond Myklebust #define encode_opentype_maxsz	(1 + encode_createmode_maxsz)
1412cebf828STrond Myklebust #define encode_claim_null_maxsz	(1 + nfs4_name_maxsz)
1422cebf828STrond Myklebust #define encode_open_maxsz	(op_encode_hdr_maxsz + \
1432cebf828STrond Myklebust 				2 + encode_share_access_maxsz + 2 + \
1442cebf828STrond Myklebust 				open_owner_id_maxsz + \
1452cebf828STrond Myklebust 				encode_opentype_maxsz + \
1462cebf828STrond Myklebust 				encode_claim_null_maxsz)
1472cebf828STrond Myklebust #define decode_ace_maxsz	(3 + nfs4_owner_maxsz)
1489104a55dSTrond Myklebust #define decode_delegation_maxsz	(1 + decode_stateid_maxsz + 1 + \
1492cebf828STrond Myklebust 				decode_ace_maxsz)
1502cebf828STrond Myklebust #define decode_change_info_maxsz	(5)
1512cebf828STrond Myklebust #define decode_open_maxsz	(op_decode_hdr_maxsz + \
1529104a55dSTrond Myklebust 				decode_stateid_maxsz + \
1532cebf828STrond Myklebust 				decode_change_info_maxsz + 1 + \
1542cebf828STrond Myklebust 				nfs4_fattr_bitmap_maxsz + \
1552cebf828STrond Myklebust 				decode_delegation_maxsz)
1569104a55dSTrond Myklebust #define encode_open_confirm_maxsz \
1579104a55dSTrond Myklebust 				(op_encode_hdr_maxsz + \
1589104a55dSTrond Myklebust 				 encode_stateid_maxsz + 1)
1599104a55dSTrond Myklebust #define decode_open_confirm_maxsz \
1609104a55dSTrond Myklebust 				(op_decode_hdr_maxsz + \
1619104a55dSTrond Myklebust 				 decode_stateid_maxsz)
1629104a55dSTrond Myklebust #define encode_open_downgrade_maxsz \
1639104a55dSTrond Myklebust 				(op_encode_hdr_maxsz + \
1649104a55dSTrond Myklebust 				 encode_stateid_maxsz + 1 + \
1659104a55dSTrond Myklebust 				 encode_share_access_maxsz)
1669104a55dSTrond Myklebust #define decode_open_downgrade_maxsz \
1679104a55dSTrond Myklebust 				(op_decode_hdr_maxsz + \
1689104a55dSTrond Myklebust 				 decode_stateid_maxsz)
1699104a55dSTrond Myklebust #define encode_close_maxsz	(op_encode_hdr_maxsz + \
1709104a55dSTrond Myklebust 				 1 + encode_stateid_maxsz)
1719104a55dSTrond Myklebust #define decode_close_maxsz	(op_decode_hdr_maxsz + \
1729104a55dSTrond Myklebust 				 decode_stateid_maxsz)
1739104a55dSTrond Myklebust #define encode_setattr_maxsz	(op_encode_hdr_maxsz + \
1749104a55dSTrond Myklebust 				 encode_stateid_maxsz + \
1759104a55dSTrond Myklebust 				 encode_attrs_maxsz)
1769104a55dSTrond Myklebust #define decode_setattr_maxsz	(op_decode_hdr_maxsz + \
1779104a55dSTrond Myklebust 				 nfs4_fattr_bitmap_maxsz)
1789104a55dSTrond Myklebust #define encode_read_maxsz	(op_encode_hdr_maxsz + \
1799104a55dSTrond Myklebust 				 encode_stateid_maxsz + 3)
1809104a55dSTrond Myklebust #define decode_read_maxsz	(op_decode_hdr_maxsz + 2)
1819104a55dSTrond Myklebust #define encode_readdir_maxsz	(op_encode_hdr_maxsz + \
1829104a55dSTrond Myklebust 				 2 + encode_verifier_maxsz + 5)
1839104a55dSTrond Myklebust #define decode_readdir_maxsz	(op_decode_hdr_maxsz + \
1849104a55dSTrond Myklebust 				 decode_verifier_maxsz)
1859104a55dSTrond Myklebust #define encode_readlink_maxsz	(op_encode_hdr_maxsz)
1869104a55dSTrond Myklebust #define decode_readlink_maxsz	(op_decode_hdr_maxsz + 1)
1879104a55dSTrond Myklebust #define encode_write_maxsz	(op_encode_hdr_maxsz + \
1889104a55dSTrond Myklebust 				 encode_stateid_maxsz + 4)
1899104a55dSTrond Myklebust #define decode_write_maxsz	(op_decode_hdr_maxsz + \
1909104a55dSTrond Myklebust 				 2 + decode_verifier_maxsz)
1919104a55dSTrond Myklebust #define encode_commit_maxsz	(op_encode_hdr_maxsz + 3)
1929104a55dSTrond Myklebust #define decode_commit_maxsz	(op_decode_hdr_maxsz + \
1939104a55dSTrond Myklebust 				 decode_verifier_maxsz)
1941da177e4SLinus Torvalds #define encode_remove_maxsz	(op_encode_hdr_maxsz + \
1951da177e4SLinus Torvalds 				nfs4_name_maxsz)
1966ce18391SBenny Halevy #define decode_remove_maxsz	(op_decode_hdr_maxsz + \
1976ce18391SBenny Halevy 				 decode_change_info_maxsz)
1981da177e4SLinus Torvalds #define encode_rename_maxsz	(op_encode_hdr_maxsz + \
1991da177e4SLinus Torvalds 				2 * nfs4_name_maxsz)
2006ce18391SBenny Halevy #define decode_rename_maxsz	(op_decode_hdr_maxsz + \
2016ce18391SBenny Halevy 				 decode_change_info_maxsz + \
2026ce18391SBenny Halevy 				 decode_change_info_maxsz)
2031da177e4SLinus Torvalds #define encode_link_maxsz	(op_encode_hdr_maxsz + \
2041da177e4SLinus Torvalds 				nfs4_name_maxsz)
2056ce18391SBenny Halevy #define decode_link_maxsz	(op_decode_hdr_maxsz + decode_change_info_maxsz)
2069104a55dSTrond Myklebust #define encode_lock_maxsz	(op_encode_hdr_maxsz + \
2079104a55dSTrond Myklebust 				 7 + \
2089104a55dSTrond Myklebust 				 1 + encode_stateid_maxsz + 8)
2099104a55dSTrond Myklebust #define decode_lock_denied_maxsz \
2109104a55dSTrond Myklebust 				(8 + decode_lockowner_maxsz)
2119104a55dSTrond Myklebust #define decode_lock_maxsz	(op_decode_hdr_maxsz + \
2129104a55dSTrond Myklebust 				 decode_lock_denied_maxsz)
2139104a55dSTrond Myklebust #define encode_lockt_maxsz	(op_encode_hdr_maxsz + 12)
2149104a55dSTrond Myklebust #define decode_lockt_maxsz	(op_decode_hdr_maxsz + \
2159104a55dSTrond Myklebust 				 decode_lock_denied_maxsz)
2169104a55dSTrond Myklebust #define encode_locku_maxsz	(op_encode_hdr_maxsz + 3 + \
2179104a55dSTrond Myklebust 				 encode_stateid_maxsz + \
2189104a55dSTrond Myklebust 				 4)
2199104a55dSTrond Myklebust #define decode_locku_maxsz	(op_decode_hdr_maxsz + \
2209104a55dSTrond Myklebust 				 decode_stateid_maxsz)
2219104a55dSTrond Myklebust #define encode_access_maxsz	(op_encode_hdr_maxsz + 1)
2229104a55dSTrond Myklebust #define decode_access_maxsz	(op_decode_hdr_maxsz + 2)
2231da177e4SLinus Torvalds #define encode_symlink_maxsz	(op_encode_hdr_maxsz + \
2241da177e4SLinus Torvalds 				1 + nfs4_name_maxsz + \
22594a6d753SChuck Lever 				1 + \
22696928206SJ. Bruce Fields 				nfs4_fattr_maxsz)
2271da177e4SLinus Torvalds #define decode_symlink_maxsz	(op_decode_hdr_maxsz + 8)
2281da177e4SLinus Torvalds #define encode_create_maxsz	(op_encode_hdr_maxsz + \
2299104a55dSTrond Myklebust 				1 + 2 + nfs4_name_maxsz + \
2309104a55dSTrond Myklebust 				encode_attrs_maxsz)
2312cebf828STrond Myklebust #define decode_create_maxsz	(op_decode_hdr_maxsz + \
2322cebf828STrond Myklebust 				decode_change_info_maxsz + \
2332cebf828STrond Myklebust 				nfs4_fattr_bitmap_maxsz)
2349104a55dSTrond Myklebust #define encode_statfs_maxsz	(encode_getattr_maxsz)
2359104a55dSTrond Myklebust #define decode_statfs_maxsz	(decode_getattr_maxsz)
2361da177e4SLinus Torvalds #define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4)
2371da177e4SLinus Torvalds #define decode_delegreturn_maxsz (op_decode_hdr_maxsz)
2389104a55dSTrond Myklebust #define encode_getacl_maxsz	(encode_getattr_maxsz)
2399104a55dSTrond Myklebust #define decode_getacl_maxsz	(op_decode_hdr_maxsz + \
2409104a55dSTrond Myklebust 				 nfs4_fattr_bitmap_maxsz + 1)
2419104a55dSTrond Myklebust #define encode_setacl_maxsz	(op_encode_hdr_maxsz + \
2429104a55dSTrond Myklebust 				 encode_stateid_maxsz + 3)
2439104a55dSTrond Myklebust #define decode_setacl_maxsz	(decode_setattr_maxsz)
244e6889620STrond Myklebust #define encode_fs_locations_maxsz \
245e6889620STrond Myklebust 				(encode_getattr_maxsz)
246e6889620STrond Myklebust #define decode_fs_locations_maxsz \
247e6889620STrond Myklebust 				(0)
2489b7b9fccSAndy Adamson 
2499b7b9fccSAndy Adamson #if defined(CONFIG_NFS_V4_1)
250fc931582SAndy Adamson #define NFS4_MAX_MACHINE_NAME_LEN (64)
251fc931582SAndy Adamson 
25299fe60d0SBenny Halevy #define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \
25399fe60d0SBenny Halevy 				encode_verifier_maxsz + \
25499fe60d0SBenny Halevy 				1 /* co_ownerid.len */ + \
25599fe60d0SBenny Halevy 				XDR_QUADLEN(NFS4_EXCHANGE_ID_LEN) + \
25699fe60d0SBenny Halevy 				1 /* flags */ + \
25799fe60d0SBenny Halevy 				1 /* spa_how */ + \
25899fe60d0SBenny Halevy 				0 /* SP4_NONE (for now) */ + \
25999fe60d0SBenny Halevy 				1 /* zero implemetation id array */)
26099fe60d0SBenny Halevy #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \
26199fe60d0SBenny Halevy 				2 /* eir_clientid */ + \
26299fe60d0SBenny Halevy 				1 /* eir_sequenceid */ + \
26399fe60d0SBenny Halevy 				1 /* eir_flags */ + \
26499fe60d0SBenny Halevy 				1 /* spr_how */ + \
26599fe60d0SBenny Halevy 				0 /* SP4_NONE (for now) */ + \
26699fe60d0SBenny Halevy 				2 /* eir_server_owner.so_minor_id */ + \
26799fe60d0SBenny Halevy 				/* eir_server_owner.so_major_id<> */ \
26899fe60d0SBenny Halevy 				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \
26999fe60d0SBenny Halevy 				/* eir_server_scope<> */ \
27099fe60d0SBenny Halevy 				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \
27199fe60d0SBenny Halevy 				1 /* eir_server_impl_id array length */ + \
27299fe60d0SBenny Halevy 				0 /* ignored eir_server_impl_id contents */)
273fc931582SAndy Adamson #define encode_channel_attrs_maxsz  (6 + 1 /* ca_rdma_ird.len (0) */)
274fc931582SAndy Adamson #define decode_channel_attrs_maxsz  (6 + \
275fc931582SAndy Adamson 				     1 /* ca_rdma_ird.len */ + \
276fc931582SAndy Adamson 				     1 /* ca_rdma_ird */)
277fc931582SAndy Adamson #define encode_create_session_maxsz  (op_encode_hdr_maxsz + \
278fc931582SAndy Adamson 				     2 /* csa_clientid */ + \
279fc931582SAndy Adamson 				     1 /* csa_sequence */ + \
280fc931582SAndy Adamson 				     1 /* csa_flags */ + \
281fc931582SAndy Adamson 				     encode_channel_attrs_maxsz + \
282fc931582SAndy Adamson 				     encode_channel_attrs_maxsz + \
283fc931582SAndy Adamson 				     1 /* csa_cb_program */ + \
284fc931582SAndy Adamson 				     1 /* csa_sec_parms.len (1) */ + \
285fc931582SAndy Adamson 				     1 /* cb_secflavor (AUTH_SYS) */ + \
286fc931582SAndy Adamson 				     1 /* stamp */ + \
287fc931582SAndy Adamson 				     1 /* machinename.len */ + \
288fc931582SAndy Adamson 				     XDR_QUADLEN(NFS4_MAX_MACHINE_NAME_LEN) + \
289fc931582SAndy Adamson 				     1 /* uid */ + \
290fc931582SAndy Adamson 				     1 /* gid */ + \
291fc931582SAndy Adamson 				     1 /* gids.len (0) */)
292fc931582SAndy Adamson #define decode_create_session_maxsz  (op_decode_hdr_maxsz +	\
293fc931582SAndy Adamson 				     XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
294fc931582SAndy Adamson 				     1 /* csr_sequence */ + \
295fc931582SAndy Adamson 				     1 /* csr_flags */ + \
296fc931582SAndy Adamson 				     decode_channel_attrs_maxsz + \
297fc931582SAndy Adamson 				     decode_channel_attrs_maxsz)
2980f3e66c6SAndy Adamson #define encode_destroy_session_maxsz    (op_encode_hdr_maxsz + 4)
2990f3e66c6SAndy Adamson #define decode_destroy_session_maxsz    (op_decode_hdr_maxsz)
300fc01cea9SAndy Adamson #define encode_sequence_maxsz	(op_encode_hdr_maxsz + \
301fc01cea9SAndy Adamson 				XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 4)
302fc01cea9SAndy Adamson #define decode_sequence_maxsz	(op_decode_hdr_maxsz + \
303fc01cea9SAndy Adamson 				XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5)
30418019753SRicardo Labiaga #define encode_reclaim_complete_maxsz	(op_encode_hdr_maxsz + 4)
30518019753SRicardo Labiaga #define decode_reclaim_complete_maxsz	(op_decode_hdr_maxsz + 4)
3069b7b9fccSAndy Adamson #else /* CONFIG_NFS_V4_1 */
3079b7b9fccSAndy Adamson #define encode_sequence_maxsz	0
3089b7b9fccSAndy Adamson #define decode_sequence_maxsz	0
3099b7b9fccSAndy Adamson #endif /* CONFIG_NFS_V4_1 */
3109b7b9fccSAndy Adamson 
3111da177e4SLinus Torvalds #define NFS4_enc_compound_sz	(1024)  /* XXX: large enough? */
3121da177e4SLinus Torvalds #define NFS4_dec_compound_sz	(1024)  /* XXX: large enough? */
3131da177e4SLinus Torvalds #define NFS4_enc_read_sz	(compound_encode_hdr_maxsz + \
3149b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
3151da177e4SLinus Torvalds 				encode_putfh_maxsz + \
3169104a55dSTrond Myklebust 				encode_read_maxsz)
3171da177e4SLinus Torvalds #define NFS4_dec_read_sz	(compound_decode_hdr_maxsz + \
3189b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
3191da177e4SLinus Torvalds 				decode_putfh_maxsz + \
3209104a55dSTrond Myklebust 				decode_read_maxsz)
3211da177e4SLinus Torvalds #define NFS4_enc_readlink_sz	(compound_encode_hdr_maxsz + \
3229b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
3231da177e4SLinus Torvalds 				encode_putfh_maxsz + \
3249104a55dSTrond Myklebust 				encode_readlink_maxsz)
3251da177e4SLinus Torvalds #define NFS4_dec_readlink_sz	(compound_decode_hdr_maxsz + \
3269b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
3271da177e4SLinus Torvalds 				decode_putfh_maxsz + \
3289104a55dSTrond Myklebust 				decode_readlink_maxsz)
3291da177e4SLinus Torvalds #define NFS4_enc_readdir_sz	(compound_encode_hdr_maxsz + \
3309b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
3311da177e4SLinus Torvalds 				encode_putfh_maxsz + \
3329104a55dSTrond Myklebust 				encode_readdir_maxsz)
3331da177e4SLinus Torvalds #define NFS4_dec_readdir_sz	(compound_decode_hdr_maxsz + \
3349b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
3351da177e4SLinus Torvalds 				decode_putfh_maxsz + \
3369104a55dSTrond Myklebust 				decode_readdir_maxsz)
3371da177e4SLinus Torvalds #define NFS4_enc_write_sz	(compound_encode_hdr_maxsz + \
3389b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
3391da177e4SLinus Torvalds 				encode_putfh_maxsz + \
3409104a55dSTrond Myklebust 				encode_write_maxsz + \
3414f9838c7STrond Myklebust 				encode_getattr_maxsz)
3421da177e4SLinus Torvalds #define NFS4_dec_write_sz	(compound_decode_hdr_maxsz + \
3439b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
3441da177e4SLinus Torvalds 				decode_putfh_maxsz + \
3459104a55dSTrond Myklebust 				decode_write_maxsz + \
3464f9838c7STrond Myklebust 				decode_getattr_maxsz)
3471da177e4SLinus Torvalds #define NFS4_enc_commit_sz	(compound_encode_hdr_maxsz + \
3489b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
3491da177e4SLinus Torvalds 				encode_putfh_maxsz + \
3509104a55dSTrond Myklebust 				encode_commit_maxsz + \
3514f9838c7STrond Myklebust 				encode_getattr_maxsz)
3521da177e4SLinus Torvalds #define NFS4_dec_commit_sz	(compound_decode_hdr_maxsz + \
3539b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
3541da177e4SLinus Torvalds 				decode_putfh_maxsz + \
3559104a55dSTrond Myklebust 				decode_commit_maxsz + \
3564f9838c7STrond Myklebust 				decode_getattr_maxsz)
3571da177e4SLinus Torvalds #define NFS4_enc_open_sz        (compound_encode_hdr_maxsz + \
3589b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
3591da177e4SLinus Torvalds 				encode_putfh_maxsz + \
3602cebf828STrond Myklebust 				encode_savefh_maxsz + \
3612cebf828STrond Myklebust 				encode_open_maxsz + \
3622cebf828STrond Myklebust 				encode_getfh_maxsz + \
3631da177e4SLinus Torvalds 				encode_getattr_maxsz + \
3642cebf828STrond Myklebust 				encode_restorefh_maxsz + \
3652cebf828STrond Myklebust 				encode_getattr_maxsz)
3661da177e4SLinus Torvalds #define NFS4_dec_open_sz        (compound_decode_hdr_maxsz + \
3679b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
3681da177e4SLinus Torvalds 				decode_putfh_maxsz + \
3692cebf828STrond Myklebust 				decode_savefh_maxsz + \
3702cebf828STrond Myklebust 				decode_open_maxsz + \
3712cebf828STrond Myklebust 				decode_getfh_maxsz + \
3721da177e4SLinus Torvalds 				decode_getattr_maxsz + \
3732cebf828STrond Myklebust 				decode_restorefh_maxsz + \
3742cebf828STrond Myklebust 				decode_getattr_maxsz)
3751da177e4SLinus Torvalds #define NFS4_enc_open_confirm_sz \
3761da177e4SLinus Torvalds 				(compound_encode_hdr_maxsz + \
3771da177e4SLinus Torvalds 				 encode_putfh_maxsz + \
3789104a55dSTrond Myklebust 				 encode_open_confirm_maxsz)
3799104a55dSTrond Myklebust #define NFS4_dec_open_confirm_sz \
3809104a55dSTrond Myklebust 				(compound_decode_hdr_maxsz + \
3811da177e4SLinus Torvalds 				 decode_putfh_maxsz + \
3829104a55dSTrond Myklebust 				 decode_open_confirm_maxsz)
3831da177e4SLinus Torvalds #define NFS4_enc_open_noattr_sz	(compound_encode_hdr_maxsz + \
3849b7b9fccSAndy Adamson 					encode_sequence_maxsz + \
3851da177e4SLinus Torvalds 					encode_putfh_maxsz + \
3862cebf828STrond Myklebust 					encode_open_maxsz + \
3872cebf828STrond Myklebust 					encode_getattr_maxsz)
3881da177e4SLinus Torvalds #define NFS4_dec_open_noattr_sz	(compound_decode_hdr_maxsz + \
3899b7b9fccSAndy Adamson 					decode_sequence_maxsz + \
3901da177e4SLinus Torvalds 					decode_putfh_maxsz + \
3912cebf828STrond Myklebust 					decode_open_maxsz + \
3922cebf828STrond Myklebust 					decode_getattr_maxsz)
3931da177e4SLinus Torvalds #define NFS4_enc_open_downgrade_sz \
3941da177e4SLinus Torvalds 				(compound_encode_hdr_maxsz + \
3959b7b9fccSAndy Adamson 				 encode_sequence_maxsz + \
3961da177e4SLinus Torvalds 				 encode_putfh_maxsz + \
3979104a55dSTrond Myklebust 				 encode_open_downgrade_maxsz + \
398516a6af6STrond Myklebust 				 encode_getattr_maxsz)
3991da177e4SLinus Torvalds #define NFS4_dec_open_downgrade_sz \
4001da177e4SLinus Torvalds 				(compound_decode_hdr_maxsz + \
4019b7b9fccSAndy Adamson 				 decode_sequence_maxsz + \
4021da177e4SLinus Torvalds 				 decode_putfh_maxsz + \
4039104a55dSTrond Myklebust 				 decode_open_downgrade_maxsz + \
404516a6af6STrond Myklebust 				 decode_getattr_maxsz)
4051da177e4SLinus Torvalds #define NFS4_enc_close_sz	(compound_encode_hdr_maxsz + \
4069b7b9fccSAndy Adamson 				 encode_sequence_maxsz + \
4071da177e4SLinus Torvalds 				 encode_putfh_maxsz + \
4089104a55dSTrond Myklebust 				 encode_close_maxsz + \
409516a6af6STrond Myklebust 				 encode_getattr_maxsz)
4101da177e4SLinus Torvalds #define NFS4_dec_close_sz	(compound_decode_hdr_maxsz + \
4119b7b9fccSAndy Adamson 				 decode_sequence_maxsz + \
4121da177e4SLinus Torvalds 				 decode_putfh_maxsz + \
4139104a55dSTrond Myklebust 				 decode_close_maxsz + \
414516a6af6STrond Myklebust 				 decode_getattr_maxsz)
4151da177e4SLinus Torvalds #define NFS4_enc_setattr_sz	(compound_encode_hdr_maxsz + \
4169b7b9fccSAndy Adamson 				 encode_sequence_maxsz + \
4171da177e4SLinus Torvalds 				 encode_putfh_maxsz + \
4189104a55dSTrond Myklebust 				 encode_setattr_maxsz + \
4191da177e4SLinus Torvalds 				 encode_getattr_maxsz)
4201da177e4SLinus Torvalds #define NFS4_dec_setattr_sz	(compound_decode_hdr_maxsz + \
4219b7b9fccSAndy Adamson 				 decode_sequence_maxsz + \
4221da177e4SLinus Torvalds 				 decode_putfh_maxsz + \
4239104a55dSTrond Myklebust 				 decode_setattr_maxsz + \
4249104a55dSTrond Myklebust 				 decode_getattr_maxsz)
4251da177e4SLinus Torvalds #define NFS4_enc_fsinfo_sz	(compound_encode_hdr_maxsz + \
4269b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
4271da177e4SLinus Torvalds 				encode_putfh_maxsz + \
4281da177e4SLinus Torvalds 				encode_fsinfo_maxsz)
4291da177e4SLinus Torvalds #define NFS4_dec_fsinfo_sz	(compound_decode_hdr_maxsz + \
4309b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
4311da177e4SLinus Torvalds 				decode_putfh_maxsz + \
4321da177e4SLinus Torvalds 				decode_fsinfo_maxsz)
4331da177e4SLinus Torvalds #define NFS4_enc_renew_sz	(compound_encode_hdr_maxsz + \
4341da177e4SLinus Torvalds 				encode_renew_maxsz)
4351da177e4SLinus Torvalds #define NFS4_dec_renew_sz	(compound_decode_hdr_maxsz + \
4361da177e4SLinus Torvalds 				decode_renew_maxsz)
4371da177e4SLinus Torvalds #define NFS4_enc_setclientid_sz	(compound_encode_hdr_maxsz + \
4381da177e4SLinus Torvalds 				encode_setclientid_maxsz)
4391da177e4SLinus Torvalds #define NFS4_dec_setclientid_sz	(compound_decode_hdr_maxsz + \
4401da177e4SLinus Torvalds 				decode_setclientid_maxsz)
4411da177e4SLinus Torvalds #define NFS4_enc_setclientid_confirm_sz \
4421da177e4SLinus Torvalds 				(compound_encode_hdr_maxsz + \
4431da177e4SLinus Torvalds 				encode_setclientid_confirm_maxsz + \
4441da177e4SLinus Torvalds 				encode_putrootfh_maxsz + \
4451da177e4SLinus Torvalds 				encode_fsinfo_maxsz)
4461da177e4SLinus Torvalds #define NFS4_dec_setclientid_confirm_sz \
4471da177e4SLinus Torvalds 				(compound_decode_hdr_maxsz + \
4481da177e4SLinus Torvalds 				decode_setclientid_confirm_maxsz + \
4491da177e4SLinus Torvalds 				decode_putrootfh_maxsz + \
4501da177e4SLinus Torvalds 				decode_fsinfo_maxsz)
4511da177e4SLinus Torvalds #define NFS4_enc_lock_sz        (compound_encode_hdr_maxsz + \
4529b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
4531da177e4SLinus Torvalds 				encode_putfh_maxsz + \
4549104a55dSTrond Myklebust 				encode_lock_maxsz)
4551da177e4SLinus Torvalds #define NFS4_dec_lock_sz        (compound_decode_hdr_maxsz + \
4569b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
4571da177e4SLinus Torvalds 				decode_putfh_maxsz + \
4589104a55dSTrond Myklebust 				decode_lock_maxsz)
4591da177e4SLinus Torvalds #define NFS4_enc_lockt_sz       (compound_encode_hdr_maxsz + \
4609b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
4611da177e4SLinus Torvalds 				encode_putfh_maxsz + \
4629104a55dSTrond Myklebust 				encode_lockt_maxsz)
4639104a55dSTrond Myklebust #define NFS4_dec_lockt_sz       (compound_decode_hdr_maxsz + \
4649b7b9fccSAndy Adamson 				 decode_sequence_maxsz + \
4659104a55dSTrond Myklebust 				 decode_putfh_maxsz + \
4669104a55dSTrond Myklebust 				 decode_lockt_maxsz)
4671da177e4SLinus Torvalds #define NFS4_enc_locku_sz       (compound_encode_hdr_maxsz + \
4689b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
4691da177e4SLinus Torvalds 				encode_putfh_maxsz + \
4709104a55dSTrond Myklebust 				encode_locku_maxsz)
4711da177e4SLinus Torvalds #define NFS4_dec_locku_sz       (compound_decode_hdr_maxsz + \
4729b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
4731da177e4SLinus Torvalds 				decode_putfh_maxsz + \
4749104a55dSTrond Myklebust 				decode_locku_maxsz)
4751da177e4SLinus Torvalds #define NFS4_enc_access_sz	(compound_encode_hdr_maxsz + \
4769b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
4771da177e4SLinus Torvalds 				encode_putfh_maxsz + \
47876b32999STrond Myklebust 				encode_access_maxsz + \
47976b32999STrond Myklebust 				encode_getattr_maxsz)
4801da177e4SLinus Torvalds #define NFS4_dec_access_sz	(compound_decode_hdr_maxsz + \
4819b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
4821da177e4SLinus Torvalds 				decode_putfh_maxsz + \
48376b32999STrond Myklebust 				decode_access_maxsz + \
48476b32999STrond Myklebust 				decode_getattr_maxsz)
4851da177e4SLinus Torvalds #define NFS4_enc_getattr_sz	(compound_encode_hdr_maxsz + \
4869b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
4871da177e4SLinus Torvalds 				encode_putfh_maxsz + \
4881da177e4SLinus Torvalds 				encode_getattr_maxsz)
4891da177e4SLinus Torvalds #define NFS4_dec_getattr_sz	(compound_decode_hdr_maxsz + \
4909b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
4911da177e4SLinus Torvalds 				decode_putfh_maxsz + \
4921da177e4SLinus Torvalds 				decode_getattr_maxsz)
4931da177e4SLinus Torvalds #define NFS4_enc_lookup_sz	(compound_encode_hdr_maxsz + \
4949b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
4951da177e4SLinus Torvalds 				encode_putfh_maxsz + \
4961da177e4SLinus Torvalds 				encode_lookup_maxsz + \
4971da177e4SLinus Torvalds 				encode_getattr_maxsz + \
4981da177e4SLinus Torvalds 				encode_getfh_maxsz)
4991da177e4SLinus Torvalds #define NFS4_dec_lookup_sz	(compound_decode_hdr_maxsz + \
5009b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
5011da177e4SLinus Torvalds 				decode_putfh_maxsz + \
502e6889620STrond Myklebust 				decode_lookup_maxsz + \
5031da177e4SLinus Torvalds 				decode_getattr_maxsz + \
5041da177e4SLinus Torvalds 				decode_getfh_maxsz)
5051da177e4SLinus Torvalds #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \
5069b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
5071da177e4SLinus Torvalds 				encode_putrootfh_maxsz + \
5081da177e4SLinus Torvalds 				encode_getattr_maxsz + \
5091da177e4SLinus Torvalds 				encode_getfh_maxsz)
5101da177e4SLinus Torvalds #define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \
5119b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
5121da177e4SLinus Torvalds 				decode_putrootfh_maxsz + \
5131da177e4SLinus Torvalds 				decode_getattr_maxsz + \
5141da177e4SLinus Torvalds 				decode_getfh_maxsz)
5151da177e4SLinus Torvalds #define NFS4_enc_remove_sz	(compound_encode_hdr_maxsz + \
5169b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
5171da177e4SLinus Torvalds 				encode_putfh_maxsz + \
51816e42959STrond Myklebust 				encode_remove_maxsz + \
51916e42959STrond Myklebust 				encode_getattr_maxsz)
5201da177e4SLinus Torvalds #define NFS4_dec_remove_sz	(compound_decode_hdr_maxsz + \
5219b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
5221da177e4SLinus Torvalds 				decode_putfh_maxsz + \
5236ce18391SBenny Halevy 				decode_remove_maxsz + \
52416e42959STrond Myklebust 				decode_getattr_maxsz)
5251da177e4SLinus Torvalds #define NFS4_enc_rename_sz	(compound_encode_hdr_maxsz + \
5269b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
5271da177e4SLinus Torvalds 				encode_putfh_maxsz + \
5281da177e4SLinus Torvalds 				encode_savefh_maxsz + \
5291da177e4SLinus Torvalds 				encode_putfh_maxsz + \
5306caf2c82STrond Myklebust 				encode_rename_maxsz + \
5316caf2c82STrond Myklebust 				encode_getattr_maxsz + \
5326caf2c82STrond Myklebust 				encode_restorefh_maxsz + \
5336caf2c82STrond Myklebust 				encode_getattr_maxsz)
5341da177e4SLinus Torvalds #define NFS4_dec_rename_sz	(compound_decode_hdr_maxsz + \
5359b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
5361da177e4SLinus Torvalds 				decode_putfh_maxsz + \
5371da177e4SLinus Torvalds 				decode_savefh_maxsz + \
5381da177e4SLinus Torvalds 				decode_putfh_maxsz + \
5396caf2c82STrond Myklebust 				decode_rename_maxsz + \
5406caf2c82STrond Myklebust 				decode_getattr_maxsz + \
5416caf2c82STrond Myklebust 				decode_restorefh_maxsz + \
5426caf2c82STrond Myklebust 				decode_getattr_maxsz)
5431da177e4SLinus Torvalds #define NFS4_enc_link_sz	(compound_encode_hdr_maxsz + \
5449b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
5451da177e4SLinus Torvalds 				encode_putfh_maxsz + \
5461da177e4SLinus Torvalds 				encode_savefh_maxsz + \
5471da177e4SLinus Torvalds 				encode_putfh_maxsz + \
54891ba2eeeSTrond Myklebust 				encode_link_maxsz + \
54991ba2eeeSTrond Myklebust 				decode_getattr_maxsz + \
55091ba2eeeSTrond Myklebust 				encode_restorefh_maxsz + \
55191ba2eeeSTrond Myklebust 				decode_getattr_maxsz)
5521da177e4SLinus Torvalds #define NFS4_dec_link_sz	(compound_decode_hdr_maxsz + \
5539b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
5541da177e4SLinus Torvalds 				decode_putfh_maxsz + \
5551da177e4SLinus Torvalds 				decode_savefh_maxsz + \
5561da177e4SLinus Torvalds 				decode_putfh_maxsz + \
55791ba2eeeSTrond Myklebust 				decode_link_maxsz + \
55891ba2eeeSTrond Myklebust 				decode_getattr_maxsz + \
55991ba2eeeSTrond Myklebust 				decode_restorefh_maxsz + \
56091ba2eeeSTrond Myklebust 				decode_getattr_maxsz)
5611da177e4SLinus Torvalds #define NFS4_enc_symlink_sz	(compound_encode_hdr_maxsz + \
5629b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
5631da177e4SLinus Torvalds 				encode_putfh_maxsz + \
5641da177e4SLinus Torvalds 				encode_symlink_maxsz + \
5651da177e4SLinus Torvalds 				encode_getattr_maxsz + \
5661da177e4SLinus Torvalds 				encode_getfh_maxsz)
5671da177e4SLinus Torvalds #define NFS4_dec_symlink_sz	(compound_decode_hdr_maxsz + \
5689b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
5691da177e4SLinus Torvalds 				decode_putfh_maxsz + \
5701da177e4SLinus Torvalds 				decode_symlink_maxsz + \
5711da177e4SLinus Torvalds 				decode_getattr_maxsz + \
5721da177e4SLinus Torvalds 				decode_getfh_maxsz)
5731da177e4SLinus Torvalds #define NFS4_enc_create_sz	(compound_encode_hdr_maxsz + \
5749b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
5751da177e4SLinus Torvalds 				encode_putfh_maxsz + \
57656ae19f3STrond Myklebust 				encode_savefh_maxsz + \
5771da177e4SLinus Torvalds 				encode_create_maxsz + \
57856ae19f3STrond Myklebust 				encode_getfh_maxsz + \
5791da177e4SLinus Torvalds 				encode_getattr_maxsz + \
58056ae19f3STrond Myklebust 				encode_restorefh_maxsz + \
58156ae19f3STrond Myklebust 				encode_getattr_maxsz)
5821da177e4SLinus Torvalds #define NFS4_dec_create_sz	(compound_decode_hdr_maxsz + \
5839b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
5841da177e4SLinus Torvalds 				decode_putfh_maxsz + \
58556ae19f3STrond Myklebust 				decode_savefh_maxsz + \
5861da177e4SLinus Torvalds 				decode_create_maxsz + \
58756ae19f3STrond Myklebust 				decode_getfh_maxsz + \
5881da177e4SLinus Torvalds 				decode_getattr_maxsz + \
58956ae19f3STrond Myklebust 				decode_restorefh_maxsz + \
59056ae19f3STrond Myklebust 				decode_getattr_maxsz)
5911da177e4SLinus Torvalds #define NFS4_enc_pathconf_sz	(compound_encode_hdr_maxsz + \
5929b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
5931da177e4SLinus Torvalds 				encode_putfh_maxsz + \
5941da177e4SLinus Torvalds 				encode_getattr_maxsz)
5951da177e4SLinus Torvalds #define NFS4_dec_pathconf_sz	(compound_decode_hdr_maxsz + \
5969b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
5971da177e4SLinus Torvalds 				decode_putfh_maxsz + \
5981da177e4SLinus Torvalds 				decode_getattr_maxsz)
5991da177e4SLinus Torvalds #define NFS4_enc_statfs_sz	(compound_encode_hdr_maxsz + \
6009b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
6011da177e4SLinus Torvalds 				encode_putfh_maxsz + \
6029104a55dSTrond Myklebust 				encode_statfs_maxsz)
6031da177e4SLinus Torvalds #define NFS4_dec_statfs_sz	(compound_decode_hdr_maxsz + \
6049b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
6051da177e4SLinus Torvalds 				decode_putfh_maxsz + \
6069104a55dSTrond Myklebust 				decode_statfs_maxsz)
6071da177e4SLinus Torvalds #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \
6089b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
609ab91f264STrond Myklebust 				encode_putfh_maxsz + \
6101da177e4SLinus Torvalds 				encode_getattr_maxsz)
6111da177e4SLinus Torvalds #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \
6129b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
613ab91f264STrond Myklebust 				decode_putfh_maxsz + \
6141da177e4SLinus Torvalds 				decode_getattr_maxsz)
6151da177e4SLinus Torvalds #define NFS4_enc_delegreturn_sz	(compound_encode_hdr_maxsz + \
6169b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
6171da177e4SLinus Torvalds 				encode_putfh_maxsz + \
618fa178f29STrond Myklebust 				encode_delegreturn_maxsz + \
619fa178f29STrond Myklebust 				encode_getattr_maxsz)
6201da177e4SLinus Torvalds #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
6219b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
622fa178f29STrond Myklebust 				decode_delegreturn_maxsz + \
623fa178f29STrond Myklebust 				decode_getattr_maxsz)
624029d105eSJ. Bruce Fields #define NFS4_enc_getacl_sz	(compound_encode_hdr_maxsz + \
6259b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
626029d105eSJ. Bruce Fields 				encode_putfh_maxsz + \
6279104a55dSTrond Myklebust 				encode_getacl_maxsz)
628029d105eSJ. Bruce Fields #define NFS4_dec_getacl_sz	(compound_decode_hdr_maxsz + \
6299b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
630029d105eSJ. Bruce Fields 				decode_putfh_maxsz + \
6319104a55dSTrond Myklebust 				decode_getacl_maxsz)
63223ec6965SJ. Bruce Fields #define NFS4_enc_setacl_sz	(compound_encode_hdr_maxsz + \
6339b7b9fccSAndy Adamson 				encode_sequence_maxsz + \
63423ec6965SJ. Bruce Fields 				encode_putfh_maxsz + \
6359104a55dSTrond Myklebust 				encode_setacl_maxsz)
63623ec6965SJ. Bruce Fields #define NFS4_dec_setacl_sz	(compound_decode_hdr_maxsz + \
6379b7b9fccSAndy Adamson 				decode_sequence_maxsz + \
63823ec6965SJ. Bruce Fields 				decode_putfh_maxsz + \
6399104a55dSTrond Myklebust 				decode_setacl_maxsz)
640683b57b4STrond Myklebust #define NFS4_enc_fs_locations_sz \
641683b57b4STrond Myklebust 				(compound_encode_hdr_maxsz + \
6429b7b9fccSAndy Adamson 				 encode_sequence_maxsz + \
643683b57b4STrond Myklebust 				 encode_putfh_maxsz + \
644e6889620STrond Myklebust 				 encode_lookup_maxsz + \
645e6889620STrond Myklebust 				 encode_fs_locations_maxsz)
646683b57b4STrond Myklebust #define NFS4_dec_fs_locations_sz \
647683b57b4STrond Myklebust 				(compound_decode_hdr_maxsz + \
6489b7b9fccSAndy Adamson 				 decode_sequence_maxsz + \
649683b57b4STrond Myklebust 				 decode_putfh_maxsz + \
650e6889620STrond Myklebust 				 decode_lookup_maxsz + \
651e6889620STrond Myklebust 				 decode_fs_locations_maxsz)
65299fe60d0SBenny Halevy #if defined(CONFIG_NFS_V4_1)
65399fe60d0SBenny Halevy #define NFS4_enc_exchange_id_sz \
65499fe60d0SBenny Halevy 				(compound_encode_hdr_maxsz + \
65599fe60d0SBenny Halevy 				 encode_exchange_id_maxsz)
65699fe60d0SBenny Halevy #define NFS4_dec_exchange_id_sz \
65799fe60d0SBenny Halevy 				(compound_decode_hdr_maxsz + \
65899fe60d0SBenny Halevy 				 decode_exchange_id_maxsz)
659fc931582SAndy Adamson #define NFS4_enc_create_session_sz \
660fc931582SAndy Adamson 				(compound_encode_hdr_maxsz + \
661fc931582SAndy Adamson 				 encode_create_session_maxsz)
662fc931582SAndy Adamson #define NFS4_dec_create_session_sz \
663fc931582SAndy Adamson 				(compound_decode_hdr_maxsz + \
664fc931582SAndy Adamson 				 decode_create_session_maxsz)
6650f3e66c6SAndy Adamson #define NFS4_enc_destroy_session_sz	(compound_encode_hdr_maxsz + \
6660f3e66c6SAndy Adamson 					 encode_destroy_session_maxsz)
6670f3e66c6SAndy Adamson #define NFS4_dec_destroy_session_sz	(compound_decode_hdr_maxsz + \
6680f3e66c6SAndy Adamson 					 decode_destroy_session_maxsz)
669fc01cea9SAndy Adamson #define NFS4_enc_sequence_sz \
670fc01cea9SAndy Adamson 				(compound_decode_hdr_maxsz + \
671fc01cea9SAndy Adamson 				 encode_sequence_maxsz)
672fc01cea9SAndy Adamson #define NFS4_dec_sequence_sz \
673fc01cea9SAndy Adamson 				(compound_decode_hdr_maxsz + \
674fc01cea9SAndy Adamson 				 decode_sequence_maxsz)
6752050f0ccSAndy Adamson #define NFS4_enc_get_lease_time_sz	(compound_encode_hdr_maxsz + \
6762050f0ccSAndy Adamson 					 encode_sequence_maxsz + \
6772050f0ccSAndy Adamson 					 encode_putrootfh_maxsz + \
6782050f0ccSAndy Adamson 					 encode_fsinfo_maxsz)
6792050f0ccSAndy Adamson #define NFS4_dec_get_lease_time_sz	(compound_decode_hdr_maxsz + \
6802050f0ccSAndy Adamson 					 decode_sequence_maxsz + \
6812050f0ccSAndy Adamson 					 decode_putrootfh_maxsz + \
6822050f0ccSAndy Adamson 					 decode_fsinfo_maxsz)
68318019753SRicardo Labiaga #define NFS4_enc_reclaim_complete_sz	(compound_encode_hdr_maxsz + \
68418019753SRicardo Labiaga 					 encode_sequence_maxsz + \
68518019753SRicardo Labiaga 					 encode_reclaim_complete_maxsz)
68618019753SRicardo Labiaga #define NFS4_dec_reclaim_complete_sz	(compound_decode_hdr_maxsz + \
68718019753SRicardo Labiaga 					 decode_sequence_maxsz + \
68818019753SRicardo Labiaga 					 decode_reclaim_complete_maxsz)
6892449ea2eSAlexandros Batsakis 
6902449ea2eSAlexandros Batsakis const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
6912449ea2eSAlexandros Batsakis 				      compound_encode_hdr_maxsz +
6922449ea2eSAlexandros Batsakis 				      encode_sequence_maxsz +
6932449ea2eSAlexandros Batsakis 				      encode_putfh_maxsz +
6942449ea2eSAlexandros Batsakis 				      encode_getattr_maxsz) *
6952449ea2eSAlexandros Batsakis 				     XDR_UNIT);
6962449ea2eSAlexandros Batsakis 
6972449ea2eSAlexandros Batsakis const u32 nfs41_maxread_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
6982449ea2eSAlexandros Batsakis 				     compound_decode_hdr_maxsz +
6992449ea2eSAlexandros Batsakis 				     decode_sequence_maxsz +
7002449ea2eSAlexandros Batsakis 				     decode_putfh_maxsz) *
7012449ea2eSAlexandros Batsakis 				    XDR_UNIT);
70299fe60d0SBenny Halevy #endif /* CONFIG_NFS_V4_1 */
7031da177e4SLinus Torvalds 
704bca79478STrond Myklebust static const umode_t nfs_type2fmt[] = {
705bca79478STrond Myklebust 	[NF4BAD] = 0,
706bca79478STrond Myklebust 	[NF4REG] = S_IFREG,
707bca79478STrond Myklebust 	[NF4DIR] = S_IFDIR,
708bca79478STrond Myklebust 	[NF4BLK] = S_IFBLK,
709bca79478STrond Myklebust 	[NF4CHR] = S_IFCHR,
710bca79478STrond Myklebust 	[NF4LNK] = S_IFLNK,
711bca79478STrond Myklebust 	[NF4SOCK] = S_IFSOCK,
712bca79478STrond Myklebust 	[NF4FIFO] = S_IFIFO,
713bca79478STrond Myklebust 	[NF4ATTRDIR] = 0,
714bca79478STrond Myklebust 	[NF4NAMEDATTR] = 0,
7151da177e4SLinus Torvalds };
7161da177e4SLinus Torvalds 
7171da177e4SLinus Torvalds struct compound_hdr {
7181da177e4SLinus Torvalds 	int32_t		status;
7191da177e4SLinus Torvalds 	uint32_t	nops;
720d017931cSAndy Adamson 	__be32 *	nops_p;
7211da177e4SLinus Torvalds 	uint32_t	taglen;
7221da177e4SLinus Torvalds 	char *		tag;
7230c4e8c18SBenny Halevy 	uint32_t	replen;		/* expected reply words */
72466cc0429SBenny Halevy 	u32		minorversion;
7251da177e4SLinus Torvalds };
7261da177e4SLinus Torvalds 
72713c65ce9SBenny Halevy static __be32 *reserve_space(struct xdr_stream *xdr, size_t nbytes)
72813c65ce9SBenny Halevy {
72913c65ce9SBenny Halevy 	__be32 *p = xdr_reserve_space(xdr, nbytes);
73013c65ce9SBenny Halevy 	BUG_ON(!p);
73113c65ce9SBenny Halevy 	return p;
73213c65ce9SBenny Halevy }
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
7351da177e4SLinus Torvalds {
7368687b63aSAl Viro 	__be32 *p;
7371da177e4SLinus Torvalds 
7381da177e4SLinus Torvalds 	p = xdr_reserve_space(xdr, 4 + len);
7391da177e4SLinus Torvalds 	BUG_ON(p == NULL);
7401da177e4SLinus Torvalds 	xdr_encode_opaque(p, str, len);
7411da177e4SLinus Torvalds }
7421da177e4SLinus Torvalds 
7430c4e8c18SBenny Halevy static void encode_compound_hdr(struct xdr_stream *xdr,
7440c4e8c18SBenny Halevy 				struct rpc_rqst *req,
7450c4e8c18SBenny Halevy 				struct compound_hdr *hdr)
7461da177e4SLinus Torvalds {
7478687b63aSAl Viro 	__be32 *p;
7480c4e8c18SBenny Halevy 	struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
7490c4e8c18SBenny Halevy 
7500c4e8c18SBenny Halevy 	/* initialize running count of expected bytes in reply.
7510c4e8c18SBenny Halevy 	 * NOTE: the replied tag SHOULD be the same is the one sent,
7520c4e8c18SBenny Halevy 	 * but this is not required as a MUST for the server to do so. */
7530c4e8c18SBenny Halevy 	hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen;
7541da177e4SLinus Torvalds 
7551da177e4SLinus Torvalds 	dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
7561da177e4SLinus Torvalds 	BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
757811652bdSBenny Halevy 	p = reserve_space(xdr, 4 + hdr->taglen + 8);
758811652bdSBenny Halevy 	p = xdr_encode_opaque(p, hdr->tag, hdr->taglen);
759e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(hdr->minorversion);
760d017931cSAndy Adamson 	hdr->nops_p = p;
76134558513SBenny Halevy 	*p = cpu_to_be32(hdr->nops);
762d017931cSAndy Adamson }
763d017931cSAndy Adamson 
764d017931cSAndy Adamson static void encode_nops(struct compound_hdr *hdr)
765d017931cSAndy Adamson {
766fc931582SAndy Adamson 	BUG_ON(hdr->nops > NFS4_MAX_OPS);
767d017931cSAndy Adamson 	*hdr->nops_p = htonl(hdr->nops);
7681da177e4SLinus Torvalds }
7691da177e4SLinus Torvalds 
7701da177e4SLinus Torvalds static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
7711da177e4SLinus Torvalds {
7728687b63aSAl Viro 	__be32 *p;
7731da177e4SLinus Torvalds 
7741da177e4SLinus Torvalds 	p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
7751da177e4SLinus Torvalds 	BUG_ON(p == NULL);
7761da177e4SLinus Torvalds 	xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE);
7771da177e4SLinus Torvalds }
7781da177e4SLinus Torvalds 
779cf8cdbe5SAndy Adamson static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
7801da177e4SLinus Torvalds {
7811da177e4SLinus Torvalds 	char owner_name[IDMAP_NAMESZ];
7821da177e4SLinus Torvalds 	char owner_group[IDMAP_NAMESZ];
7831da177e4SLinus Torvalds 	int owner_namelen = 0;
7841da177e4SLinus Torvalds 	int owner_grouplen = 0;
7858687b63aSAl Viro 	__be32 *p;
7868687b63aSAl Viro 	__be32 *q;
7871da177e4SLinus Torvalds 	int len;
7881da177e4SLinus Torvalds 	uint32_t bmval0 = 0;
7891da177e4SLinus Torvalds 	uint32_t bmval1 = 0;
7901da177e4SLinus Torvalds 
7911da177e4SLinus Torvalds 	/*
7921da177e4SLinus Torvalds 	 * We reserve enough space to write the entire attribute buffer at once.
7931da177e4SLinus Torvalds 	 * In the worst-case, this would be
7941da177e4SLinus Torvalds 	 *   12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
7951da177e4SLinus Torvalds 	 *          = 36 bytes, plus any contribution from variable-length fields
79623ec6965SJ. Bruce Fields 	 *            such as owner/group.
7971da177e4SLinus Torvalds 	 */
7981da177e4SLinus Torvalds 	len = 16;
7991da177e4SLinus Torvalds 
8001da177e4SLinus Torvalds 	/* Sigh */
8011da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_SIZE)
8021da177e4SLinus Torvalds 		len += 8;
8031da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_MODE)
8041da177e4SLinus Torvalds 		len += 4;
8051da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_UID) {
8067539bbabSDavid Howells 		owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
8071da177e4SLinus Torvalds 		if (owner_namelen < 0) {
808fe82a183SChuck Lever 			dprintk("nfs: couldn't resolve uid %d to string\n",
8091da177e4SLinus Torvalds 					iap->ia_uid);
8101da177e4SLinus Torvalds 			/* XXX */
8111da177e4SLinus Torvalds 			strcpy(owner_name, "nobody");
8121da177e4SLinus Torvalds 			owner_namelen = sizeof("nobody") - 1;
8131da177e4SLinus Torvalds 			/* goto out; */
8141da177e4SLinus Torvalds 		}
8151da177e4SLinus Torvalds 		len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
8161da177e4SLinus Torvalds 	}
8171da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_GID) {
8187539bbabSDavid Howells 		owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group);
8191da177e4SLinus Torvalds 		if (owner_grouplen < 0) {
820fe82a183SChuck Lever 			dprintk("nfs: couldn't resolve gid %d to string\n",
8211da177e4SLinus Torvalds 					iap->ia_gid);
8221da177e4SLinus Torvalds 			strcpy(owner_group, "nobody");
8231da177e4SLinus Torvalds 			owner_grouplen = sizeof("nobody") - 1;
8241da177e4SLinus Torvalds 			/* goto out; */
8251da177e4SLinus Torvalds 		}
8261da177e4SLinus Torvalds 		len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
8271da177e4SLinus Torvalds 	}
8281da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_ATIME_SET)
8291da177e4SLinus Torvalds 		len += 16;
8301da177e4SLinus Torvalds 	else if (iap->ia_valid & ATTR_ATIME)
8311da177e4SLinus Torvalds 		len += 4;
8321da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_MTIME_SET)
8331da177e4SLinus Torvalds 		len += 16;
8341da177e4SLinus Torvalds 	else if (iap->ia_valid & ATTR_MTIME)
8351da177e4SLinus Torvalds 		len += 4;
83613c65ce9SBenny Halevy 	p = reserve_space(xdr, len);
8371da177e4SLinus Torvalds 
8381da177e4SLinus Torvalds 	/*
8391da177e4SLinus Torvalds 	 * We write the bitmap length now, but leave the bitmap and the attribute
8401da177e4SLinus Torvalds 	 * buffer length to be backfilled at the end of this routine.
8411da177e4SLinus Torvalds 	 */
842e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(2);
8431da177e4SLinus Torvalds 	q = p;
8441da177e4SLinus Torvalds 	p += 3;
8451da177e4SLinus Torvalds 
8461da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_SIZE) {
8471da177e4SLinus Torvalds 		bmval0 |= FATTR4_WORD0_SIZE;
848b95be5a9SBenny Halevy 		p = xdr_encode_hyper(p, iap->ia_size);
8491da177e4SLinus Torvalds 	}
8501da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_MODE) {
8511da177e4SLinus Torvalds 		bmval1 |= FATTR4_WORD1_MODE;
852e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO);
8531da177e4SLinus Torvalds 	}
8541da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_UID) {
8551da177e4SLinus Torvalds 		bmval1 |= FATTR4_WORD1_OWNER;
856811652bdSBenny Halevy 		p = xdr_encode_opaque(p, owner_name, owner_namelen);
8571da177e4SLinus Torvalds 	}
8581da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_GID) {
8591da177e4SLinus Torvalds 		bmval1 |= FATTR4_WORD1_OWNER_GROUP;
860811652bdSBenny Halevy 		p = xdr_encode_opaque(p, owner_group, owner_grouplen);
8611da177e4SLinus Torvalds 	}
8621da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_ATIME_SET) {
8631da177e4SLinus Torvalds 		bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
864e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
865e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(0);
866e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(iap->ia_mtime.tv_sec);
867e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(iap->ia_mtime.tv_nsec);
8681da177e4SLinus Torvalds 	}
8691da177e4SLinus Torvalds 	else if (iap->ia_valid & ATTR_ATIME) {
8701da177e4SLinus Torvalds 		bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
871e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
8721da177e4SLinus Torvalds 	}
8731da177e4SLinus Torvalds 	if (iap->ia_valid & ATTR_MTIME_SET) {
8741da177e4SLinus Torvalds 		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
875e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
876e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(0);
877e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(iap->ia_mtime.tv_sec);
878e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(iap->ia_mtime.tv_nsec);
8791da177e4SLinus Torvalds 	}
8801da177e4SLinus Torvalds 	else if (iap->ia_valid & ATTR_MTIME) {
8811da177e4SLinus Torvalds 		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
882e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
8831da177e4SLinus Torvalds 	}
8841da177e4SLinus Torvalds 
8851da177e4SLinus Torvalds 	/*
8861da177e4SLinus Torvalds 	 * Now we backfill the bitmap and the attribute buffer length.
8871da177e4SLinus Torvalds 	 */
8881da177e4SLinus Torvalds 	if (len != ((char *)p - (char *)q) + 4) {
889fe82a183SChuck Lever 		printk(KERN_ERR "nfs: Attr length error, %u != %Zu\n",
8901da177e4SLinus Torvalds 				len, ((char *)p - (char *)q) + 4);
8911da177e4SLinus Torvalds 		BUG();
8921da177e4SLinus Torvalds 	}
8931da177e4SLinus Torvalds 	len = (char *)p - (char *)q - 12;
8941da177e4SLinus Torvalds 	*q++ = htonl(bmval0);
8951da177e4SLinus Torvalds 	*q++ = htonl(bmval1);
89634558513SBenny Halevy 	*q = htonl(len);
8971da177e4SLinus Torvalds 
8981da177e4SLinus Torvalds /* out: */
8991da177e4SLinus Torvalds }
9001da177e4SLinus Torvalds 
901cf8cdbe5SAndy Adamson static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hdr *hdr)
9021da177e4SLinus Torvalds {
9038687b63aSAl Viro 	__be32 *p;
9041da177e4SLinus Torvalds 
90513c65ce9SBenny Halevy 	p = reserve_space(xdr, 8);
906e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_ACCESS);
90734558513SBenny Halevy 	*p = cpu_to_be32(access);
908d017931cSAndy Adamson 	hdr->nops++;
909dadf0c27SBenny Halevy 	hdr->replen += decode_access_maxsz;
9101da177e4SLinus Torvalds }
9111da177e4SLinus Torvalds 
912cf8cdbe5SAndy Adamson static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
9131da177e4SLinus Torvalds {
9148687b63aSAl Viro 	__be32 *p;
9151da177e4SLinus Torvalds 
91613c65ce9SBenny Halevy 	p = reserve_space(xdr, 8+NFS4_STATEID_SIZE);
917e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_CLOSE);
918e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(arg->seqid->sequence->counter);
91934558513SBenny Halevy 	xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
920d017931cSAndy Adamson 	hdr->nops++;
921dadf0c27SBenny Halevy 	hdr->replen += decode_close_maxsz;
9221da177e4SLinus Torvalds }
9231da177e4SLinus Torvalds 
924cf8cdbe5SAndy Adamson static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
9251da177e4SLinus Torvalds {
9268687b63aSAl Viro 	__be32 *p;
9271da177e4SLinus Torvalds 
92813c65ce9SBenny Halevy 	p = reserve_space(xdr, 16);
929e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_COMMIT);
930b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, args->offset);
93134558513SBenny Halevy 	*p = cpu_to_be32(args->count);
932d017931cSAndy Adamson 	hdr->nops++;
933dadf0c27SBenny Halevy 	hdr->replen += decode_commit_maxsz;
9341da177e4SLinus Torvalds }
9351da177e4SLinus Torvalds 
936cf8cdbe5SAndy Adamson static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr)
9371da177e4SLinus Torvalds {
9388687b63aSAl Viro 	__be32 *p;
9391da177e4SLinus Torvalds 
94013c65ce9SBenny Halevy 	p = reserve_space(xdr, 8);
941e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_CREATE);
94234558513SBenny Halevy 	*p = cpu_to_be32(create->ftype);
9431da177e4SLinus Torvalds 
9441da177e4SLinus Torvalds 	switch (create->ftype) {
9451da177e4SLinus Torvalds 	case NF4LNK:
94613c65ce9SBenny Halevy 		p = reserve_space(xdr, 4);
94734558513SBenny Halevy 		*p = cpu_to_be32(create->u.symlink.len);
94894a6d753SChuck Lever 		xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len);
9491da177e4SLinus Torvalds 		break;
9501da177e4SLinus Torvalds 
9511da177e4SLinus Torvalds 	case NF4BLK: case NF4CHR:
95213c65ce9SBenny Halevy 		p = reserve_space(xdr, 8);
953e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(create->u.device.specdata1);
95434558513SBenny Halevy 		*p = cpu_to_be32(create->u.device.specdata2);
9551da177e4SLinus Torvalds 		break;
9561da177e4SLinus Torvalds 
9571da177e4SLinus Torvalds 	default:
9581da177e4SLinus Torvalds 		break;
9591da177e4SLinus Torvalds 	}
9601da177e4SLinus Torvalds 
961811652bdSBenny Halevy 	encode_string(xdr, create->name->len, create->name->name);
962d017931cSAndy Adamson 	hdr->nops++;
963dadf0c27SBenny Halevy 	hdr->replen += decode_create_maxsz;
9641da177e4SLinus Torvalds 
965cf8cdbe5SAndy Adamson 	encode_attrs(xdr, create->attrs, create->server);
9661da177e4SLinus Torvalds }
9671da177e4SLinus Torvalds 
968cf8cdbe5SAndy Adamson static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr)
9691da177e4SLinus Torvalds {
9708687b63aSAl Viro 	__be32 *p;
9711da177e4SLinus Torvalds 
97213c65ce9SBenny Halevy 	p = reserve_space(xdr, 12);
973e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_GETATTR);
974e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(1);
97534558513SBenny Halevy 	*p = cpu_to_be32(bitmap);
976d017931cSAndy Adamson 	hdr->nops++;
977dadf0c27SBenny Halevy 	hdr->replen += decode_getattr_maxsz;
9781da177e4SLinus Torvalds }
9791da177e4SLinus Torvalds 
980cf8cdbe5SAndy Adamson static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr)
9811da177e4SLinus Torvalds {
9828687b63aSAl Viro 	__be32 *p;
9831da177e4SLinus Torvalds 
98413c65ce9SBenny Halevy 	p = reserve_space(xdr, 16);
985e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_GETATTR);
986e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(2);
987e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(bm0);
98834558513SBenny Halevy 	*p = cpu_to_be32(bm1);
989d017931cSAndy Adamson 	hdr->nops++;
990dadf0c27SBenny Halevy 	hdr->replen += decode_getattr_maxsz;
9911da177e4SLinus Torvalds }
9921da177e4SLinus Torvalds 
993cf8cdbe5SAndy Adamson static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
9941da177e4SLinus Torvalds {
995cf8cdbe5SAndy Adamson 	encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
996d017931cSAndy Adamson 			   bitmask[1] & nfs4_fattr_bitmap[1], hdr);
9971da177e4SLinus Torvalds }
9981da177e4SLinus Torvalds 
999cf8cdbe5SAndy Adamson static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
10001da177e4SLinus Torvalds {
1001cf8cdbe5SAndy Adamson 	encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
1002d017931cSAndy Adamson 			   bitmask[1] & nfs4_fsinfo_bitmap[1], hdr);
10031da177e4SLinus Torvalds }
10041da177e4SLinus Torvalds 
1005cf8cdbe5SAndy Adamson static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
1006830b8e33SManoj Naik {
1007cf8cdbe5SAndy Adamson 	encode_getattr_two(xdr, bitmask[0] & nfs4_fs_locations_bitmap[0],
1008cf8cdbe5SAndy Adamson 			   bitmask[1] & nfs4_fs_locations_bitmap[1], hdr);
1009830b8e33SManoj Naik }
1010830b8e33SManoj Naik 
1011cf8cdbe5SAndy Adamson static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
10121da177e4SLinus Torvalds {
10138687b63aSAl Viro 	__be32 *p;
10141da177e4SLinus Torvalds 
101513c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
101634558513SBenny Halevy 	*p = cpu_to_be32(OP_GETFH);
1017d017931cSAndy Adamson 	hdr->nops++;
1018dadf0c27SBenny Halevy 	hdr->replen += decode_getfh_maxsz;
10191da177e4SLinus Torvalds }
10201da177e4SLinus Torvalds 
1021cf8cdbe5SAndy Adamson static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
10221da177e4SLinus Torvalds {
10238687b63aSAl Viro 	__be32 *p;
10241da177e4SLinus Torvalds 
102513c65ce9SBenny Halevy 	p = reserve_space(xdr, 8 + name->len);
1026e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_LINK);
1027811652bdSBenny Halevy 	xdr_encode_opaque(p, name->name, name->len);
1028d017931cSAndy Adamson 	hdr->nops++;
1029dadf0c27SBenny Halevy 	hdr->replen += decode_link_maxsz;
10301da177e4SLinus Torvalds }
10311da177e4SLinus Torvalds 
1032911d1aafSTrond Myklebust static inline int nfs4_lock_type(struct file_lock *fl, int block)
1033911d1aafSTrond Myklebust {
1034911d1aafSTrond Myklebust 	if ((fl->fl_type & (F_RDLCK|F_WRLCK|F_UNLCK)) == F_RDLCK)
1035911d1aafSTrond Myklebust 		return block ? NFS4_READW_LT : NFS4_READ_LT;
1036911d1aafSTrond Myklebust 	return block ? NFS4_WRITEW_LT : NFS4_WRITE_LT;
1037911d1aafSTrond Myklebust }
1038911d1aafSTrond Myklebust 
1039911d1aafSTrond Myklebust static inline uint64_t nfs4_lock_length(struct file_lock *fl)
1040911d1aafSTrond Myklebust {
1041911d1aafSTrond Myklebust 	if (fl->fl_end == OFFSET_MAX)
1042911d1aafSTrond Myklebust 		return ~(uint64_t)0;
1043911d1aafSTrond Myklebust 	return fl->fl_end - fl->fl_start + 1;
1044911d1aafSTrond Myklebust }
1045911d1aafSTrond Myklebust 
10461da177e4SLinus Torvalds /*
10471da177e4SLinus Torvalds  * opcode,type,reclaim,offset,length,new_lock_owner = 32
10481da177e4SLinus Torvalds  * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
10491da177e4SLinus Torvalds  */
1050cf8cdbe5SAndy Adamson static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args, struct compound_hdr *hdr)
10511da177e4SLinus Torvalds {
10528687b63aSAl Viro 	__be32 *p;
10531da177e4SLinus Torvalds 
105413c65ce9SBenny Halevy 	p = reserve_space(xdr, 32);
1055e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_LOCK);
1056e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, args->block));
1057e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->reclaim);
1058b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, args->fl->fl_start);
1059b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
106034558513SBenny Halevy 	*p = cpu_to_be32(args->new_lock_owner);
1061911d1aafSTrond Myklebust 	if (args->new_lock_owner){
106213c65ce9SBenny Halevy 		p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+32);
1063e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(args->open_seqid->sequence->counter);
106493f0cf25SBenny Halevy 		p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE);
1065e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(args->lock_seqid->sequence->counter);
1066b95be5a9SBenny Halevy 		p = xdr_encode_hyper(p, args->lock_owner.clientid);
1067e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(16);
106893f0cf25SBenny Halevy 		p = xdr_encode_opaque_fixed(p, "lock id:", 8);
106934558513SBenny Halevy 		xdr_encode_hyper(p, args->lock_owner.id);
10701da177e4SLinus Torvalds 	}
10711da177e4SLinus Torvalds 	else {
107213c65ce9SBenny Halevy 		p = reserve_space(xdr, NFS4_STATEID_SIZE+4);
107393f0cf25SBenny Halevy 		p = xdr_encode_opaque_fixed(p, args->lock_stateid->data, NFS4_STATEID_SIZE);
107434558513SBenny Halevy 		*p = cpu_to_be32(args->lock_seqid->sequence->counter);
10751da177e4SLinus Torvalds 	}
1076d017931cSAndy Adamson 	hdr->nops++;
1077dadf0c27SBenny Halevy 	hdr->replen += decode_lock_maxsz;
10781da177e4SLinus Torvalds }
10791da177e4SLinus Torvalds 
1080cf8cdbe5SAndy Adamson static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr)
10811da177e4SLinus Torvalds {
10828687b63aSAl Viro 	__be32 *p;
10831da177e4SLinus Torvalds 
108413c65ce9SBenny Halevy 	p = reserve_space(xdr, 52);
1085e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_LOCKT);
1086e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
1087b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, args->fl->fl_start);
1088b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
1089b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, args->lock_owner.clientid);
1090e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(16);
109193f0cf25SBenny Halevy 	p = xdr_encode_opaque_fixed(p, "lock id:", 8);
109234558513SBenny Halevy 	xdr_encode_hyper(p, args->lock_owner.id);
1093d017931cSAndy Adamson 	hdr->nops++;
1094dadf0c27SBenny Halevy 	hdr->replen += decode_lockt_maxsz;
10951da177e4SLinus Torvalds }
10961da177e4SLinus Torvalds 
1097cf8cdbe5SAndy Adamson static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr)
10981da177e4SLinus Torvalds {
10998687b63aSAl Viro 	__be32 *p;
11001da177e4SLinus Torvalds 
110113c65ce9SBenny Halevy 	p = reserve_space(xdr, 12+NFS4_STATEID_SIZE+16);
1102e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_LOCKU);
1103e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
1104e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->seqid->sequence->counter);
110593f0cf25SBenny Halevy 	p = xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
1106b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, args->fl->fl_start);
110734558513SBenny Halevy 	xdr_encode_hyper(p, nfs4_lock_length(args->fl));
1108d017931cSAndy Adamson 	hdr->nops++;
1109dadf0c27SBenny Halevy 	hdr->replen += decode_locku_maxsz;
11101da177e4SLinus Torvalds }
11111da177e4SLinus Torvalds 
1112cf8cdbe5SAndy Adamson static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
11131da177e4SLinus Torvalds {
11141da177e4SLinus Torvalds 	int len = name->len;
11158687b63aSAl Viro 	__be32 *p;
11161da177e4SLinus Torvalds 
111713c65ce9SBenny Halevy 	p = reserve_space(xdr, 8 + len);
1118e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_LOOKUP);
1119811652bdSBenny Halevy 	xdr_encode_opaque(p, name->name, len);
1120d017931cSAndy Adamson 	hdr->nops++;
1121dadf0c27SBenny Halevy 	hdr->replen += decode_lookup_maxsz;
11221da177e4SLinus Torvalds }
11231da177e4SLinus Torvalds 
1124dc0b027dSTrond Myklebust static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode)
11251da177e4SLinus Torvalds {
11268687b63aSAl Viro 	__be32 *p;
11271da177e4SLinus Torvalds 
112813c65ce9SBenny Halevy 	p = reserve_space(xdr, 8);
1129dc0b027dSTrond Myklebust 	switch (fmode & (FMODE_READ|FMODE_WRITE)) {
11301da177e4SLinus Torvalds 	case FMODE_READ:
1131e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_READ);
11321da177e4SLinus Torvalds 		break;
11331da177e4SLinus Torvalds 	case FMODE_WRITE:
1134e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_WRITE);
11351da177e4SLinus Torvalds 		break;
11361da177e4SLinus Torvalds 	case FMODE_READ|FMODE_WRITE:
1137e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_BOTH);
11381da177e4SLinus Torvalds 		break;
11391da177e4SLinus Torvalds 	default:
1140e75bc1c8SBenny Halevy 		*p++ = cpu_to_be32(0);
11411da177e4SLinus Torvalds 	}
114234558513SBenny Halevy 	*p = cpu_to_be32(0);		/* for linux, share_deny = 0 always */
11431da177e4SLinus Torvalds }
11441da177e4SLinus Torvalds 
11451da177e4SLinus Torvalds static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg)
11461da177e4SLinus Torvalds {
11478687b63aSAl Viro 	__be32 *p;
11481da177e4SLinus Torvalds  /*
11491da177e4SLinus Torvalds  * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
11501da177e4SLinus Torvalds  * owner 4 = 32
11511da177e4SLinus Torvalds  */
115213c65ce9SBenny Halevy 	p = reserve_space(xdr, 8);
1153e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_OPEN);
115434558513SBenny Halevy 	*p = cpu_to_be32(arg->seqid->sequence->counter);
1155dc0b027dSTrond Myklebust 	encode_share_access(xdr, arg->fmode);
115613c65ce9SBenny Halevy 	p = reserve_space(xdr, 28);
1157b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, arg->clientid);
1158e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(16);
115993f0cf25SBenny Halevy 	p = xdr_encode_opaque_fixed(p, "open id:", 8);
116034558513SBenny Halevy 	xdr_encode_hyper(p, arg->id);
11611da177e4SLinus Torvalds }
11621da177e4SLinus Torvalds 
11631da177e4SLinus Torvalds static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
11641da177e4SLinus Torvalds {
11658687b63aSAl Viro 	__be32 *p;
11664882ef72SAlexandros Batsakis 	struct nfs_client *clp;
11671da177e4SLinus Torvalds 
116813c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
11691da177e4SLinus Torvalds 	switch(arg->open_flags & O_EXCL) {
11701da177e4SLinus Torvalds 	case 0:
117134558513SBenny Halevy 		*p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
11721da177e4SLinus Torvalds 		encode_attrs(xdr, arg->u.attrs, arg->server);
11731da177e4SLinus Torvalds 		break;
11741da177e4SLinus Torvalds 	default:
11754882ef72SAlexandros Batsakis 		clp = arg->server->nfs_client;
11764882ef72SAlexandros Batsakis 		if (clp->cl_minorversion > 0) {
11774882ef72SAlexandros Batsakis 			if (nfs4_has_persistent_session(clp)) {
11784882ef72SAlexandros Batsakis 				*p = cpu_to_be32(NFS4_CREATE_GUARDED);
11794882ef72SAlexandros Batsakis 				encode_attrs(xdr, arg->u.attrs, arg->server);
11804882ef72SAlexandros Batsakis 			} else {
11814882ef72SAlexandros Batsakis 				struct iattr dummy;
11824882ef72SAlexandros Batsakis 
11834882ef72SAlexandros Batsakis 				*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
11844882ef72SAlexandros Batsakis 				encode_nfs4_verifier(xdr, &arg->u.verifier);
11854882ef72SAlexandros Batsakis 				dummy.ia_valid = 0;
11864882ef72SAlexandros Batsakis 				encode_attrs(xdr, &dummy, arg->server);
11874882ef72SAlexandros Batsakis 			}
11884882ef72SAlexandros Batsakis 		} else {
118934558513SBenny Halevy 			*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
11901da177e4SLinus Torvalds 			encode_nfs4_verifier(xdr, &arg->u.verifier);
11911da177e4SLinus Torvalds 		}
11921da177e4SLinus Torvalds 	}
11934882ef72SAlexandros Batsakis }
11941da177e4SLinus Torvalds 
11951da177e4SLinus Torvalds static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *arg)
11961da177e4SLinus Torvalds {
11978687b63aSAl Viro 	__be32 *p;
11981da177e4SLinus Torvalds 
119913c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
12001da177e4SLinus Torvalds 	switch (arg->open_flags & O_CREAT) {
12011da177e4SLinus Torvalds 	case 0:
120234558513SBenny Halevy 		*p = cpu_to_be32(NFS4_OPEN_NOCREATE);
12031da177e4SLinus Torvalds 		break;
12041da177e4SLinus Torvalds 	default:
12051da177e4SLinus Torvalds 		BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL);
120634558513SBenny Halevy 		*p = cpu_to_be32(NFS4_OPEN_CREATE);
12071da177e4SLinus Torvalds 		encode_createmode(xdr, arg);
12081da177e4SLinus Torvalds 	}
12091da177e4SLinus Torvalds }
12101da177e4SLinus Torvalds 
1211bd7bf9d5STrond Myklebust static inline void encode_delegation_type(struct xdr_stream *xdr, fmode_t delegation_type)
12121da177e4SLinus Torvalds {
12138687b63aSAl Viro 	__be32 *p;
12141da177e4SLinus Torvalds 
121513c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
12161da177e4SLinus Torvalds 	switch (delegation_type) {
12171da177e4SLinus Torvalds 	case 0:
121834558513SBenny Halevy 		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_NONE);
12191da177e4SLinus Torvalds 		break;
12201da177e4SLinus Torvalds 	case FMODE_READ:
122134558513SBenny Halevy 		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_READ);
12221da177e4SLinus Torvalds 		break;
12231da177e4SLinus Torvalds 	case FMODE_WRITE|FMODE_READ:
122434558513SBenny Halevy 		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_WRITE);
12251da177e4SLinus Torvalds 		break;
12261da177e4SLinus Torvalds 	default:
12271da177e4SLinus Torvalds 		BUG();
12281da177e4SLinus Torvalds 	}
12291da177e4SLinus Torvalds }
12301da177e4SLinus Torvalds 
12311da177e4SLinus Torvalds static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr *name)
12321da177e4SLinus Torvalds {
12338687b63aSAl Viro 	__be32 *p;
12341da177e4SLinus Torvalds 
123513c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
123634558513SBenny Halevy 	*p = cpu_to_be32(NFS4_OPEN_CLAIM_NULL);
12371da177e4SLinus Torvalds 	encode_string(xdr, name->len, name->name);
12381da177e4SLinus Torvalds }
12391da177e4SLinus Torvalds 
1240bd7bf9d5STrond Myklebust static inline void encode_claim_previous(struct xdr_stream *xdr, fmode_t type)
12411da177e4SLinus Torvalds {
12428687b63aSAl Viro 	__be32 *p;
12431da177e4SLinus Torvalds 
124413c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
124534558513SBenny Halevy 	*p = cpu_to_be32(NFS4_OPEN_CLAIM_PREVIOUS);
12461da177e4SLinus Torvalds 	encode_delegation_type(xdr, type);
12471da177e4SLinus Torvalds }
12481da177e4SLinus Torvalds 
12491da177e4SLinus Torvalds static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struct qstr *name, const nfs4_stateid *stateid)
12501da177e4SLinus Torvalds {
12518687b63aSAl Viro 	__be32 *p;
12521da177e4SLinus Torvalds 
125313c65ce9SBenny Halevy 	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
1254e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
125534558513SBenny Halevy 	xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
12561da177e4SLinus Torvalds 	encode_string(xdr, name->len, name->name);
12571da177e4SLinus Torvalds }
12581da177e4SLinus Torvalds 
1259cf8cdbe5SAndy Adamson static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr)
12601da177e4SLinus Torvalds {
12611da177e4SLinus Torvalds 	encode_openhdr(xdr, arg);
12621da177e4SLinus Torvalds 	encode_opentype(xdr, arg);
12631da177e4SLinus Torvalds 	switch (arg->claim) {
12641da177e4SLinus Torvalds 	case NFS4_OPEN_CLAIM_NULL:
12651da177e4SLinus Torvalds 		encode_claim_null(xdr, arg->name);
12661da177e4SLinus Torvalds 		break;
12671da177e4SLinus Torvalds 	case NFS4_OPEN_CLAIM_PREVIOUS:
12681da177e4SLinus Torvalds 		encode_claim_previous(xdr, arg->u.delegation_type);
12691da177e4SLinus Torvalds 		break;
12701da177e4SLinus Torvalds 	case NFS4_OPEN_CLAIM_DELEGATE_CUR:
12711da177e4SLinus Torvalds 		encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation);
12721da177e4SLinus Torvalds 		break;
12731da177e4SLinus Torvalds 	default:
12741da177e4SLinus Torvalds 		BUG();
12751da177e4SLinus Torvalds 	}
1276d017931cSAndy Adamson 	hdr->nops++;
1277dadf0c27SBenny Halevy 	hdr->replen += decode_open_maxsz;
12781da177e4SLinus Torvalds }
12791da177e4SLinus Torvalds 
1280cf8cdbe5SAndy Adamson static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr)
12811da177e4SLinus Torvalds {
12828687b63aSAl Viro 	__be32 *p;
12831da177e4SLinus Torvalds 
128413c65ce9SBenny Halevy 	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
1285e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_OPEN_CONFIRM);
128693f0cf25SBenny Halevy 	p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
128734558513SBenny Halevy 	*p = cpu_to_be32(arg->seqid->sequence->counter);
1288d017931cSAndy Adamson 	hdr->nops++;
1289dadf0c27SBenny Halevy 	hdr->replen += decode_open_confirm_maxsz;
12901da177e4SLinus Torvalds }
12911da177e4SLinus Torvalds 
1292cf8cdbe5SAndy Adamson static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
12931da177e4SLinus Torvalds {
12948687b63aSAl Viro 	__be32 *p;
12951da177e4SLinus Torvalds 
129613c65ce9SBenny Halevy 	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
1297e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_OPEN_DOWNGRADE);
129893f0cf25SBenny Halevy 	p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
129934558513SBenny Halevy 	*p = cpu_to_be32(arg->seqid->sequence->counter);
1300dc0b027dSTrond Myklebust 	encode_share_access(xdr, arg->fmode);
1301d017931cSAndy Adamson 	hdr->nops++;
1302dadf0c27SBenny Halevy 	hdr->replen += decode_open_downgrade_maxsz;
13031da177e4SLinus Torvalds }
13041da177e4SLinus Torvalds 
1305cf8cdbe5SAndy Adamson static void
1306d017931cSAndy Adamson encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hdr *hdr)
13071da177e4SLinus Torvalds {
13081da177e4SLinus Torvalds 	int len = fh->size;
13098687b63aSAl Viro 	__be32 *p;
13101da177e4SLinus Torvalds 
131113c65ce9SBenny Halevy 	p = reserve_space(xdr, 8 + len);
1312e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_PUTFH);
1313811652bdSBenny Halevy 	xdr_encode_opaque(p, fh->data, len);
1314d017931cSAndy Adamson 	hdr->nops++;
1315dadf0c27SBenny Halevy 	hdr->replen += decode_putfh_maxsz;
13161da177e4SLinus Torvalds }
13171da177e4SLinus Torvalds 
1318cf8cdbe5SAndy Adamson static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
13191da177e4SLinus Torvalds {
13208687b63aSAl Viro 	__be32 *p;
13211da177e4SLinus Torvalds 
132213c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
132334558513SBenny Halevy 	*p = cpu_to_be32(OP_PUTROOTFH);
1324d017931cSAndy Adamson 	hdr->nops++;
1325dadf0c27SBenny Halevy 	hdr->replen += decode_putrootfh_maxsz;
13261da177e4SLinus Torvalds }
13271da177e4SLinus Torvalds 
13281da177e4SLinus Torvalds static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx)
13291da177e4SLinus Torvalds {
13301da177e4SLinus Torvalds 	nfs4_stateid stateid;
13318687b63aSAl Viro 	__be32 *p;
13321da177e4SLinus Torvalds 
133313c65ce9SBenny Halevy 	p = reserve_space(xdr, NFS4_STATEID_SIZE);
13341da177e4SLinus Torvalds 	if (ctx->state != NULL) {
13351da177e4SLinus Torvalds 		nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner);
133634558513SBenny Halevy 		xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE);
13371da177e4SLinus Torvalds 	} else
133834558513SBenny Halevy 		xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
13391da177e4SLinus Torvalds }
13401da177e4SLinus Torvalds 
1341cf8cdbe5SAndy Adamson static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr)
13421da177e4SLinus Torvalds {
13438687b63aSAl Viro 	__be32 *p;
13441da177e4SLinus Torvalds 
134513c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
134634558513SBenny Halevy 	*p = cpu_to_be32(OP_READ);
13471da177e4SLinus Torvalds 
13481da177e4SLinus Torvalds 	encode_stateid(xdr, args->context);
13491da177e4SLinus Torvalds 
135013c65ce9SBenny Halevy 	p = reserve_space(xdr, 12);
1351b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, args->offset);
135234558513SBenny Halevy 	*p = cpu_to_be32(args->count);
1353d017931cSAndy Adamson 	hdr->nops++;
1354dadf0c27SBenny Halevy 	hdr->replen += decode_read_maxsz;
13551da177e4SLinus Torvalds }
13561da177e4SLinus Torvalds 
1357cf8cdbe5SAndy Adamson static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
13581da177e4SLinus Torvalds {
135997d312d0SManoj Naik 	uint32_t attrs[2] = {
136097d312d0SManoj Naik 		FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID,
136197d312d0SManoj Naik 		FATTR4_WORD1_MOUNTED_ON_FILEID,
136297d312d0SManoj Naik 	};
13638687b63aSAl Viro 	__be32 *p;
13641da177e4SLinus Torvalds 
136513c65ce9SBenny Halevy 	p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
1366e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_READDIR);
1367b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, readdir->cookie);
136893f0cf25SBenny Halevy 	p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE);
1369e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(readdir->count >> 1);  /* We're not doing readdirplus */
1370e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(readdir->count);
1371e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(2);
137297d312d0SManoj Naik 	/* Switch to mounted_on_fileid if the server supports it */
137397d312d0SManoj Naik 	if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
137497d312d0SManoj Naik 		attrs[0] &= ~FATTR4_WORD0_FILEID;
137597d312d0SManoj Naik 	else
137697d312d0SManoj Naik 		attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
1377e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]);
137834558513SBenny Halevy 	*p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
1379d017931cSAndy Adamson 	hdr->nops++;
1380dadf0c27SBenny Halevy 	hdr->replen += decode_readdir_maxsz;
138144109241SFred Isaman 	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
138244109241SFred Isaman 			__func__,
1383eadf4598STrond Myklebust 			(unsigned long long)readdir->cookie,
1384eadf4598STrond Myklebust 			((u32 *)readdir->verifier.data)[0],
1385eadf4598STrond Myklebust 			((u32 *)readdir->verifier.data)[1],
1386eadf4598STrond Myklebust 			attrs[0] & readdir->bitmask[0],
1387eadf4598STrond Myklebust 			attrs[1] & readdir->bitmask[1]);
13881da177e4SLinus Torvalds }
13891da177e4SLinus Torvalds 
1390cf8cdbe5SAndy Adamson static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
13911da177e4SLinus Torvalds {
13928687b63aSAl Viro 	__be32 *p;
13931da177e4SLinus Torvalds 
139413c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
139534558513SBenny Halevy 	*p = cpu_to_be32(OP_READLINK);
1396d017931cSAndy Adamson 	hdr->nops++;
1397dadf0c27SBenny Halevy 	hdr->replen += decode_readlink_maxsz;
13981da177e4SLinus Torvalds }
13991da177e4SLinus Torvalds 
1400cf8cdbe5SAndy Adamson static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
14011da177e4SLinus Torvalds {
14028687b63aSAl Viro 	__be32 *p;
14031da177e4SLinus Torvalds 
140413c65ce9SBenny Halevy 	p = reserve_space(xdr, 8 + name->len);
1405e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_REMOVE);
1406811652bdSBenny Halevy 	xdr_encode_opaque(p, name->name, name->len);
1407d017931cSAndy Adamson 	hdr->nops++;
1408dadf0c27SBenny Halevy 	hdr->replen += decode_remove_maxsz;
14091da177e4SLinus Torvalds }
14101da177e4SLinus Torvalds 
1411cf8cdbe5SAndy Adamson static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr)
14121da177e4SLinus Torvalds {
14138687b63aSAl Viro 	__be32 *p;
14141da177e4SLinus Torvalds 
1415811652bdSBenny Halevy 	p = reserve_space(xdr, 4);
1416811652bdSBenny Halevy 	*p = cpu_to_be32(OP_RENAME);
1417811652bdSBenny Halevy 	encode_string(xdr, oldname->len, oldname->name);
1418811652bdSBenny Halevy 	encode_string(xdr, newname->len, newname->name);
1419d017931cSAndy Adamson 	hdr->nops++;
1420dadf0c27SBenny Halevy 	hdr->replen += decode_rename_maxsz;
14211da177e4SLinus Torvalds }
14221da177e4SLinus Torvalds 
1423cf8cdbe5SAndy Adamson static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr)
14241da177e4SLinus Torvalds {
14258687b63aSAl Viro 	__be32 *p;
14261da177e4SLinus Torvalds 
142713c65ce9SBenny Halevy 	p = reserve_space(xdr, 12);
1428e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_RENEW);
142934558513SBenny Halevy 	xdr_encode_hyper(p, client_stateid->cl_clientid);
1430d017931cSAndy Adamson 	hdr->nops++;
1431dadf0c27SBenny Halevy 	hdr->replen += decode_renew_maxsz;
14321da177e4SLinus Torvalds }
14331da177e4SLinus Torvalds 
1434cf8cdbe5SAndy Adamson static void
1435d017931cSAndy Adamson encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
143656ae19f3STrond Myklebust {
14378687b63aSAl Viro 	__be32 *p;
143856ae19f3STrond Myklebust 
143913c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
144034558513SBenny Halevy 	*p = cpu_to_be32(OP_RESTOREFH);
1441d017931cSAndy Adamson 	hdr->nops++;
1442dadf0c27SBenny Halevy 	hdr->replen += decode_restorefh_maxsz;
144356ae19f3STrond Myklebust }
144456ae19f3STrond Myklebust 
144556ae19f3STrond Myklebust static int
1446d017931cSAndy Adamson encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compound_hdr *hdr)
144723ec6965SJ. Bruce Fields {
14488687b63aSAl Viro 	__be32 *p;
144923ec6965SJ. Bruce Fields 
145013c65ce9SBenny Halevy 	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
1451e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_SETATTR);
145234558513SBenny Halevy 	xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
145313c65ce9SBenny Halevy 	p = reserve_space(xdr, 2*4);
1454e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(1);
145534558513SBenny Halevy 	*p = cpu_to_be32(FATTR4_WORD0_ACL);
145623ec6965SJ. Bruce Fields 	if (arg->acl_len % 4)
145723ec6965SJ. Bruce Fields 		return -EINVAL;
145813c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
145934558513SBenny Halevy 	*p = cpu_to_be32(arg->acl_len);
146023ec6965SJ. Bruce Fields 	xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
1461d017931cSAndy Adamson 	hdr->nops++;
1462dadf0c27SBenny Halevy 	hdr->replen += decode_setacl_maxsz;
146323ec6965SJ. Bruce Fields 	return 0;
146423ec6965SJ. Bruce Fields }
146523ec6965SJ. Bruce Fields 
1466cf8cdbe5SAndy Adamson static void
1467d017931cSAndy Adamson encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
14681da177e4SLinus Torvalds {
14698687b63aSAl Viro 	__be32 *p;
14701da177e4SLinus Torvalds 
147113c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
147234558513SBenny Halevy 	*p = cpu_to_be32(OP_SAVEFH);
1473d017931cSAndy Adamson 	hdr->nops++;
1474dadf0c27SBenny Halevy 	hdr->replen += decode_savefh_maxsz;
14751da177e4SLinus Torvalds }
14761da177e4SLinus Torvalds 
1477cf8cdbe5SAndy Adamson static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr)
14781da177e4SLinus Torvalds {
14798687b63aSAl Viro 	__be32 *p;
14801da177e4SLinus Torvalds 
148113c65ce9SBenny Halevy 	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
1482e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_SETATTR);
148334558513SBenny Halevy 	xdr_encode_opaque_fixed(p, arg->stateid.data, NFS4_STATEID_SIZE);
1484d017931cSAndy Adamson 	hdr->nops++;
1485dadf0c27SBenny Halevy 	hdr->replen += decode_setattr_maxsz;
1486cf8cdbe5SAndy Adamson 	encode_attrs(xdr, arg->iap, server);
14871da177e4SLinus Torvalds }
14881da177e4SLinus Torvalds 
1489cf8cdbe5SAndy Adamson static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)
14901da177e4SLinus Torvalds {
14918687b63aSAl Viro 	__be32 *p;
14921da177e4SLinus Torvalds 
149313c65ce9SBenny Halevy 	p = reserve_space(xdr, 4 + NFS4_VERIFIER_SIZE);
1494e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_SETCLIENTID);
149534558513SBenny Halevy 	xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE);
14961da177e4SLinus Torvalds 
14971da177e4SLinus Torvalds 	encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
149813c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
149934558513SBenny Halevy 	*p = cpu_to_be32(setclientid->sc_prog);
15001da177e4SLinus Torvalds 	encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid);
15011da177e4SLinus Torvalds 	encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
150213c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
150334558513SBenny Halevy 	*p = cpu_to_be32(setclientid->sc_cb_ident);
1504d017931cSAndy Adamson 	hdr->nops++;
1505dadf0c27SBenny Halevy 	hdr->replen += decode_setclientid_maxsz;
15061da177e4SLinus Torvalds }
15071da177e4SLinus Torvalds 
1508cf8cdbe5SAndy Adamson static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr)
15091da177e4SLinus Torvalds {
15108687b63aSAl Viro 	__be32 *p;
15111da177e4SLinus Torvalds 
151213c65ce9SBenny Halevy 	p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE);
1513e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM);
1514b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, client_state->cl_clientid);
151534558513SBenny Halevy 	xdr_encode_opaque_fixed(p, client_state->cl_confirm.data, NFS4_VERIFIER_SIZE);
1516d017931cSAndy Adamson 	hdr->nops++;
1517dadf0c27SBenny Halevy 	hdr->replen += decode_setclientid_confirm_maxsz;
15181da177e4SLinus Torvalds }
15191da177e4SLinus Torvalds 
1520cf8cdbe5SAndy Adamson static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
15211da177e4SLinus Torvalds {
15228687b63aSAl Viro 	__be32 *p;
15231da177e4SLinus Torvalds 
152413c65ce9SBenny Halevy 	p = reserve_space(xdr, 4);
152534558513SBenny Halevy 	*p = cpu_to_be32(OP_WRITE);
15261da177e4SLinus Torvalds 
15271da177e4SLinus Torvalds 	encode_stateid(xdr, args->context);
15281da177e4SLinus Torvalds 
152913c65ce9SBenny Halevy 	p = reserve_space(xdr, 16);
1530b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, args->offset);
1531e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->stable);
153234558513SBenny Halevy 	*p = cpu_to_be32(args->count);
15331da177e4SLinus Torvalds 
15341da177e4SLinus Torvalds 	xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
1535d017931cSAndy Adamson 	hdr->nops++;
1536dadf0c27SBenny Halevy 	hdr->replen += decode_write_maxsz;
15371da177e4SLinus Torvalds }
15381da177e4SLinus Torvalds 
1539cf8cdbe5SAndy Adamson static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr)
15401da177e4SLinus Torvalds {
15418687b63aSAl Viro 	__be32 *p;
15421da177e4SLinus Torvalds 
154313c65ce9SBenny Halevy 	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
15441da177e4SLinus Torvalds 
1545e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_DELEGRETURN);
154634558513SBenny Halevy 	xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
1547d017931cSAndy Adamson 	hdr->nops++;
1548dadf0c27SBenny Halevy 	hdr->replen += decode_delegreturn_maxsz;
15491da177e4SLinus Torvalds }
15509b7b9fccSAndy Adamson 
155199fe60d0SBenny Halevy #if defined(CONFIG_NFS_V4_1)
15529b7b9fccSAndy Adamson /* NFSv4.1 operations */
155399fe60d0SBenny Halevy static void encode_exchange_id(struct xdr_stream *xdr,
155499fe60d0SBenny Halevy 			       struct nfs41_exchange_id_args *args,
155599fe60d0SBenny Halevy 			       struct compound_hdr *hdr)
155699fe60d0SBenny Halevy {
155799fe60d0SBenny Halevy 	__be32 *p;
155899fe60d0SBenny Halevy 
155913c65ce9SBenny Halevy 	p = reserve_space(xdr, 4 + sizeof(args->verifier->data));
1560e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_EXCHANGE_ID);
156134558513SBenny Halevy 	xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data));
156299fe60d0SBenny Halevy 
156399fe60d0SBenny Halevy 	encode_string(xdr, args->id_len, args->id);
156499fe60d0SBenny Halevy 
156513c65ce9SBenny Halevy 	p = reserve_space(xdr, 12);
1566e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->flags);
1567e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(0);	/* zero length state_protect4_a */
156834558513SBenny Halevy 	*p = cpu_to_be32(0);	/* zero length implementation id array */
156999fe60d0SBenny Halevy 	hdr->nops++;
157099fe60d0SBenny Halevy 	hdr->replen += decode_exchange_id_maxsz;
157199fe60d0SBenny Halevy }
1572fc931582SAndy Adamson 
1573fc931582SAndy Adamson static void encode_create_session(struct xdr_stream *xdr,
1574fc931582SAndy Adamson 				  struct nfs41_create_session_args *args,
1575fc931582SAndy Adamson 				  struct compound_hdr *hdr)
1576fc931582SAndy Adamson {
1577fc931582SAndy Adamson 	__be32 *p;
1578fc931582SAndy Adamson 	char machine_name[NFS4_MAX_MACHINE_NAME_LEN];
1579fc931582SAndy Adamson 	uint32_t len;
1580fc931582SAndy Adamson 	struct nfs_client *clp = args->client;
15818e0d46e1SMike Sager 	u32 max_resp_sz_cached;
15828e0d46e1SMike Sager 
15838e0d46e1SMike Sager 	/*
15848e0d46e1SMike Sager 	 * Assumes OPEN is the biggest non-idempotent compound.
15858e0d46e1SMike Sager 	 * 2 is the verifier.
15868e0d46e1SMike Sager 	 */
15878e0d46e1SMike Sager 	max_resp_sz_cached = (NFS4_dec_open_sz + RPC_REPHDRSIZE +
15888e0d46e1SMike Sager 			      RPC_MAX_AUTH_SIZE + 2) * XDR_UNIT;
1589fc931582SAndy Adamson 
1590fc931582SAndy Adamson 	len = scnprintf(machine_name, sizeof(machine_name), "%s",
1591fc931582SAndy Adamson 			clp->cl_ipaddr);
159242edd698SBenny Halevy 
159313c65ce9SBenny Halevy 	p = reserve_space(xdr, 20 + 2*28 + 20 + len + 12);
1594e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_CREATE_SESSION);
1595b95be5a9SBenny Halevy 	p = xdr_encode_hyper(p, clp->cl_ex_clid);
1596e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(clp->cl_seqid);			/*Sequence id */
1597e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->flags);			/*flags */
1598fc931582SAndy Adamson 
1599fc931582SAndy Adamson 	/* Fore Channel */
1600e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->fc_attrs.headerpadsz);	/* header padding size */
1601e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->fc_attrs.max_rqst_sz);	/* max req size */
1602e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->fc_attrs.max_resp_sz);	/* max resp size */
16038e0d46e1SMike Sager 	*p++ = cpu_to_be32(max_resp_sz_cached);		/* Max resp sz cached */
1604e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->fc_attrs.max_ops);	/* max operations */
1605e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->fc_attrs.max_reqs);	/* max requests */
1606e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(0);				/* rdmachannel_attrs */
1607fc931582SAndy Adamson 
1608fc931582SAndy Adamson 	/* Back Channel */
1609e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->fc_attrs.headerpadsz);	/* header padding size */
1610e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->bc_attrs.max_rqst_sz);	/* max req size */
1611e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->bc_attrs.max_resp_sz);	/* max resp size */
1612e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->bc_attrs.max_resp_sz_cached);	/* Max resp sz cached */
1613e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->bc_attrs.max_ops);	/* max operations */
1614e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->bc_attrs.max_reqs);	/* max requests */
1615e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(0);				/* rdmachannel_attrs */
1616fc931582SAndy Adamson 
1617e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->cb_program);		/* cb_program */
1618e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(1);
1619e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(RPC_AUTH_UNIX);			/* auth_sys */
1620fc931582SAndy Adamson 
1621fc931582SAndy Adamson 	/* authsys_parms rfc1831 */
1622e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32((u32)clp->cl_boot_time.tv_nsec);	/* stamp */
1623811652bdSBenny Halevy 	p = xdr_encode_opaque(p, machine_name, len);
1624e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(0);				/* UID */
1625e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(0);				/* GID */
162634558513SBenny Halevy 	*p = cpu_to_be32(0);				/* No more gids */
1627fc931582SAndy Adamson 	hdr->nops++;
1628fc931582SAndy Adamson 	hdr->replen += decode_create_session_maxsz;
1629fc931582SAndy Adamson }
16300f3e66c6SAndy Adamson 
16310f3e66c6SAndy Adamson static void encode_destroy_session(struct xdr_stream *xdr,
16320f3e66c6SAndy Adamson 				   struct nfs4_session *session,
16330f3e66c6SAndy Adamson 				   struct compound_hdr *hdr)
16340f3e66c6SAndy Adamson {
16350f3e66c6SAndy Adamson 	__be32 *p;
163613c65ce9SBenny Halevy 	p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN);
1637e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_DESTROY_SESSION);
163834558513SBenny Halevy 	xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
16390f3e66c6SAndy Adamson 	hdr->nops++;
16400f3e66c6SAndy Adamson 	hdr->replen += decode_destroy_session_maxsz;
16410f3e66c6SAndy Adamson }
164218019753SRicardo Labiaga 
164318019753SRicardo Labiaga static void encode_reclaim_complete(struct xdr_stream *xdr,
164418019753SRicardo Labiaga 				    struct nfs41_reclaim_complete_args *args,
164518019753SRicardo Labiaga 				    struct compound_hdr *hdr)
164618019753SRicardo Labiaga {
164718019753SRicardo Labiaga 	__be32 *p;
164818019753SRicardo Labiaga 
164918019753SRicardo Labiaga 	p = reserve_space(xdr, 8);
165018019753SRicardo Labiaga 	*p++ = cpu_to_be32(OP_RECLAIM_COMPLETE);
165118019753SRicardo Labiaga 	*p++ = cpu_to_be32(args->one_fs);
165218019753SRicardo Labiaga 	hdr->nops++;
165318019753SRicardo Labiaga 	hdr->replen += decode_reclaim_complete_maxsz;
165418019753SRicardo Labiaga }
165599fe60d0SBenny Halevy #endif /* CONFIG_NFS_V4_1 */
165699fe60d0SBenny Halevy 
16579b7b9fccSAndy Adamson static void encode_sequence(struct xdr_stream *xdr,
16589b7b9fccSAndy Adamson 			    const struct nfs4_sequence_args *args,
16599b7b9fccSAndy Adamson 			    struct compound_hdr *hdr)
16609b7b9fccSAndy Adamson {
16619b7b9fccSAndy Adamson #if defined(CONFIG_NFS_V4_1)
16629b7b9fccSAndy Adamson 	struct nfs4_session *session = args->sa_session;
1663fc01cea9SAndy Adamson 	struct nfs4_slot_table *tp;
1664fc01cea9SAndy Adamson 	struct nfs4_slot *slot;
1665fc01cea9SAndy Adamson 	__be32 *p;
16669b7b9fccSAndy Adamson 
16679b7b9fccSAndy Adamson 	if (!session)
16689b7b9fccSAndy Adamson 		return;
16699b7b9fccSAndy Adamson 
1670fc01cea9SAndy Adamson 	tp = &session->fc_slot_table;
1671fc01cea9SAndy Adamson 
1672fc01cea9SAndy Adamson 	WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE);
1673fc01cea9SAndy Adamson 	slot = tp->slots + args->sa_slotid;
1674fc01cea9SAndy Adamson 
167513c65ce9SBenny Halevy 	p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN + 16);
1676e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(OP_SEQUENCE);
1677fc01cea9SAndy Adamson 
1678fc01cea9SAndy Adamson 	/*
1679fc01cea9SAndy Adamson 	 * Sessionid + seqid + slotid + max slotid + cache_this
1680fc01cea9SAndy Adamson 	 */
1681fc01cea9SAndy Adamson 	dprintk("%s: sessionid=%u:%u:%u:%u seqid=%d slotid=%d "
1682fc01cea9SAndy Adamson 		"max_slotid=%d cache_this=%d\n",
1683fc01cea9SAndy Adamson 		__func__,
1684fc01cea9SAndy Adamson 		((u32 *)session->sess_id.data)[0],
1685fc01cea9SAndy Adamson 		((u32 *)session->sess_id.data)[1],
1686fc01cea9SAndy Adamson 		((u32 *)session->sess_id.data)[2],
1687fc01cea9SAndy Adamson 		((u32 *)session->sess_id.data)[3],
1688fc01cea9SAndy Adamson 		slot->seq_nr, args->sa_slotid,
1689fc01cea9SAndy Adamson 		tp->highest_used_slotid, args->sa_cache_this);
169093f0cf25SBenny Halevy 	p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
1691e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(slot->seq_nr);
1692e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(args->sa_slotid);
1693e75bc1c8SBenny Halevy 	*p++ = cpu_to_be32(tp->highest_used_slotid);
169434558513SBenny Halevy 	*p = cpu_to_be32(args->sa_cache_this);
16959b7b9fccSAndy Adamson 	hdr->nops++;
16969b7b9fccSAndy Adamson 	hdr->replen += decode_sequence_maxsz;
16979b7b9fccSAndy Adamson #endif /* CONFIG_NFS_V4_1 */
16989b7b9fccSAndy Adamson }
16999b7b9fccSAndy Adamson 
17001da177e4SLinus Torvalds /*
17011da177e4SLinus Torvalds  * END OF "GENERIC" ENCODE ROUTINES.
17021da177e4SLinus Torvalds  */
17031da177e4SLinus Torvalds 
170466cc0429SBenny Halevy static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args)
170566cc0429SBenny Halevy {
170666cc0429SBenny Halevy #if defined(CONFIG_NFS_V4_1)
170766cc0429SBenny Halevy 	if (args->sa_session)
170866cc0429SBenny Halevy 		return args->sa_session->clp->cl_minorversion;
170966cc0429SBenny Halevy #endif /* CONFIG_NFS_V4_1 */
171066cc0429SBenny Halevy 	return 0;
171166cc0429SBenny Halevy }
171266cc0429SBenny Halevy 
17131da177e4SLinus Torvalds /*
17141da177e4SLinus Torvalds  * Encode an ACCESS request
17151da177e4SLinus Torvalds  */
17168687b63aSAl Viro static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs4_accessargs *args)
17171da177e4SLinus Torvalds {
17181da177e4SLinus Torvalds 	struct xdr_stream xdr;
17191da177e4SLinus Torvalds 	struct compound_hdr hdr = {
172066cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
17211da177e4SLinus Torvalds 	};
17221da177e4SLinus Torvalds 
17231da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
17240c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
17259b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1726cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1727cf8cdbe5SAndy Adamson 	encode_access(&xdr, args->access, &hdr);
1728cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1729d017931cSAndy Adamson 	encode_nops(&hdr);
1730cf8cdbe5SAndy Adamson 	return 0;
17311da177e4SLinus Torvalds }
17321da177e4SLinus Torvalds 
17331da177e4SLinus Torvalds /*
17341da177e4SLinus Torvalds  * Encode LOOKUP request
17351da177e4SLinus Torvalds  */
17368687b63aSAl Viro static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_arg *args)
17371da177e4SLinus Torvalds {
17381da177e4SLinus Torvalds 	struct xdr_stream xdr;
17391da177e4SLinus Torvalds 	struct compound_hdr hdr = {
174066cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
17411da177e4SLinus Torvalds 	};
17421da177e4SLinus Torvalds 
17431da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
17440c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
17459b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1746cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->dir_fh, &hdr);
1747cf8cdbe5SAndy Adamson 	encode_lookup(&xdr, args->name, &hdr);
1748cf8cdbe5SAndy Adamson 	encode_getfh(&xdr, &hdr);
1749cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1750d017931cSAndy Adamson 	encode_nops(&hdr);
1751cf8cdbe5SAndy Adamson 	return 0;
17521da177e4SLinus Torvalds }
17531da177e4SLinus Torvalds 
17541da177e4SLinus Torvalds /*
17551da177e4SLinus Torvalds  * Encode LOOKUP_ROOT request
17561da177e4SLinus Torvalds  */
17578687b63aSAl Viro static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_root_arg *args)
17581da177e4SLinus Torvalds {
17591da177e4SLinus Torvalds 	struct xdr_stream xdr;
17601da177e4SLinus Torvalds 	struct compound_hdr hdr = {
176166cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
17621da177e4SLinus Torvalds 	};
17631da177e4SLinus Torvalds 
17641da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
17650c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
17669b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1767cf8cdbe5SAndy Adamson 	encode_putrootfh(&xdr, &hdr);
1768cf8cdbe5SAndy Adamson 	encode_getfh(&xdr, &hdr);
1769cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1770d017931cSAndy Adamson 	encode_nops(&hdr);
1771cf8cdbe5SAndy Adamson 	return 0;
17721da177e4SLinus Torvalds }
17731da177e4SLinus Torvalds 
17741da177e4SLinus Torvalds /*
17751da177e4SLinus Torvalds  * Encode REMOVE request
17761da177e4SLinus Torvalds  */
17774fdc17b2STrond Myklebust static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
17781da177e4SLinus Torvalds {
17791da177e4SLinus Torvalds 	struct xdr_stream xdr;
17801da177e4SLinus Torvalds 	struct compound_hdr hdr = {
178166cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
17821da177e4SLinus Torvalds 	};
17831da177e4SLinus Torvalds 
17841da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
17850c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
17869b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1787cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1788cf8cdbe5SAndy Adamson 	encode_remove(&xdr, &args->name, &hdr);
1789cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1790d017931cSAndy Adamson 	encode_nops(&hdr);
1791cf8cdbe5SAndy Adamson 	return 0;
17921da177e4SLinus Torvalds }
17931da177e4SLinus Torvalds 
17941da177e4SLinus Torvalds /*
17951da177e4SLinus Torvalds  * Encode RENAME request
17961da177e4SLinus Torvalds  */
17978687b63aSAl Viro static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs4_rename_arg *args)
17981da177e4SLinus Torvalds {
17991da177e4SLinus Torvalds 	struct xdr_stream xdr;
18001da177e4SLinus Torvalds 	struct compound_hdr hdr = {
180166cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
18021da177e4SLinus Torvalds 	};
18031da177e4SLinus Torvalds 
18041da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
18050c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
18069b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1807cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->old_dir, &hdr);
1808cf8cdbe5SAndy Adamson 	encode_savefh(&xdr, &hdr);
1809cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->new_dir, &hdr);
1810cf8cdbe5SAndy Adamson 	encode_rename(&xdr, args->old_name, args->new_name, &hdr);
1811cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1812cf8cdbe5SAndy Adamson 	encode_restorefh(&xdr, &hdr);
1813cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1814d017931cSAndy Adamson 	encode_nops(&hdr);
1815cf8cdbe5SAndy Adamson 	return 0;
18161da177e4SLinus Torvalds }
18171da177e4SLinus Torvalds 
18181da177e4SLinus Torvalds /*
18191da177e4SLinus Torvalds  * Encode LINK request
18201da177e4SLinus Torvalds  */
18218687b63aSAl Viro static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_link_arg *args)
18221da177e4SLinus Torvalds {
18231da177e4SLinus Torvalds 	struct xdr_stream xdr;
18241da177e4SLinus Torvalds 	struct compound_hdr hdr = {
182566cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
18261da177e4SLinus Torvalds 	};
18271da177e4SLinus Torvalds 
18281da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
18290c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
18309b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1831cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1832cf8cdbe5SAndy Adamson 	encode_savefh(&xdr, &hdr);
1833cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->dir_fh, &hdr);
1834cf8cdbe5SAndy Adamson 	encode_link(&xdr, args->name, &hdr);
1835cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1836cf8cdbe5SAndy Adamson 	encode_restorefh(&xdr, &hdr);
1837cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1838d017931cSAndy Adamson 	encode_nops(&hdr);
1839cf8cdbe5SAndy Adamson 	return 0;
18401da177e4SLinus Torvalds }
18411da177e4SLinus Torvalds 
18421da177e4SLinus Torvalds /*
18431da177e4SLinus Torvalds  * Encode CREATE request
18441da177e4SLinus Torvalds  */
18458687b63aSAl Viro static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
18461da177e4SLinus Torvalds {
18471da177e4SLinus Torvalds 	struct xdr_stream xdr;
18481da177e4SLinus Torvalds 	struct compound_hdr hdr = {
184966cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
18501da177e4SLinus Torvalds 	};
18511da177e4SLinus Torvalds 
18521da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
18530c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
18549b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1855cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->dir_fh, &hdr);
1856cf8cdbe5SAndy Adamson 	encode_savefh(&xdr, &hdr);
1857cf8cdbe5SAndy Adamson 	encode_create(&xdr, args, &hdr);
1858cf8cdbe5SAndy Adamson 	encode_getfh(&xdr, &hdr);
1859cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1860cf8cdbe5SAndy Adamson 	encode_restorefh(&xdr, &hdr);
1861cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1862d017931cSAndy Adamson 	encode_nops(&hdr);
1863cf8cdbe5SAndy Adamson 	return 0;
18641da177e4SLinus Torvalds }
18651da177e4SLinus Torvalds 
18661da177e4SLinus Torvalds /*
18671da177e4SLinus Torvalds  * Encode SYMLINK request
18681da177e4SLinus Torvalds  */
18698687b63aSAl Viro static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
18701da177e4SLinus Torvalds {
18711da177e4SLinus Torvalds 	return nfs4_xdr_enc_create(req, p, args);
18721da177e4SLinus Torvalds }
18731da177e4SLinus Torvalds 
18741da177e4SLinus Torvalds /*
18751da177e4SLinus Torvalds  * Encode GETATTR request
18761da177e4SLinus Torvalds  */
18778687b63aSAl Viro static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nfs4_getattr_arg *args)
18781da177e4SLinus Torvalds {
18791da177e4SLinus Torvalds 	struct xdr_stream xdr;
18801da177e4SLinus Torvalds 	struct compound_hdr hdr = {
188166cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
18821da177e4SLinus Torvalds 	};
18831da177e4SLinus Torvalds 
18841da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
18850c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
18869b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1887cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1888cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1889d017931cSAndy Adamson 	encode_nops(&hdr);
1890cf8cdbe5SAndy Adamson 	return 0;
18911da177e4SLinus Torvalds }
18921da177e4SLinus Torvalds 
18931da177e4SLinus Torvalds /*
18941da177e4SLinus Torvalds  * Encode a CLOSE request
18951da177e4SLinus Torvalds  */
18968687b63aSAl Viro static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
18971da177e4SLinus Torvalds {
18981da177e4SLinus Torvalds 	struct xdr_stream xdr;
18991da177e4SLinus Torvalds 	struct compound_hdr hdr = {
190066cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
19011da177e4SLinus Torvalds 	};
19021da177e4SLinus Torvalds 
19031da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
19040c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
19059b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1906cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1907cf8cdbe5SAndy Adamson 	encode_close(&xdr, args, &hdr);
1908cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1909d017931cSAndy Adamson 	encode_nops(&hdr);
1910cf8cdbe5SAndy Adamson 	return 0;
19111da177e4SLinus Torvalds }
19121da177e4SLinus Torvalds 
19131da177e4SLinus Torvalds /*
19141da177e4SLinus Torvalds  * Encode an OPEN request
19151da177e4SLinus Torvalds  */
19168687b63aSAl Viro static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
19171da177e4SLinus Torvalds {
19181da177e4SLinus Torvalds 	struct xdr_stream xdr;
19191da177e4SLinus Torvalds 	struct compound_hdr hdr = {
192066cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
19211da177e4SLinus Torvalds 	};
19221da177e4SLinus Torvalds 
19231da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
19240c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
19259b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1926cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1927cf8cdbe5SAndy Adamson 	encode_savefh(&xdr, &hdr);
1928cf8cdbe5SAndy Adamson 	encode_open(&xdr, args, &hdr);
1929cf8cdbe5SAndy Adamson 	encode_getfh(&xdr, &hdr);
1930cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1931cf8cdbe5SAndy Adamson 	encode_restorefh(&xdr, &hdr);
1932cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1933d017931cSAndy Adamson 	encode_nops(&hdr);
1934cf8cdbe5SAndy Adamson 	return 0;
19351da177e4SLinus Torvalds }
19361da177e4SLinus Torvalds 
19371da177e4SLinus Torvalds /*
19381da177e4SLinus Torvalds  * Encode an OPEN_CONFIRM request
19391da177e4SLinus Torvalds  */
19408687b63aSAl Viro static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_open_confirmargs *args)
19411da177e4SLinus Torvalds {
19421da177e4SLinus Torvalds 	struct xdr_stream xdr;
19431da177e4SLinus Torvalds 	struct compound_hdr hdr = {
1944d017931cSAndy Adamson 		.nops   = 0,
19451da177e4SLinus Torvalds 	};
19461da177e4SLinus Torvalds 
19471da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
19480c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
1949cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1950cf8cdbe5SAndy Adamson 	encode_open_confirm(&xdr, args, &hdr);
1951d017931cSAndy Adamson 	encode_nops(&hdr);
1952cf8cdbe5SAndy Adamson 	return 0;
19531da177e4SLinus Torvalds }
19541da177e4SLinus Torvalds 
19551da177e4SLinus Torvalds /*
19561da177e4SLinus Torvalds  * Encode an OPEN request with no attributes.
19571da177e4SLinus Torvalds  */
19588687b63aSAl Viro static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
19591da177e4SLinus Torvalds {
19601da177e4SLinus Torvalds 	struct xdr_stream xdr;
19611da177e4SLinus Torvalds 	struct compound_hdr hdr = {
196266cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
19631da177e4SLinus Torvalds 	};
19641da177e4SLinus Torvalds 
19651da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
19660c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
19679b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1968cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1969cf8cdbe5SAndy Adamson 	encode_open(&xdr, args, &hdr);
1970cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1971d017931cSAndy Adamson 	encode_nops(&hdr);
1972cf8cdbe5SAndy Adamson 	return 0;
19731da177e4SLinus Torvalds }
19741da177e4SLinus Torvalds 
19751da177e4SLinus Torvalds /*
19761da177e4SLinus Torvalds  * Encode an OPEN_DOWNGRADE request
19771da177e4SLinus Torvalds  */
19788687b63aSAl Viro static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
19791da177e4SLinus Torvalds {
19801da177e4SLinus Torvalds 	struct xdr_stream xdr;
19811da177e4SLinus Torvalds 	struct compound_hdr hdr = {
198266cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
19831da177e4SLinus Torvalds 	};
19841da177e4SLinus Torvalds 
19851da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
19860c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
19879b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
1988cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
1989cf8cdbe5SAndy Adamson 	encode_open_downgrade(&xdr, args, &hdr);
1990cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
1991d017931cSAndy Adamson 	encode_nops(&hdr);
1992cf8cdbe5SAndy Adamson 	return 0;
19931da177e4SLinus Torvalds }
19941da177e4SLinus Torvalds 
19951da177e4SLinus Torvalds /*
19961da177e4SLinus Torvalds  * Encode a LOCK request
19971da177e4SLinus Torvalds  */
19988687b63aSAl Viro static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_args *args)
19991da177e4SLinus Torvalds {
20001da177e4SLinus Torvalds 	struct xdr_stream xdr;
20011da177e4SLinus Torvalds 	struct compound_hdr hdr = {
200266cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
20031da177e4SLinus Torvalds 	};
20041da177e4SLinus Torvalds 
20051da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
20060c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
20079b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2008cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2009cf8cdbe5SAndy Adamson 	encode_lock(&xdr, args, &hdr);
2010d017931cSAndy Adamson 	encode_nops(&hdr);
2011cf8cdbe5SAndy Adamson 	return 0;
20121da177e4SLinus Torvalds }
20131da177e4SLinus Torvalds 
20141da177e4SLinus Torvalds /*
20151da177e4SLinus Torvalds  * Encode a LOCKT request
20161da177e4SLinus Torvalds  */
20178687b63aSAl Viro static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_args *args)
20181da177e4SLinus Torvalds {
20191da177e4SLinus Torvalds 	struct xdr_stream xdr;
20201da177e4SLinus Torvalds 	struct compound_hdr hdr = {
202166cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
20221da177e4SLinus Torvalds 	};
20231da177e4SLinus Torvalds 
20241da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
20250c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
20269b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2027cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2028cf8cdbe5SAndy Adamson 	encode_lockt(&xdr, args, &hdr);
2029d017931cSAndy Adamson 	encode_nops(&hdr);
2030cf8cdbe5SAndy Adamson 	return 0;
20311da177e4SLinus Torvalds }
20321da177e4SLinus Torvalds 
20331da177e4SLinus Torvalds /*
20341da177e4SLinus Torvalds  * Encode a LOCKU request
20351da177e4SLinus Torvalds  */
20368687b63aSAl Viro static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_args *args)
20371da177e4SLinus Torvalds {
20381da177e4SLinus Torvalds 	struct xdr_stream xdr;
20391da177e4SLinus Torvalds 	struct compound_hdr hdr = {
204066cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
20411da177e4SLinus Torvalds 	};
20421da177e4SLinus Torvalds 
20431da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
20440c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
20459b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2046cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2047cf8cdbe5SAndy Adamson 	encode_locku(&xdr, args, &hdr);
2048d017931cSAndy Adamson 	encode_nops(&hdr);
2049cf8cdbe5SAndy Adamson 	return 0;
20501da177e4SLinus Torvalds }
20511da177e4SLinus Torvalds 
20521da177e4SLinus Torvalds /*
20531da177e4SLinus Torvalds  * Encode a READLINK request
20541da177e4SLinus Torvalds  */
20558687b63aSAl Viro static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_readlink *args)
20561da177e4SLinus Torvalds {
20571da177e4SLinus Torvalds 	struct xdr_stream xdr;
20581da177e4SLinus Torvalds 	struct compound_hdr hdr = {
205966cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
20601da177e4SLinus Torvalds 	};
20611da177e4SLinus Torvalds 
20621da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
20630c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
20649b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2065cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2066cf8cdbe5SAndy Adamson 	encode_readlink(&xdr, args, req, &hdr);
2067e3a535e1STrond Myklebust 
206828f56694SBenny Halevy 	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
2069e3a535e1STrond Myklebust 			args->pgbase, args->pglen);
2070d017931cSAndy Adamson 	encode_nops(&hdr);
2071cf8cdbe5SAndy Adamson 	return 0;
20721da177e4SLinus Torvalds }
20731da177e4SLinus Torvalds 
20741da177e4SLinus Torvalds /*
20751da177e4SLinus Torvalds  * Encode a READDIR request
20761da177e4SLinus Torvalds  */
20778687b63aSAl Viro static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nfs4_readdir_arg *args)
20781da177e4SLinus Torvalds {
20791da177e4SLinus Torvalds 	struct xdr_stream xdr;
20801da177e4SLinus Torvalds 	struct compound_hdr hdr = {
208166cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
20821da177e4SLinus Torvalds 	};
20831da177e4SLinus Torvalds 
20841da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
20850c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
20869b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2087cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2088cf8cdbe5SAndy Adamson 	encode_readdir(&xdr, args, req, &hdr);
2089d6ac02dfSTrond Myklebust 
209028f56694SBenny Halevy 	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
2091d6ac02dfSTrond Myklebust 			 args->pgbase, args->count);
2092d6ac02dfSTrond Myklebust 	dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
209328f56694SBenny Halevy 			__func__, hdr.replen << 2, args->pages,
2094d6ac02dfSTrond Myklebust 			args->pgbase, args->count);
2095d017931cSAndy Adamson 	encode_nops(&hdr);
2096cf8cdbe5SAndy Adamson 	return 0;
20971da177e4SLinus Torvalds }
20981da177e4SLinus Torvalds 
20991da177e4SLinus Torvalds /*
21001da177e4SLinus Torvalds  * Encode a READ request
21011da177e4SLinus Torvalds  */
21028687b63aSAl Viro static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
21031da177e4SLinus Torvalds {
21041da177e4SLinus Torvalds 	struct xdr_stream xdr;
21051da177e4SLinus Torvalds 	struct compound_hdr hdr = {
210666cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
21071da177e4SLinus Torvalds 	};
21081da177e4SLinus Torvalds 
21091da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
21100c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
21119b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2112cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2113cf8cdbe5SAndy Adamson 	encode_read(&xdr, args, &hdr);
21141da177e4SLinus Torvalds 
211528f56694SBenny Halevy 	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2,
21161da177e4SLinus Torvalds 			 args->pages, args->pgbase, args->count);
21174f22ccc3S\"Talpey, Thomas\ 	req->rq_rcv_buf.flags |= XDRBUF_READ;
2118d017931cSAndy Adamson 	encode_nops(&hdr);
2119cf8cdbe5SAndy Adamson 	return 0;
21201da177e4SLinus Torvalds }
21211da177e4SLinus Torvalds 
21221da177e4SLinus Torvalds /*
21231da177e4SLinus Torvalds  * Encode an SETATTR request
21241da177e4SLinus Torvalds  */
21258687b63aSAl Viro static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args)
21261da177e4SLinus Torvalds {
21271da177e4SLinus Torvalds 	struct xdr_stream xdr;
21281da177e4SLinus Torvalds 	struct compound_hdr hdr = {
212966cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
21301da177e4SLinus Torvalds 	};
21311da177e4SLinus Torvalds 
21321da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
21330c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
21349b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2135cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2136cf8cdbe5SAndy Adamson 	encode_setattr(&xdr, args, args->server, &hdr);
2137cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
2138d017931cSAndy Adamson 	encode_nops(&hdr);
2139cf8cdbe5SAndy Adamson 	return 0;
21401da177e4SLinus Torvalds }
21411da177e4SLinus Torvalds 
21421da177e4SLinus Torvalds /*
2143029d105eSJ. Bruce Fields  * Encode a GETACL request
2144029d105eSJ. Bruce Fields  */
2145029d105eSJ. Bruce Fields static int
21468687b63aSAl Viro nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
2147029d105eSJ. Bruce Fields 		struct nfs_getaclargs *args)
2148029d105eSJ. Bruce Fields {
2149029d105eSJ. Bruce Fields 	struct xdr_stream xdr;
2150029d105eSJ. Bruce Fields 	struct compound_hdr hdr = {
215166cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
2152029d105eSJ. Bruce Fields 	};
215328f56694SBenny Halevy 	uint32_t replen;
2154029d105eSJ. Bruce Fields 
2155029d105eSJ. Bruce Fields 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
21560c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
21579b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2158cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2159d327cf74SJ. Bruce Fields 	replen = hdr.replen + op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz + 1;
2160cf8cdbe5SAndy Adamson 	encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr);
2161cf8cdbe5SAndy Adamson 
216228f56694SBenny Halevy 	xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
2163029d105eSJ. Bruce Fields 		args->acl_pages, args->acl_pgbase, args->acl_len);
2164d017931cSAndy Adamson 	encode_nops(&hdr);
2165cf8cdbe5SAndy Adamson 	return 0;
2166029d105eSJ. Bruce Fields }
2167029d105eSJ. Bruce Fields 
2168029d105eSJ. Bruce Fields /*
21691da177e4SLinus Torvalds  * Encode a WRITE request
21701da177e4SLinus Torvalds  */
21718687b63aSAl Viro static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
21721da177e4SLinus Torvalds {
21731da177e4SLinus Torvalds 	struct xdr_stream xdr;
21741da177e4SLinus Torvalds 	struct compound_hdr hdr = {
217566cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
21761da177e4SLinus Torvalds 	};
21771da177e4SLinus Torvalds 
21781da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
21790c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
21809b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2181cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2182cf8cdbe5SAndy Adamson 	encode_write(&xdr, args, &hdr);
21834f22ccc3S\"Talpey, Thomas\ 	req->rq_snd_buf.flags |= XDRBUF_WRITE;
2184cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
2185d017931cSAndy Adamson 	encode_nops(&hdr);
2186cf8cdbe5SAndy Adamson 	return 0;
21871da177e4SLinus Torvalds }
21881da177e4SLinus Torvalds 
21891da177e4SLinus Torvalds /*
21901da177e4SLinus Torvalds  *  a COMMIT request
21911da177e4SLinus Torvalds  */
21928687b63aSAl Viro static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
21931da177e4SLinus Torvalds {
21941da177e4SLinus Torvalds 	struct xdr_stream xdr;
21951da177e4SLinus Torvalds 	struct compound_hdr hdr = {
219666cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
21971da177e4SLinus Torvalds 	};
21981da177e4SLinus Torvalds 
21991da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
22000c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
22019b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2202cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2203cf8cdbe5SAndy Adamson 	encode_commit(&xdr, args, &hdr);
2204cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
2205d017931cSAndy Adamson 	encode_nops(&hdr);
2206cf8cdbe5SAndy Adamson 	return 0;
22071da177e4SLinus Torvalds }
22081da177e4SLinus Torvalds 
22091da177e4SLinus Torvalds /*
22101da177e4SLinus Torvalds  * FSINFO request
22111da177e4SLinus Torvalds  */
22128687b63aSAl Viro static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsinfo_arg *args)
22131da177e4SLinus Torvalds {
22141da177e4SLinus Torvalds 	struct xdr_stream xdr;
22151da177e4SLinus Torvalds 	struct compound_hdr hdr = {
221666cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
22171da177e4SLinus Torvalds 	};
22181da177e4SLinus Torvalds 
22191da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
22200c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
22219b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2222cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2223cf8cdbe5SAndy Adamson 	encode_fsinfo(&xdr, args->bitmask, &hdr);
2224d017931cSAndy Adamson 	encode_nops(&hdr);
2225cf8cdbe5SAndy Adamson 	return 0;
22261da177e4SLinus Torvalds }
22271da177e4SLinus Torvalds 
22281da177e4SLinus Torvalds /*
22291da177e4SLinus Torvalds  * a PATHCONF request
22301da177e4SLinus Torvalds  */
22318687b63aSAl Viro static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct nfs4_pathconf_arg *args)
22321da177e4SLinus Torvalds {
22331da177e4SLinus Torvalds 	struct xdr_stream xdr;
22341da177e4SLinus Torvalds 	struct compound_hdr hdr = {
223566cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
22361da177e4SLinus Torvalds 	};
22371da177e4SLinus Torvalds 
22381da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
22390c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
22409b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2241cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2242cf8cdbe5SAndy Adamson 	encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0],
2243d017931cSAndy Adamson 			   &hdr);
2244d017931cSAndy Adamson 	encode_nops(&hdr);
2245cf8cdbe5SAndy Adamson 	return 0;
22461da177e4SLinus Torvalds }
22471da177e4SLinus Torvalds 
22481da177e4SLinus Torvalds /*
22491da177e4SLinus Torvalds  * a STATFS request
22501da177e4SLinus Torvalds  */
22518687b63aSAl Viro static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs4_statfs_arg *args)
22521da177e4SLinus Torvalds {
22531da177e4SLinus Torvalds 	struct xdr_stream xdr;
22541da177e4SLinus Torvalds 	struct compound_hdr hdr = {
225566cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
22561da177e4SLinus Torvalds 	};
22571da177e4SLinus Torvalds 
22581da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
22590c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
22609b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2261cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
2262cf8cdbe5SAndy Adamson 	encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0],
2263d017931cSAndy Adamson 			   args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr);
2264d017931cSAndy Adamson 	encode_nops(&hdr);
2265cf8cdbe5SAndy Adamson 	return 0;
22661da177e4SLinus Torvalds }
22671da177e4SLinus Torvalds 
22681da177e4SLinus Torvalds /*
22691da177e4SLinus Torvalds  * GETATTR_BITMAP request
22701da177e4SLinus Torvalds  */
227143652ad5SBenny Halevy static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p,
227243652ad5SBenny Halevy 				    struct nfs4_server_caps_arg *args)
22731da177e4SLinus Torvalds {
22741da177e4SLinus Torvalds 	struct xdr_stream xdr;
22751da177e4SLinus Torvalds 	struct compound_hdr hdr = {
227666cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
22771da177e4SLinus Torvalds 	};
22781da177e4SLinus Torvalds 
22791da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
22800c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
22819b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
228243652ad5SBenny Halevy 	encode_putfh(&xdr, args->fhandle, &hdr);
2283cf8cdbe5SAndy Adamson 	encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
22841da177e4SLinus Torvalds 			   FATTR4_WORD0_LINK_SUPPORT|
22851da177e4SLinus Torvalds 			   FATTR4_WORD0_SYMLINK_SUPPORT|
2286d017931cSAndy Adamson 			   FATTR4_WORD0_ACLSUPPORT, &hdr);
2287d017931cSAndy Adamson 	encode_nops(&hdr);
2288cf8cdbe5SAndy Adamson 	return 0;
22891da177e4SLinus Torvalds }
22901da177e4SLinus Torvalds 
22911da177e4SLinus Torvalds /*
22921da177e4SLinus Torvalds  * a RENEW request
22931da177e4SLinus Torvalds  */
22948687b63aSAl Viro static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
22951da177e4SLinus Torvalds {
22961da177e4SLinus Torvalds 	struct xdr_stream xdr;
22971da177e4SLinus Torvalds 	struct compound_hdr hdr = {
2298d017931cSAndy Adamson 		.nops	= 0,
22991da177e4SLinus Torvalds 	};
23001da177e4SLinus Torvalds 
23011da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
23020c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
2303cf8cdbe5SAndy Adamson 	encode_renew(&xdr, clp, &hdr);
2304d017931cSAndy Adamson 	encode_nops(&hdr);
2305cf8cdbe5SAndy Adamson 	return 0;
23061da177e4SLinus Torvalds }
23071da177e4SLinus Torvalds 
23081da177e4SLinus Torvalds /*
23091da177e4SLinus Torvalds  * a SETCLIENTID request
23101da177e4SLinus Torvalds  */
23118687b63aSAl Viro static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid *sc)
23121da177e4SLinus Torvalds {
23131da177e4SLinus Torvalds 	struct xdr_stream xdr;
23141da177e4SLinus Torvalds 	struct compound_hdr hdr = {
2315d017931cSAndy Adamson 		.nops	= 0,
23161da177e4SLinus Torvalds 	};
23171da177e4SLinus Torvalds 
23181da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
23190c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
2320cf8cdbe5SAndy Adamson 	encode_setclientid(&xdr, sc, &hdr);
2321d017931cSAndy Adamson 	encode_nops(&hdr);
2322cf8cdbe5SAndy Adamson 	return 0;
23231da177e4SLinus Torvalds }
23241da177e4SLinus Torvalds 
23251da177e4SLinus Torvalds /*
23261da177e4SLinus Torvalds  * a SETCLIENTID_CONFIRM request
23271da177e4SLinus Torvalds  */
23288687b63aSAl Viro static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
23291da177e4SLinus Torvalds {
23301da177e4SLinus Torvalds 	struct xdr_stream xdr;
23311da177e4SLinus Torvalds 	struct compound_hdr hdr = {
2332d017931cSAndy Adamson 		.nops	= 0,
23331da177e4SLinus Torvalds 	};
23341da177e4SLinus Torvalds 	const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
23351da177e4SLinus Torvalds 
23361da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
23370c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
2338cf8cdbe5SAndy Adamson 	encode_setclientid_confirm(&xdr, clp, &hdr);
2339cf8cdbe5SAndy Adamson 	encode_putrootfh(&xdr, &hdr);
2340cf8cdbe5SAndy Adamson 	encode_fsinfo(&xdr, lease_bitmap, &hdr);
2341d017931cSAndy Adamson 	encode_nops(&hdr);
2342cf8cdbe5SAndy Adamson 	return 0;
23431da177e4SLinus Torvalds }
23441da177e4SLinus Torvalds 
23451da177e4SLinus Torvalds /*
23461da177e4SLinus Torvalds  * DELEGRETURN request
23471da177e4SLinus Torvalds  */
23488687b63aSAl Viro static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struct nfs4_delegreturnargs *args)
23491da177e4SLinus Torvalds {
23501da177e4SLinus Torvalds 	struct xdr_stream xdr;
23511da177e4SLinus Torvalds 	struct compound_hdr hdr = {
235266cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
23531da177e4SLinus Torvalds 	};
23541da177e4SLinus Torvalds 
23551da177e4SLinus Torvalds 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
23560c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
23579b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2358cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fhandle, &hdr);
2359cf8cdbe5SAndy Adamson 	encode_delegreturn(&xdr, args->stateid, &hdr);
2360cf8cdbe5SAndy Adamson 	encode_getfattr(&xdr, args->bitmask, &hdr);
2361d017931cSAndy Adamson 	encode_nops(&hdr);
2362cf8cdbe5SAndy Adamson 	return 0;
23631da177e4SLinus Torvalds }
23641da177e4SLinus Torvalds 
23651da177e4SLinus Torvalds /*
2366683b57b4STrond Myklebust  * Encode FS_LOCATIONS request
2367683b57b4STrond Myklebust  */
23688687b63aSAl Viro static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations_arg *args)
2369683b57b4STrond Myklebust {
2370683b57b4STrond Myklebust 	struct xdr_stream xdr;
2371683b57b4STrond Myklebust 	struct compound_hdr hdr = {
237266cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
2373683b57b4STrond Myklebust 	};
237428f56694SBenny Halevy 	uint32_t replen;
2375683b57b4STrond Myklebust 
2376683b57b4STrond Myklebust 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
23770c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
23789b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
2379cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->dir_fh, &hdr);
2380cf8cdbe5SAndy Adamson 	encode_lookup(&xdr, args->name, &hdr);
238128f56694SBenny Halevy 	replen = hdr.replen;	/* get the attribute into args->page */
2382cf8cdbe5SAndy Adamson 	encode_fs_locations(&xdr, args->bitmask, &hdr);
2383cf8cdbe5SAndy Adamson 
238428f56694SBenny Halevy 	xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page,
2385683b57b4STrond Myklebust 			0, PAGE_SIZE);
2386d017931cSAndy Adamson 	encode_nops(&hdr);
2387cf8cdbe5SAndy Adamson 	return 0;
2388683b57b4STrond Myklebust }
2389683b57b4STrond Myklebust 
239099fe60d0SBenny Halevy #if defined(CONFIG_NFS_V4_1)
239199fe60d0SBenny Halevy /*
239299fe60d0SBenny Halevy  * EXCHANGE_ID request
239399fe60d0SBenny Halevy  */
239499fe60d0SBenny Halevy static int nfs4_xdr_enc_exchange_id(struct rpc_rqst *req, uint32_t *p,
239599fe60d0SBenny Halevy 				    struct nfs41_exchange_id_args *args)
239699fe60d0SBenny Halevy {
239799fe60d0SBenny Halevy 	struct xdr_stream xdr;
239899fe60d0SBenny Halevy 	struct compound_hdr hdr = {
239999fe60d0SBenny Halevy 		.minorversion = args->client->cl_minorversion,
240099fe60d0SBenny Halevy 	};
240199fe60d0SBenny Halevy 
240299fe60d0SBenny Halevy 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
240399fe60d0SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
240499fe60d0SBenny Halevy 	encode_exchange_id(&xdr, args, &hdr);
240599fe60d0SBenny Halevy 	encode_nops(&hdr);
240699fe60d0SBenny Halevy 	return 0;
240799fe60d0SBenny Halevy }
24082050f0ccSAndy Adamson 
24092050f0ccSAndy Adamson /*
2410fc931582SAndy Adamson  * a CREATE_SESSION request
2411fc931582SAndy Adamson  */
2412fc931582SAndy Adamson static int nfs4_xdr_enc_create_session(struct rpc_rqst *req, uint32_t *p,
2413fc931582SAndy Adamson 				       struct nfs41_create_session_args *args)
2414fc931582SAndy Adamson {
2415fc931582SAndy Adamson 	struct xdr_stream xdr;
2416fc931582SAndy Adamson 	struct compound_hdr hdr = {
2417fc931582SAndy Adamson 		.minorversion = args->client->cl_minorversion,
2418fc931582SAndy Adamson 	};
2419fc931582SAndy Adamson 
2420fc931582SAndy Adamson 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2421fc931582SAndy Adamson 	encode_compound_hdr(&xdr, req, &hdr);
2422fc931582SAndy Adamson 	encode_create_session(&xdr, args, &hdr);
2423fc931582SAndy Adamson 	encode_nops(&hdr);
2424fc931582SAndy Adamson 	return 0;
2425fc931582SAndy Adamson }
2426fc931582SAndy Adamson 
2427fc931582SAndy Adamson /*
24280f3e66c6SAndy Adamson  * a DESTROY_SESSION request
24290f3e66c6SAndy Adamson  */
24300f3e66c6SAndy Adamson static int nfs4_xdr_enc_destroy_session(struct rpc_rqst *req, uint32_t *p,
24310f3e66c6SAndy Adamson 					struct nfs4_session *session)
24320f3e66c6SAndy Adamson {
24330f3e66c6SAndy Adamson 	struct xdr_stream xdr;
24340f3e66c6SAndy Adamson 	struct compound_hdr hdr = {
24350f3e66c6SAndy Adamson 		.minorversion = session->clp->cl_minorversion,
24360f3e66c6SAndy Adamson 	};
24370f3e66c6SAndy Adamson 
24380f3e66c6SAndy Adamson 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
24390f3e66c6SAndy Adamson 	encode_compound_hdr(&xdr, req, &hdr);
24400f3e66c6SAndy Adamson 	encode_destroy_session(&xdr, session, &hdr);
24410f3e66c6SAndy Adamson 	encode_nops(&hdr);
24420f3e66c6SAndy Adamson 	return 0;
24430f3e66c6SAndy Adamson }
24440f3e66c6SAndy Adamson 
24450f3e66c6SAndy Adamson /*
2446fc01cea9SAndy Adamson  * a SEQUENCE request
2447fc01cea9SAndy Adamson  */
2448fc01cea9SAndy Adamson static int nfs4_xdr_enc_sequence(struct rpc_rqst *req, uint32_t *p,
2449fc01cea9SAndy Adamson 				 struct nfs4_sequence_args *args)
2450fc01cea9SAndy Adamson {
2451fc01cea9SAndy Adamson 	struct xdr_stream xdr;
2452fc01cea9SAndy Adamson 	struct compound_hdr hdr = {
2453fc01cea9SAndy Adamson 		.minorversion = nfs4_xdr_minorversion(args),
2454fc01cea9SAndy Adamson 	};
2455fc01cea9SAndy Adamson 
2456fc01cea9SAndy Adamson 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2457fc01cea9SAndy Adamson 	encode_compound_hdr(&xdr, req, &hdr);
2458fc01cea9SAndy Adamson 	encode_sequence(&xdr, args, &hdr);
2459fc01cea9SAndy Adamson 	encode_nops(&hdr);
2460fc01cea9SAndy Adamson 	return 0;
2461fc01cea9SAndy Adamson }
2462fc01cea9SAndy Adamson 
2463fc01cea9SAndy Adamson /*
24642050f0ccSAndy Adamson  * a GET_LEASE_TIME request
24652050f0ccSAndy Adamson  */
24662050f0ccSAndy Adamson static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p,
24672050f0ccSAndy Adamson 				       struct nfs4_get_lease_time_args *args)
24682050f0ccSAndy Adamson {
24692050f0ccSAndy Adamson 	struct xdr_stream xdr;
24702050f0ccSAndy Adamson 	struct compound_hdr hdr = {
24712050f0ccSAndy Adamson 		.minorversion = nfs4_xdr_minorversion(&args->la_seq_args),
24722050f0ccSAndy Adamson 	};
24732050f0ccSAndy Adamson 	const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };
24742050f0ccSAndy Adamson 
24752050f0ccSAndy Adamson 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
24762050f0ccSAndy Adamson 	encode_compound_hdr(&xdr, req, &hdr);
24772050f0ccSAndy Adamson 	encode_sequence(&xdr, &args->la_seq_args, &hdr);
24782050f0ccSAndy Adamson 	encode_putrootfh(&xdr, &hdr);
24792050f0ccSAndy Adamson 	encode_fsinfo(&xdr, lease_bitmap, &hdr);
24802050f0ccSAndy Adamson 	encode_nops(&hdr);
24812050f0ccSAndy Adamson 	return 0;
24822050f0ccSAndy Adamson }
248318019753SRicardo Labiaga 
248418019753SRicardo Labiaga /*
248518019753SRicardo Labiaga  * a RECLAIM_COMPLETE request
248618019753SRicardo Labiaga  */
248718019753SRicardo Labiaga static int nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req, uint32_t *p,
248818019753SRicardo Labiaga 				     struct nfs41_reclaim_complete_args *args)
248918019753SRicardo Labiaga {
249018019753SRicardo Labiaga 	struct xdr_stream xdr;
249118019753SRicardo Labiaga 	struct compound_hdr hdr = {
249218019753SRicardo Labiaga 		.minorversion = nfs4_xdr_minorversion(&args->seq_args)
249318019753SRicardo Labiaga 	};
249418019753SRicardo Labiaga 
249518019753SRicardo Labiaga 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
249618019753SRicardo Labiaga 	encode_compound_hdr(&xdr, req, &hdr);
249718019753SRicardo Labiaga 	encode_sequence(&xdr, &args->seq_args, &hdr);
249818019753SRicardo Labiaga 	encode_reclaim_complete(&xdr, args, &hdr);
249918019753SRicardo Labiaga 	encode_nops(&hdr);
250018019753SRicardo Labiaga 	return 0;
250118019753SRicardo Labiaga }
250218019753SRicardo Labiaga 
250399fe60d0SBenny Halevy #endif /* CONFIG_NFS_V4_1 */
250499fe60d0SBenny Halevy 
2505686841b3SBenny Halevy static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
2506686841b3SBenny Halevy {
2507686841b3SBenny Halevy 	dprintk("nfs: %s: prematurely hit end of receive buffer. "
2508686841b3SBenny Halevy 		"Remaining buffer length is %tu words.\n",
2509686841b3SBenny Halevy 		func, xdr->end - xdr->p);
2510686841b3SBenny Halevy }
25111da177e4SLinus Torvalds 
2512683b57b4STrond Myklebust static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
25131da177e4SLinus Torvalds {
25148687b63aSAl Viro 	__be32 *p;
25151da177e4SLinus Torvalds 
2516c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
2517c0eae66eSBenny Halevy 	if (unlikely(!p))
2518c0eae66eSBenny Halevy 		goto out_overflow;
2519cccddf4fSBenny Halevy 	*len = be32_to_cpup(p);
2520c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, *len);
2521c0eae66eSBenny Halevy 	if (unlikely(!p))
2522c0eae66eSBenny Halevy 		goto out_overflow;
25231da177e4SLinus Torvalds 	*string = (char *)p;
25241da177e4SLinus Torvalds 	return 0;
2525c0eae66eSBenny Halevy out_overflow:
2526c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2527c0eae66eSBenny Halevy 	return -EIO;
25281da177e4SLinus Torvalds }
25291da177e4SLinus Torvalds 
25301da177e4SLinus Torvalds static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
25311da177e4SLinus Torvalds {
25328687b63aSAl Viro 	__be32 *p;
25331da177e4SLinus Torvalds 
2534c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
2535c0eae66eSBenny Halevy 	if (unlikely(!p))
2536c0eae66eSBenny Halevy 		goto out_overflow;
25376f723f77SBenny Halevy 	hdr->status = be32_to_cpup(p++);
2538cccddf4fSBenny Halevy 	hdr->taglen = be32_to_cpup(p);
25391da177e4SLinus Torvalds 
2540c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, hdr->taglen + 4);
2541c0eae66eSBenny Halevy 	if (unlikely(!p))
2542c0eae66eSBenny Halevy 		goto out_overflow;
25431da177e4SLinus Torvalds 	hdr->tag = (char *)p;
25441da177e4SLinus Torvalds 	p += XDR_QUADLEN(hdr->taglen);
2545cccddf4fSBenny Halevy 	hdr->nops = be32_to_cpup(p);
2546aadf6152SBenny Halevy 	if (unlikely(hdr->nops < 1))
2547aadf6152SBenny Halevy 		return nfs4_stat_to_errno(hdr->status);
25481da177e4SLinus Torvalds 	return 0;
2549c0eae66eSBenny Halevy out_overflow:
2550c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2551c0eae66eSBenny Halevy 	return -EIO;
25521da177e4SLinus Torvalds }
25531da177e4SLinus Torvalds 
25541da177e4SLinus Torvalds static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
25551da177e4SLinus Torvalds {
25568687b63aSAl Viro 	__be32 *p;
25571da177e4SLinus Torvalds 	uint32_t opnum;
25581da177e4SLinus Torvalds 	int32_t nfserr;
25591da177e4SLinus Torvalds 
2560c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
2561c0eae66eSBenny Halevy 	if (unlikely(!p))
2562c0eae66eSBenny Halevy 		goto out_overflow;
25636f723f77SBenny Halevy 	opnum = be32_to_cpup(p++);
25641da177e4SLinus Torvalds 	if (opnum != expected) {
2565fe82a183SChuck Lever 		dprintk("nfs: Server returned operation"
25661da177e4SLinus Torvalds 			" %d but we issued a request for %d\n",
25671da177e4SLinus Torvalds 				opnum, expected);
25681da177e4SLinus Torvalds 		return -EIO;
25691da177e4SLinus Torvalds 	}
2570cccddf4fSBenny Halevy 	nfserr = be32_to_cpup(p);
25711da177e4SLinus Torvalds 	if (nfserr != NFS_OK)
2572856dff3dSBenny Halevy 		return nfs4_stat_to_errno(nfserr);
25731da177e4SLinus Torvalds 	return 0;
2574c0eae66eSBenny Halevy out_overflow:
2575c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2576c0eae66eSBenny Halevy 	return -EIO;
25771da177e4SLinus Torvalds }
25781da177e4SLinus Torvalds 
25791da177e4SLinus Torvalds /* Dummy routine */
2580adfa6f98SDavid Howells static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp)
25811da177e4SLinus Torvalds {
25828687b63aSAl Viro 	__be32 *p;
2583683b57b4STrond Myklebust 	unsigned int strlen;
25841da177e4SLinus Torvalds 	char *str;
25851da177e4SLinus Torvalds 
2586c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 12);
2587c0eae66eSBenny Halevy 	if (likely(p))
25881da177e4SLinus Torvalds 		return decode_opaque_inline(xdr, &strlen, &str);
2589c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2590c0eae66eSBenny Halevy 	return -EIO;
25911da177e4SLinus Torvalds }
25921da177e4SLinus Torvalds 
25931da177e4SLinus Torvalds static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
25941da177e4SLinus Torvalds {
25958687b63aSAl Viro 	uint32_t bmlen;
25968687b63aSAl Viro 	__be32 *p;
25971da177e4SLinus Torvalds 
2598c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
2599c0eae66eSBenny Halevy 	if (unlikely(!p))
2600c0eae66eSBenny Halevy 		goto out_overflow;
2601cccddf4fSBenny Halevy 	bmlen = be32_to_cpup(p);
26021da177e4SLinus Torvalds 
26031da177e4SLinus Torvalds 	bitmap[0] = bitmap[1] = 0;
2604c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, (bmlen << 2));
2605c0eae66eSBenny Halevy 	if (unlikely(!p))
2606c0eae66eSBenny Halevy 		goto out_overflow;
26071da177e4SLinus Torvalds 	if (bmlen > 0) {
26086f723f77SBenny Halevy 		bitmap[0] = be32_to_cpup(p++);
26091da177e4SLinus Torvalds 		if (bmlen > 1)
2610cccddf4fSBenny Halevy 			bitmap[1] = be32_to_cpup(p);
26111da177e4SLinus Torvalds 	}
26121da177e4SLinus Torvalds 	return 0;
2613c0eae66eSBenny Halevy out_overflow:
2614c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2615c0eae66eSBenny Halevy 	return -EIO;
26161da177e4SLinus Torvalds }
26171da177e4SLinus Torvalds 
26188687b63aSAl Viro static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep)
26191da177e4SLinus Torvalds {
26208687b63aSAl Viro 	__be32 *p;
26211da177e4SLinus Torvalds 
2622c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
2623c0eae66eSBenny Halevy 	if (unlikely(!p))
2624c0eae66eSBenny Halevy 		goto out_overflow;
2625cccddf4fSBenny Halevy 	*attrlen = be32_to_cpup(p);
26261da177e4SLinus Torvalds 	*savep = xdr->p;
26271da177e4SLinus Torvalds 	return 0;
2628c0eae66eSBenny Halevy out_overflow:
2629c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2630c0eae66eSBenny Halevy 	return -EIO;
26311da177e4SLinus Torvalds }
26321da177e4SLinus Torvalds 
26331da177e4SLinus Torvalds static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask)
26341da177e4SLinus Torvalds {
26351da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_SUPPORTED_ATTRS)) {
26361da177e4SLinus Torvalds 		decode_attr_bitmap(xdr, bitmask);
26371da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS;
26381da177e4SLinus Torvalds 	} else
26391da177e4SLinus Torvalds 		bitmask[0] = bitmask[1] = 0;
264044109241SFred Isaman 	dprintk("%s: bitmask=%08x:%08x\n", __func__, bitmask[0], bitmask[1]);
26411da177e4SLinus Torvalds 	return 0;
26421da177e4SLinus Torvalds }
26431da177e4SLinus Torvalds 
26441da177e4SLinus Torvalds static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
26451da177e4SLinus Torvalds {
26468687b63aSAl Viro 	__be32 *p;
2647409924e4STrond Myklebust 	int ret = 0;
26481da177e4SLinus Torvalds 
26491da177e4SLinus Torvalds 	*type = 0;
26501da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
26511da177e4SLinus Torvalds 		return -EIO;
26521da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_TYPE)) {
2653c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
2654c0eae66eSBenny Halevy 		if (unlikely(!p))
2655c0eae66eSBenny Halevy 			goto out_overflow;
2656cccddf4fSBenny Halevy 		*type = be32_to_cpup(p);
26571da177e4SLinus Torvalds 		if (*type < NF4REG || *type > NF4NAMEDATTR) {
26583110ff80SHarvey Harrison 			dprintk("%s: bad type %d\n", __func__, *type);
26591da177e4SLinus Torvalds 			return -EIO;
26601da177e4SLinus Torvalds 		}
26611da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_TYPE;
2662409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_TYPE;
26631da177e4SLinus Torvalds 	}
2664bca79478STrond Myklebust 	dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type]);
2665409924e4STrond Myklebust 	return ret;
2666c0eae66eSBenny Halevy out_overflow:
2667c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2668c0eae66eSBenny Halevy 	return -EIO;
26691da177e4SLinus Torvalds }
26701da177e4SLinus Torvalds 
26711da177e4SLinus Torvalds static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
26721da177e4SLinus Torvalds {
26738687b63aSAl Viro 	__be32 *p;
2674409924e4STrond Myklebust 	int ret = 0;
26751da177e4SLinus Torvalds 
26761da177e4SLinus Torvalds 	*change = 0;
26771da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
26781da177e4SLinus Torvalds 		return -EIO;
26791da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) {
2680c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
2681c0eae66eSBenny Halevy 		if (unlikely(!p))
2682c0eae66eSBenny Halevy 			goto out_overflow;
2683cccddf4fSBenny Halevy 		xdr_decode_hyper(p, change);
26841da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_CHANGE;
2685409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_CHANGE;
26861da177e4SLinus Torvalds 	}
26873110ff80SHarvey Harrison 	dprintk("%s: change attribute=%Lu\n", __func__,
26881da177e4SLinus Torvalds 			(unsigned long long)*change);
2689409924e4STrond Myklebust 	return ret;
2690c0eae66eSBenny Halevy out_overflow:
2691c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2692c0eae66eSBenny Halevy 	return -EIO;
26931da177e4SLinus Torvalds }
26941da177e4SLinus Torvalds 
26951da177e4SLinus Torvalds static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
26961da177e4SLinus Torvalds {
26978687b63aSAl Viro 	__be32 *p;
2698409924e4STrond Myklebust 	int ret = 0;
26991da177e4SLinus Torvalds 
27001da177e4SLinus Torvalds 	*size = 0;
27011da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
27021da177e4SLinus Torvalds 		return -EIO;
27031da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) {
2704c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
2705c0eae66eSBenny Halevy 		if (unlikely(!p))
2706c0eae66eSBenny Halevy 			goto out_overflow;
2707cccddf4fSBenny Halevy 		xdr_decode_hyper(p, size);
27081da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_SIZE;
2709409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_SIZE;
27101da177e4SLinus Torvalds 	}
27113110ff80SHarvey Harrison 	dprintk("%s: file size=%Lu\n", __func__, (unsigned long long)*size);
2712409924e4STrond Myklebust 	return ret;
2713c0eae66eSBenny Halevy out_overflow:
2714c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2715c0eae66eSBenny Halevy 	return -EIO;
27161da177e4SLinus Torvalds }
27171da177e4SLinus Torvalds 
27181da177e4SLinus Torvalds static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
27191da177e4SLinus Torvalds {
27208687b63aSAl Viro 	__be32 *p;
27211da177e4SLinus Torvalds 
27221da177e4SLinus Torvalds 	*res = 0;
27231da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U)))
27241da177e4SLinus Torvalds 		return -EIO;
27251da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) {
2726c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
2727c0eae66eSBenny Halevy 		if (unlikely(!p))
2728c0eae66eSBenny Halevy 			goto out_overflow;
2729cccddf4fSBenny Halevy 		*res = be32_to_cpup(p);
27301da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT;
27311da177e4SLinus Torvalds 	}
27323110ff80SHarvey Harrison 	dprintk("%s: link support=%s\n", __func__, *res == 0 ? "false" : "true");
27331da177e4SLinus Torvalds 	return 0;
2734c0eae66eSBenny Halevy out_overflow:
2735c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2736c0eae66eSBenny Halevy 	return -EIO;
27371da177e4SLinus Torvalds }
27381da177e4SLinus Torvalds 
27391da177e4SLinus Torvalds static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
27401da177e4SLinus Torvalds {
27418687b63aSAl Viro 	__be32 *p;
27421da177e4SLinus Torvalds 
27431da177e4SLinus Torvalds 	*res = 0;
27441da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U)))
27451da177e4SLinus Torvalds 		return -EIO;
27461da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) {
2747c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
2748c0eae66eSBenny Halevy 		if (unlikely(!p))
2749c0eae66eSBenny Halevy 			goto out_overflow;
2750cccddf4fSBenny Halevy 		*res = be32_to_cpup(p);
27511da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT;
27521da177e4SLinus Torvalds 	}
27533110ff80SHarvey Harrison 	dprintk("%s: symlink support=%s\n", __func__, *res == 0 ? "false" : "true");
27541da177e4SLinus Torvalds 	return 0;
2755c0eae66eSBenny Halevy out_overflow:
2756c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2757c0eae66eSBenny Halevy 	return -EIO;
27581da177e4SLinus Torvalds }
27591da177e4SLinus Torvalds 
27608b4bdcf8STrond Myklebust static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
27611da177e4SLinus Torvalds {
27628687b63aSAl Viro 	__be32 *p;
2763409924e4STrond Myklebust 	int ret = 0;
27641da177e4SLinus Torvalds 
27651da177e4SLinus Torvalds 	fsid->major = 0;
27661da177e4SLinus Torvalds 	fsid->minor = 0;
27671da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_FSID - 1U)))
27681da177e4SLinus Torvalds 		return -EIO;
27691da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_FSID)) {
2770c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 16);
2771c0eae66eSBenny Halevy 		if (unlikely(!p))
2772c0eae66eSBenny Halevy 			goto out_overflow;
27733ceb4dbbSBenny Halevy 		p = xdr_decode_hyper(p, &fsid->major);
2774cccddf4fSBenny Halevy 		xdr_decode_hyper(p, &fsid->minor);
27751da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_FSID;
2776409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_FSID;
27771da177e4SLinus Torvalds 	}
27783110ff80SHarvey Harrison 	dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __func__,
27791da177e4SLinus Torvalds 			(unsigned long long)fsid->major,
27801da177e4SLinus Torvalds 			(unsigned long long)fsid->minor);
2781409924e4STrond Myklebust 	return ret;
2782c0eae66eSBenny Halevy out_overflow:
2783c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2784c0eae66eSBenny Halevy 	return -EIO;
27851da177e4SLinus Torvalds }
27861da177e4SLinus Torvalds 
27871da177e4SLinus Torvalds static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
27881da177e4SLinus Torvalds {
27898687b63aSAl Viro 	__be32 *p;
27901da177e4SLinus Torvalds 
27911da177e4SLinus Torvalds 	*res = 60;
27921da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U)))
27931da177e4SLinus Torvalds 		return -EIO;
27941da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) {
2795c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
2796c0eae66eSBenny Halevy 		if (unlikely(!p))
2797c0eae66eSBenny Halevy 			goto out_overflow;
2798cccddf4fSBenny Halevy 		*res = be32_to_cpup(p);
27991da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME;
28001da177e4SLinus Torvalds 	}
28013110ff80SHarvey Harrison 	dprintk("%s: file size=%u\n", __func__, (unsigned int)*res);
28021da177e4SLinus Torvalds 	return 0;
2803c0eae66eSBenny Halevy out_overflow:
2804c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2805c0eae66eSBenny Halevy 	return -EIO;
28061da177e4SLinus Torvalds }
28071da177e4SLinus Torvalds 
28081da177e4SLinus Torvalds static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
28091da177e4SLinus Torvalds {
28108687b63aSAl Viro 	__be32 *p;
28111da177e4SLinus Torvalds 
28121da177e4SLinus Torvalds 	*res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL;
28131da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
28141da177e4SLinus Torvalds 		return -EIO;
28151da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) {
2816c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
2817c0eae66eSBenny Halevy 		if (unlikely(!p))
2818c0eae66eSBenny Halevy 			goto out_overflow;
2819cccddf4fSBenny Halevy 		*res = be32_to_cpup(p);
28201da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT;
28211da177e4SLinus Torvalds 	}
28223110ff80SHarvey Harrison 	dprintk("%s: ACLs supported=%u\n", __func__, (unsigned int)*res);
28231da177e4SLinus Torvalds 	return 0;
2824c0eae66eSBenny Halevy out_overflow:
2825c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2826c0eae66eSBenny Halevy 	return -EIO;
28271da177e4SLinus Torvalds }
28281da177e4SLinus Torvalds 
28291da177e4SLinus Torvalds static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
28301da177e4SLinus Torvalds {
28318687b63aSAl Viro 	__be32 *p;
2832409924e4STrond Myklebust 	int ret = 0;
28331da177e4SLinus Torvalds 
28341da177e4SLinus Torvalds 	*fileid = 0;
28351da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
28361da177e4SLinus Torvalds 		return -EIO;
28371da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) {
2838c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
2839c0eae66eSBenny Halevy 		if (unlikely(!p))
2840c0eae66eSBenny Halevy 			goto out_overflow;
2841cccddf4fSBenny Halevy 		xdr_decode_hyper(p, fileid);
28421da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_FILEID;
2843409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_FILEID;
28441da177e4SLinus Torvalds 	}
28453110ff80SHarvey Harrison 	dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
2846409924e4STrond Myklebust 	return ret;
2847c0eae66eSBenny Halevy out_overflow:
2848c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2849c0eae66eSBenny Halevy 	return -EIO;
28501da177e4SLinus Torvalds }
28511da177e4SLinus Torvalds 
285299baf625SManoj Naik static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
285399baf625SManoj Naik {
28548687b63aSAl Viro 	__be32 *p;
2855409924e4STrond Myklebust 	int ret = 0;
285699baf625SManoj Naik 
285799baf625SManoj Naik 	*fileid = 0;
285899baf625SManoj Naik 	if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
285999baf625SManoj Naik 		return -EIO;
286099baf625SManoj Naik 	if (likely(bitmap[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) {
2861c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
2862c0eae66eSBenny Halevy 		if (unlikely(!p))
2863c0eae66eSBenny Halevy 			goto out_overflow;
2864cccddf4fSBenny Halevy 		xdr_decode_hyper(p, fileid);
286599baf625SManoj Naik 		bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
2866409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_FILEID;
286799baf625SManoj Naik 	}
28683110ff80SHarvey Harrison 	dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
2869409924e4STrond Myklebust 	return ret;
2870c0eae66eSBenny Halevy out_overflow:
2871c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2872c0eae66eSBenny Halevy 	return -EIO;
287399baf625SManoj Naik }
287499baf625SManoj Naik 
28751da177e4SLinus Torvalds static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
28761da177e4SLinus Torvalds {
28778687b63aSAl Viro 	__be32 *p;
28781da177e4SLinus Torvalds 	int status = 0;
28791da177e4SLinus Torvalds 
28801da177e4SLinus Torvalds 	*res = 0;
28811da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_AVAIL - 1U)))
28821da177e4SLinus Torvalds 		return -EIO;
28831da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_FILES_AVAIL)) {
2884c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
2885c0eae66eSBenny Halevy 		if (unlikely(!p))
2886c0eae66eSBenny Halevy 			goto out_overflow;
2887cccddf4fSBenny Halevy 		xdr_decode_hyper(p, res);
28881da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL;
28891da177e4SLinus Torvalds 	}
28903110ff80SHarvey Harrison 	dprintk("%s: files avail=%Lu\n", __func__, (unsigned long long)*res);
28911da177e4SLinus Torvalds 	return status;
2892c0eae66eSBenny Halevy out_overflow:
2893c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2894c0eae66eSBenny Halevy 	return -EIO;
28951da177e4SLinus Torvalds }
28961da177e4SLinus Torvalds 
28971da177e4SLinus Torvalds static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
28981da177e4SLinus Torvalds {
28998687b63aSAl Viro 	__be32 *p;
29001da177e4SLinus Torvalds 	int status = 0;
29011da177e4SLinus Torvalds 
29021da177e4SLinus Torvalds 	*res = 0;
29031da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_FREE - 1U)))
29041da177e4SLinus Torvalds 		return -EIO;
29051da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_FILES_FREE)) {
2906c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
2907c0eae66eSBenny Halevy 		if (unlikely(!p))
2908c0eae66eSBenny Halevy 			goto out_overflow;
2909cccddf4fSBenny Halevy 		xdr_decode_hyper(p, res);
29101da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_FILES_FREE;
29111da177e4SLinus Torvalds 	}
29123110ff80SHarvey Harrison 	dprintk("%s: files free=%Lu\n", __func__, (unsigned long long)*res);
29131da177e4SLinus Torvalds 	return status;
2914c0eae66eSBenny Halevy out_overflow:
2915c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2916c0eae66eSBenny Halevy 	return -EIO;
29171da177e4SLinus Torvalds }
29181da177e4SLinus Torvalds 
29191da177e4SLinus Torvalds static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
29201da177e4SLinus Torvalds {
29218687b63aSAl Viro 	__be32 *p;
29221da177e4SLinus Torvalds 	int status = 0;
29231da177e4SLinus Torvalds 
29241da177e4SLinus Torvalds 	*res = 0;
29251da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_TOTAL - 1U)))
29261da177e4SLinus Torvalds 		return -EIO;
29271da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_FILES_TOTAL)) {
2928c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
2929c0eae66eSBenny Halevy 		if (unlikely(!p))
2930c0eae66eSBenny Halevy 			goto out_overflow;
2931cccddf4fSBenny Halevy 		xdr_decode_hyper(p, res);
29321da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL;
29331da177e4SLinus Torvalds 	}
29343110ff80SHarvey Harrison 	dprintk("%s: files total=%Lu\n", __func__, (unsigned long long)*res);
29351da177e4SLinus Torvalds 	return status;
2936c0eae66eSBenny Halevy out_overflow:
2937c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2938c0eae66eSBenny Halevy 	return -EIO;
29391da177e4SLinus Torvalds }
29401da177e4SLinus Torvalds 
29417aaa0b3bSManoj Naik static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
29427aaa0b3bSManoj Naik {
2943464ad6b1SChuck Lever 	u32 n;
29448687b63aSAl Viro 	__be32 *p;
29457aaa0b3bSManoj Naik 	int status = 0;
29467aaa0b3bSManoj Naik 
2947c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
2948c0eae66eSBenny Halevy 	if (unlikely(!p))
2949c0eae66eSBenny Halevy 		goto out_overflow;
2950cccddf4fSBenny Halevy 	n = be32_to_cpup(p);
295133a43f28SAndy Adamson 	if (n == 0)
295233a43f28SAndy Adamson 		goto root_path;
29537aaa0b3bSManoj Naik 	dprintk("path ");
29547aaa0b3bSManoj Naik 	path->ncomponents = 0;
29557aaa0b3bSManoj Naik 	while (path->ncomponents < n) {
29567aaa0b3bSManoj Naik 		struct nfs4_string *component = &path->components[path->ncomponents];
29577aaa0b3bSManoj Naik 		status = decode_opaque_inline(xdr, &component->len, &component->data);
29587aaa0b3bSManoj Naik 		if (unlikely(status != 0))
29597aaa0b3bSManoj Naik 			goto out_eio;
29607aaa0b3bSManoj Naik 		if (path->ncomponents != n)
29617aaa0b3bSManoj Naik 			dprintk("/");
29627aaa0b3bSManoj Naik 		dprintk("%s", component->data);
29637aaa0b3bSManoj Naik 		if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS)
29647aaa0b3bSManoj Naik 			path->ncomponents++;
29657aaa0b3bSManoj Naik 		else {
29667aaa0b3bSManoj Naik 			dprintk("cannot parse %d components in path\n", n);
29677aaa0b3bSManoj Naik 			goto out_eio;
29687aaa0b3bSManoj Naik 		}
29697aaa0b3bSManoj Naik 	}
29707aaa0b3bSManoj Naik out:
29717aaa0b3bSManoj Naik 	dprintk("\n");
29727aaa0b3bSManoj Naik 	return status;
297333a43f28SAndy Adamson root_path:
297433a43f28SAndy Adamson /* a root pathname is sent as a zero component4 */
297533a43f28SAndy Adamson 	path->ncomponents = 1;
297633a43f28SAndy Adamson 	path->components[0].len=0;
297733a43f28SAndy Adamson 	path->components[0].data=NULL;
297833a43f28SAndy Adamson 	dprintk("path /\n");
297933a43f28SAndy Adamson 	goto out;
29807aaa0b3bSManoj Naik out_eio:
29817aaa0b3bSManoj Naik 	dprintk(" status %d", status);
29827aaa0b3bSManoj Naik 	status = -EIO;
29837aaa0b3bSManoj Naik 	goto out;
2984c0eae66eSBenny Halevy out_overflow:
2985c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
2986c0eae66eSBenny Halevy 	return -EIO;
29877aaa0b3bSManoj Naik }
29887aaa0b3bSManoj Naik 
29897aaa0b3bSManoj Naik static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res)
2990683b57b4STrond Myklebust {
2991683b57b4STrond Myklebust 	int n;
29928687b63aSAl Viro 	__be32 *p;
2993683b57b4STrond Myklebust 	int status = -EIO;
2994683b57b4STrond Myklebust 
2995683b57b4STrond Myklebust 	if (unlikely(bitmap[0] & (FATTR4_WORD0_FS_LOCATIONS -1U)))
2996683b57b4STrond Myklebust 		goto out;
2997683b57b4STrond Myklebust 	status = 0;
2998683b57b4STrond Myklebust 	if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
2999683b57b4STrond Myklebust 		goto out;
30003110ff80SHarvey Harrison 	dprintk("%s: fsroot ", __func__);
30017aaa0b3bSManoj Naik 	status = decode_pathname(xdr, &res->fs_path);
3002683b57b4STrond Myklebust 	if (unlikely(status != 0))
3003683b57b4STrond Myklebust 		goto out;
3004c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
3005c0eae66eSBenny Halevy 	if (unlikely(!p))
3006c0eae66eSBenny Halevy 		goto out_overflow;
3007cccddf4fSBenny Halevy 	n = be32_to_cpup(p);
3008683b57b4STrond Myklebust 	if (n <= 0)
3009683b57b4STrond Myklebust 		goto out_eio;
3010683b57b4STrond Myklebust 	res->nlocations = 0;
3011683b57b4STrond Myklebust 	while (res->nlocations < n) {
3012464ad6b1SChuck Lever 		u32 m;
30137aaa0b3bSManoj Naik 		struct nfs4_fs_location *loc = &res->locations[res->nlocations];
3014683b57b4STrond Myklebust 
3015c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
3016c0eae66eSBenny Halevy 		if (unlikely(!p))
3017c0eae66eSBenny Halevy 			goto out_overflow;
3018cccddf4fSBenny Halevy 		m = be32_to_cpup(p);
30197aaa0b3bSManoj Naik 
30207aaa0b3bSManoj Naik 		loc->nservers = 0;
30213110ff80SHarvey Harrison 		dprintk("%s: servers ", __func__);
30227aaa0b3bSManoj Naik 		while (loc->nservers < m) {
30237aaa0b3bSManoj Naik 			struct nfs4_string *server = &loc->servers[loc->nservers];
30247aaa0b3bSManoj Naik 			status = decode_opaque_inline(xdr, &server->len, &server->data);
3025683b57b4STrond Myklebust 			if (unlikely(status != 0))
3026683b57b4STrond Myklebust 				goto out_eio;
30277aaa0b3bSManoj Naik 			dprintk("%s ", server->data);
30287aaa0b3bSManoj Naik 			if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS)
30297aaa0b3bSManoj Naik 				loc->nservers++;
30307aaa0b3bSManoj Naik 			else {
3031464ad6b1SChuck Lever 				unsigned int i;
3032464ad6b1SChuck Lever 				dprintk("%s: using first %u of %u servers "
3033464ad6b1SChuck Lever 					"returned for location %u\n",
30343110ff80SHarvey Harrison 						__func__,
3035464ad6b1SChuck Lever 						NFS4_FS_LOCATION_MAXSERVERS,
3036464ad6b1SChuck Lever 						m, res->nlocations);
30377aaa0b3bSManoj Naik 				for (i = loc->nservers; i < m; i++) {
30382e42c3e2STrond Myklebust 					unsigned int len;
30397aaa0b3bSManoj Naik 					char *data;
30407aaa0b3bSManoj Naik 					status = decode_opaque_inline(xdr, &len, &data);
3041683b57b4STrond Myklebust 					if (unlikely(status != 0))
3042683b57b4STrond Myklebust 						goto out_eio;
30437aaa0b3bSManoj Naik 				}
30447aaa0b3bSManoj Naik 			}
30457aaa0b3bSManoj Naik 		}
30467aaa0b3bSManoj Naik 		status = decode_pathname(xdr, &loc->rootpath);
30477aaa0b3bSManoj Naik 		if (unlikely(status != 0))
30487aaa0b3bSManoj Naik 			goto out_eio;
30497aaa0b3bSManoj Naik 		if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
3050683b57b4STrond Myklebust 			res->nlocations++;
3051683b57b4STrond Myklebust 	}
3052409924e4STrond Myklebust 	if (res->nlocations != 0)
3053409924e4STrond Myklebust 		status = NFS_ATTR_FATTR_V4_REFERRAL;
3054683b57b4STrond Myklebust out:
30553110ff80SHarvey Harrison 	dprintk("%s: fs_locations done, error = %d\n", __func__, status);
3056683b57b4STrond Myklebust 	return status;
3057c0eae66eSBenny Halevy out_overflow:
3058c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3059683b57b4STrond Myklebust out_eio:
3060683b57b4STrond Myklebust 	status = -EIO;
3061683b57b4STrond Myklebust 	goto out;
3062683b57b4STrond Myklebust }
3063683b57b4STrond Myklebust 
30641da177e4SLinus Torvalds static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
30651da177e4SLinus Torvalds {
30668687b63aSAl Viro 	__be32 *p;
30671da177e4SLinus Torvalds 	int status = 0;
30681da177e4SLinus Torvalds 
30691da177e4SLinus Torvalds 	*res = 0;
30701da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXFILESIZE - 1U)))
30711da177e4SLinus Torvalds 		return -EIO;
30721da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_MAXFILESIZE)) {
3073c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
3074c0eae66eSBenny Halevy 		if (unlikely(!p))
3075c0eae66eSBenny Halevy 			goto out_overflow;
3076cccddf4fSBenny Halevy 		xdr_decode_hyper(p, res);
30771da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE;
30781da177e4SLinus Torvalds 	}
30793110ff80SHarvey Harrison 	dprintk("%s: maxfilesize=%Lu\n", __func__, (unsigned long long)*res);
30801da177e4SLinus Torvalds 	return status;
3081c0eae66eSBenny Halevy out_overflow:
3082c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3083c0eae66eSBenny Halevy 	return -EIO;
30841da177e4SLinus Torvalds }
30851da177e4SLinus Torvalds 
30861da177e4SLinus Torvalds static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink)
30871da177e4SLinus Torvalds {
30888687b63aSAl Viro 	__be32 *p;
30891da177e4SLinus Torvalds 	int status = 0;
30901da177e4SLinus Torvalds 
30911da177e4SLinus Torvalds 	*maxlink = 1;
30921da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXLINK - 1U)))
30931da177e4SLinus Torvalds 		return -EIO;
30941da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_MAXLINK)) {
3095c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
3096c0eae66eSBenny Halevy 		if (unlikely(!p))
3097c0eae66eSBenny Halevy 			goto out_overflow;
3098cccddf4fSBenny Halevy 		*maxlink = be32_to_cpup(p);
30991da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_MAXLINK;
31001da177e4SLinus Torvalds 	}
31013110ff80SHarvey Harrison 	dprintk("%s: maxlink=%u\n", __func__, *maxlink);
31021da177e4SLinus Torvalds 	return status;
3103c0eae66eSBenny Halevy out_overflow:
3104c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3105c0eae66eSBenny Halevy 	return -EIO;
31061da177e4SLinus Torvalds }
31071da177e4SLinus Torvalds 
31081da177e4SLinus Torvalds static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname)
31091da177e4SLinus Torvalds {
31108687b63aSAl Viro 	__be32 *p;
31111da177e4SLinus Torvalds 	int status = 0;
31121da177e4SLinus Torvalds 
31131da177e4SLinus Torvalds 	*maxname = 1024;
31141da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXNAME - 1U)))
31151da177e4SLinus Torvalds 		return -EIO;
31161da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_MAXNAME)) {
3117c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
3118c0eae66eSBenny Halevy 		if (unlikely(!p))
3119c0eae66eSBenny Halevy 			goto out_overflow;
3120cccddf4fSBenny Halevy 		*maxname = be32_to_cpup(p);
31211da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_MAXNAME;
31221da177e4SLinus Torvalds 	}
31233110ff80SHarvey Harrison 	dprintk("%s: maxname=%u\n", __func__, *maxname);
31241da177e4SLinus Torvalds 	return status;
3125c0eae66eSBenny Halevy out_overflow:
3126c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3127c0eae66eSBenny Halevy 	return -EIO;
31281da177e4SLinus Torvalds }
31291da177e4SLinus Torvalds 
31301da177e4SLinus Torvalds static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
31311da177e4SLinus Torvalds {
31328687b63aSAl Viro 	__be32 *p;
31331da177e4SLinus Torvalds 	int status = 0;
31341da177e4SLinus Torvalds 
31351da177e4SLinus Torvalds 	*res = 1024;
31361da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXREAD - 1U)))
31371da177e4SLinus Torvalds 		return -EIO;
31381da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_MAXREAD)) {
31391da177e4SLinus Torvalds 		uint64_t maxread;
3140c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
3141c0eae66eSBenny Halevy 		if (unlikely(!p))
3142c0eae66eSBenny Halevy 			goto out_overflow;
3143cccddf4fSBenny Halevy 		xdr_decode_hyper(p, &maxread);
31441da177e4SLinus Torvalds 		if (maxread > 0x7FFFFFFF)
31451da177e4SLinus Torvalds 			maxread = 0x7FFFFFFF;
31461da177e4SLinus Torvalds 		*res = (uint32_t)maxread;
31471da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_MAXREAD;
31481da177e4SLinus Torvalds 	}
31493110ff80SHarvey Harrison 	dprintk("%s: maxread=%lu\n", __func__, (unsigned long)*res);
31501da177e4SLinus Torvalds 	return status;
3151c0eae66eSBenny Halevy out_overflow:
3152c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3153c0eae66eSBenny Halevy 	return -EIO;
31541da177e4SLinus Torvalds }
31551da177e4SLinus Torvalds 
31561da177e4SLinus Torvalds static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
31571da177e4SLinus Torvalds {
31588687b63aSAl Viro 	__be32 *p;
31591da177e4SLinus Torvalds 	int status = 0;
31601da177e4SLinus Torvalds 
31611da177e4SLinus Torvalds 	*res = 1024;
31621da177e4SLinus Torvalds 	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXWRITE - 1U)))
31631da177e4SLinus Torvalds 		return -EIO;
31641da177e4SLinus Torvalds 	if (likely(bitmap[0] & FATTR4_WORD0_MAXWRITE)) {
31651da177e4SLinus Torvalds 		uint64_t maxwrite;
3166c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
3167c0eae66eSBenny Halevy 		if (unlikely(!p))
3168c0eae66eSBenny Halevy 			goto out_overflow;
3169cccddf4fSBenny Halevy 		xdr_decode_hyper(p, &maxwrite);
31701da177e4SLinus Torvalds 		if (maxwrite > 0x7FFFFFFF)
31711da177e4SLinus Torvalds 			maxwrite = 0x7FFFFFFF;
31721da177e4SLinus Torvalds 		*res = (uint32_t)maxwrite;
31731da177e4SLinus Torvalds 		bitmap[0] &= ~FATTR4_WORD0_MAXWRITE;
31741da177e4SLinus Torvalds 	}
31753110ff80SHarvey Harrison 	dprintk("%s: maxwrite=%lu\n", __func__, (unsigned long)*res);
31761da177e4SLinus Torvalds 	return status;
3177c0eae66eSBenny Halevy out_overflow:
3178c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3179c0eae66eSBenny Halevy 	return -EIO;
31801da177e4SLinus Torvalds }
31811da177e4SLinus Torvalds 
3182bca79478STrond Myklebust static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *mode)
31831da177e4SLinus Torvalds {
3184bca79478STrond Myklebust 	uint32_t tmp;
31858687b63aSAl Viro 	__be32 *p;
3186409924e4STrond Myklebust 	int ret = 0;
31871da177e4SLinus Torvalds 
31881da177e4SLinus Torvalds 	*mode = 0;
31891da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
31901da177e4SLinus Torvalds 		return -EIO;
31911da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_MODE)) {
3192c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
3193c0eae66eSBenny Halevy 		if (unlikely(!p))
3194c0eae66eSBenny Halevy 			goto out_overflow;
3195cccddf4fSBenny Halevy 		tmp = be32_to_cpup(p);
3196bca79478STrond Myklebust 		*mode = tmp & ~S_IFMT;
31971da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_MODE;
3198409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_MODE;
31991da177e4SLinus Torvalds 	}
32003110ff80SHarvey Harrison 	dprintk("%s: file mode=0%o\n", __func__, (unsigned int)*mode);
3201409924e4STrond Myklebust 	return ret;
3202c0eae66eSBenny Halevy out_overflow:
3203c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3204c0eae66eSBenny Halevy 	return -EIO;
32051da177e4SLinus Torvalds }
32061da177e4SLinus Torvalds 
32071da177e4SLinus Torvalds static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
32081da177e4SLinus Torvalds {
32098687b63aSAl Viro 	__be32 *p;
3210409924e4STrond Myklebust 	int ret = 0;
32111da177e4SLinus Torvalds 
32121da177e4SLinus Torvalds 	*nlink = 1;
32131da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
32141da177e4SLinus Torvalds 		return -EIO;
32151da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) {
3216c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
3217c0eae66eSBenny Halevy 		if (unlikely(!p))
3218c0eae66eSBenny Halevy 			goto out_overflow;
3219cccddf4fSBenny Halevy 		*nlink = be32_to_cpup(p);
32201da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_NUMLINKS;
3221409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_NLINK;
32221da177e4SLinus Torvalds 	}
32233110ff80SHarvey Harrison 	dprintk("%s: nlink=%u\n", __func__, (unsigned int)*nlink);
3224409924e4STrond Myklebust 	return ret;
3225c0eae66eSBenny Halevy out_overflow:
3226c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3227c0eae66eSBenny Halevy 	return -EIO;
32281da177e4SLinus Torvalds }
32291da177e4SLinus Torvalds 
323080e52aceSTrond Myklebust static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap,
323180e52aceSTrond Myklebust 		struct nfs_client *clp, uint32_t *uid, int may_sleep)
32321da177e4SLinus Torvalds {
32338687b63aSAl Viro 	uint32_t len;
32348687b63aSAl Viro 	__be32 *p;
3235409924e4STrond Myklebust 	int ret = 0;
32361da177e4SLinus Torvalds 
32371da177e4SLinus Torvalds 	*uid = -2;
32381da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
32391da177e4SLinus Torvalds 		return -EIO;
32401da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) {
3241c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
3242c0eae66eSBenny Halevy 		if (unlikely(!p))
3243c0eae66eSBenny Halevy 			goto out_overflow;
3244cccddf4fSBenny Halevy 		len = be32_to_cpup(p);
3245c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, len);
3246c0eae66eSBenny Halevy 		if (unlikely(!p))
3247c0eae66eSBenny Halevy 			goto out_overflow;
324880e52aceSTrond Myklebust 		if (!may_sleep) {
324980e52aceSTrond Myklebust 			/* do nothing */
325080e52aceSTrond Myklebust 		} else if (len < XDR_MAX_NETOBJ) {
3251409924e4STrond Myklebust 			if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0)
3252409924e4STrond Myklebust 				ret = NFS_ATTR_FATTR_OWNER;
3253409924e4STrond Myklebust 			else
32541da177e4SLinus Torvalds 				dprintk("%s: nfs_map_name_to_uid failed!\n",
32553110ff80SHarvey Harrison 						__func__);
32561da177e4SLinus Torvalds 		} else
3257fe82a183SChuck Lever 			dprintk("%s: name too long (%u)!\n",
32583110ff80SHarvey Harrison 					__func__, len);
32591da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_OWNER;
32601da177e4SLinus Torvalds 	}
32613110ff80SHarvey Harrison 	dprintk("%s: uid=%d\n", __func__, (int)*uid);
3262409924e4STrond Myklebust 	return ret;
3263c0eae66eSBenny Halevy out_overflow:
3264c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3265c0eae66eSBenny Halevy 	return -EIO;
32661da177e4SLinus Torvalds }
32671da177e4SLinus Torvalds 
326880e52aceSTrond Myklebust static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap,
326980e52aceSTrond Myklebust 		struct nfs_client *clp, uint32_t *gid, int may_sleep)
32701da177e4SLinus Torvalds {
32718687b63aSAl Viro 	uint32_t len;
32728687b63aSAl Viro 	__be32 *p;
3273409924e4STrond Myklebust 	int ret = 0;
32741da177e4SLinus Torvalds 
32751da177e4SLinus Torvalds 	*gid = -2;
32761da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
32771da177e4SLinus Torvalds 		return -EIO;
32781da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) {
3279c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
3280c0eae66eSBenny Halevy 		if (unlikely(!p))
3281c0eae66eSBenny Halevy 			goto out_overflow;
3282cccddf4fSBenny Halevy 		len = be32_to_cpup(p);
3283c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, len);
3284c0eae66eSBenny Halevy 		if (unlikely(!p))
3285c0eae66eSBenny Halevy 			goto out_overflow;
328680e52aceSTrond Myklebust 		if (!may_sleep) {
328780e52aceSTrond Myklebust 			/* do nothing */
328880e52aceSTrond Myklebust 		} else if (len < XDR_MAX_NETOBJ) {
3289409924e4STrond Myklebust 			if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0)
3290409924e4STrond Myklebust 				ret = NFS_ATTR_FATTR_GROUP;
3291409924e4STrond Myklebust 			else
32921da177e4SLinus Torvalds 				dprintk("%s: nfs_map_group_to_gid failed!\n",
32933110ff80SHarvey Harrison 						__func__);
32941da177e4SLinus Torvalds 		} else
3295fe82a183SChuck Lever 			dprintk("%s: name too long (%u)!\n",
32963110ff80SHarvey Harrison 					__func__, len);
32971da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
32981da177e4SLinus Torvalds 	}
32993110ff80SHarvey Harrison 	dprintk("%s: gid=%d\n", __func__, (int)*gid);
3300409924e4STrond Myklebust 	return ret;
3301c0eae66eSBenny Halevy out_overflow:
3302c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3303c0eae66eSBenny Halevy 	return -EIO;
33041da177e4SLinus Torvalds }
33051da177e4SLinus Torvalds 
33061da177e4SLinus Torvalds static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
33071da177e4SLinus Torvalds {
33088687b63aSAl Viro 	uint32_t major = 0, minor = 0;
33098687b63aSAl Viro 	__be32 *p;
3310409924e4STrond Myklebust 	int ret = 0;
33111da177e4SLinus Torvalds 
33121da177e4SLinus Torvalds 	*rdev = MKDEV(0,0);
33131da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U)))
33141da177e4SLinus Torvalds 		return -EIO;
33151da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_RAWDEV)) {
33161da177e4SLinus Torvalds 		dev_t tmp;
33171da177e4SLinus Torvalds 
3318c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
3319c0eae66eSBenny Halevy 		if (unlikely(!p))
3320c0eae66eSBenny Halevy 			goto out_overflow;
33216f723f77SBenny Halevy 		major = be32_to_cpup(p++);
3322cccddf4fSBenny Halevy 		minor = be32_to_cpup(p);
33231da177e4SLinus Torvalds 		tmp = MKDEV(major, minor);
33241da177e4SLinus Torvalds 		if (MAJOR(tmp) == major && MINOR(tmp) == minor)
33251da177e4SLinus Torvalds 			*rdev = tmp;
33261da177e4SLinus Torvalds 		bitmap[1] &= ~ FATTR4_WORD1_RAWDEV;
3327409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_RDEV;
33281da177e4SLinus Torvalds 	}
33293110ff80SHarvey Harrison 	dprintk("%s: rdev=(0x%x:0x%x)\n", __func__, major, minor);
3330409924e4STrond Myklebust 	return ret;
3331c0eae66eSBenny Halevy out_overflow:
3332c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3333c0eae66eSBenny Halevy 	return -EIO;
33341da177e4SLinus Torvalds }
33351da177e4SLinus Torvalds 
33361da177e4SLinus Torvalds static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
33371da177e4SLinus Torvalds {
33388687b63aSAl Viro 	__be32 *p;
33391da177e4SLinus Torvalds 	int status = 0;
33401da177e4SLinus Torvalds 
33411da177e4SLinus Torvalds 	*res = 0;
33421da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_AVAIL - 1U)))
33431da177e4SLinus Torvalds 		return -EIO;
33441da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_AVAIL)) {
3345c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
3346c0eae66eSBenny Halevy 		if (unlikely(!p))
3347c0eae66eSBenny Halevy 			goto out_overflow;
3348cccddf4fSBenny Halevy 		xdr_decode_hyper(p, res);
33491da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL;
33501da177e4SLinus Torvalds 	}
33513110ff80SHarvey Harrison 	dprintk("%s: space avail=%Lu\n", __func__, (unsigned long long)*res);
33521da177e4SLinus Torvalds 	return status;
3353c0eae66eSBenny Halevy out_overflow:
3354c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3355c0eae66eSBenny Halevy 	return -EIO;
33561da177e4SLinus Torvalds }
33571da177e4SLinus Torvalds 
33581da177e4SLinus Torvalds static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
33591da177e4SLinus Torvalds {
33608687b63aSAl Viro 	__be32 *p;
33611da177e4SLinus Torvalds 	int status = 0;
33621da177e4SLinus Torvalds 
33631da177e4SLinus Torvalds 	*res = 0;
33641da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_FREE - 1U)))
33651da177e4SLinus Torvalds 		return -EIO;
33661da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_FREE)) {
3367c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
3368c0eae66eSBenny Halevy 		if (unlikely(!p))
3369c0eae66eSBenny Halevy 			goto out_overflow;
3370cccddf4fSBenny Halevy 		xdr_decode_hyper(p, res);
33711da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE;
33721da177e4SLinus Torvalds 	}
33733110ff80SHarvey Harrison 	dprintk("%s: space free=%Lu\n", __func__, (unsigned long long)*res);
33741da177e4SLinus Torvalds 	return status;
3375c0eae66eSBenny Halevy out_overflow:
3376c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3377c0eae66eSBenny Halevy 	return -EIO;
33781da177e4SLinus Torvalds }
33791da177e4SLinus Torvalds 
33801da177e4SLinus Torvalds static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
33811da177e4SLinus Torvalds {
33828687b63aSAl Viro 	__be32 *p;
33831da177e4SLinus Torvalds 	int status = 0;
33841da177e4SLinus Torvalds 
33851da177e4SLinus Torvalds 	*res = 0;
33861da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_TOTAL - 1U)))
33871da177e4SLinus Torvalds 		return -EIO;
33881da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_TOTAL)) {
3389c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
3390c0eae66eSBenny Halevy 		if (unlikely(!p))
3391c0eae66eSBenny Halevy 			goto out_overflow;
3392cccddf4fSBenny Halevy 		xdr_decode_hyper(p, res);
33931da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL;
33941da177e4SLinus Torvalds 	}
33953110ff80SHarvey Harrison 	dprintk("%s: space total=%Lu\n", __func__, (unsigned long long)*res);
33961da177e4SLinus Torvalds 	return status;
3397c0eae66eSBenny Halevy out_overflow:
3398c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3399c0eae66eSBenny Halevy 	return -EIO;
34001da177e4SLinus Torvalds }
34011da177e4SLinus Torvalds 
34021da177e4SLinus Torvalds static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
34031da177e4SLinus Torvalds {
34048687b63aSAl Viro 	__be32 *p;
3405409924e4STrond Myklebust 	int ret = 0;
34061da177e4SLinus Torvalds 
34071da177e4SLinus Torvalds 	*used = 0;
34081da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
34091da177e4SLinus Torvalds 		return -EIO;
34101da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) {
3411c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8);
3412c0eae66eSBenny Halevy 		if (unlikely(!p))
3413c0eae66eSBenny Halevy 			goto out_overflow;
3414cccddf4fSBenny Halevy 		xdr_decode_hyper(p, used);
34151da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_SPACE_USED;
3416409924e4STrond Myklebust 		ret = NFS_ATTR_FATTR_SPACE_USED;
34171da177e4SLinus Torvalds 	}
34183110ff80SHarvey Harrison 	dprintk("%s: space used=%Lu\n", __func__,
34191da177e4SLinus Torvalds 			(unsigned long long)*used);
3420409924e4STrond Myklebust 	return ret;
3421c0eae66eSBenny Halevy out_overflow:
3422c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3423c0eae66eSBenny Halevy 	return -EIO;
34241da177e4SLinus Torvalds }
34251da177e4SLinus Torvalds 
34261da177e4SLinus Torvalds static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
34271da177e4SLinus Torvalds {
34288687b63aSAl Viro 	__be32 *p;
34291da177e4SLinus Torvalds 	uint64_t sec;
34301da177e4SLinus Torvalds 	uint32_t nsec;
34311da177e4SLinus Torvalds 
3432c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 12);
3433c0eae66eSBenny Halevy 	if (unlikely(!p))
3434c0eae66eSBenny Halevy 		goto out_overflow;
34353ceb4dbbSBenny Halevy 	p = xdr_decode_hyper(p, &sec);
3436cccddf4fSBenny Halevy 	nsec = be32_to_cpup(p);
34371da177e4SLinus Torvalds 	time->tv_sec = (time_t)sec;
34381da177e4SLinus Torvalds 	time->tv_nsec = (long)nsec;
34391da177e4SLinus Torvalds 	return 0;
3440c0eae66eSBenny Halevy out_overflow:
3441c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3442c0eae66eSBenny Halevy 	return -EIO;
34431da177e4SLinus Torvalds }
34441da177e4SLinus Torvalds 
34451da177e4SLinus Torvalds static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
34461da177e4SLinus Torvalds {
34471da177e4SLinus Torvalds 	int status = 0;
34481da177e4SLinus Torvalds 
34491da177e4SLinus Torvalds 	time->tv_sec = 0;
34501da177e4SLinus Torvalds 	time->tv_nsec = 0;
34511da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_ACCESS - 1U)))
34521da177e4SLinus Torvalds 		return -EIO;
34531da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_TIME_ACCESS)) {
34541da177e4SLinus Torvalds 		status = decode_attr_time(xdr, time);
3455409924e4STrond Myklebust 		if (status == 0)
3456409924e4STrond Myklebust 			status = NFS_ATTR_FATTR_ATIME;
34571da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS;
34581da177e4SLinus Torvalds 	}
34593110ff80SHarvey Harrison 	dprintk("%s: atime=%ld\n", __func__, (long)time->tv_sec);
34601da177e4SLinus Torvalds 	return status;
34611da177e4SLinus Torvalds }
34621da177e4SLinus Torvalds 
34631da177e4SLinus Torvalds static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
34641da177e4SLinus Torvalds {
34651da177e4SLinus Torvalds 	int status = 0;
34661da177e4SLinus Torvalds 
34671da177e4SLinus Torvalds 	time->tv_sec = 0;
34681da177e4SLinus Torvalds 	time->tv_nsec = 0;
34691da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_METADATA - 1U)))
34701da177e4SLinus Torvalds 		return -EIO;
34711da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) {
34721da177e4SLinus Torvalds 		status = decode_attr_time(xdr, time);
3473409924e4STrond Myklebust 		if (status == 0)
3474409924e4STrond Myklebust 			status = NFS_ATTR_FATTR_CTIME;
34751da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
34761da177e4SLinus Torvalds 	}
34773110ff80SHarvey Harrison 	dprintk("%s: ctime=%ld\n", __func__, (long)time->tv_sec);
34781da177e4SLinus Torvalds 	return status;
34791da177e4SLinus Torvalds }
34801da177e4SLinus Torvalds 
34811da177e4SLinus Torvalds static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
34821da177e4SLinus Torvalds {
34831da177e4SLinus Torvalds 	int status = 0;
34841da177e4SLinus Torvalds 
34851da177e4SLinus Torvalds 	time->tv_sec = 0;
34861da177e4SLinus Torvalds 	time->tv_nsec = 0;
34871da177e4SLinus Torvalds 	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_MODIFY - 1U)))
34881da177e4SLinus Torvalds 		return -EIO;
34891da177e4SLinus Torvalds 	if (likely(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) {
34901da177e4SLinus Torvalds 		status = decode_attr_time(xdr, time);
3491409924e4STrond Myklebust 		if (status == 0)
3492409924e4STrond Myklebust 			status = NFS_ATTR_FATTR_MTIME;
34931da177e4SLinus Torvalds 		bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
34941da177e4SLinus Torvalds 	}
34953110ff80SHarvey Harrison 	dprintk("%s: mtime=%ld\n", __func__, (long)time->tv_sec);
34961da177e4SLinus Torvalds 	return status;
34971da177e4SLinus Torvalds }
34981da177e4SLinus Torvalds 
34998687b63aSAl Viro static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
35001da177e4SLinus Torvalds {
35011da177e4SLinus Torvalds 	unsigned int attrwords = XDR_QUADLEN(attrlen);
35021da177e4SLinus Torvalds 	unsigned int nwords = xdr->p - savep;
35031da177e4SLinus Torvalds 
35041da177e4SLinus Torvalds 	if (unlikely(attrwords != nwords)) {
3505fe82a183SChuck Lever 		dprintk("%s: server returned incorrect attribute length: "
3506fe82a183SChuck Lever 			"%u %c %u\n",
35073110ff80SHarvey Harrison 				__func__,
35081da177e4SLinus Torvalds 				attrwords << 2,
35091da177e4SLinus Torvalds 				(attrwords < nwords) ? '<' : '>',
35101da177e4SLinus Torvalds 				nwords << 2);
35111da177e4SLinus Torvalds 		return -EIO;
35121da177e4SLinus Torvalds 	}
35131da177e4SLinus Torvalds 	return 0;
35141da177e4SLinus Torvalds }
35151da177e4SLinus Torvalds 
35161da177e4SLinus Torvalds static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
35171da177e4SLinus Torvalds {
35188687b63aSAl Viro 	__be32 *p;
35191da177e4SLinus Torvalds 
3520c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 20);
3521c0eae66eSBenny Halevy 	if (unlikely(!p))
3522c0eae66eSBenny Halevy 		goto out_overflow;
35236f723f77SBenny Halevy 	cinfo->atomic = be32_to_cpup(p++);
35243ceb4dbbSBenny Halevy 	p = xdr_decode_hyper(p, &cinfo->before);
3525cccddf4fSBenny Halevy 	xdr_decode_hyper(p, &cinfo->after);
35261da177e4SLinus Torvalds 	return 0;
3527c0eae66eSBenny Halevy out_overflow:
3528c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3529c0eae66eSBenny Halevy 	return -EIO;
35301da177e4SLinus Torvalds }
35311da177e4SLinus Torvalds 
35321da177e4SLinus Torvalds static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
35331da177e4SLinus Torvalds {
35348687b63aSAl Viro 	__be32 *p;
35351da177e4SLinus Torvalds 	uint32_t supp, acc;
35361da177e4SLinus Torvalds 	int status;
35371da177e4SLinus Torvalds 
35381da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_ACCESS);
35391da177e4SLinus Torvalds 	if (status)
35401da177e4SLinus Torvalds 		return status;
3541c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
3542c0eae66eSBenny Halevy 	if (unlikely(!p))
3543c0eae66eSBenny Halevy 		goto out_overflow;
35446f723f77SBenny Halevy 	supp = be32_to_cpup(p++);
3545cccddf4fSBenny Halevy 	acc = be32_to_cpup(p);
35461da177e4SLinus Torvalds 	access->supported = supp;
35471da177e4SLinus Torvalds 	access->access = acc;
35481da177e4SLinus Torvalds 	return 0;
3549c0eae66eSBenny Halevy out_overflow:
3550c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3551c0eae66eSBenny Halevy 	return -EIO;
35521da177e4SLinus Torvalds }
35531da177e4SLinus Torvalds 
355407d30434SBenny Halevy static int decode_opaque_fixed(struct xdr_stream *xdr, void *buf, size_t len)
35551da177e4SLinus Torvalds {
35568687b63aSAl Viro 	__be32 *p;
355707d30434SBenny Halevy 
355807d30434SBenny Halevy 	p = xdr_inline_decode(xdr, len);
355907d30434SBenny Halevy 	if (likely(p)) {
356007d30434SBenny Halevy 		memcpy(buf, p, len);
356107d30434SBenny Halevy 		return 0;
356207d30434SBenny Halevy 	}
356307d30434SBenny Halevy 	print_overflow_msg(__func__, xdr);
356407d30434SBenny Halevy 	return -EIO;
356507d30434SBenny Halevy }
356607d30434SBenny Halevy 
356707d30434SBenny Halevy static int decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
356807d30434SBenny Halevy {
356907d30434SBenny Halevy 	return decode_opaque_fixed(xdr, stateid->data, NFS4_STATEID_SIZE);
35701da177e4SLinus Torvalds }
35711da177e4SLinus Torvalds 
35721da177e4SLinus Torvalds static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
35731da177e4SLinus Torvalds {
35741da177e4SLinus Torvalds 	int status;
35751da177e4SLinus Torvalds 
35761da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_CLOSE);
3577c1d51931STrond Myklebust 	if (status != -EIO)
3578c1d51931STrond Myklebust 		nfs_increment_open_seqid(status, res->seqid);
357907d30434SBenny Halevy 	if (!status)
358007d30434SBenny Halevy 		status = decode_stateid(xdr, &res->stateid);
35811da177e4SLinus Torvalds 	return status;
35821da177e4SLinus Torvalds }
35831da177e4SLinus Torvalds 
3584db942bbdSBenny Halevy static int decode_verifier(struct xdr_stream *xdr, void *verifier)
3585db942bbdSBenny Halevy {
3586db942bbdSBenny Halevy 	return decode_opaque_fixed(xdr, verifier, 8);
35871da177e4SLinus Torvalds }
35881da177e4SLinus Torvalds 
35891da177e4SLinus Torvalds static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
35901da177e4SLinus Torvalds {
35911da177e4SLinus Torvalds 	int status;
35921da177e4SLinus Torvalds 
35931da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_COMMIT);
3594db942bbdSBenny Halevy 	if (!status)
3595db942bbdSBenny Halevy 		status = decode_verifier(xdr, res->verf->verifier);
35961da177e4SLinus Torvalds 	return status;
35971da177e4SLinus Torvalds }
35981da177e4SLinus Torvalds 
35991da177e4SLinus Torvalds static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
36001da177e4SLinus Torvalds {
36018687b63aSAl Viro 	__be32 *p;
36021da177e4SLinus Torvalds 	uint32_t bmlen;
36031da177e4SLinus Torvalds 	int status;
36041da177e4SLinus Torvalds 
36051da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_CREATE);
36061da177e4SLinus Torvalds 	if (status)
36071da177e4SLinus Torvalds 		return status;
36081da177e4SLinus Torvalds 	if ((status = decode_change_info(xdr, cinfo)))
36091da177e4SLinus Torvalds 		return status;
3610c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
3611c0eae66eSBenny Halevy 	if (unlikely(!p))
3612c0eae66eSBenny Halevy 		goto out_overflow;
3613cccddf4fSBenny Halevy 	bmlen = be32_to_cpup(p);
3614c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, bmlen << 2);
3615c0eae66eSBenny Halevy 	if (likely(p))
36161da177e4SLinus Torvalds 		return 0;
3617c0eae66eSBenny Halevy out_overflow:
3618c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3619c0eae66eSBenny Halevy 	return -EIO;
36201da177e4SLinus Torvalds }
36211da177e4SLinus Torvalds 
36221da177e4SLinus Torvalds static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
36231da177e4SLinus Torvalds {
36248687b63aSAl Viro 	__be32 *savep;
36256c0195a4SAndy Adamson 	uint32_t attrlen, bitmap[2] = {0};
36261da177e4SLinus Torvalds 	int status;
36271da177e4SLinus Torvalds 
36281da177e4SLinus Torvalds 	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
36291da177e4SLinus Torvalds 		goto xdr_error;
36301da177e4SLinus Torvalds 	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
36311da177e4SLinus Torvalds 		goto xdr_error;
36321da177e4SLinus Torvalds 	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
36331da177e4SLinus Torvalds 		goto xdr_error;
36341da177e4SLinus Torvalds 	if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0)
36351da177e4SLinus Torvalds 		goto xdr_error;
36361da177e4SLinus Torvalds 	if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0)
36371da177e4SLinus Torvalds 		goto xdr_error;
36381da177e4SLinus Torvalds 	if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0)
36391da177e4SLinus Torvalds 		goto xdr_error;
36401da177e4SLinus Torvalds 	if ((status = decode_attr_aclsupport(xdr, bitmap, &res->acl_bitmask)) != 0)
36411da177e4SLinus Torvalds 		goto xdr_error;
36421da177e4SLinus Torvalds 	status = verify_attr_len(xdr, savep, attrlen);
36431da177e4SLinus Torvalds xdr_error:
36443110ff80SHarvey Harrison 	dprintk("%s: xdr returned %d!\n", __func__, -status);
36451da177e4SLinus Torvalds 	return status;
36461da177e4SLinus Torvalds }
36471da177e4SLinus Torvalds 
36481da177e4SLinus Torvalds static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
36491da177e4SLinus Torvalds {
36508687b63aSAl Viro 	__be32 *savep;
36516c0195a4SAndy Adamson 	uint32_t attrlen, bitmap[2] = {0};
36521da177e4SLinus Torvalds 	int status;
36531da177e4SLinus Torvalds 
36541da177e4SLinus Torvalds 	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
36551da177e4SLinus Torvalds 		goto xdr_error;
36561da177e4SLinus Torvalds 	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
36571da177e4SLinus Torvalds 		goto xdr_error;
36581da177e4SLinus Torvalds 	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
36591da177e4SLinus Torvalds 		goto xdr_error;
36601da177e4SLinus Torvalds 
36611da177e4SLinus Torvalds 	if ((status = decode_attr_files_avail(xdr, bitmap, &fsstat->afiles)) != 0)
36621da177e4SLinus Torvalds 		goto xdr_error;
36631da177e4SLinus Torvalds 	if ((status = decode_attr_files_free(xdr, bitmap, &fsstat->ffiles)) != 0)
36641da177e4SLinus Torvalds 		goto xdr_error;
36651da177e4SLinus Torvalds 	if ((status = decode_attr_files_total(xdr, bitmap, &fsstat->tfiles)) != 0)
36661da177e4SLinus Torvalds 		goto xdr_error;
36671da177e4SLinus Torvalds 	if ((status = decode_attr_space_avail(xdr, bitmap, &fsstat->abytes)) != 0)
36681da177e4SLinus Torvalds 		goto xdr_error;
36691da177e4SLinus Torvalds 	if ((status = decode_attr_space_free(xdr, bitmap, &fsstat->fbytes)) != 0)
36701da177e4SLinus Torvalds 		goto xdr_error;
36711da177e4SLinus Torvalds 	if ((status = decode_attr_space_total(xdr, bitmap, &fsstat->tbytes)) != 0)
36721da177e4SLinus Torvalds 		goto xdr_error;
36731da177e4SLinus Torvalds 
36741da177e4SLinus Torvalds 	status = verify_attr_len(xdr, savep, attrlen);
36751da177e4SLinus Torvalds xdr_error:
36763110ff80SHarvey Harrison 	dprintk("%s: xdr returned %d!\n", __func__, -status);
36771da177e4SLinus Torvalds 	return status;
36781da177e4SLinus Torvalds }
36791da177e4SLinus Torvalds 
36801da177e4SLinus Torvalds static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
36811da177e4SLinus Torvalds {
36828687b63aSAl Viro 	__be32 *savep;
36836c0195a4SAndy Adamson 	uint32_t attrlen, bitmap[2] = {0};
36841da177e4SLinus Torvalds 	int status;
36851da177e4SLinus Torvalds 
36861da177e4SLinus Torvalds 	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
36871da177e4SLinus Torvalds 		goto xdr_error;
36881da177e4SLinus Torvalds 	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
36891da177e4SLinus Torvalds 		goto xdr_error;
36901da177e4SLinus Torvalds 	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
36911da177e4SLinus Torvalds 		goto xdr_error;
36921da177e4SLinus Torvalds 
36931da177e4SLinus Torvalds 	if ((status = decode_attr_maxlink(xdr, bitmap, &pathconf->max_link)) != 0)
36941da177e4SLinus Torvalds 		goto xdr_error;
36951da177e4SLinus Torvalds 	if ((status = decode_attr_maxname(xdr, bitmap, &pathconf->max_namelen)) != 0)
36961da177e4SLinus Torvalds 		goto xdr_error;
36971da177e4SLinus Torvalds 
36981da177e4SLinus Torvalds 	status = verify_attr_len(xdr, savep, attrlen);
36991da177e4SLinus Torvalds xdr_error:
37003110ff80SHarvey Harrison 	dprintk("%s: xdr returned %d!\n", __func__, -status);
37011da177e4SLinus Torvalds 	return status;
37021da177e4SLinus Torvalds }
37031da177e4SLinus Torvalds 
370480e52aceSTrond Myklebust static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
370580e52aceSTrond Myklebust 		const struct nfs_server *server, int may_sleep)
37061da177e4SLinus Torvalds {
37078687b63aSAl Viro 	__be32 *savep;
37081da177e4SLinus Torvalds 	uint32_t attrlen,
37091da177e4SLinus Torvalds 		 bitmap[2] = {0},
37101da177e4SLinus Torvalds 		 type;
3711bca79478STrond Myklebust 	int status;
3712bca79478STrond Myklebust 	umode_t fmode = 0;
371399baf625SManoj Naik 	uint64_t fileid;
37141da177e4SLinus Torvalds 
3715f26c7a78STrond Myklebust 	status = decode_op_hdr(xdr, OP_GETATTR);
3716f26c7a78STrond Myklebust 	if (status < 0)
37171da177e4SLinus Torvalds 		goto xdr_error;
37181da177e4SLinus Torvalds 
3719f26c7a78STrond Myklebust 	status = decode_attr_bitmap(xdr, bitmap);
3720f26c7a78STrond Myklebust 	if (status < 0)
3721f26c7a78STrond Myklebust 		goto xdr_error;
3722f26c7a78STrond Myklebust 
3723f26c7a78STrond Myklebust 	status = decode_attr_length(xdr, &attrlen, &savep);
3724f26c7a78STrond Myklebust 	if (status < 0)
37251da177e4SLinus Torvalds 		goto xdr_error;
37261da177e4SLinus Torvalds 
37271da177e4SLinus Torvalds 
3728f26c7a78STrond Myklebust 	status = decode_attr_type(xdr, bitmap, &type);
3729f26c7a78STrond Myklebust 	if (status < 0)
37301da177e4SLinus Torvalds 		goto xdr_error;
3731409924e4STrond Myklebust 	fattr->mode = 0;
3732409924e4STrond Myklebust 	if (status != 0) {
3733409924e4STrond Myklebust 		fattr->mode |= nfs_type2fmt[type];
3734409924e4STrond Myklebust 		fattr->valid |= status;
3735409924e4STrond Myklebust 	}
37361da177e4SLinus Torvalds 
3737f26c7a78STrond Myklebust 	status = decode_attr_change(xdr, bitmap, &fattr->change_attr);
3738f26c7a78STrond Myklebust 	if (status < 0)
37391da177e4SLinus Torvalds 		goto xdr_error;
3740409924e4STrond Myklebust 	fattr->valid |= status;
3741f26c7a78STrond Myklebust 
3742f26c7a78STrond Myklebust 	status = decode_attr_size(xdr, bitmap, &fattr->size);
3743f26c7a78STrond Myklebust 	if (status < 0)
37441da177e4SLinus Torvalds 		goto xdr_error;
3745409924e4STrond Myklebust 	fattr->valid |= status;
3746f26c7a78STrond Myklebust 
3747f26c7a78STrond Myklebust 	status = decode_attr_fsid(xdr, bitmap, &fattr->fsid);
3748f26c7a78STrond Myklebust 	if (status < 0)
37491da177e4SLinus Torvalds 		goto xdr_error;
3750409924e4STrond Myklebust 	fattr->valid |= status;
3751f26c7a78STrond Myklebust 
3752f26c7a78STrond Myklebust 	status = decode_attr_fileid(xdr, bitmap, &fattr->fileid);
3753f26c7a78STrond Myklebust 	if (status < 0)
37541da177e4SLinus Torvalds 		goto xdr_error;
3755409924e4STrond Myklebust 	fattr->valid |= status;
3756f26c7a78STrond Myklebust 
3757f26c7a78STrond Myklebust 	status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
37587aaa0b3bSManoj Naik 						struct nfs4_fs_locations,
3759f26c7a78STrond Myklebust 						fattr));
3760f26c7a78STrond Myklebust 	if (status < 0)
3761683b57b4STrond Myklebust 		goto xdr_error;
3762409924e4STrond Myklebust 	fattr->valid |= status;
3763f26c7a78STrond Myklebust 
3764f26c7a78STrond Myklebust 	status = decode_attr_mode(xdr, bitmap, &fmode);
3765f26c7a78STrond Myklebust 	if (status < 0)
37661da177e4SLinus Torvalds 		goto xdr_error;
3767409924e4STrond Myklebust 	if (status != 0) {
37681da177e4SLinus Torvalds 		fattr->mode |= fmode;
3769409924e4STrond Myklebust 		fattr->valid |= status;
3770409924e4STrond Myklebust 	}
3771f26c7a78STrond Myklebust 
3772f26c7a78STrond Myklebust 	status = decode_attr_nlink(xdr, bitmap, &fattr->nlink);
3773f26c7a78STrond Myklebust 	if (status < 0)
37741da177e4SLinus Torvalds 		goto xdr_error;
3775409924e4STrond Myklebust 	fattr->valid |= status;
3776f26c7a78STrond Myklebust 
377780e52aceSTrond Myklebust 	status = decode_attr_owner(xdr, bitmap, server->nfs_client,
377880e52aceSTrond Myklebust 			&fattr->uid, may_sleep);
3779f26c7a78STrond Myklebust 	if (status < 0)
37801da177e4SLinus Torvalds 		goto xdr_error;
3781409924e4STrond Myklebust 	fattr->valid |= status;
3782f26c7a78STrond Myklebust 
378380e52aceSTrond Myklebust 	status = decode_attr_group(xdr, bitmap, server->nfs_client,
378480e52aceSTrond Myklebust 			&fattr->gid, may_sleep);
3785f26c7a78STrond Myklebust 	if (status < 0)
37861da177e4SLinus Torvalds 		goto xdr_error;
3787409924e4STrond Myklebust 	fattr->valid |= status;
3788f26c7a78STrond Myklebust 
3789f26c7a78STrond Myklebust 	status = decode_attr_rdev(xdr, bitmap, &fattr->rdev);
3790f26c7a78STrond Myklebust 	if (status < 0)
37911da177e4SLinus Torvalds 		goto xdr_error;
3792409924e4STrond Myklebust 	fattr->valid |= status;
3793f26c7a78STrond Myklebust 
3794f26c7a78STrond Myklebust 	status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used);
3795f26c7a78STrond Myklebust 	if (status < 0)
37961da177e4SLinus Torvalds 		goto xdr_error;
3797409924e4STrond Myklebust 	fattr->valid |= status;
3798f26c7a78STrond Myklebust 
3799f26c7a78STrond Myklebust 	status = decode_attr_time_access(xdr, bitmap, &fattr->atime);
3800f26c7a78STrond Myklebust 	if (status < 0)
38011da177e4SLinus Torvalds 		goto xdr_error;
3802409924e4STrond Myklebust 	fattr->valid |= status;
3803f26c7a78STrond Myklebust 
3804f26c7a78STrond Myklebust 	status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
3805f26c7a78STrond Myklebust 	if (status < 0)
38061da177e4SLinus Torvalds 		goto xdr_error;
3807409924e4STrond Myklebust 	fattr->valid |= status;
3808f26c7a78STrond Myklebust 
3809f26c7a78STrond Myklebust 	status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime);
3810f26c7a78STrond Myklebust 	if (status < 0)
38111da177e4SLinus Torvalds 		goto xdr_error;
3812409924e4STrond Myklebust 	fattr->valid |= status;
3813f26c7a78STrond Myklebust 
3814f26c7a78STrond Myklebust 	status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid);
3815f26c7a78STrond Myklebust 	if (status < 0)
381699baf625SManoj Naik 		goto xdr_error;
3817409924e4STrond Myklebust 	if (status != 0 && !(fattr->valid & status)) {
381899baf625SManoj Naik 		fattr->fileid = fileid;
3819409924e4STrond Myklebust 		fattr->valid |= status;
3820409924e4STrond Myklebust 	}
3821f26c7a78STrond Myklebust 
3822f26c7a78STrond Myklebust 	status = verify_attr_len(xdr, savep, attrlen);
38231da177e4SLinus Torvalds xdr_error:
38243110ff80SHarvey Harrison 	dprintk("%s: xdr returned %d\n", __func__, -status);
38251da177e4SLinus Torvalds 	return status;
38261da177e4SLinus Torvalds }
38271da177e4SLinus Torvalds 
38281da177e4SLinus Torvalds 
38291da177e4SLinus Torvalds static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
38301da177e4SLinus Torvalds {
38318687b63aSAl Viro 	__be32 *savep;
38321da177e4SLinus Torvalds 	uint32_t attrlen, bitmap[2];
38331da177e4SLinus Torvalds 	int status;
38341da177e4SLinus Torvalds 
38351da177e4SLinus Torvalds 	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
38361da177e4SLinus Torvalds 		goto xdr_error;
38371da177e4SLinus Torvalds 	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
38381da177e4SLinus Torvalds 		goto xdr_error;
38391da177e4SLinus Torvalds 	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
38401da177e4SLinus Torvalds 		goto xdr_error;
38411da177e4SLinus Torvalds 
38421da177e4SLinus Torvalds 	fsinfo->rtmult = fsinfo->wtmult = 512;	/* ??? */
38431da177e4SLinus Torvalds 
38441da177e4SLinus Torvalds 	if ((status = decode_attr_lease_time(xdr, bitmap, &fsinfo->lease_time)) != 0)
38451da177e4SLinus Torvalds 		goto xdr_error;
38461da177e4SLinus Torvalds 	if ((status = decode_attr_maxfilesize(xdr, bitmap, &fsinfo->maxfilesize)) != 0)
38471da177e4SLinus Torvalds 		goto xdr_error;
38481da177e4SLinus Torvalds 	if ((status = decode_attr_maxread(xdr, bitmap, &fsinfo->rtmax)) != 0)
38491da177e4SLinus Torvalds 		goto xdr_error;
38501da177e4SLinus Torvalds 	fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax;
38511da177e4SLinus Torvalds 	if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0)
38521da177e4SLinus Torvalds 		goto xdr_error;
38531da177e4SLinus Torvalds 	fsinfo->wtpref = fsinfo->wtmax;
38541da177e4SLinus Torvalds 
38551da177e4SLinus Torvalds 	status = verify_attr_len(xdr, savep, attrlen);
38561da177e4SLinus Torvalds xdr_error:
38573110ff80SHarvey Harrison 	dprintk("%s: xdr returned %d!\n", __func__, -status);
38581da177e4SLinus Torvalds 	return status;
38591da177e4SLinus Torvalds }
38601da177e4SLinus Torvalds 
38611da177e4SLinus Torvalds static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
38621da177e4SLinus Torvalds {
38638687b63aSAl Viro 	__be32 *p;
38641da177e4SLinus Torvalds 	uint32_t len;
38651da177e4SLinus Torvalds 	int status;
38661da177e4SLinus Torvalds 
38679936781dSTrond Myklebust 	/* Zero handle first to allow comparisons */
38689936781dSTrond Myklebust 	memset(fh, 0, sizeof(*fh));
38699936781dSTrond Myklebust 
38701da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_GETFH);
38711da177e4SLinus Torvalds 	if (status)
38721da177e4SLinus Torvalds 		return status;
38731da177e4SLinus Torvalds 
3874c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
3875c0eae66eSBenny Halevy 	if (unlikely(!p))
3876c0eae66eSBenny Halevy 		goto out_overflow;
3877cccddf4fSBenny Halevy 	len = be32_to_cpup(p);
38781da177e4SLinus Torvalds 	if (len > NFS4_FHSIZE)
38791da177e4SLinus Torvalds 		return -EIO;
38801da177e4SLinus Torvalds 	fh->size = len;
3881c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, len);
3882c0eae66eSBenny Halevy 	if (unlikely(!p))
3883c0eae66eSBenny Halevy 		goto out_overflow;
388499398d06SBenny Halevy 	memcpy(fh->data, p, len);
38851da177e4SLinus Torvalds 	return 0;
3886c0eae66eSBenny Halevy out_overflow:
3887c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3888c0eae66eSBenny Halevy 	return -EIO;
38891da177e4SLinus Torvalds }
38901da177e4SLinus Torvalds 
38911da177e4SLinus Torvalds static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
38921da177e4SLinus Torvalds {
38931da177e4SLinus Torvalds 	int status;
38941da177e4SLinus Torvalds 
38951da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_LINK);
38961da177e4SLinus Torvalds 	if (status)
38971da177e4SLinus Torvalds 		return status;
38981da177e4SLinus Torvalds 	return decode_change_info(xdr, cinfo);
38991da177e4SLinus Torvalds }
39001da177e4SLinus Torvalds 
39011da177e4SLinus Torvalds /*
39021da177e4SLinus Torvalds  * We create the owner, so we know a proper owner.id length is 4.
39031da177e4SLinus Torvalds  */
3904911d1aafSTrond Myklebust static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
39051da177e4SLinus Torvalds {
3906911d1aafSTrond Myklebust 	uint64_t offset, length, clientid;
39078687b63aSAl Viro 	__be32 *p;
3908911d1aafSTrond Myklebust 	uint32_t namelen, type;
39091da177e4SLinus Torvalds 
3910c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 32);
3911c0eae66eSBenny Halevy 	if (unlikely(!p))
3912c0eae66eSBenny Halevy 		goto out_overflow;
39133ceb4dbbSBenny Halevy 	p = xdr_decode_hyper(p, &offset);
39143ceb4dbbSBenny Halevy 	p = xdr_decode_hyper(p, &length);
39156f723f77SBenny Halevy 	type = be32_to_cpup(p++);
3916911d1aafSTrond Myklebust 	if (fl != NULL) {
3917911d1aafSTrond Myklebust 		fl->fl_start = (loff_t)offset;
3918911d1aafSTrond Myklebust 		fl->fl_end = fl->fl_start + (loff_t)length - 1;
3919911d1aafSTrond Myklebust 		if (length == ~(uint64_t)0)
3920911d1aafSTrond Myklebust 			fl->fl_end = OFFSET_MAX;
3921911d1aafSTrond Myklebust 		fl->fl_type = F_WRLCK;
3922911d1aafSTrond Myklebust 		if (type & 1)
3923911d1aafSTrond Myklebust 			fl->fl_type = F_RDLCK;
3924911d1aafSTrond Myklebust 		fl->fl_pid = 0;
3925911d1aafSTrond Myklebust 	}
39263ceb4dbbSBenny Halevy 	p = xdr_decode_hyper(p, &clientid);
3927cccddf4fSBenny Halevy 	namelen = be32_to_cpup(p);
3928c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, namelen);
3929c0eae66eSBenny Halevy 	if (likely(p))
39301da177e4SLinus Torvalds 		return -NFS4ERR_DENIED;
3931c0eae66eSBenny Halevy out_overflow:
3932c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
3933c0eae66eSBenny Halevy 	return -EIO;
39341da177e4SLinus Torvalds }
39351da177e4SLinus Torvalds 
3936911d1aafSTrond Myklebust static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
39371da177e4SLinus Torvalds {
39381da177e4SLinus Torvalds 	int status;
39391da177e4SLinus Torvalds 
39401da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_LOCK);
3941c1d51931STrond Myklebust 	if (status == -EIO)
3942c1d51931STrond Myklebust 		goto out;
39431da177e4SLinus Torvalds 	if (status == 0) {
394407d30434SBenny Halevy 		status = decode_stateid(xdr, &res->stateid);
394507d30434SBenny Halevy 		if (unlikely(status))
394607d30434SBenny Halevy 			goto out;
39471da177e4SLinus Torvalds 	} else if (status == -NFS4ERR_DENIED)
3948c1d51931STrond Myklebust 		status = decode_lock_denied(xdr, NULL);
3949c1d51931STrond Myklebust 	if (res->open_seqid != NULL)
3950c1d51931STrond Myklebust 		nfs_increment_open_seqid(status, res->open_seqid);
3951c1d51931STrond Myklebust 	nfs_increment_lock_seqid(status, res->lock_seqid);
3952c1d51931STrond Myklebust out:
39531da177e4SLinus Torvalds 	return status;
39541da177e4SLinus Torvalds }
39551da177e4SLinus Torvalds 
3956911d1aafSTrond Myklebust static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res)
39571da177e4SLinus Torvalds {
39581da177e4SLinus Torvalds 	int status;
39591da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_LOCKT);
39601da177e4SLinus Torvalds 	if (status == -NFS4ERR_DENIED)
3961911d1aafSTrond Myklebust 		return decode_lock_denied(xdr, res->denied);
39621da177e4SLinus Torvalds 	return status;
39631da177e4SLinus Torvalds }
39641da177e4SLinus Torvalds 
3965911d1aafSTrond Myklebust static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
39661da177e4SLinus Torvalds {
39671da177e4SLinus Torvalds 	int status;
39681da177e4SLinus Torvalds 
39691da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_LOCKU);
3970c1d51931STrond Myklebust 	if (status != -EIO)
3971c1d51931STrond Myklebust 		nfs_increment_lock_seqid(status, res->seqid);
397207d30434SBenny Halevy 	if (status == 0)
397307d30434SBenny Halevy 		status = decode_stateid(xdr, &res->stateid);
39741da177e4SLinus Torvalds 	return status;
39751da177e4SLinus Torvalds }
39761da177e4SLinus Torvalds 
39771da177e4SLinus Torvalds static int decode_lookup(struct xdr_stream *xdr)
39781da177e4SLinus Torvalds {
39791da177e4SLinus Torvalds 	return decode_op_hdr(xdr, OP_LOOKUP);
39801da177e4SLinus Torvalds }
39811da177e4SLinus Torvalds 
39821da177e4SLinus Torvalds /* This is too sick! */
39831da177e4SLinus Torvalds static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
39841da177e4SLinus Torvalds {
39858687b63aSAl Viro 	__be32 *p;
39861da177e4SLinus Torvalds 	uint32_t limit_type, nblocks, blocksize;
39871da177e4SLinus Torvalds 
3988c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 12);
3989c0eae66eSBenny Halevy 	if (unlikely(!p))
3990c0eae66eSBenny Halevy 		goto out_overflow;
39916f723f77SBenny Halevy 	limit_type = be32_to_cpup(p++);
39921da177e4SLinus Torvalds 	switch (limit_type) {
39931da177e4SLinus Torvalds 	case 1:
3994cccddf4fSBenny Halevy 		xdr_decode_hyper(p, maxsize);
39951da177e4SLinus Torvalds 		break;
39961da177e4SLinus Torvalds 	case 2:
39976f723f77SBenny Halevy 		nblocks = be32_to_cpup(p++);
3998cccddf4fSBenny Halevy 		blocksize = be32_to_cpup(p);
39991da177e4SLinus Torvalds 		*maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
40001da177e4SLinus Torvalds 	}
40011da177e4SLinus Torvalds 	return 0;
4002c0eae66eSBenny Halevy out_overflow:
4003c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4004c0eae66eSBenny Halevy 	return -EIO;
40051da177e4SLinus Torvalds }
40061da177e4SLinus Torvalds 
40071da177e4SLinus Torvalds static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
40081da177e4SLinus Torvalds {
40098687b63aSAl Viro 	__be32 *p;
40101da177e4SLinus Torvalds 	uint32_t delegation_type;
401107d30434SBenny Halevy 	int status;
40121da177e4SLinus Torvalds 
4013c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
4014c0eae66eSBenny Halevy 	if (unlikely(!p))
4015c0eae66eSBenny Halevy 		goto out_overflow;
4016cccddf4fSBenny Halevy 	delegation_type = be32_to_cpup(p);
40171da177e4SLinus Torvalds 	if (delegation_type == NFS4_OPEN_DELEGATE_NONE) {
40181da177e4SLinus Torvalds 		res->delegation_type = 0;
40191da177e4SLinus Torvalds 		return 0;
40201da177e4SLinus Torvalds 	}
402107d30434SBenny Halevy 	status = decode_stateid(xdr, &res->delegation);
402207d30434SBenny Halevy 	if (unlikely(status))
402307d30434SBenny Halevy 		return status;
4024c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
4025c0eae66eSBenny Halevy 	if (unlikely(!p))
4026c0eae66eSBenny Halevy 		goto out_overflow;
4027cccddf4fSBenny Halevy 	res->do_recall = be32_to_cpup(p);
402805d564feSAndy Adamson 
40291da177e4SLinus Torvalds 	switch (delegation_type) {
40301da177e4SLinus Torvalds 	case NFS4_OPEN_DELEGATE_READ:
40311da177e4SLinus Torvalds 		res->delegation_type = FMODE_READ;
40321da177e4SLinus Torvalds 		break;
40331da177e4SLinus Torvalds 	case NFS4_OPEN_DELEGATE_WRITE:
40341da177e4SLinus Torvalds 		res->delegation_type = FMODE_WRITE|FMODE_READ;
40351da177e4SLinus Torvalds 		if (decode_space_limit(xdr, &res->maxsize) < 0)
40361da177e4SLinus Torvalds 				return -EIO;
40371da177e4SLinus Torvalds 	}
40387539bbabSDavid Howells 	return decode_ace(xdr, NULL, res->server->nfs_client);
4039c0eae66eSBenny Halevy out_overflow:
4040c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4041c0eae66eSBenny Halevy 	return -EIO;
40421da177e4SLinus Torvalds }
40431da177e4SLinus Torvalds 
40441da177e4SLinus Torvalds static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
40451da177e4SLinus Torvalds {
40468687b63aSAl Viro 	__be32 *p;
4047aa53ed54SJeff Layton 	uint32_t savewords, bmlen, i;
40481da177e4SLinus Torvalds 	int status;
40491da177e4SLinus Torvalds 
40501da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_OPEN);
4051c1d51931STrond Myklebust 	if (status != -EIO)
4052c1d51931STrond Myklebust 		nfs_increment_open_seqid(status, res->seqid);
405307d30434SBenny Halevy 	if (!status)
405407d30434SBenny Halevy 		status = decode_stateid(xdr, &res->stateid);
405507d30434SBenny Halevy 	if (unlikely(status))
40561da177e4SLinus Torvalds 		return status;
40571da177e4SLinus Torvalds 
40581da177e4SLinus Torvalds 	decode_change_info(xdr, &res->cinfo);
40591da177e4SLinus Torvalds 
4060c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
4061c0eae66eSBenny Halevy 	if (unlikely(!p))
4062c0eae66eSBenny Halevy 		goto out_overflow;
40636f723f77SBenny Halevy 	res->rflags = be32_to_cpup(p++);
4064cccddf4fSBenny Halevy 	bmlen = be32_to_cpup(p);
40651da177e4SLinus Torvalds 	if (bmlen > 10)
40661da177e4SLinus Torvalds 		goto xdr_error;
40671da177e4SLinus Torvalds 
4068c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, bmlen << 2);
4069c0eae66eSBenny Halevy 	if (unlikely(!p))
4070c0eae66eSBenny Halevy 		goto out_overflow;
4071aa53ed54SJeff Layton 	savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE);
4072aa53ed54SJeff Layton 	for (i = 0; i < savewords; ++i)
40736f723f77SBenny Halevy 		res->attrset[i] = be32_to_cpup(p++);
4074aa53ed54SJeff Layton 	for (; i < NFS4_BITMAP_SIZE; i++)
4075aa53ed54SJeff Layton 		res->attrset[i] = 0;
4076aa53ed54SJeff Layton 
40771da177e4SLinus Torvalds 	return decode_delegation(xdr, res);
40781da177e4SLinus Torvalds xdr_error:
40793110ff80SHarvey Harrison 	dprintk("%s: Bitmap too large! Length = %u\n", __func__, bmlen);
40801da177e4SLinus Torvalds 	return -EIO;
4081c0eae66eSBenny Halevy out_overflow:
4082c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4083c0eae66eSBenny Halevy 	return -EIO;
40841da177e4SLinus Torvalds }
40851da177e4SLinus Torvalds 
40861da177e4SLinus Torvalds static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
40871da177e4SLinus Torvalds {
40881da177e4SLinus Torvalds 	int status;
40891da177e4SLinus Torvalds 
40901da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
4091c1d51931STrond Myklebust 	if (status != -EIO)
4092c1d51931STrond Myklebust 		nfs_increment_open_seqid(status, res->seqid);
409307d30434SBenny Halevy 	if (!status)
409407d30434SBenny Halevy 		status = decode_stateid(xdr, &res->stateid);
40951da177e4SLinus Torvalds 	return status;
40961da177e4SLinus Torvalds }
40971da177e4SLinus Torvalds 
40981da177e4SLinus Torvalds static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
40991da177e4SLinus Torvalds {
41001da177e4SLinus Torvalds 	int status;
41011da177e4SLinus Torvalds 
41021da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE);
4103c1d51931STrond Myklebust 	if (status != -EIO)
4104c1d51931STrond Myklebust 		nfs_increment_open_seqid(status, res->seqid);
410507d30434SBenny Halevy 	if (!status)
410607d30434SBenny Halevy 		status = decode_stateid(xdr, &res->stateid);
41071da177e4SLinus Torvalds 	return status;
41081da177e4SLinus Torvalds }
41091da177e4SLinus Torvalds 
41101da177e4SLinus Torvalds static int decode_putfh(struct xdr_stream *xdr)
41111da177e4SLinus Torvalds {
41121da177e4SLinus Torvalds 	return decode_op_hdr(xdr, OP_PUTFH);
41131da177e4SLinus Torvalds }
41141da177e4SLinus Torvalds 
41151da177e4SLinus Torvalds static int decode_putrootfh(struct xdr_stream *xdr)
41161da177e4SLinus Torvalds {
41171da177e4SLinus Torvalds 	return decode_op_hdr(xdr, OP_PUTROOTFH);
41181da177e4SLinus Torvalds }
41191da177e4SLinus Torvalds 
41201da177e4SLinus Torvalds static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
41211da177e4SLinus Torvalds {
41221da177e4SLinus Torvalds 	struct kvec *iov = req->rq_rcv_buf.head;
41238687b63aSAl Viro 	__be32 *p;
41241da177e4SLinus Torvalds 	uint32_t count, eof, recvd, hdrlen;
41251da177e4SLinus Torvalds 	int status;
41261da177e4SLinus Torvalds 
41271da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_READ);
41281da177e4SLinus Torvalds 	if (status)
41291da177e4SLinus Torvalds 		return status;
4130c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
4131c0eae66eSBenny Halevy 	if (unlikely(!p))
4132c0eae66eSBenny Halevy 		goto out_overflow;
41336f723f77SBenny Halevy 	eof = be32_to_cpup(p++);
4134cccddf4fSBenny Halevy 	count = be32_to_cpup(p);
41351da177e4SLinus Torvalds 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
41361da177e4SLinus Torvalds 	recvd = req->rq_rcv_buf.len - hdrlen;
41371da177e4SLinus Torvalds 	if (count > recvd) {
4138fe82a183SChuck Lever 		dprintk("NFS: server cheating in read reply: "
41391da177e4SLinus Torvalds 				"count %u > recvd %u\n", count, recvd);
41401da177e4SLinus Torvalds 		count = recvd;
41411da177e4SLinus Torvalds 		eof = 0;
41421da177e4SLinus Torvalds 	}
41431da177e4SLinus Torvalds 	xdr_read_pages(xdr, count);
41441da177e4SLinus Torvalds 	res->eof = eof;
41451da177e4SLinus Torvalds 	res->count = count;
41461da177e4SLinus Torvalds 	return 0;
4147c0eae66eSBenny Halevy out_overflow:
4148c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4149c0eae66eSBenny Halevy 	return -EIO;
41501da177e4SLinus Torvalds }
41511da177e4SLinus Torvalds 
41521da177e4SLinus Torvalds static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
41531da177e4SLinus Torvalds {
41541da177e4SLinus Torvalds 	struct xdr_buf	*rcvbuf = &req->rq_rcv_buf;
41551da177e4SLinus Torvalds 	struct page	*page = *rcvbuf->pages;
41561da177e4SLinus Torvalds 	struct kvec	*iov = rcvbuf->head;
4157bcecff77SChuck Lever 	size_t		hdrlen;
4158bcecff77SChuck Lever 	u32		recvd, pglen = rcvbuf->page_len;
41598687b63aSAl Viro 	__be32		*end, *entry, *p, *kaddr;
41607bda2cdfSJeff Layton 	unsigned int	nr = 0;
4161bcecff77SChuck Lever 	int		status;
41621da177e4SLinus Torvalds 
41631da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_READDIR);
4164db942bbdSBenny Halevy 	if (!status)
4165db942bbdSBenny Halevy 		status = decode_verifier(xdr, readdir->verifier.data);
4166db942bbdSBenny Halevy 	if (unlikely(status))
41671da177e4SLinus Torvalds 		return status;
416844109241SFred Isaman 	dprintk("%s: verifier = %08x:%08x\n",
416944109241SFred Isaman 			__func__,
4170eadf4598STrond Myklebust 			((u32 *)readdir->verifier.data)[0],
4171eadf4598STrond Myklebust 			((u32 *)readdir->verifier.data)[1]);
4172eadf4598STrond Myklebust 
41731da177e4SLinus Torvalds 
4174db942bbdSBenny Halevy 	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
41751da177e4SLinus Torvalds 	recvd = rcvbuf->len - hdrlen;
41761da177e4SLinus Torvalds 	if (pglen > recvd)
41771da177e4SLinus Torvalds 		pglen = recvd;
41781da177e4SLinus Torvalds 	xdr_read_pages(xdr, pglen);
41791da177e4SLinus Torvalds 
41801da177e4SLinus Torvalds 	BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
41818687b63aSAl Viro 	kaddr = p = kmap_atomic(page, KM_USER0);
4182e8896495SDavid Howells 	end = p + ((pglen + readdir->pgbase) >> 2);
41831da177e4SLinus Torvalds 	entry = p;
41847bda2cdfSJeff Layton 
41857bda2cdfSJeff Layton 	/* Make sure the packet actually has a value_follows and EOF entry */
41867bda2cdfSJeff Layton 	if ((entry + 1) > end)
41877bda2cdfSJeff Layton 		goto short_pkt;
41887bda2cdfSJeff Layton 
41897bda2cdfSJeff Layton 	for (; *p++; nr++) {
4190bcecff77SChuck Lever 		u32 len, attrlen, xlen;
4191e8896495SDavid Howells 		if (end - p < 3)
41921da177e4SLinus Torvalds 			goto short_pkt;
4193eadf4598STrond Myklebust 		dprintk("cookie = %Lu, ", *((unsigned long long *)p));
41941da177e4SLinus Torvalds 		p += 2;			/* cookie */
41951da177e4SLinus Torvalds 		len = ntohl(*p++);	/* filename length */
41961da177e4SLinus Torvalds 		if (len > NFS4_MAXNAMLEN) {
4197fe82a183SChuck Lever 			dprintk("NFS: giant filename in readdir (len 0x%x)\n",
4198fe82a183SChuck Lever 					len);
41991da177e4SLinus Torvalds 			goto err_unmap;
42001da177e4SLinus Torvalds 		}
4201e8896495SDavid Howells 		xlen = XDR_QUADLEN(len);
4202e8896495SDavid Howells 		if (end - p < xlen + 1)
4203e8896495SDavid Howells 			goto short_pkt;
4204eadf4598STrond Myklebust 		dprintk("filename = %*s\n", len, (char *)p);
4205e8896495SDavid Howells 		p += xlen;
42061da177e4SLinus Torvalds 		len = ntohl(*p++);	/* bitmap length */
4207e8896495SDavid Howells 		if (end - p < len + 1)
4208e8896495SDavid Howells 			goto short_pkt;
42091da177e4SLinus Torvalds 		p += len;
42101da177e4SLinus Torvalds 		attrlen = XDR_QUADLEN(ntohl(*p++));
4211e8896495SDavid Howells 		if (end - p < attrlen + 2)
42121da177e4SLinus Torvalds 			goto short_pkt;
4213e8896495SDavid Howells 		p += attrlen;		/* attributes */
42141da177e4SLinus Torvalds 		entry = p;
42151da177e4SLinus Torvalds 	}
42167bda2cdfSJeff Layton 	/*
42177bda2cdfSJeff Layton 	 * Apparently some server sends responses that are a valid size, but
42187bda2cdfSJeff Layton 	 * contain no entries, and have value_follows==0 and EOF==0. For
42197bda2cdfSJeff Layton 	 * those, just set the EOF marker.
42207bda2cdfSJeff Layton 	 */
42217bda2cdfSJeff Layton 	if (!nr && entry[1] == 0) {
42227bda2cdfSJeff Layton 		dprintk("NFS: readdir reply truncated!\n");
42237bda2cdfSJeff Layton 		entry[1] = 1;
42247bda2cdfSJeff Layton 	}
42251da177e4SLinus Torvalds out:
42261da177e4SLinus Torvalds 	kunmap_atomic(kaddr, KM_USER0);
42271da177e4SLinus Torvalds 	return 0;
42281da177e4SLinus Torvalds short_pkt:
42297bda2cdfSJeff Layton 	/*
42307bda2cdfSJeff Layton 	 * When we get a short packet there are 2 possibilities. We can
42317bda2cdfSJeff Layton 	 * return an error, or fix up the response to look like a valid
42327bda2cdfSJeff Layton 	 * response and return what we have so far. If there are no
42337bda2cdfSJeff Layton 	 * entries and the packet was short, then return -EIO. If there
42347bda2cdfSJeff Layton 	 * are valid entries in the response, return them and pretend that
42357bda2cdfSJeff Layton 	 * the call was successful, but incomplete. The caller can retry the
42367bda2cdfSJeff Layton 	 * readdir starting at the last cookie.
42377bda2cdfSJeff Layton 	 */
42383110ff80SHarvey Harrison 	dprintk("%s: short packet at entry %d\n", __func__, nr);
42391da177e4SLinus Torvalds 	entry[0] = entry[1] = 0;
42407bda2cdfSJeff Layton 	if (nr)
42411da177e4SLinus Torvalds 		goto out;
42421da177e4SLinus Torvalds err_unmap:
42431da177e4SLinus Torvalds 	kunmap_atomic(kaddr, KM_USER0);
42441da177e4SLinus Torvalds 	return -errno_NFSERR_IO;
42451da177e4SLinus Torvalds }
42461da177e4SLinus Torvalds 
42471da177e4SLinus Torvalds static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
42481da177e4SLinus Torvalds {
42491da177e4SLinus Torvalds 	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
42501da177e4SLinus Torvalds 	struct kvec *iov = rcvbuf->head;
4251bcecff77SChuck Lever 	size_t hdrlen;
4252bcecff77SChuck Lever 	u32 len, recvd;
42538687b63aSAl Viro 	__be32 *p;
42541da177e4SLinus Torvalds 	char *kaddr;
42551da177e4SLinus Torvalds 	int status;
42561da177e4SLinus Torvalds 
42571da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_READLINK);
42581da177e4SLinus Torvalds 	if (status)
42591da177e4SLinus Torvalds 		return status;
42601da177e4SLinus Torvalds 
42611da177e4SLinus Torvalds 	/* Convert length of symlink */
4262c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
4263c0eae66eSBenny Halevy 	if (unlikely(!p))
4264c0eae66eSBenny Halevy 		goto out_overflow;
4265cccddf4fSBenny Halevy 	len = be32_to_cpup(p);
42661da177e4SLinus Torvalds 	if (len >= rcvbuf->page_len || len <= 0) {
4267fe82a183SChuck Lever 		dprintk("nfs: server returned giant symlink!\n");
42681da177e4SLinus Torvalds 		return -ENAMETOOLONG;
42691da177e4SLinus Torvalds 	}
42701da177e4SLinus Torvalds 	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
42711da177e4SLinus Torvalds 	recvd = req->rq_rcv_buf.len - hdrlen;
42721da177e4SLinus Torvalds 	if (recvd < len) {
4273fe82a183SChuck Lever 		dprintk("NFS: server cheating in readlink reply: "
42741da177e4SLinus Torvalds 				"count %u > recvd %u\n", len, recvd);
42751da177e4SLinus Torvalds 		return -EIO;
42761da177e4SLinus Torvalds 	}
42771da177e4SLinus Torvalds 	xdr_read_pages(xdr, len);
42781da177e4SLinus Torvalds 	/*
42791da177e4SLinus Torvalds 	 * The XDR encode routine has set things up so that
42801da177e4SLinus Torvalds 	 * the link text will be copied directly into the
42811da177e4SLinus Torvalds 	 * buffer.  We just have to do overflow-checking,
42821da177e4SLinus Torvalds 	 * and and null-terminate the text (the VFS expects
42831da177e4SLinus Torvalds 	 * null-termination).
42841da177e4SLinus Torvalds 	 */
42851da177e4SLinus Torvalds 	kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
42861da177e4SLinus Torvalds 	kaddr[len+rcvbuf->page_base] = '\0';
42871da177e4SLinus Torvalds 	kunmap_atomic(kaddr, KM_USER0);
42881da177e4SLinus Torvalds 	return 0;
4289c0eae66eSBenny Halevy out_overflow:
4290c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4291c0eae66eSBenny Halevy 	return -EIO;
42921da177e4SLinus Torvalds }
42931da177e4SLinus Torvalds 
42941da177e4SLinus Torvalds static int decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
42951da177e4SLinus Torvalds {
42961da177e4SLinus Torvalds 	int status;
42971da177e4SLinus Torvalds 
42981da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_REMOVE);
42991da177e4SLinus Torvalds 	if (status)
43001da177e4SLinus Torvalds 		goto out;
43011da177e4SLinus Torvalds 	status = decode_change_info(xdr, cinfo);
43021da177e4SLinus Torvalds out:
43031da177e4SLinus Torvalds 	return status;
43041da177e4SLinus Torvalds }
43051da177e4SLinus Torvalds 
43061da177e4SLinus Torvalds static int decode_rename(struct xdr_stream *xdr, struct nfs4_change_info *old_cinfo,
43071da177e4SLinus Torvalds 	      struct nfs4_change_info *new_cinfo)
43081da177e4SLinus Torvalds {
43091da177e4SLinus Torvalds 	int status;
43101da177e4SLinus Torvalds 
43111da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_RENAME);
43121da177e4SLinus Torvalds 	if (status)
43131da177e4SLinus Torvalds 		goto out;
43141da177e4SLinus Torvalds 	if ((status = decode_change_info(xdr, old_cinfo)))
43151da177e4SLinus Torvalds 		goto out;
43161da177e4SLinus Torvalds 	status = decode_change_info(xdr, new_cinfo);
43171da177e4SLinus Torvalds out:
43181da177e4SLinus Torvalds 	return status;
43191da177e4SLinus Torvalds }
43201da177e4SLinus Torvalds 
43211da177e4SLinus Torvalds static int decode_renew(struct xdr_stream *xdr)
43221da177e4SLinus Torvalds {
43231da177e4SLinus Torvalds 	return decode_op_hdr(xdr, OP_RENEW);
43241da177e4SLinus Torvalds }
43251da177e4SLinus Torvalds 
432656ae19f3STrond Myklebust static int
432756ae19f3STrond Myklebust decode_restorefh(struct xdr_stream *xdr)
432856ae19f3STrond Myklebust {
432956ae19f3STrond Myklebust 	return decode_op_hdr(xdr, OP_RESTOREFH);
433056ae19f3STrond Myklebust }
433156ae19f3STrond Myklebust 
4332029d105eSJ. Bruce Fields static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
4333029d105eSJ. Bruce Fields 		size_t *acl_len)
4334029d105eSJ. Bruce Fields {
43358687b63aSAl Viro 	__be32 *savep;
4336029d105eSJ. Bruce Fields 	uint32_t attrlen,
4337029d105eSJ. Bruce Fields 		 bitmap[2] = {0};
4338029d105eSJ. Bruce Fields 	struct kvec *iov = req->rq_rcv_buf.head;
4339029d105eSJ. Bruce Fields 	int status;
4340029d105eSJ. Bruce Fields 
4341029d105eSJ. Bruce Fields 	*acl_len = 0;
4342029d105eSJ. Bruce Fields 	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
4343029d105eSJ. Bruce Fields 		goto out;
4344029d105eSJ. Bruce Fields 	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
4345029d105eSJ. Bruce Fields 		goto out;
4346029d105eSJ. Bruce Fields 	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
4347029d105eSJ. Bruce Fields 		goto out;
4348029d105eSJ. Bruce Fields 
4349029d105eSJ. Bruce Fields 	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
4350029d105eSJ. Bruce Fields 		return -EIO;
4351029d105eSJ. Bruce Fields 	if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
4352bcecff77SChuck Lever 		size_t hdrlen;
4353bcecff77SChuck Lever 		u32 recvd;
4354029d105eSJ. Bruce Fields 
4355029d105eSJ. Bruce Fields 		/* We ignore &savep and don't do consistency checks on
4356029d105eSJ. Bruce Fields 		 * the attr length.  Let userspace figure it out.... */
4357029d105eSJ. Bruce Fields 		hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
4358029d105eSJ. Bruce Fields 		recvd = req->rq_rcv_buf.len - hdrlen;
4359029d105eSJ. Bruce Fields 		if (attrlen > recvd) {
4360fe82a183SChuck Lever 			dprintk("NFS: server cheating in getattr"
4361029d105eSJ. Bruce Fields 					" acl reply: attrlen %u > recvd %u\n",
4362029d105eSJ. Bruce Fields 					attrlen, recvd);
4363029d105eSJ. Bruce Fields 			return -EINVAL;
4364029d105eSJ. Bruce Fields 		}
4365029d105eSJ. Bruce Fields 		xdr_read_pages(xdr, attrlen);
4366029d105eSJ. Bruce Fields 		*acl_len = attrlen;
43678c233cf9SJ. Bruce Fields 	} else
43688c233cf9SJ. Bruce Fields 		status = -EOPNOTSUPP;
4369029d105eSJ. Bruce Fields 
4370029d105eSJ. Bruce Fields out:
4371029d105eSJ. Bruce Fields 	return status;
4372029d105eSJ. Bruce Fields }
4373029d105eSJ. Bruce Fields 
43741da177e4SLinus Torvalds static int
43751da177e4SLinus Torvalds decode_savefh(struct xdr_stream *xdr)
43761da177e4SLinus Torvalds {
43771da177e4SLinus Torvalds 	return decode_op_hdr(xdr, OP_SAVEFH);
43781da177e4SLinus Torvalds }
43791da177e4SLinus Torvalds 
43809e9ecc03SBenny Halevy static int decode_setattr(struct xdr_stream *xdr)
43811da177e4SLinus Torvalds {
43828687b63aSAl Viro 	__be32 *p;
43831da177e4SLinus Torvalds 	uint32_t bmlen;
43841da177e4SLinus Torvalds 	int status;
43851da177e4SLinus Torvalds 
43861da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_SETATTR);
43871da177e4SLinus Torvalds 	if (status)
43881da177e4SLinus Torvalds 		return status;
4389c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 4);
4390c0eae66eSBenny Halevy 	if (unlikely(!p))
4391c0eae66eSBenny Halevy 		goto out_overflow;
4392cccddf4fSBenny Halevy 	bmlen = be32_to_cpup(p);
4393c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, bmlen << 2);
4394c0eae66eSBenny Halevy 	if (likely(p))
43951da177e4SLinus Torvalds 		return 0;
4396c0eae66eSBenny Halevy out_overflow:
4397c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4398c0eae66eSBenny Halevy 	return -EIO;
43991da177e4SLinus Torvalds }
44001da177e4SLinus Torvalds 
4401adfa6f98SDavid Howells static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp)
44021da177e4SLinus Torvalds {
44038687b63aSAl Viro 	__be32 *p;
44041da177e4SLinus Torvalds 	uint32_t opnum;
44051da177e4SLinus Torvalds 	int32_t nfserr;
44061da177e4SLinus Torvalds 
4407c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
4408c0eae66eSBenny Halevy 	if (unlikely(!p))
4409c0eae66eSBenny Halevy 		goto out_overflow;
44106f723f77SBenny Halevy 	opnum = be32_to_cpup(p++);
44111da177e4SLinus Torvalds 	if (opnum != OP_SETCLIENTID) {
4412fe82a183SChuck Lever 		dprintk("nfs: decode_setclientid: Server returned operation"
44131da177e4SLinus Torvalds 			" %d\n", opnum);
44141da177e4SLinus Torvalds 		return -EIO;
44151da177e4SLinus Torvalds 	}
4416cccddf4fSBenny Halevy 	nfserr = be32_to_cpup(p);
44171da177e4SLinus Torvalds 	if (nfserr == NFS_OK) {
4418c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE);
4419c0eae66eSBenny Halevy 		if (unlikely(!p))
4420c0eae66eSBenny Halevy 			goto out_overflow;
44213ceb4dbbSBenny Halevy 		p = xdr_decode_hyper(p, &clp->cl_clientid);
442299398d06SBenny Halevy 		memcpy(clp->cl_confirm.data, p, NFS4_VERIFIER_SIZE);
44231da177e4SLinus Torvalds 	} else if (nfserr == NFSERR_CLID_INUSE) {
44241da177e4SLinus Torvalds 		uint32_t len;
44251da177e4SLinus Torvalds 
44261da177e4SLinus Torvalds 		/* skip netid string */
4427c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
4428c0eae66eSBenny Halevy 		if (unlikely(!p))
4429c0eae66eSBenny Halevy 			goto out_overflow;
4430cccddf4fSBenny Halevy 		len = be32_to_cpup(p);
4431c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, len);
4432c0eae66eSBenny Halevy 		if (unlikely(!p))
4433c0eae66eSBenny Halevy 			goto out_overflow;
44341da177e4SLinus Torvalds 
44351da177e4SLinus Torvalds 		/* skip uaddr string */
4436c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4);
4437c0eae66eSBenny Halevy 		if (unlikely(!p))
4438c0eae66eSBenny Halevy 			goto out_overflow;
4439cccddf4fSBenny Halevy 		len = be32_to_cpup(p);
4440c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, len);
4441c0eae66eSBenny Halevy 		if (unlikely(!p))
4442c0eae66eSBenny Halevy 			goto out_overflow;
44431da177e4SLinus Torvalds 		return -NFSERR_CLID_INUSE;
44441da177e4SLinus Torvalds 	} else
4445856dff3dSBenny Halevy 		return nfs4_stat_to_errno(nfserr);
44461da177e4SLinus Torvalds 
44471da177e4SLinus Torvalds 	return 0;
4448c0eae66eSBenny Halevy out_overflow:
4449c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4450c0eae66eSBenny Halevy 	return -EIO;
44511da177e4SLinus Torvalds }
44521da177e4SLinus Torvalds 
44531da177e4SLinus Torvalds static int decode_setclientid_confirm(struct xdr_stream *xdr)
44541da177e4SLinus Torvalds {
44551da177e4SLinus Torvalds 	return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM);
44561da177e4SLinus Torvalds }
44571da177e4SLinus Torvalds 
44581da177e4SLinus Torvalds static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
44591da177e4SLinus Torvalds {
44608687b63aSAl Viro 	__be32 *p;
44611da177e4SLinus Torvalds 	int status;
44621da177e4SLinus Torvalds 
44631da177e4SLinus Torvalds 	status = decode_op_hdr(xdr, OP_WRITE);
44641da177e4SLinus Torvalds 	if (status)
44651da177e4SLinus Torvalds 		return status;
44661da177e4SLinus Torvalds 
4467c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 16);
4468c0eae66eSBenny Halevy 	if (unlikely(!p))
4469c0eae66eSBenny Halevy 		goto out_overflow;
44706f723f77SBenny Halevy 	res->count = be32_to_cpup(p++);
44716f723f77SBenny Halevy 	res->verf->committed = be32_to_cpup(p++);
447299398d06SBenny Halevy 	memcpy(res->verf->verifier, p, 8);
44731da177e4SLinus Torvalds 	return 0;
4474c0eae66eSBenny Halevy out_overflow:
4475c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4476c0eae66eSBenny Halevy 	return -EIO;
44771da177e4SLinus Torvalds }
44781da177e4SLinus Torvalds 
44791da177e4SLinus Torvalds static int decode_delegreturn(struct xdr_stream *xdr)
44801da177e4SLinus Torvalds {
44811da177e4SLinus Torvalds 	return decode_op_hdr(xdr, OP_DELEGRETURN);
44821da177e4SLinus Torvalds }
44831da177e4SLinus Torvalds 
448499fe60d0SBenny Halevy #if defined(CONFIG_NFS_V4_1)
448599fe60d0SBenny Halevy static int decode_exchange_id(struct xdr_stream *xdr,
448699fe60d0SBenny Halevy 			      struct nfs41_exchange_id_res *res)
448799fe60d0SBenny Halevy {
448899fe60d0SBenny Halevy 	__be32 *p;
448999fe60d0SBenny Halevy 	uint32_t dummy;
44902460ba57SBenny Halevy 	char *dummy_str;
449199fe60d0SBenny Halevy 	int status;
449299fe60d0SBenny Halevy 	struct nfs_client *clp = res->client;
449399fe60d0SBenny Halevy 
449499fe60d0SBenny Halevy 	status = decode_op_hdr(xdr, OP_EXCHANGE_ID);
449599fe60d0SBenny Halevy 	if (status)
449699fe60d0SBenny Halevy 		return status;
449799fe60d0SBenny Halevy 
4498c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
4499c0eae66eSBenny Halevy 	if (unlikely(!p))
4500c0eae66eSBenny Halevy 		goto out_overflow;
4501cccddf4fSBenny Halevy 	xdr_decode_hyper(p, &clp->cl_ex_clid);
4502c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 12);
4503c0eae66eSBenny Halevy 	if (unlikely(!p))
4504c0eae66eSBenny Halevy 		goto out_overflow;
45056f723f77SBenny Halevy 	clp->cl_seqid = be32_to_cpup(p++);
45066f723f77SBenny Halevy 	clp->cl_exchange_flags = be32_to_cpup(p++);
450799fe60d0SBenny Halevy 
450899fe60d0SBenny Halevy 	/* We ask for SP4_NONE */
4509cccddf4fSBenny Halevy 	dummy = be32_to_cpup(p);
451099fe60d0SBenny Halevy 	if (dummy != SP4_NONE)
451199fe60d0SBenny Halevy 		return -EIO;
451299fe60d0SBenny Halevy 
451399fe60d0SBenny Halevy 	/* Throw away minor_id */
4514c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
4515c0eae66eSBenny Halevy 	if (unlikely(!p))
4516c0eae66eSBenny Halevy 		goto out_overflow;
451799fe60d0SBenny Halevy 
451899fe60d0SBenny Halevy 	/* Throw away Major id */
45192460ba57SBenny Halevy 	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
45202460ba57SBenny Halevy 	if (unlikely(status))
45212460ba57SBenny Halevy 		return status;
452299fe60d0SBenny Halevy 
452399fe60d0SBenny Halevy 	/* Throw away server_scope */
45242460ba57SBenny Halevy 	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
45252460ba57SBenny Halevy 	if (unlikely(status))
45262460ba57SBenny Halevy 		return status;
452799fe60d0SBenny Halevy 
452899fe60d0SBenny Halevy 	/* Throw away Implementation id array */
45292460ba57SBenny Halevy 	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
45302460ba57SBenny Halevy 	if (unlikely(status))
45312460ba57SBenny Halevy 		return status;
453299fe60d0SBenny Halevy 
453399fe60d0SBenny Halevy 	return 0;
4534c0eae66eSBenny Halevy out_overflow:
4535c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4536c0eae66eSBenny Halevy 	return -EIO;
453799fe60d0SBenny Halevy }
4538fc931582SAndy Adamson 
4539fc931582SAndy Adamson static int decode_chan_attrs(struct xdr_stream *xdr,
4540fc931582SAndy Adamson 			     struct nfs4_channel_attrs *attrs)
4541fc931582SAndy Adamson {
4542fc931582SAndy Adamson 	__be32 *p;
4543fc931582SAndy Adamson 	u32 nr_attrs;
4544fc931582SAndy Adamson 
4545c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 28);
4546c0eae66eSBenny Halevy 	if (unlikely(!p))
4547c0eae66eSBenny Halevy 		goto out_overflow;
45486f723f77SBenny Halevy 	attrs->headerpadsz = be32_to_cpup(p++);
45496f723f77SBenny Halevy 	attrs->max_rqst_sz = be32_to_cpup(p++);
45506f723f77SBenny Halevy 	attrs->max_resp_sz = be32_to_cpup(p++);
45516f723f77SBenny Halevy 	attrs->max_resp_sz_cached = be32_to_cpup(p++);
45526f723f77SBenny Halevy 	attrs->max_ops = be32_to_cpup(p++);
45536f723f77SBenny Halevy 	attrs->max_reqs = be32_to_cpup(p++);
4554cccddf4fSBenny Halevy 	nr_attrs = be32_to_cpup(p);
4555fc931582SAndy Adamson 	if (unlikely(nr_attrs > 1)) {
4556fc931582SAndy Adamson 		printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n",
4557fc931582SAndy Adamson 			__func__, nr_attrs);
4558fc931582SAndy Adamson 		return -EINVAL;
4559fc931582SAndy Adamson 	}
4560c0eae66eSBenny Halevy 	if (nr_attrs == 1) {
4561c0eae66eSBenny Halevy 		p = xdr_inline_decode(xdr, 4); /* skip rdma_attrs */
4562c0eae66eSBenny Halevy 		if (unlikely(!p))
4563c0eae66eSBenny Halevy 			goto out_overflow;
4564c0eae66eSBenny Halevy 	}
4565fc931582SAndy Adamson 	return 0;
4566c0eae66eSBenny Halevy out_overflow:
4567c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4568c0eae66eSBenny Halevy 	return -EIO;
4569fc931582SAndy Adamson }
4570fc931582SAndy Adamson 
4571e78291e4SBenny Halevy static int decode_sessionid(struct xdr_stream *xdr, struct nfs4_sessionid *sid)
4572e78291e4SBenny Halevy {
4573e78291e4SBenny Halevy 	return decode_opaque_fixed(xdr, sid->data, NFS4_MAX_SESSIONID_LEN);
4574fc931582SAndy Adamson }
4575fc931582SAndy Adamson 
4576fc931582SAndy Adamson static int decode_create_session(struct xdr_stream *xdr,
4577fc931582SAndy Adamson 				 struct nfs41_create_session_res *res)
4578fc931582SAndy Adamson {
4579fc931582SAndy Adamson 	__be32 *p;
4580fc931582SAndy Adamson 	int status;
4581fc931582SAndy Adamson 	struct nfs_client *clp = res->client;
4582fc931582SAndy Adamson 	struct nfs4_session *session = clp->cl_session;
4583fc931582SAndy Adamson 
4584fc931582SAndy Adamson 	status = decode_op_hdr(xdr, OP_CREATE_SESSION);
4585e78291e4SBenny Halevy 	if (!status)
4586e78291e4SBenny Halevy 		status = decode_sessionid(xdr, &session->sess_id);
4587e78291e4SBenny Halevy 	if (unlikely(status))
4588fc931582SAndy Adamson 		return status;
4589fc931582SAndy Adamson 
4590fc931582SAndy Adamson 	/* seqid, flags */
4591c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 8);
4592c0eae66eSBenny Halevy 	if (unlikely(!p))
4593c0eae66eSBenny Halevy 		goto out_overflow;
45946f723f77SBenny Halevy 	clp->cl_seqid = be32_to_cpup(p++);
4595cccddf4fSBenny Halevy 	session->flags = be32_to_cpup(p);
4596fc931582SAndy Adamson 
4597fc931582SAndy Adamson 	/* Channel attributes */
4598fc931582SAndy Adamson 	status = decode_chan_attrs(xdr, &session->fc_attrs);
4599fc931582SAndy Adamson 	if (!status)
4600fc931582SAndy Adamson 		status = decode_chan_attrs(xdr, &session->bc_attrs);
4601fc931582SAndy Adamson 	return status;
4602c0eae66eSBenny Halevy out_overflow:
4603c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4604c0eae66eSBenny Halevy 	return -EIO;
4605fc931582SAndy Adamson }
46060f3e66c6SAndy Adamson 
46070f3e66c6SAndy Adamson static int decode_destroy_session(struct xdr_stream *xdr, void *dummy)
46080f3e66c6SAndy Adamson {
46090f3e66c6SAndy Adamson 	return decode_op_hdr(xdr, OP_DESTROY_SESSION);
46100f3e66c6SAndy Adamson }
461118019753SRicardo Labiaga 
461218019753SRicardo Labiaga static int decode_reclaim_complete(struct xdr_stream *xdr, void *dummy)
461318019753SRicardo Labiaga {
461418019753SRicardo Labiaga 	return decode_op_hdr(xdr, OP_RECLAIM_COMPLETE);
461518019753SRicardo Labiaga }
461699fe60d0SBenny Halevy #endif /* CONFIG_NFS_V4_1 */
461799fe60d0SBenny Halevy 
46189b7b9fccSAndy Adamson static int decode_sequence(struct xdr_stream *xdr,
46199b7b9fccSAndy Adamson 			   struct nfs4_sequence_res *res,
46209b7b9fccSAndy Adamson 			   struct rpc_rqst *rqstp)
46219b7b9fccSAndy Adamson {
46229b7b9fccSAndy Adamson #if defined(CONFIG_NFS_V4_1)
4623fc01cea9SAndy Adamson 	struct nfs4_slot *slot;
4624fc01cea9SAndy Adamson 	struct nfs4_sessionid id;
4625fc01cea9SAndy Adamson 	u32 dummy;
4626fc01cea9SAndy Adamson 	int status;
4627fc01cea9SAndy Adamson 	__be32 *p;
4628fc01cea9SAndy Adamson 
46299b7b9fccSAndy Adamson 	if (!res->sr_session)
46309b7b9fccSAndy Adamson 		return 0;
46319b7b9fccSAndy Adamson 
4632fc01cea9SAndy Adamson 	status = decode_op_hdr(xdr, OP_SEQUENCE);
4633e78291e4SBenny Halevy 	if (!status)
4634e78291e4SBenny Halevy 		status = decode_sessionid(xdr, &id);
4635e78291e4SBenny Halevy 	if (unlikely(status))
4636fc01cea9SAndy Adamson 		goto out_err;
46379b7b9fccSAndy Adamson 
4638fc01cea9SAndy Adamson 	/*
4639fc01cea9SAndy Adamson 	 * If the server returns different values for sessionID, slotID or
4640fc01cea9SAndy Adamson 	 * sequence number, the server is looney tunes.
4641fc01cea9SAndy Adamson 	 */
4642fdcb4577STrond Myklebust 	status = -EREMOTEIO;
4643fc01cea9SAndy Adamson 
4644fc01cea9SAndy Adamson 	if (memcmp(id.data, res->sr_session->sess_id.data,
4645fc01cea9SAndy Adamson 		   NFS4_MAX_SESSIONID_LEN)) {
4646fc01cea9SAndy Adamson 		dprintk("%s Invalid session id\n", __func__);
4647fc01cea9SAndy Adamson 		goto out_err;
4648fc01cea9SAndy Adamson 	}
4649e78291e4SBenny Halevy 
4650c0eae66eSBenny Halevy 	p = xdr_inline_decode(xdr, 20);
4651c0eae66eSBenny Halevy 	if (unlikely(!p))
4652c0eae66eSBenny Halevy 		goto out_overflow;
4653e78291e4SBenny Halevy 
4654fc01cea9SAndy Adamson 	/* seqid */
4655e78291e4SBenny Halevy 	slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid];
46566f723f77SBenny Halevy 	dummy = be32_to_cpup(p++);
4657fc01cea9SAndy Adamson 	if (dummy != slot->seq_nr) {
4658fc01cea9SAndy Adamson 		dprintk("%s Invalid sequence number\n", __func__);
4659fc01cea9SAndy Adamson 		goto out_err;
4660fc01cea9SAndy Adamson 	}
4661fc01cea9SAndy Adamson 	/* slot id */
46626f723f77SBenny Halevy 	dummy = be32_to_cpup(p++);
4663fc01cea9SAndy Adamson 	if (dummy != res->sr_slotid) {
4664fc01cea9SAndy Adamson 		dprintk("%s Invalid slot id\n", __func__);
4665fc01cea9SAndy Adamson 		goto out_err;
4666fc01cea9SAndy Adamson 	}
4667fc01cea9SAndy Adamson 	/* highest slot id - currently not processed */
46686f723f77SBenny Halevy 	dummy = be32_to_cpup(p++);
4669fc01cea9SAndy Adamson 	/* target highest slot id - currently not processed */
46706f723f77SBenny Halevy 	dummy = be32_to_cpup(p++);
46710629e370SAlexandros Batsakis 	/* result flags */
46720629e370SAlexandros Batsakis 	res->sr_status_flags = be32_to_cpup(p);
4673fc01cea9SAndy Adamson 	status = 0;
4674fc01cea9SAndy Adamson out_err:
4675fc01cea9SAndy Adamson 	res->sr_status = status;
4676fc01cea9SAndy Adamson 	return status;
4677c0eae66eSBenny Halevy out_overflow:
4678c0eae66eSBenny Halevy 	print_overflow_msg(__func__, xdr);
4679c0eae66eSBenny Halevy 	status = -EIO;
4680c0eae66eSBenny Halevy 	goto out_err;
4681fc01cea9SAndy Adamson #else  /* CONFIG_NFS_V4_1 */
46829b7b9fccSAndy Adamson 	return 0;
4683fc01cea9SAndy Adamson #endif /* CONFIG_NFS_V4_1 */
46849b7b9fccSAndy Adamson }
46859b7b9fccSAndy Adamson 
46861da177e4SLinus Torvalds /*
468749c2559eSBenny Halevy  * END OF "GENERIC" DECODE ROUTINES.
468849c2559eSBenny Halevy  */
468949c2559eSBenny Halevy 
469049c2559eSBenny Halevy /*
46911da177e4SLinus Torvalds  * Decode OPEN_DOWNGRADE response
46921da177e4SLinus Torvalds  */
46938687b63aSAl Viro static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
46941da177e4SLinus Torvalds {
46951da177e4SLinus Torvalds 	struct xdr_stream xdr;
46961da177e4SLinus Torvalds 	struct compound_hdr hdr;
46971da177e4SLinus Torvalds 	int status;
46981da177e4SLinus Torvalds 
46991da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
47001da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
47011da177e4SLinus Torvalds 	if (status)
47021da177e4SLinus Torvalds 		goto out;
47039b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
47049b7b9fccSAndy Adamson 	if (status)
47059b7b9fccSAndy Adamson 		goto out;
47061da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
47071da177e4SLinus Torvalds 	if (status)
47081da177e4SLinus Torvalds 		goto out;
47091da177e4SLinus Torvalds 	status = decode_open_downgrade(&xdr, res);
4710516a6af6STrond Myklebust 	if (status != 0)
4711516a6af6STrond Myklebust 		goto out;
471280e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->fattr, res->server,
471380e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
47141da177e4SLinus Torvalds out:
47151da177e4SLinus Torvalds 	return status;
47161da177e4SLinus Torvalds }
47171da177e4SLinus Torvalds 
47181da177e4SLinus Torvalds /*
47191da177e4SLinus Torvalds  * Decode ACCESS response
47201da177e4SLinus Torvalds  */
47218687b63aSAl Viro static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res)
47221da177e4SLinus Torvalds {
47231da177e4SLinus Torvalds 	struct xdr_stream xdr;
47241da177e4SLinus Torvalds 	struct compound_hdr hdr;
47251da177e4SLinus Torvalds 	int status;
47261da177e4SLinus Torvalds 
47271da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
47289b7b9fccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
47299b7b9fccSAndy Adamson 	if (status)
47309b7b9fccSAndy Adamson 		goto out;
47319b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
47329b7b9fccSAndy Adamson 	if (status)
47331da177e4SLinus Torvalds 		goto out;
473476b32999STrond Myklebust 	status = decode_putfh(&xdr);
473576b32999STrond Myklebust 	if (status != 0)
473676b32999STrond Myklebust 		goto out;
47371da177e4SLinus Torvalds 	status = decode_access(&xdr, res);
473876b32999STrond Myklebust 	if (status != 0)
473976b32999STrond Myklebust 		goto out;
474080e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->fattr, res->server,
474180e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
47421da177e4SLinus Torvalds out:
47431da177e4SLinus Torvalds 	return status;
47441da177e4SLinus Torvalds }
47451da177e4SLinus Torvalds 
47461da177e4SLinus Torvalds /*
47471da177e4SLinus Torvalds  * Decode LOOKUP response
47481da177e4SLinus Torvalds  */
47498687b63aSAl Viro static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
47501da177e4SLinus Torvalds {
47511da177e4SLinus Torvalds 	struct xdr_stream xdr;
47521da177e4SLinus Torvalds 	struct compound_hdr hdr;
47531da177e4SLinus Torvalds 	int status;
47541da177e4SLinus Torvalds 
47551da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
47569b7b9fccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
47579b7b9fccSAndy Adamson 	if (status)
47589b7b9fccSAndy Adamson 		goto out;
47599b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
47609b7b9fccSAndy Adamson 	if (status)
47611da177e4SLinus Torvalds 		goto out;
47621da177e4SLinus Torvalds 	if ((status = decode_putfh(&xdr)) != 0)
47631da177e4SLinus Torvalds 		goto out;
47641da177e4SLinus Torvalds 	if ((status = decode_lookup(&xdr)) != 0)
47651da177e4SLinus Torvalds 		goto out;
47661da177e4SLinus Torvalds 	if ((status = decode_getfh(&xdr, res->fh)) != 0)
47671da177e4SLinus Torvalds 		goto out;
476880e52aceSTrond Myklebust 	status = decode_getfattr(&xdr, res->fattr, res->server
476980e52aceSTrond Myklebust 			,!RPC_IS_ASYNC(rqstp->rq_task));
47701da177e4SLinus Torvalds out:
47711da177e4SLinus Torvalds 	return status;
47721da177e4SLinus Torvalds }
47731da177e4SLinus Torvalds 
47741da177e4SLinus Torvalds /*
47751da177e4SLinus Torvalds  * Decode LOOKUP_ROOT response
47761da177e4SLinus Torvalds  */
47778687b63aSAl Viro static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
47781da177e4SLinus Torvalds {
47791da177e4SLinus Torvalds 	struct xdr_stream xdr;
47801da177e4SLinus Torvalds 	struct compound_hdr hdr;
47811da177e4SLinus Torvalds 	int status;
47821da177e4SLinus Torvalds 
47831da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
47849b7b9fccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
47859b7b9fccSAndy Adamson 	if (status)
47869b7b9fccSAndy Adamson 		goto out;
47879b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
47889b7b9fccSAndy Adamson 	if (status)
47891da177e4SLinus Torvalds 		goto out;
47901da177e4SLinus Torvalds 	if ((status = decode_putrootfh(&xdr)) != 0)
47911da177e4SLinus Torvalds 		goto out;
47921da177e4SLinus Torvalds 	if ((status = decode_getfh(&xdr, res->fh)) == 0)
479380e52aceSTrond Myklebust 		status = decode_getfattr(&xdr, res->fattr, res->server,
479480e52aceSTrond Myklebust 				!RPC_IS_ASYNC(rqstp->rq_task));
47951da177e4SLinus Torvalds out:
47961da177e4SLinus Torvalds 	return status;
47971da177e4SLinus Torvalds }
47981da177e4SLinus Torvalds 
47991da177e4SLinus Torvalds /*
48001da177e4SLinus Torvalds  * Decode REMOVE response
48011da177e4SLinus Torvalds  */
48024fdc17b2STrond Myklebust static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_removeres *res)
48031da177e4SLinus Torvalds {
48041da177e4SLinus Torvalds 	struct xdr_stream xdr;
48051da177e4SLinus Torvalds 	struct compound_hdr hdr;
48061da177e4SLinus Torvalds 	int status;
48071da177e4SLinus Torvalds 
48081da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
48099b7b9fccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
48109b7b9fccSAndy Adamson 	if (status)
48119b7b9fccSAndy Adamson 		goto out;
48129b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
48139b7b9fccSAndy Adamson 	if (status)
48141da177e4SLinus Torvalds 		goto out;
481516e42959STrond Myklebust 	if ((status = decode_putfh(&xdr)) != 0)
481616e42959STrond Myklebust 		goto out;
481716e42959STrond Myklebust 	if ((status = decode_remove(&xdr, &res->cinfo)) != 0)
481816e42959STrond Myklebust 		goto out;
481980e52aceSTrond Myklebust 	decode_getfattr(&xdr, &res->dir_attr, res->server,
482080e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
48211da177e4SLinus Torvalds out:
48221da177e4SLinus Torvalds 	return status;
48231da177e4SLinus Torvalds }
48241da177e4SLinus Torvalds 
48251da177e4SLinus Torvalds /*
48261da177e4SLinus Torvalds  * Decode RENAME response
48271da177e4SLinus Torvalds  */
48288687b63aSAl Viro static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res)
48291da177e4SLinus Torvalds {
48301da177e4SLinus Torvalds 	struct xdr_stream xdr;
48311da177e4SLinus Torvalds 	struct compound_hdr hdr;
48321da177e4SLinus Torvalds 	int status;
48331da177e4SLinus Torvalds 
48341da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
48359b7b9fccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
48369b7b9fccSAndy Adamson 	if (status)
48379b7b9fccSAndy Adamson 		goto out;
48389b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
48399b7b9fccSAndy Adamson 	if (status)
48401da177e4SLinus Torvalds 		goto out;
48411da177e4SLinus Torvalds 	if ((status = decode_putfh(&xdr)) != 0)
48421da177e4SLinus Torvalds 		goto out;
48431da177e4SLinus Torvalds 	if ((status = decode_savefh(&xdr)) != 0)
48441da177e4SLinus Torvalds 		goto out;
48451da177e4SLinus Torvalds 	if ((status = decode_putfh(&xdr)) != 0)
48461da177e4SLinus Torvalds 		goto out;
48476caf2c82STrond Myklebust 	if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0)
48486caf2c82STrond Myklebust 		goto out;
48496caf2c82STrond Myklebust 	/* Current FH is target directory */
485080e52aceSTrond Myklebust 	if (decode_getfattr(&xdr, res->new_fattr, res->server,
485180e52aceSTrond Myklebust 				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
48526caf2c82STrond Myklebust 		goto out;
48536caf2c82STrond Myklebust 	if ((status = decode_restorefh(&xdr)) != 0)
48546caf2c82STrond Myklebust 		goto out;
485580e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->old_fattr, res->server,
485680e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
48571da177e4SLinus Torvalds out:
48581da177e4SLinus Torvalds 	return status;
48591da177e4SLinus Torvalds }
48601da177e4SLinus Torvalds 
48611da177e4SLinus Torvalds /*
48621da177e4SLinus Torvalds  * Decode LINK response
48631da177e4SLinus Torvalds  */
48648687b63aSAl Viro static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link_res *res)
48651da177e4SLinus Torvalds {
48661da177e4SLinus Torvalds 	struct xdr_stream xdr;
48671da177e4SLinus Torvalds 	struct compound_hdr hdr;
48681da177e4SLinus Torvalds 	int status;
48691da177e4SLinus Torvalds 
48701da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
48719b7b9fccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
48729b7b9fccSAndy Adamson 	if (status)
48739b7b9fccSAndy Adamson 		goto out;
48749b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
48759b7b9fccSAndy Adamson 	if (status)
48761da177e4SLinus Torvalds 		goto out;
48771da177e4SLinus Torvalds 	if ((status = decode_putfh(&xdr)) != 0)
48781da177e4SLinus Torvalds 		goto out;
48791da177e4SLinus Torvalds 	if ((status = decode_savefh(&xdr)) != 0)
48801da177e4SLinus Torvalds 		goto out;
48811da177e4SLinus Torvalds 	if ((status = decode_putfh(&xdr)) != 0)
48821da177e4SLinus Torvalds 		goto out;
488391ba2eeeSTrond Myklebust 	if ((status = decode_link(&xdr, &res->cinfo)) != 0)
488491ba2eeeSTrond Myklebust 		goto out;
488591ba2eeeSTrond Myklebust 	/*
488691ba2eeeSTrond Myklebust 	 * Note order: OP_LINK leaves the directory as the current
488791ba2eeeSTrond Myklebust 	 *             filehandle.
488891ba2eeeSTrond Myklebust 	 */
488980e52aceSTrond Myklebust 	if (decode_getfattr(&xdr, res->dir_attr, res->server,
489080e52aceSTrond Myklebust 				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
489191ba2eeeSTrond Myklebust 		goto out;
489291ba2eeeSTrond Myklebust 	if ((status = decode_restorefh(&xdr)) != 0)
489391ba2eeeSTrond Myklebust 		goto out;
489480e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->fattr, res->server,
489580e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
48961da177e4SLinus Torvalds out:
48971da177e4SLinus Torvalds 	return status;
48981da177e4SLinus Torvalds }
48991da177e4SLinus Torvalds 
49001da177e4SLinus Torvalds /*
49011da177e4SLinus Torvalds  * Decode CREATE response
49021da177e4SLinus Torvalds  */
49038687b63aSAl Viro static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
49041da177e4SLinus Torvalds {
49051da177e4SLinus Torvalds 	struct xdr_stream xdr;
49061da177e4SLinus Torvalds 	struct compound_hdr hdr;
49071da177e4SLinus Torvalds 	int status;
49081da177e4SLinus Torvalds 
49091da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
49109b7b9fccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
49119b7b9fccSAndy Adamson 	if (status)
49129b7b9fccSAndy Adamson 		goto out;
49139b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
49149b7b9fccSAndy Adamson 	if (status)
49151da177e4SLinus Torvalds 		goto out;
49161da177e4SLinus Torvalds 	if ((status = decode_putfh(&xdr)) != 0)
49171da177e4SLinus Torvalds 		goto out;
491856ae19f3STrond Myklebust 	if ((status = decode_savefh(&xdr)) != 0)
491956ae19f3STrond Myklebust 		goto out;
49201da177e4SLinus Torvalds 	if ((status = decode_create(&xdr,&res->dir_cinfo)) != 0)
49211da177e4SLinus Torvalds 		goto out;
49221da177e4SLinus Torvalds 	if ((status = decode_getfh(&xdr, res->fh)) != 0)
49231da177e4SLinus Torvalds 		goto out;
492480e52aceSTrond Myklebust 	if (decode_getfattr(&xdr, res->fattr, res->server,
492580e52aceSTrond Myklebust 				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
492656ae19f3STrond Myklebust 		goto out;
492756ae19f3STrond Myklebust 	if ((status = decode_restorefh(&xdr)) != 0)
492856ae19f3STrond Myklebust 		goto out;
492980e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->dir_fattr, res->server,
493080e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
49311da177e4SLinus Torvalds out:
49321da177e4SLinus Torvalds 	return status;
49331da177e4SLinus Torvalds }
49341da177e4SLinus Torvalds 
49351da177e4SLinus Torvalds /*
49361da177e4SLinus Torvalds  * Decode SYMLINK response
49371da177e4SLinus Torvalds  */
49388687b63aSAl Viro static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
49391da177e4SLinus Torvalds {
49401da177e4SLinus Torvalds 	return nfs4_xdr_dec_create(rqstp, p, res);
49411da177e4SLinus Torvalds }
49421da177e4SLinus Torvalds 
49431da177e4SLinus Torvalds /*
49441da177e4SLinus Torvalds  * Decode GETATTR response
49451da177e4SLinus Torvalds  */
49468687b63aSAl Viro static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_getattr_res *res)
49471da177e4SLinus Torvalds {
49481da177e4SLinus Torvalds 	struct xdr_stream xdr;
49491da177e4SLinus Torvalds 	struct compound_hdr hdr;
49501da177e4SLinus Torvalds 	int status;
49511da177e4SLinus Torvalds 
49521da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
49531da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
49541da177e4SLinus Torvalds 	if (status)
49551da177e4SLinus Torvalds 		goto out;
49569b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
49579b7b9fccSAndy Adamson 	if (status)
49589b7b9fccSAndy Adamson 		goto out;
49591da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
49601da177e4SLinus Torvalds 	if (status)
49611da177e4SLinus Torvalds 		goto out;
496280e52aceSTrond Myklebust 	status = decode_getfattr(&xdr, res->fattr, res->server,
496380e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
49641da177e4SLinus Torvalds out:
49651da177e4SLinus Torvalds 	return status;
49661da177e4SLinus Torvalds }
49671da177e4SLinus Torvalds 
496823ec6965SJ. Bruce Fields /*
496923ec6965SJ. Bruce Fields  * Encode an SETACL request
497023ec6965SJ. Bruce Fields  */
497123ec6965SJ. Bruce Fields static int
49728687b63aSAl Viro nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args)
497323ec6965SJ. Bruce Fields {
497423ec6965SJ. Bruce Fields 	struct xdr_stream xdr;
497523ec6965SJ. Bruce Fields 	struct compound_hdr hdr = {
497666cc0429SBenny Halevy 		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
497723ec6965SJ. Bruce Fields 	};
497823ec6965SJ. Bruce Fields 	int status;
497923ec6965SJ. Bruce Fields 
498023ec6965SJ. Bruce Fields 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
49810c4e8c18SBenny Halevy 	encode_compound_hdr(&xdr, req, &hdr);
49829b7b9fccSAndy Adamson 	encode_sequence(&xdr, &args->seq_args, &hdr);
4983cf8cdbe5SAndy Adamson 	encode_putfh(&xdr, args->fh, &hdr);
4984d017931cSAndy Adamson 	status = encode_setacl(&xdr, args, &hdr);
4985d017931cSAndy Adamson 	encode_nops(&hdr);
498623ec6965SJ. Bruce Fields 	return status;
498723ec6965SJ. Bruce Fields }
498805d564feSAndy Adamson 
498923ec6965SJ. Bruce Fields /*
499023ec6965SJ. Bruce Fields  * Decode SETACL response
499123ec6965SJ. Bruce Fields  */
499223ec6965SJ. Bruce Fields static int
499373c403a9SBenny Halevy nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p,
499473c403a9SBenny Halevy 		    struct nfs_setaclres *res)
499523ec6965SJ. Bruce Fields {
499623ec6965SJ. Bruce Fields 	struct xdr_stream xdr;
499723ec6965SJ. Bruce Fields 	struct compound_hdr hdr;
499823ec6965SJ. Bruce Fields 	int status;
499923ec6965SJ. Bruce Fields 
500023ec6965SJ. Bruce Fields 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
500123ec6965SJ. Bruce Fields 	status = decode_compound_hdr(&xdr, &hdr);
500223ec6965SJ. Bruce Fields 	if (status)
500323ec6965SJ. Bruce Fields 		goto out;
50049b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
50059b7b9fccSAndy Adamson 	if (status)
50069b7b9fccSAndy Adamson 		goto out;
500723ec6965SJ. Bruce Fields 	status = decode_putfh(&xdr);
500823ec6965SJ. Bruce Fields 	if (status)
500923ec6965SJ. Bruce Fields 		goto out;
50109e9ecc03SBenny Halevy 	status = decode_setattr(&xdr);
501123ec6965SJ. Bruce Fields out:
501223ec6965SJ. Bruce Fields 	return status;
501323ec6965SJ. Bruce Fields }
50141da177e4SLinus Torvalds 
50151da177e4SLinus Torvalds /*
5016029d105eSJ. Bruce Fields  * Decode GETACL response
5017029d105eSJ. Bruce Fields  */
5018029d105eSJ. Bruce Fields static int
5019663c79b3SBenny Halevy nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p,
5020663c79b3SBenny Halevy 		    struct nfs_getaclres *res)
5021029d105eSJ. Bruce Fields {
5022029d105eSJ. Bruce Fields 	struct xdr_stream xdr;
5023029d105eSJ. Bruce Fields 	struct compound_hdr hdr;
5024029d105eSJ. Bruce Fields 	int status;
5025029d105eSJ. Bruce Fields 
5026029d105eSJ. Bruce Fields 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
5027029d105eSJ. Bruce Fields 	status = decode_compound_hdr(&xdr, &hdr);
5028029d105eSJ. Bruce Fields 	if (status)
5029029d105eSJ. Bruce Fields 		goto out;
50309b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
50319b7b9fccSAndy Adamson 	if (status)
50329b7b9fccSAndy Adamson 		goto out;
5033029d105eSJ. Bruce Fields 	status = decode_putfh(&xdr);
5034029d105eSJ. Bruce Fields 	if (status)
5035029d105eSJ. Bruce Fields 		goto out;
5036663c79b3SBenny Halevy 	status = decode_getacl(&xdr, rqstp, &res->acl_len);
5037029d105eSJ. Bruce Fields 
5038029d105eSJ. Bruce Fields out:
5039029d105eSJ. Bruce Fields 	return status;
5040029d105eSJ. Bruce Fields }
5041029d105eSJ. Bruce Fields 
5042029d105eSJ. Bruce Fields /*
50431da177e4SLinus Torvalds  * Decode CLOSE response
50441da177e4SLinus Torvalds  */
50458687b63aSAl Viro static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
50461da177e4SLinus Torvalds {
50471da177e4SLinus Torvalds 	struct xdr_stream xdr;
50481da177e4SLinus Torvalds 	struct compound_hdr hdr;
50491da177e4SLinus Torvalds 	int status;
50501da177e4SLinus Torvalds 
50511da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
50521da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
50531da177e4SLinus Torvalds 	if (status)
50541da177e4SLinus Torvalds 		goto out;
50559b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
50569b7b9fccSAndy Adamson 	if (status)
50579b7b9fccSAndy Adamson 		goto out;
50581da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
50591da177e4SLinus Torvalds 	if (status)
50601da177e4SLinus Torvalds 		goto out;
50611da177e4SLinus Torvalds 	status = decode_close(&xdr, res);
5062516a6af6STrond Myklebust 	if (status != 0)
5063516a6af6STrond Myklebust 		goto out;
5064516a6af6STrond Myklebust 	/*
5065516a6af6STrond Myklebust 	 * Note: Server may do delete on close for this file
5066516a6af6STrond Myklebust 	 * 	in which case the getattr call will fail with
5067516a6af6STrond Myklebust 	 * 	an ESTALE error. Shouldn't be a problem,
5068516a6af6STrond Myklebust 	 * 	though, since fattr->valid will remain unset.
5069516a6af6STrond Myklebust 	 */
507080e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->fattr, res->server,
507180e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
50721da177e4SLinus Torvalds out:
50731da177e4SLinus Torvalds 	return status;
50741da177e4SLinus Torvalds }
50751da177e4SLinus Torvalds 
50761da177e4SLinus Torvalds /*
50771da177e4SLinus Torvalds  * Decode OPEN response
50781da177e4SLinus Torvalds  */
50798687b63aSAl Viro static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
50801da177e4SLinus Torvalds {
50811da177e4SLinus Torvalds 	struct xdr_stream xdr;
50821da177e4SLinus Torvalds 	struct compound_hdr hdr;
50831da177e4SLinus Torvalds 	int status;
50841da177e4SLinus Torvalds 
50851da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
50861da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
50871da177e4SLinus Torvalds 	if (status)
50881da177e4SLinus Torvalds 		goto out;
50899b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
50909b7b9fccSAndy Adamson 	if (status)
50919b7b9fccSAndy Adamson 		goto out;
50921da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
50931da177e4SLinus Torvalds 	if (status)
50941da177e4SLinus Torvalds 		goto out;
509556ae19f3STrond Myklebust 	status = decode_savefh(&xdr);
509656ae19f3STrond Myklebust 	if (status)
509756ae19f3STrond Myklebust 		goto out;
50981da177e4SLinus Torvalds 	status = decode_open(&xdr, res);
50991da177e4SLinus Torvalds 	if (status)
51001da177e4SLinus Torvalds 		goto out;
51019936781dSTrond Myklebust 	if (decode_getfh(&xdr, &res->fh) != 0)
51021da177e4SLinus Torvalds 		goto out;
510380e52aceSTrond Myklebust 	if (decode_getfattr(&xdr, res->f_attr, res->server,
510480e52aceSTrond Myklebust 				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
510556ae19f3STrond Myklebust 		goto out;
5106365c8f58STrond Myklebust 	if (decode_restorefh(&xdr) != 0)
510756ae19f3STrond Myklebust 		goto out;
510880e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->dir_attr, res->server,
510980e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
51101da177e4SLinus Torvalds out:
51111da177e4SLinus Torvalds 	return status;
51121da177e4SLinus Torvalds }
51131da177e4SLinus Torvalds 
51141da177e4SLinus Torvalds /*
51151da177e4SLinus Torvalds  * Decode OPEN_CONFIRM response
51161da177e4SLinus Torvalds  */
51178687b63aSAl Viro static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, __be32 *p, struct nfs_open_confirmres *res)
51181da177e4SLinus Torvalds {
51191da177e4SLinus Torvalds 	struct xdr_stream xdr;
51201da177e4SLinus Torvalds 	struct compound_hdr hdr;
51211da177e4SLinus Torvalds 	int status;
51221da177e4SLinus Torvalds 
51231da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
51241da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
51251da177e4SLinus Torvalds 	if (status)
51261da177e4SLinus Torvalds 		goto out;
51271da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
51281da177e4SLinus Torvalds 	if (status)
51291da177e4SLinus Torvalds 		goto out;
51301da177e4SLinus Torvalds 	status = decode_open_confirm(&xdr, res);
51311da177e4SLinus Torvalds out:
51321da177e4SLinus Torvalds 	return status;
51331da177e4SLinus Torvalds }
51341da177e4SLinus Torvalds 
51351da177e4SLinus Torvalds /*
51361da177e4SLinus Torvalds  * Decode OPEN response
51371da177e4SLinus Torvalds  */
51388687b63aSAl Viro static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
51391da177e4SLinus Torvalds {
51401da177e4SLinus Torvalds 	struct xdr_stream xdr;
51411da177e4SLinus Torvalds 	struct compound_hdr hdr;
51421da177e4SLinus Torvalds 	int status;
51431da177e4SLinus Torvalds 
51441da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
51451da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
51461da177e4SLinus Torvalds 	if (status)
51471da177e4SLinus Torvalds 		goto out;
51489b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
51499b7b9fccSAndy Adamson 	if (status)
51509b7b9fccSAndy Adamson 		goto out;
51511da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
51521da177e4SLinus Torvalds 	if (status)
51531da177e4SLinus Torvalds 		goto out;
51541da177e4SLinus Torvalds 	status = decode_open(&xdr, res);
5155864472e9STrond Myklebust 	if (status)
5156864472e9STrond Myklebust 		goto out;
515780e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->f_attr, res->server,
515880e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
51591da177e4SLinus Torvalds out:
51601da177e4SLinus Torvalds 	return status;
51611da177e4SLinus Torvalds }
51621da177e4SLinus Torvalds 
51631da177e4SLinus Torvalds /*
51641da177e4SLinus Torvalds  * Decode SETATTR response
51651da177e4SLinus Torvalds  */
51668687b63aSAl Viro static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res)
51671da177e4SLinus Torvalds {
51681da177e4SLinus Torvalds 	struct xdr_stream xdr;
51691da177e4SLinus Torvalds 	struct compound_hdr hdr;
51701da177e4SLinus Torvalds 	int status;
51711da177e4SLinus Torvalds 
51721da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
51731da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
51741da177e4SLinus Torvalds 	if (status)
51751da177e4SLinus Torvalds 		goto out;
51769b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
51779b7b9fccSAndy Adamson 	if (status)
51789b7b9fccSAndy Adamson 		goto out;
51791da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
51801da177e4SLinus Torvalds 	if (status)
51811da177e4SLinus Torvalds 		goto out;
51829e9ecc03SBenny Halevy 	status = decode_setattr(&xdr);
51831da177e4SLinus Torvalds 	if (status)
51841da177e4SLinus Torvalds 		goto out;
518580e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->fattr, res->server,
518680e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
51871da177e4SLinus Torvalds out:
51881da177e4SLinus Torvalds 	return status;
51891da177e4SLinus Torvalds }
51901da177e4SLinus Torvalds 
51911da177e4SLinus Torvalds /*
51921da177e4SLinus Torvalds  * Decode LOCK response
51931da177e4SLinus Torvalds  */
51948687b63aSAl Viro static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_res *res)
51951da177e4SLinus Torvalds {
51961da177e4SLinus Torvalds 	struct xdr_stream xdr;
51971da177e4SLinus Torvalds 	struct compound_hdr hdr;
51981da177e4SLinus Torvalds 	int status;
51991da177e4SLinus Torvalds 
52001da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
52011da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
52021da177e4SLinus Torvalds 	if (status)
52031da177e4SLinus Torvalds 		goto out;
52049b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
52059b7b9fccSAndy Adamson 	if (status)
52069b7b9fccSAndy Adamson 		goto out;
52071da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
52081da177e4SLinus Torvalds 	if (status)
52091da177e4SLinus Torvalds 		goto out;
52101da177e4SLinus Torvalds 	status = decode_lock(&xdr, res);
52111da177e4SLinus Torvalds out:
52121da177e4SLinus Torvalds 	return status;
52131da177e4SLinus Torvalds }
52141da177e4SLinus Torvalds 
52151da177e4SLinus Torvalds /*
52161da177e4SLinus Torvalds  * Decode LOCKT response
52171da177e4SLinus Torvalds  */
52188687b63aSAl Viro static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lockt_res *res)
52191da177e4SLinus Torvalds {
52201da177e4SLinus Torvalds 	struct xdr_stream xdr;
52211da177e4SLinus Torvalds 	struct compound_hdr hdr;
52221da177e4SLinus Torvalds 	int status;
52231da177e4SLinus Torvalds 
52241da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
52251da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
52261da177e4SLinus Torvalds 	if (status)
52271da177e4SLinus Torvalds 		goto out;
52289b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
52299b7b9fccSAndy Adamson 	if (status)
52309b7b9fccSAndy Adamson 		goto out;
52311da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
52321da177e4SLinus Torvalds 	if (status)
52331da177e4SLinus Torvalds 		goto out;
52341da177e4SLinus Torvalds 	status = decode_lockt(&xdr, res);
52351da177e4SLinus Torvalds out:
52361da177e4SLinus Torvalds 	return status;
52371da177e4SLinus Torvalds }
52381da177e4SLinus Torvalds 
52391da177e4SLinus Torvalds /*
52401da177e4SLinus Torvalds  * Decode LOCKU response
52411da177e4SLinus Torvalds  */
52428687b63aSAl Viro static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_locku_res *res)
52431da177e4SLinus Torvalds {
52441da177e4SLinus Torvalds 	struct xdr_stream xdr;
52451da177e4SLinus Torvalds 	struct compound_hdr hdr;
52461da177e4SLinus Torvalds 	int status;
52471da177e4SLinus Torvalds 
52481da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
52491da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
52501da177e4SLinus Torvalds 	if (status)
52511da177e4SLinus Torvalds 		goto out;
52529b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
52539b7b9fccSAndy Adamson 	if (status)
52549b7b9fccSAndy Adamson 		goto out;
52551da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
52561da177e4SLinus Torvalds 	if (status)
52571da177e4SLinus Torvalds 		goto out;
52581da177e4SLinus Torvalds 	status = decode_locku(&xdr, res);
52591da177e4SLinus Torvalds out:
52601da177e4SLinus Torvalds 	return status;
52611da177e4SLinus Torvalds }
52621da177e4SLinus Torvalds 
52631da177e4SLinus Torvalds /*
52641da177e4SLinus Torvalds  * Decode READLINK response
52651da177e4SLinus Torvalds  */
5266f50c7000SBenny Halevy static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p,
5267f50c7000SBenny Halevy 				 struct nfs4_readlink_res *res)
52681da177e4SLinus Torvalds {
52691da177e4SLinus Torvalds 	struct xdr_stream xdr;
52701da177e4SLinus Torvalds 	struct compound_hdr hdr;
52711da177e4SLinus Torvalds 	int status;
52721da177e4SLinus Torvalds 
52731da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
52741da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
52751da177e4SLinus Torvalds 	if (status)
52761da177e4SLinus Torvalds 		goto out;
52779b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
52789b7b9fccSAndy Adamson 	if (status)
52799b7b9fccSAndy Adamson 		goto out;
52801da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
52811da177e4SLinus Torvalds 	if (status)
52821da177e4SLinus Torvalds 		goto out;
52831da177e4SLinus Torvalds 	status = decode_readlink(&xdr, rqstp);
52841da177e4SLinus Torvalds out:
52851da177e4SLinus Torvalds 	return status;
52861da177e4SLinus Torvalds }
52871da177e4SLinus Torvalds 
52881da177e4SLinus Torvalds /*
52891da177e4SLinus Torvalds  * Decode READDIR response
52901da177e4SLinus Torvalds  */
52918687b63aSAl Viro static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_readdir_res *res)
52921da177e4SLinus Torvalds {
52931da177e4SLinus Torvalds 	struct xdr_stream xdr;
52941da177e4SLinus Torvalds 	struct compound_hdr hdr;
52951da177e4SLinus Torvalds 	int status;
52961da177e4SLinus Torvalds 
52971da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
52981da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
52991da177e4SLinus Torvalds 	if (status)
53001da177e4SLinus Torvalds 		goto out;
53019b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
53029b7b9fccSAndy Adamson 	if (status)
53039b7b9fccSAndy Adamson 		goto out;
53041da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
53051da177e4SLinus Torvalds 	if (status)
53061da177e4SLinus Torvalds 		goto out;
53071da177e4SLinus Torvalds 	status = decode_readdir(&xdr, rqstp, res);
53081da177e4SLinus Torvalds out:
53091da177e4SLinus Torvalds 	return status;
53101da177e4SLinus Torvalds }
53111da177e4SLinus Torvalds 
53121da177e4SLinus Torvalds /*
53131da177e4SLinus Torvalds  * Decode Read response
53141da177e4SLinus Torvalds  */
53158687b63aSAl Viro static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readres *res)
53161da177e4SLinus Torvalds {
53171da177e4SLinus Torvalds 	struct xdr_stream xdr;
53181da177e4SLinus Torvalds 	struct compound_hdr hdr;
53191da177e4SLinus Torvalds 	int status;
53201da177e4SLinus Torvalds 
53211da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
53221da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
53231da177e4SLinus Torvalds 	if (status)
53241da177e4SLinus Torvalds 		goto out;
53259b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
53269b7b9fccSAndy Adamson 	if (status)
53279b7b9fccSAndy Adamson 		goto out;
53281da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
53291da177e4SLinus Torvalds 	if (status)
53301da177e4SLinus Torvalds 		goto out;
53311da177e4SLinus Torvalds 	status = decode_read(&xdr, rqstp, res);
53321da177e4SLinus Torvalds 	if (!status)
53331da177e4SLinus Torvalds 		status = res->count;
53341da177e4SLinus Torvalds out:
53351da177e4SLinus Torvalds 	return status;
53361da177e4SLinus Torvalds }
53371da177e4SLinus Torvalds 
53381da177e4SLinus Torvalds /*
53391da177e4SLinus Torvalds  * Decode WRITE response
53401da177e4SLinus Torvalds  */
53418687b63aSAl Viro static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
53421da177e4SLinus Torvalds {
53431da177e4SLinus Torvalds 	struct xdr_stream xdr;
53441da177e4SLinus Torvalds 	struct compound_hdr hdr;
53451da177e4SLinus Torvalds 	int status;
53461da177e4SLinus Torvalds 
53471da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
53481da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
53491da177e4SLinus Torvalds 	if (status)
53501da177e4SLinus Torvalds 		goto out;
53519b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
53529b7b9fccSAndy Adamson 	if (status)
53539b7b9fccSAndy Adamson 		goto out;
53541da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
53551da177e4SLinus Torvalds 	if (status)
53561da177e4SLinus Torvalds 		goto out;
53571da177e4SLinus Torvalds 	status = decode_write(&xdr, res);
53584f9838c7STrond Myklebust 	if (status)
53594f9838c7STrond Myklebust 		goto out;
536080e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->fattr, res->server,
536180e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
53621da177e4SLinus Torvalds 	if (!status)
53631da177e4SLinus Torvalds 		status = res->count;
53641da177e4SLinus Torvalds out:
53651da177e4SLinus Torvalds 	return status;
53661da177e4SLinus Torvalds }
53671da177e4SLinus Torvalds 
53681da177e4SLinus Torvalds /*
53691da177e4SLinus Torvalds  * Decode COMMIT response
53701da177e4SLinus Torvalds  */
53718687b63aSAl Viro static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
53721da177e4SLinus Torvalds {
53731da177e4SLinus Torvalds 	struct xdr_stream xdr;
53741da177e4SLinus Torvalds 	struct compound_hdr hdr;
53751da177e4SLinus Torvalds 	int status;
53761da177e4SLinus Torvalds 
53771da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
53781da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
53791da177e4SLinus Torvalds 	if (status)
53801da177e4SLinus Torvalds 		goto out;
53819b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
53829b7b9fccSAndy Adamson 	if (status)
53839b7b9fccSAndy Adamson 		goto out;
53841da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
53851da177e4SLinus Torvalds 	if (status)
53861da177e4SLinus Torvalds 		goto out;
53871da177e4SLinus Torvalds 	status = decode_commit(&xdr, res);
53884f9838c7STrond Myklebust 	if (status)
53894f9838c7STrond Myklebust 		goto out;
539080e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->fattr, res->server,
539180e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
53921da177e4SLinus Torvalds out:
53931da177e4SLinus Torvalds 	return status;
53941da177e4SLinus Torvalds }
53951da177e4SLinus Torvalds 
53961da177e4SLinus Torvalds /*
53978b173218SRicardo Labiaga  * Decode FSINFO response
53981da177e4SLinus Torvalds  */
53993dda5e43SBenny Halevy static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p,
54003dda5e43SBenny Halevy 			       struct nfs4_fsinfo_res *res)
54011da177e4SLinus Torvalds {
54021da177e4SLinus Torvalds 	struct xdr_stream xdr;
54031da177e4SLinus Torvalds 	struct compound_hdr hdr;
54041da177e4SLinus Torvalds 	int status;
54051da177e4SLinus Torvalds 
54061da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
54071da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
54081da177e4SLinus Torvalds 	if (!status)
54099b7b9fccSAndy Adamson 		status = decode_sequence(&xdr, &res->seq_res, req);
54109b7b9fccSAndy Adamson 	if (!status)
54111da177e4SLinus Torvalds 		status = decode_putfh(&xdr);
54121da177e4SLinus Torvalds 	if (!status)
54133dda5e43SBenny Halevy 		status = decode_fsinfo(&xdr, res->fsinfo);
54141da177e4SLinus Torvalds 	return status;
54151da177e4SLinus Torvalds }
54161da177e4SLinus Torvalds 
54171da177e4SLinus Torvalds /*
54188b173218SRicardo Labiaga  * Decode PATHCONF response
54191da177e4SLinus Torvalds  */
5420d45b2989SBenny Halevy static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p,
5421d45b2989SBenny Halevy 				 struct nfs4_pathconf_res *res)
54221da177e4SLinus Torvalds {
54231da177e4SLinus Torvalds 	struct xdr_stream xdr;
54241da177e4SLinus Torvalds 	struct compound_hdr hdr;
54251da177e4SLinus Torvalds 	int status;
54261da177e4SLinus Torvalds 
54271da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
54281da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
54291da177e4SLinus Torvalds 	if (!status)
54309b7b9fccSAndy Adamson 		status = decode_sequence(&xdr, &res->seq_res, req);
54319b7b9fccSAndy Adamson 	if (!status)
54321da177e4SLinus Torvalds 		status = decode_putfh(&xdr);
54331da177e4SLinus Torvalds 	if (!status)
5434d45b2989SBenny Halevy 		status = decode_pathconf(&xdr, res->pathconf);
54351da177e4SLinus Torvalds 	return status;
54361da177e4SLinus Torvalds }
54371da177e4SLinus Torvalds 
54381da177e4SLinus Torvalds /*
54398b173218SRicardo Labiaga  * Decode STATFS response
54401da177e4SLinus Torvalds  */
544124ad148aSBenny Halevy static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p,
544224ad148aSBenny Halevy 			       struct nfs4_statfs_res *res)
54431da177e4SLinus Torvalds {
54441da177e4SLinus Torvalds 	struct xdr_stream xdr;
54451da177e4SLinus Torvalds 	struct compound_hdr hdr;
54461da177e4SLinus Torvalds 	int status;
54471da177e4SLinus Torvalds 
54481da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
54491da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
54501da177e4SLinus Torvalds 	if (!status)
54519b7b9fccSAndy Adamson 		status = decode_sequence(&xdr, &res->seq_res, req);
54529b7b9fccSAndy Adamson 	if (!status)
54531da177e4SLinus Torvalds 		status = decode_putfh(&xdr);
54541da177e4SLinus Torvalds 	if (!status)
545524ad148aSBenny Halevy 		status = decode_statfs(&xdr, res->fsstat);
54561da177e4SLinus Torvalds 	return status;
54571da177e4SLinus Torvalds }
54581da177e4SLinus Torvalds 
54591da177e4SLinus Torvalds /*
54608b173218SRicardo Labiaga  * Decode GETATTR_BITMAP response
54611da177e4SLinus Torvalds  */
54628687b63aSAl Viro static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4_server_caps_res *res)
54631da177e4SLinus Torvalds {
54641da177e4SLinus Torvalds 	struct xdr_stream xdr;
54651da177e4SLinus Torvalds 	struct compound_hdr hdr;
54661da177e4SLinus Torvalds 	int status;
54671da177e4SLinus Torvalds 
54681da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
54699b7b9fccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
54709b7b9fccSAndy Adamson 	if (status)
54719b7b9fccSAndy Adamson 		goto out;
54729b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, req);
54739b7b9fccSAndy Adamson 	if (status)
54741da177e4SLinus Torvalds 		goto out;
54751da177e4SLinus Torvalds 	if ((status = decode_putfh(&xdr)) != 0)
54761da177e4SLinus Torvalds 		goto out;
54771da177e4SLinus Torvalds 	status = decode_server_caps(&xdr, res);
54781da177e4SLinus Torvalds out:
54791da177e4SLinus Torvalds 	return status;
54801da177e4SLinus Torvalds }
54811da177e4SLinus Torvalds 
54821da177e4SLinus Torvalds /*
54831da177e4SLinus Torvalds  * Decode RENEW response
54841da177e4SLinus Torvalds  */
54858687b63aSAl Viro static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy)
54861da177e4SLinus Torvalds {
54871da177e4SLinus Torvalds 	struct xdr_stream xdr;
54881da177e4SLinus Torvalds 	struct compound_hdr hdr;
54891da177e4SLinus Torvalds 	int status;
54901da177e4SLinus Torvalds 
54911da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
54921da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
54931da177e4SLinus Torvalds 	if (!status)
54941da177e4SLinus Torvalds 		status = decode_renew(&xdr);
54951da177e4SLinus Torvalds 	return status;
54961da177e4SLinus Torvalds }
54971da177e4SLinus Torvalds 
54981da177e4SLinus Torvalds /*
54998b173218SRicardo Labiaga  * Decode SETCLIENTID response
55001da177e4SLinus Torvalds  */
55018687b63aSAl Viro static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p,
5502adfa6f98SDavid Howells 		struct nfs_client *clp)
55031da177e4SLinus Torvalds {
55041da177e4SLinus Torvalds 	struct xdr_stream xdr;
55051da177e4SLinus Torvalds 	struct compound_hdr hdr;
55061da177e4SLinus Torvalds 	int status;
55071da177e4SLinus Torvalds 
55081da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
55091da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
55101da177e4SLinus Torvalds 	if (!status)
55111da177e4SLinus Torvalds 		status = decode_setclientid(&xdr, clp);
55121da177e4SLinus Torvalds 	return status;
55131da177e4SLinus Torvalds }
55141da177e4SLinus Torvalds 
55151da177e4SLinus Torvalds /*
55168b173218SRicardo Labiaga  * Decode SETCLIENTID_CONFIRM response
55171da177e4SLinus Torvalds  */
55188687b63aSAl Viro static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
55191da177e4SLinus Torvalds {
55201da177e4SLinus Torvalds 	struct xdr_stream xdr;
55211da177e4SLinus Torvalds 	struct compound_hdr hdr;
55221da177e4SLinus Torvalds 	int status;
55231da177e4SLinus Torvalds 
55241da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
55251da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
55261da177e4SLinus Torvalds 	if (!status)
55271da177e4SLinus Torvalds 		status = decode_setclientid_confirm(&xdr);
55281da177e4SLinus Torvalds 	if (!status)
55291da177e4SLinus Torvalds 		status = decode_putrootfh(&xdr);
55301da177e4SLinus Torvalds 	if (!status)
55311da177e4SLinus Torvalds 		status = decode_fsinfo(&xdr, fsinfo);
55321da177e4SLinus Torvalds 	return status;
55331da177e4SLinus Torvalds }
55341da177e4SLinus Torvalds 
55351da177e4SLinus Torvalds /*
55368b173218SRicardo Labiaga  * Decode DELEGRETURN response
55371da177e4SLinus Torvalds  */
55388687b63aSAl Viro static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_delegreturnres *res)
55391da177e4SLinus Torvalds {
55401da177e4SLinus Torvalds 	struct xdr_stream xdr;
55411da177e4SLinus Torvalds 	struct compound_hdr hdr;
55421da177e4SLinus Torvalds 	int status;
55431da177e4SLinus Torvalds 
55441da177e4SLinus Torvalds 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
55451da177e4SLinus Torvalds 	status = decode_compound_hdr(&xdr, &hdr);
55469b7b9fccSAndy Adamson 	if (status)
55479b7b9fccSAndy Adamson 		goto out;
55489b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, rqstp);
55499b7b9fccSAndy Adamson 	if (status)
5550fa178f29STrond Myklebust 		goto out;
55511da177e4SLinus Torvalds 	status = decode_putfh(&xdr);
5552fa178f29STrond Myklebust 	if (status != 0)
5553fa178f29STrond Myklebust 		goto out;
55541da177e4SLinus Torvalds 	status = decode_delegreturn(&xdr);
5555556ae3bbSJeff Layton 	if (status != 0)
5556556ae3bbSJeff Layton 		goto out;
555780e52aceSTrond Myklebust 	decode_getfattr(&xdr, res->fattr, res->server,
555880e52aceSTrond Myklebust 			!RPC_IS_ASYNC(rqstp->rq_task));
5559fa178f29STrond Myklebust out:
55601da177e4SLinus Torvalds 	return status;
55611da177e4SLinus Torvalds }
55621da177e4SLinus Torvalds 
5563683b57b4STrond Myklebust /*
55648b173218SRicardo Labiaga  * Decode FS_LOCATIONS response
5565683b57b4STrond Myklebust  */
556622958463SBenny Halevy static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p,
556722958463SBenny Halevy 				     struct nfs4_fs_locations_res *res)
5568683b57b4STrond Myklebust {
5569683b57b4STrond Myklebust 	struct xdr_stream xdr;
5570683b57b4STrond Myklebust 	struct compound_hdr hdr;
5571683b57b4STrond Myklebust 	int status;
5572683b57b4STrond Myklebust 
5573683b57b4STrond Myklebust 	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
5574683b57b4STrond Myklebust 	status = decode_compound_hdr(&xdr, &hdr);
55759b7b9fccSAndy Adamson 	if (status)
55769b7b9fccSAndy Adamson 		goto out;
55779b7b9fccSAndy Adamson 	status = decode_sequence(&xdr, &res->seq_res, req);
55789b7b9fccSAndy Adamson 	if (status)
5579683b57b4STrond Myklebust 		goto out;
5580683b57b4STrond Myklebust 	if ((status = decode_putfh(&xdr)) != 0)
5581683b57b4STrond Myklebust 		goto out;
5582683b57b4STrond Myklebust 	if ((status = decode_lookup(&xdr)) != 0)
5583683b57b4STrond Myklebust 		goto out;
5584683b57b4STrond Myklebust 	xdr_enter_page(&xdr, PAGE_SIZE);
558522958463SBenny Halevy 	status = decode_getfattr(&xdr, &res->fs_locations->fattr,
558680e52aceSTrond Myklebust 				 res->fs_locations->server,
558780e52aceSTrond Myklebust 				 !RPC_IS_ASYNC(req->rq_task));
5588683b57b4STrond Myklebust out:
5589683b57b4STrond Myklebust 	return status;
5590683b57b4STrond Myklebust }
5591683b57b4STrond Myklebust 
559299fe60d0SBenny Halevy #if defined(CONFIG_NFS_V4_1)
559399fe60d0SBenny Halevy /*
55948b173218SRicardo Labiaga  * Decode EXCHANGE_ID response
559599fe60d0SBenny Halevy  */
559699fe60d0SBenny Halevy static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp, uint32_t *p,
559799fe60d0SBenny Halevy 				    void *res)
559899fe60d0SBenny Halevy {
559999fe60d0SBenny Halevy 	struct xdr_stream xdr;
560099fe60d0SBenny Halevy 	struct compound_hdr hdr;
560199fe60d0SBenny Halevy 	int status;
560299fe60d0SBenny Halevy 
560399fe60d0SBenny Halevy 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
560499fe60d0SBenny Halevy 	status = decode_compound_hdr(&xdr, &hdr);
560599fe60d0SBenny Halevy 	if (!status)
560699fe60d0SBenny Halevy 		status = decode_exchange_id(&xdr, res);
560799fe60d0SBenny Halevy 	return status;
560899fe60d0SBenny Halevy }
56092050f0ccSAndy Adamson 
56102050f0ccSAndy Adamson /*
56118b173218SRicardo Labiaga  * Decode CREATE_SESSION response
5612fc931582SAndy Adamson  */
5613fc931582SAndy Adamson static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp, uint32_t *p,
5614fc931582SAndy Adamson 				       struct nfs41_create_session_res *res)
5615fc931582SAndy Adamson {
5616fc931582SAndy Adamson 	struct xdr_stream xdr;
5617fc931582SAndy Adamson 	struct compound_hdr hdr;
5618fc931582SAndy Adamson 	int status;
5619fc931582SAndy Adamson 
5620fc931582SAndy Adamson 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
5621fc931582SAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
5622fc931582SAndy Adamson 	if (!status)
5623fc931582SAndy Adamson 		status = decode_create_session(&xdr, res);
5624fc931582SAndy Adamson 	return status;
5625fc931582SAndy Adamson }
5626fc931582SAndy Adamson 
5627fc931582SAndy Adamson /*
56288b173218SRicardo Labiaga  * Decode DESTROY_SESSION response
56290f3e66c6SAndy Adamson  */
56300f3e66c6SAndy Adamson static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp, uint32_t *p,
56310f3e66c6SAndy Adamson 					void *dummy)
56320f3e66c6SAndy Adamson {
56330f3e66c6SAndy Adamson 	struct xdr_stream xdr;
56340f3e66c6SAndy Adamson 	struct compound_hdr hdr;
56350f3e66c6SAndy Adamson 	int status;
56360f3e66c6SAndy Adamson 
56370f3e66c6SAndy Adamson 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
56380f3e66c6SAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
56390f3e66c6SAndy Adamson 	if (!status)
56400f3e66c6SAndy Adamson 		status = decode_destroy_session(&xdr, dummy);
56410f3e66c6SAndy Adamson 	return status;
56420f3e66c6SAndy Adamson }
56430f3e66c6SAndy Adamson 
56440f3e66c6SAndy Adamson /*
56458b173218SRicardo Labiaga  * Decode SEQUENCE response
5646fc01cea9SAndy Adamson  */
5647fc01cea9SAndy Adamson static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp, uint32_t *p,
5648fc01cea9SAndy Adamson 				 struct nfs4_sequence_res *res)
5649fc01cea9SAndy Adamson {
5650fc01cea9SAndy Adamson 	struct xdr_stream xdr;
5651fc01cea9SAndy Adamson 	struct compound_hdr hdr;
5652fc01cea9SAndy Adamson 	int status;
5653fc01cea9SAndy Adamson 
5654fc01cea9SAndy Adamson 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
5655fc01cea9SAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
5656fc01cea9SAndy Adamson 	if (!status)
5657fc01cea9SAndy Adamson 		status = decode_sequence(&xdr, res, rqstp);
5658fc01cea9SAndy Adamson 	return status;
5659fc01cea9SAndy Adamson }
5660fc01cea9SAndy Adamson 
5661fc01cea9SAndy Adamson /*
56628b173218SRicardo Labiaga  * Decode GET_LEASE_TIME response
56632050f0ccSAndy Adamson  */
56642050f0ccSAndy Adamson static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p,
56652050f0ccSAndy Adamson 				       struct nfs4_get_lease_time_res *res)
56662050f0ccSAndy Adamson {
56672050f0ccSAndy Adamson 	struct xdr_stream xdr;
56682050f0ccSAndy Adamson 	struct compound_hdr hdr;
56692050f0ccSAndy Adamson 	int status;
56702050f0ccSAndy Adamson 
56712050f0ccSAndy Adamson 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
56722050f0ccSAndy Adamson 	status = decode_compound_hdr(&xdr, &hdr);
56732050f0ccSAndy Adamson 	if (!status)
56742050f0ccSAndy Adamson 		status = decode_sequence(&xdr, &res->lr_seq_res, rqstp);
56752050f0ccSAndy Adamson 	if (!status)
56762050f0ccSAndy Adamson 		status = decode_putrootfh(&xdr);
56772050f0ccSAndy Adamson 	if (!status)
56782050f0ccSAndy Adamson 		status = decode_fsinfo(&xdr, res->lr_fsinfo);
56792050f0ccSAndy Adamson 	return status;
56802050f0ccSAndy Adamson }
568118019753SRicardo Labiaga 
568218019753SRicardo Labiaga /*
568318019753SRicardo Labiaga  * Decode RECLAIM_COMPLETE response
568418019753SRicardo Labiaga  */
568518019753SRicardo Labiaga static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp, uint32_t *p,
568618019753SRicardo Labiaga 					 struct nfs41_reclaim_complete_res *res)
568718019753SRicardo Labiaga {
568818019753SRicardo Labiaga 	struct xdr_stream xdr;
568918019753SRicardo Labiaga 	struct compound_hdr hdr;
569018019753SRicardo Labiaga 	int status;
569118019753SRicardo Labiaga 
569218019753SRicardo Labiaga 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
569318019753SRicardo Labiaga 	status = decode_compound_hdr(&xdr, &hdr);
569418019753SRicardo Labiaga 	if (!status)
569518019753SRicardo Labiaga 		status = decode_sequence(&xdr, &res->seq_res, rqstp);
569618019753SRicardo Labiaga 	if (!status)
569718019753SRicardo Labiaga 		status = decode_reclaim_complete(&xdr, (void *)NULL);
569818019753SRicardo Labiaga 	return status;
569918019753SRicardo Labiaga }
570099fe60d0SBenny Halevy #endif /* CONFIG_NFS_V4_1 */
570199fe60d0SBenny Halevy 
57020dbb4c67SAl Viro __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
57031da177e4SLinus Torvalds {
57041da177e4SLinus Torvalds 	uint32_t bitmap[2] = {0};
57051da177e4SLinus Torvalds 	uint32_t len;
57061da177e4SLinus Torvalds 
57071da177e4SLinus Torvalds 	if (!*p++) {
57081da177e4SLinus Torvalds 		if (!*p)
57091da177e4SLinus Torvalds 			return ERR_PTR(-EAGAIN);
57101da177e4SLinus Torvalds 		entry->eof = 1;
57111da177e4SLinus Torvalds 		return ERR_PTR(-EBADCOOKIE);
57121da177e4SLinus Torvalds 	}
57131da177e4SLinus Torvalds 
57141da177e4SLinus Torvalds 	entry->prev_cookie = entry->cookie;
57151da177e4SLinus Torvalds 	p = xdr_decode_hyper(p, &entry->cookie);
57161da177e4SLinus Torvalds 	entry->len = ntohl(*p++);
57171da177e4SLinus Torvalds 	entry->name = (const char *) p;
57181da177e4SLinus Torvalds 	p += XDR_QUADLEN(entry->len);
57191da177e4SLinus Torvalds 
57201da177e4SLinus Torvalds 	/*
57211da177e4SLinus Torvalds 	 * In case the server doesn't return an inode number,
57221da177e4SLinus Torvalds 	 * we fake one here.  (We don't use inode number 0,
57231da177e4SLinus Torvalds 	 * since glibc seems to choke on it...)
57241da177e4SLinus Torvalds 	 */
57251da177e4SLinus Torvalds 	entry->ino = 1;
57261da177e4SLinus Torvalds 
57271da177e4SLinus Torvalds 	len = ntohl(*p++);		/* bitmap length */
57281da177e4SLinus Torvalds 	if (len-- > 0) {
57291da177e4SLinus Torvalds 		bitmap[0] = ntohl(*p++);
57301da177e4SLinus Torvalds 		if (len-- > 0) {
57311da177e4SLinus Torvalds 			bitmap[1] = ntohl(*p++);
57321da177e4SLinus Torvalds 			p += len;
57331da177e4SLinus Torvalds 		}
57341da177e4SLinus Torvalds 	}
57351da177e4SLinus Torvalds 	len = XDR_QUADLEN(ntohl(*p++));	/* attribute buffer length */
57361da177e4SLinus Torvalds 	if (len > 0) {
573797d312d0SManoj Naik 		if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) {
573897d312d0SManoj Naik 			bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR;
573997d312d0SManoj Naik 			/* Ignore the return value of rdattr_error for now */
574097d312d0SManoj Naik 			p++;
574197d312d0SManoj Naik 			len--;
574297d312d0SManoj Naik 		}
57431da177e4SLinus Torvalds 		if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID)
57441da177e4SLinus Torvalds 			xdr_decode_hyper(p, &entry->ino);
57451da177e4SLinus Torvalds 		else if (bitmap[0] == FATTR4_WORD0_FILEID)
57461da177e4SLinus Torvalds 			xdr_decode_hyper(p, &entry->ino);
57471da177e4SLinus Torvalds 		p += len;
57481da177e4SLinus Torvalds 	}
57491da177e4SLinus Torvalds 
57501da177e4SLinus Torvalds 	entry->eof = !p[0] && p[1];
57511da177e4SLinus Torvalds 	return p;
57521da177e4SLinus Torvalds }
57531da177e4SLinus Torvalds 
57541da177e4SLinus Torvalds /*
57551da177e4SLinus Torvalds  * We need to translate between nfs status return values and
57561da177e4SLinus Torvalds  * the local errno values which may not be the same.
57571da177e4SLinus Torvalds  */
57581da177e4SLinus Torvalds static struct {
57591da177e4SLinus Torvalds 	int stat;
57601da177e4SLinus Torvalds 	int errno;
57611da177e4SLinus Torvalds } nfs_errtbl[] = {
57621da177e4SLinus Torvalds 	{ NFS4_OK,		0		},
5763856dff3dSBenny Halevy 	{ NFS4ERR_PERM,		-EPERM		},
5764856dff3dSBenny Halevy 	{ NFS4ERR_NOENT,	-ENOENT		},
5765856dff3dSBenny Halevy 	{ NFS4ERR_IO,		-errno_NFSERR_IO},
5766856dff3dSBenny Halevy 	{ NFS4ERR_NXIO,		-ENXIO		},
5767856dff3dSBenny Halevy 	{ NFS4ERR_ACCESS,	-EACCES		},
5768856dff3dSBenny Halevy 	{ NFS4ERR_EXIST,	-EEXIST		},
5769856dff3dSBenny Halevy 	{ NFS4ERR_XDEV,		-EXDEV		},
5770856dff3dSBenny Halevy 	{ NFS4ERR_NOTDIR,	-ENOTDIR	},
5771856dff3dSBenny Halevy 	{ NFS4ERR_ISDIR,	-EISDIR		},
5772856dff3dSBenny Halevy 	{ NFS4ERR_INVAL,	-EINVAL		},
5773856dff3dSBenny Halevy 	{ NFS4ERR_FBIG,		-EFBIG		},
5774856dff3dSBenny Halevy 	{ NFS4ERR_NOSPC,	-ENOSPC		},
5775856dff3dSBenny Halevy 	{ NFS4ERR_ROFS,		-EROFS		},
5776856dff3dSBenny Halevy 	{ NFS4ERR_MLINK,	-EMLINK		},
5777856dff3dSBenny Halevy 	{ NFS4ERR_NAMETOOLONG,	-ENAMETOOLONG	},
5778856dff3dSBenny Halevy 	{ NFS4ERR_NOTEMPTY,	-ENOTEMPTY	},
5779856dff3dSBenny Halevy 	{ NFS4ERR_DQUOT,	-EDQUOT		},
5780856dff3dSBenny Halevy 	{ NFS4ERR_STALE,	-ESTALE		},
5781856dff3dSBenny Halevy 	{ NFS4ERR_BADHANDLE,	-EBADHANDLE	},
5782856dff3dSBenny Halevy 	{ NFS4ERR_BADOWNER,	-EINVAL		},
5783856dff3dSBenny Halevy 	{ NFS4ERR_BADNAME,	-EINVAL		},
5784856dff3dSBenny Halevy 	{ NFS4ERR_BAD_COOKIE,	-EBADCOOKIE	},
5785856dff3dSBenny Halevy 	{ NFS4ERR_NOTSUPP,	-ENOTSUPP	},
5786856dff3dSBenny Halevy 	{ NFS4ERR_TOOSMALL,	-ETOOSMALL	},
5787fdcb4577STrond Myklebust 	{ NFS4ERR_SERVERFAULT,	-EREMOTEIO	},
5788856dff3dSBenny Halevy 	{ NFS4ERR_BADTYPE,	-EBADTYPE	},
5789856dff3dSBenny Halevy 	{ NFS4ERR_LOCKED,	-EAGAIN		},
5790856dff3dSBenny Halevy 	{ NFS4ERR_SYMLINK,	-ELOOP		},
5791856dff3dSBenny Halevy 	{ NFS4ERR_OP_ILLEGAL,	-EOPNOTSUPP	},
5792856dff3dSBenny Halevy 	{ NFS4ERR_DEADLOCK,	-EDEADLK	},
5793856dff3dSBenny Halevy 	{ NFS4ERR_WRONGSEC,	-EPERM		}, /* FIXME: this needs
57941da177e4SLinus Torvalds 						    * to be handled by a
57951da177e4SLinus Torvalds 						    * middle-layer.
57961da177e4SLinus Torvalds 						    */
5797856dff3dSBenny Halevy 	{ -1,			-EIO		}
57981da177e4SLinus Torvalds };
57991da177e4SLinus Torvalds 
58001da177e4SLinus Torvalds /*
58011da177e4SLinus Torvalds  * Convert an NFS error code to a local one.
58021da177e4SLinus Torvalds  * This one is used jointly by NFSv2 and NFSv3.
58031da177e4SLinus Torvalds  */
58041da177e4SLinus Torvalds static int
58050a8ea437SDavid Howells nfs4_stat_to_errno(int stat)
58061da177e4SLinus Torvalds {
58071da177e4SLinus Torvalds 	int i;
58081da177e4SLinus Torvalds 	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
58091da177e4SLinus Torvalds 		if (nfs_errtbl[i].stat == stat)
58101da177e4SLinus Torvalds 			return nfs_errtbl[i].errno;
58111da177e4SLinus Torvalds 	}
58121da177e4SLinus Torvalds 	if (stat <= 10000 || stat > 10100) {
58131da177e4SLinus Torvalds 		/* The server is looney tunes. */
5814fdcb4577STrond Myklebust 		return -EREMOTEIO;
58151da177e4SLinus Torvalds 	}
58161da177e4SLinus Torvalds 	/* If we cannot translate the error, the recovery routines should
58171da177e4SLinus Torvalds 	 * handle it.
58181da177e4SLinus Torvalds 	 * Note: remaining NFSv4 error codes have values > 10000, so should
58191da177e4SLinus Torvalds 	 * not conflict with native Linux error codes.
58201da177e4SLinus Torvalds 	 */
5821856dff3dSBenny Halevy 	return -stat;
58221da177e4SLinus Torvalds }
58231da177e4SLinus Torvalds 
58241da177e4SLinus Torvalds #define PROC(proc, argtype, restype)				\
58251da177e4SLinus Torvalds [NFSPROC4_CLNT_##proc] = {					\
58261da177e4SLinus Torvalds 	.p_proc   = NFSPROC4_COMPOUND,				\
58271da177e4SLinus Torvalds 	.p_encode = (kxdrproc_t) nfs4_xdr_##argtype,		\
58281da177e4SLinus Torvalds 	.p_decode = (kxdrproc_t) nfs4_xdr_##restype,		\
58292bea90d4SChuck Lever 	.p_arglen = NFS4_##argtype##_sz,			\
58302bea90d4SChuck Lever 	.p_replen = NFS4_##restype##_sz,			\
5831cc0175c1SChuck Lever 	.p_statidx = NFSPROC4_CLNT_##proc,			\
5832cc0175c1SChuck Lever 	.p_name   = #proc,					\
58331da177e4SLinus Torvalds }
58341da177e4SLinus Torvalds 
58351da177e4SLinus Torvalds struct rpc_procinfo	nfs4_procedures[] = {
58361da177e4SLinus Torvalds   PROC(READ,		enc_read,	dec_read),
58371da177e4SLinus Torvalds   PROC(WRITE,		enc_write,	dec_write),
58381da177e4SLinus Torvalds   PROC(COMMIT,		enc_commit,	dec_commit),
58391da177e4SLinus Torvalds   PROC(OPEN,		enc_open,	dec_open),
58401da177e4SLinus Torvalds   PROC(OPEN_CONFIRM,	enc_open_confirm,	dec_open_confirm),
58411da177e4SLinus Torvalds   PROC(OPEN_NOATTR,	enc_open_noattr,	dec_open_noattr),
58421da177e4SLinus Torvalds   PROC(OPEN_DOWNGRADE,	enc_open_downgrade,	dec_open_downgrade),
58431da177e4SLinus Torvalds   PROC(CLOSE,		enc_close,	dec_close),
58441da177e4SLinus Torvalds   PROC(SETATTR,		enc_setattr,	dec_setattr),
58451da177e4SLinus Torvalds   PROC(FSINFO,		enc_fsinfo,	dec_fsinfo),
58461da177e4SLinus Torvalds   PROC(RENEW,		enc_renew,	dec_renew),
58471da177e4SLinus Torvalds   PROC(SETCLIENTID,	enc_setclientid,	dec_setclientid),
58481da177e4SLinus Torvalds   PROC(SETCLIENTID_CONFIRM,	enc_setclientid_confirm,	dec_setclientid_confirm),
58491da177e4SLinus Torvalds   PROC(LOCK,            enc_lock,       dec_lock),
58501da177e4SLinus Torvalds   PROC(LOCKT,           enc_lockt,      dec_lockt),
58511da177e4SLinus Torvalds   PROC(LOCKU,           enc_locku,      dec_locku),
58521da177e4SLinus Torvalds   PROC(ACCESS,		enc_access,	dec_access),
58531da177e4SLinus Torvalds   PROC(GETATTR,		enc_getattr,	dec_getattr),
58541da177e4SLinus Torvalds   PROC(LOOKUP,		enc_lookup,	dec_lookup),
58551da177e4SLinus Torvalds   PROC(LOOKUP_ROOT,	enc_lookup_root,	dec_lookup_root),
58561da177e4SLinus Torvalds   PROC(REMOVE,		enc_remove,	dec_remove),
58571da177e4SLinus Torvalds   PROC(RENAME,		enc_rename,	dec_rename),
58581da177e4SLinus Torvalds   PROC(LINK,		enc_link,	dec_link),
58591da177e4SLinus Torvalds   PROC(SYMLINK,		enc_symlink,	dec_symlink),
58601da177e4SLinus Torvalds   PROC(CREATE,		enc_create,	dec_create),
58611da177e4SLinus Torvalds   PROC(PATHCONF,	enc_pathconf,	dec_pathconf),
58621da177e4SLinus Torvalds   PROC(STATFS,		enc_statfs,	dec_statfs),
58631da177e4SLinus Torvalds   PROC(READLINK,	enc_readlink,	dec_readlink),
58641da177e4SLinus Torvalds   PROC(READDIR,		enc_readdir,	dec_readdir),
58651da177e4SLinus Torvalds   PROC(SERVER_CAPS,	enc_server_caps, dec_server_caps),
58661da177e4SLinus Torvalds   PROC(DELEGRETURN,	enc_delegreturn, dec_delegreturn),
5867029d105eSJ. Bruce Fields   PROC(GETACL,		enc_getacl,	dec_getacl),
586823ec6965SJ. Bruce Fields   PROC(SETACL,		enc_setacl,	dec_setacl),
5869683b57b4STrond Myklebust   PROC(FS_LOCATIONS,	enc_fs_locations, dec_fs_locations),
587099fe60d0SBenny Halevy #if defined(CONFIG_NFS_V4_1)
587199fe60d0SBenny Halevy   PROC(EXCHANGE_ID,	enc_exchange_id,	dec_exchange_id),
5872fc931582SAndy Adamson   PROC(CREATE_SESSION,	enc_create_session,	dec_create_session),
58730f3e66c6SAndy Adamson   PROC(DESTROY_SESSION,	enc_destroy_session,	dec_destroy_session),
5874fc01cea9SAndy Adamson   PROC(SEQUENCE,	enc_sequence,	dec_sequence),
58752050f0ccSAndy Adamson   PROC(GET_LEASE_TIME,	enc_get_lease_time,	dec_get_lease_time),
587618019753SRicardo Labiaga   PROC(RECLAIM_COMPLETE, enc_reclaim_complete,  dec_reclaim_complete),
587799fe60d0SBenny Halevy #endif /* CONFIG_NFS_V4_1 */
58781da177e4SLinus Torvalds };
58791da177e4SLinus Torvalds 
58801da177e4SLinus Torvalds struct rpc_version		nfs_version4 = {
58811da177e4SLinus Torvalds 	.number			= 4,
5882e8c96f8cSTobias Klauser 	.nrprocs		= ARRAY_SIZE(nfs4_procedures),
58831da177e4SLinus Torvalds 	.procs			= nfs4_procedures
58841da177e4SLinus Torvalds };
58851da177e4SLinus Torvalds 
58861da177e4SLinus Torvalds /*
58871da177e4SLinus Torvalds  * Local variables:
58881da177e4SLinus Torvalds  *  c-basic-offset: 8
58891da177e4SLinus Torvalds  * End:
58901da177e4SLinus Torvalds  */
5891