Skip to content
Snippets Groups Projects
nfs4xdr.c 143 KiB
Newer Older
  • Learn to ignore specific revisions
  • Linus Torvalds's avatar
    Linus Torvalds committed
    /*
     *  fs/nfs/nfs4xdr.c
     *
     *  Client-side XDR for NFSv4.
     *
     *  Copyright (c) 2002 The Regents of the University of Michigan.
     *  All rights reserved.
     *
     *  Kendrick Smith <kmsmith@umich.edu>
     *  Andy Adamson   <andros@umich.edu>
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     *  Redistribution and use in source and binary forms, with or without
     *  modification, are permitted provided that the following conditions
     *  are met:
     *
     *  1. Redistributions of source code must retain the above copyright
     *     notice, this list of conditions and the following disclaimer.
     *  2. Redistributions in binary form must reproduce the above copyright
     *     notice, this list of conditions and the following disclaimer in the
     *     documentation and/or other materials provided with the distribution.
     *  3. Neither the name of the University nor the names of its
     *     contributors may be used to endorse or promote products derived
     *     from this software without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
     *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include <linux/param.h>
    #include <linux/time.h>
    #include <linux/mm.h>
    #include <linux/slab.h>
    #include <linux/utsname.h>
    #include <linux/errno.h>
    #include <linux/string.h>
    #include <linux/in.h>
    #include <linux/pagemap.h>
    #include <linux/proc_fs.h>
    #include <linux/kdev_t.h>
    #include <linux/sunrpc/clnt.h>
    #include <linux/nfs.h>
    #include <linux/nfs4.h>
    #include <linux/nfs_fs.h>
    #include <linux/nfs_idmap.h>
    
    #include "nfs4_fs.h"
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    #define NFSDBG_FACILITY		NFSDBG_XDR
    
    /* Mapping from NFS error code to "errno" error code. */
    #define errno_NFSERR_IO		EIO
    
    
    static int nfs4_stat_to_errno(int);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    /* NFSv4 COMPOUND tags are only wanted for debugging purposes */
    #ifdef DEBUG
    #define NFS4_MAXTAGLEN		20
    #else
    #define NFS4_MAXTAGLEN		0
    #endif
    
    
    /* lock,open owner id:
    
     * we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT  >> 2)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     */
    
    #define open_owner_id_maxsz	(1 + 4)
    #define lock_owner_id_maxsz	(1 + 4)
    
    #define decode_lockowner_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define compound_encode_hdr_maxsz	(3 + (NFS4_MAXTAGLEN >> 2))
    #define compound_decode_hdr_maxsz	(3 + (NFS4_MAXTAGLEN >> 2))
    #define op_encode_hdr_maxsz	(1)
    #define op_decode_hdr_maxsz	(2)
    
    #define encode_stateid_maxsz	(XDR_QUADLEN(NFS4_STATEID_SIZE))
    #define decode_stateid_maxsz	(XDR_QUADLEN(NFS4_STATEID_SIZE))
    #define encode_verifier_maxsz	(XDR_QUADLEN(NFS4_VERIFIER_SIZE))
    #define decode_verifier_maxsz	(XDR_QUADLEN(NFS4_VERIFIER_SIZE))
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define encode_putfh_maxsz	(op_encode_hdr_maxsz + 1 + \
    				(NFS4_FHSIZE >> 2))
    #define decode_putfh_maxsz	(op_decode_hdr_maxsz)
    #define encode_putrootfh_maxsz	(op_encode_hdr_maxsz)
    #define decode_putrootfh_maxsz	(op_decode_hdr_maxsz)
    #define encode_getfh_maxsz      (op_encode_hdr_maxsz)
    #define decode_getfh_maxsz      (op_decode_hdr_maxsz + 1 + \
    				((3+NFS4_FHSIZE) >> 2))
    
    #define nfs4_fattr_bitmap_maxsz 3
    #define encode_getattr_maxsz    (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define nfs4_name_maxsz		(1 + ((3 + NFS4_MAXNAMLEN) >> 2))
    #define nfs4_path_maxsz		(1 + ((3 + NFS4_MAXPATHLEN) >> 2))
    
    #define nfs4_owner_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
    #define nfs4_group_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
    
    /* This is based on getfattr, which uses the most attributes: */
    #define nfs4_fattr_value_maxsz	(1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \
    
    				3 + 3 + 3 + nfs4_owner_maxsz + nfs4_group_maxsz))
    
    #define nfs4_fattr_maxsz	(nfs4_fattr_bitmap_maxsz + \
    				nfs4_fattr_value_maxsz)
    #define decode_getattr_maxsz    (op_decode_hdr_maxsz + nfs4_fattr_maxsz)
    
    #define encode_attrs_maxsz	(nfs4_fattr_bitmap_maxsz + \
    				 1 + 2 + 1 + \
    				nfs4_owner_maxsz + \
    				nfs4_group_maxsz + \
    				4 + 4)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define encode_savefh_maxsz     (op_encode_hdr_maxsz)
    #define decode_savefh_maxsz     (op_decode_hdr_maxsz)
    
    #define encode_restorefh_maxsz  (op_encode_hdr_maxsz)
    #define decode_restorefh_maxsz  (op_decode_hdr_maxsz)
    
    #define encode_fsinfo_maxsz	(encode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define decode_fsinfo_maxsz	(op_decode_hdr_maxsz + 11)
    #define encode_renew_maxsz	(op_encode_hdr_maxsz + 3)
    #define decode_renew_maxsz	(op_decode_hdr_maxsz)
    #define encode_setclientid_maxsz \
    				(op_encode_hdr_maxsz + \
    
    				XDR_QUADLEN(NFS4_VERIFIER_SIZE) + \
    				XDR_QUADLEN(NFS4_SETCLIENTID_NAMELEN) + \
    				1 /* sc_prog */ + \
    				XDR_QUADLEN(RPCBIND_MAXNETIDLEN) + \
    				XDR_QUADLEN(RPCBIND_MAXUADDRLEN) + \
    				1) /* sc_cb_ident */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define decode_setclientid_maxsz \
    				(op_decode_hdr_maxsz + \
    				2 + \
    				1024) /* large value for CLID_INUSE */
    #define encode_setclientid_confirm_maxsz \
    				(op_encode_hdr_maxsz + \
    				3 + (NFS4_VERIFIER_SIZE >> 2))
    #define decode_setclientid_confirm_maxsz \
    				(op_decode_hdr_maxsz)
    
    #define encode_lookup_maxsz	(op_encode_hdr_maxsz + nfs4_name_maxsz)
    #define decode_lookup_maxsz	(op_decode_hdr_maxsz)
    
    #define encode_share_access_maxsz \
    				(2)
    
    #define encode_createmode_maxsz	(1 + encode_attrs_maxsz)
    
    #define encode_opentype_maxsz	(1 + encode_createmode_maxsz)
    #define encode_claim_null_maxsz	(1 + nfs4_name_maxsz)
    #define encode_open_maxsz	(op_encode_hdr_maxsz + \
    				2 + encode_share_access_maxsz + 2 + \
    				open_owner_id_maxsz + \
    				encode_opentype_maxsz + \
    				encode_claim_null_maxsz)
    #define decode_ace_maxsz	(3 + nfs4_owner_maxsz)
    
    #define decode_delegation_maxsz	(1 + decode_stateid_maxsz + 1 + \
    
    				decode_ace_maxsz)
    #define decode_change_info_maxsz	(5)
    #define decode_open_maxsz	(op_decode_hdr_maxsz + \
    
    				decode_stateid_maxsz + \
    
    				decode_change_info_maxsz + 1 + \
    				nfs4_fattr_bitmap_maxsz + \
    				decode_delegation_maxsz)
    
    #define encode_open_confirm_maxsz \
    				(op_encode_hdr_maxsz + \
    				 encode_stateid_maxsz + 1)
    #define decode_open_confirm_maxsz \
    				(op_decode_hdr_maxsz + \
    				 decode_stateid_maxsz)
    #define encode_open_downgrade_maxsz \
    				(op_encode_hdr_maxsz + \
    				 encode_stateid_maxsz + 1 + \
    				 encode_share_access_maxsz)
    #define decode_open_downgrade_maxsz \
    				(op_decode_hdr_maxsz + \
    				 decode_stateid_maxsz)
    #define encode_close_maxsz	(op_encode_hdr_maxsz + \
    				 1 + encode_stateid_maxsz)
    #define decode_close_maxsz	(op_decode_hdr_maxsz + \
    				 decode_stateid_maxsz)
    #define encode_setattr_maxsz	(op_encode_hdr_maxsz + \
    				 encode_stateid_maxsz + \
    				 encode_attrs_maxsz)
    #define decode_setattr_maxsz	(op_decode_hdr_maxsz + \
    				 nfs4_fattr_bitmap_maxsz)
    #define encode_read_maxsz	(op_encode_hdr_maxsz + \
    				 encode_stateid_maxsz + 3)
    #define decode_read_maxsz	(op_decode_hdr_maxsz + 2)
    #define encode_readdir_maxsz	(op_encode_hdr_maxsz + \
    				 2 + encode_verifier_maxsz + 5)
    #define decode_readdir_maxsz	(op_decode_hdr_maxsz + \
    				 decode_verifier_maxsz)
    #define encode_readlink_maxsz	(op_encode_hdr_maxsz)
    #define decode_readlink_maxsz	(op_decode_hdr_maxsz + 1)
    #define encode_write_maxsz	(op_encode_hdr_maxsz + \
    				 encode_stateid_maxsz + 4)
    #define decode_write_maxsz	(op_decode_hdr_maxsz + \
    				 2 + decode_verifier_maxsz)
    #define encode_commit_maxsz	(op_encode_hdr_maxsz + 3)
    #define decode_commit_maxsz	(op_decode_hdr_maxsz + \
    				 decode_verifier_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define encode_remove_maxsz	(op_encode_hdr_maxsz + \
    				nfs4_name_maxsz)
    
    #define decode_remove_maxsz	(op_decode_hdr_maxsz + \
    				 decode_change_info_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define encode_rename_maxsz	(op_encode_hdr_maxsz + \
    				2 * nfs4_name_maxsz)
    
    #define decode_rename_maxsz	(op_decode_hdr_maxsz + \
    				 decode_change_info_maxsz + \
    				 decode_change_info_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define encode_link_maxsz	(op_encode_hdr_maxsz + \
    				nfs4_name_maxsz)
    
    #define decode_link_maxsz	(op_decode_hdr_maxsz + decode_change_info_maxsz)
    
    #define encode_lock_maxsz	(op_encode_hdr_maxsz + \
    				 7 + \
    				 1 + encode_stateid_maxsz + 8)
    #define decode_lock_denied_maxsz \
    				(8 + decode_lockowner_maxsz)
    #define decode_lock_maxsz	(op_decode_hdr_maxsz + \
    				 decode_lock_denied_maxsz)
    #define encode_lockt_maxsz	(op_encode_hdr_maxsz + 12)
    #define decode_lockt_maxsz	(op_decode_hdr_maxsz + \
    				 decode_lock_denied_maxsz)
    #define encode_locku_maxsz	(op_encode_hdr_maxsz + 3 + \
    				 encode_stateid_maxsz + \
    				 4)
    #define decode_locku_maxsz	(op_decode_hdr_maxsz + \
    				 decode_stateid_maxsz)
    #define encode_access_maxsz	(op_encode_hdr_maxsz + 1)
    #define decode_access_maxsz	(op_decode_hdr_maxsz + 2)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define encode_symlink_maxsz	(op_encode_hdr_maxsz + \
    				1 + nfs4_name_maxsz + \
    
    				nfs4_fattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define decode_symlink_maxsz	(op_decode_hdr_maxsz + 8)
    #define encode_create_maxsz	(op_encode_hdr_maxsz + \
    
    				1 + 2 + nfs4_name_maxsz + \
    				encode_attrs_maxsz)
    
    #define decode_create_maxsz	(op_decode_hdr_maxsz + \
    				decode_change_info_maxsz + \
    				nfs4_fattr_bitmap_maxsz)
    
    #define encode_statfs_maxsz	(encode_getattr_maxsz)
    #define decode_statfs_maxsz	(decode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4)
    #define decode_delegreturn_maxsz (op_decode_hdr_maxsz)
    
    #define encode_getacl_maxsz	(encode_getattr_maxsz)
    #define decode_getacl_maxsz	(op_decode_hdr_maxsz + \
    				 nfs4_fattr_bitmap_maxsz + 1)
    #define encode_setacl_maxsz	(op_encode_hdr_maxsz + \
    				 encode_stateid_maxsz + 3)
    #define decode_setacl_maxsz	(decode_setattr_maxsz)
    
    #define encode_fs_locations_maxsz \
    				(encode_getattr_maxsz)
    #define decode_fs_locations_maxsz \
    				(0)
    
    
    #if defined(CONFIG_NFS_V4_1)
    
    #define NFS4_MAX_MACHINE_NAME_LEN (64)
    
    
    #define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \
    				encode_verifier_maxsz + \
    				1 /* co_ownerid.len */ + \
    				XDR_QUADLEN(NFS4_EXCHANGE_ID_LEN) + \
    				1 /* flags */ + \
    				1 /* spa_how */ + \
    				0 /* SP4_NONE (for now) */ + \
    				1 /* zero implemetation id array */)
    #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \
    				2 /* eir_clientid */ + \
    				1 /* eir_sequenceid */ + \
    				1 /* eir_flags */ + \
    				1 /* spr_how */ + \
    				0 /* SP4_NONE (for now) */ + \
    				2 /* eir_server_owner.so_minor_id */ + \
    				/* eir_server_owner.so_major_id<> */ \
    				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \
    				/* eir_server_scope<> */ \
    				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \
    				1 /* eir_server_impl_id array length */ + \
    				0 /* ignored eir_server_impl_id contents */)
    
    #define encode_channel_attrs_maxsz  (6 + 1 /* ca_rdma_ird.len (0) */)
    #define decode_channel_attrs_maxsz  (6 + \
    				     1 /* ca_rdma_ird.len */ + \
    				     1 /* ca_rdma_ird */)
    #define encode_create_session_maxsz  (op_encode_hdr_maxsz + \
    				     2 /* csa_clientid */ + \
    				     1 /* csa_sequence */ + \
    				     1 /* csa_flags */ + \
    				     encode_channel_attrs_maxsz + \
    				     encode_channel_attrs_maxsz + \
    				     1 /* csa_cb_program */ + \
    				     1 /* csa_sec_parms.len (1) */ + \
    				     1 /* cb_secflavor (AUTH_SYS) */ + \
    				     1 /* stamp */ + \
    				     1 /* machinename.len */ + \
    				     XDR_QUADLEN(NFS4_MAX_MACHINE_NAME_LEN) + \
    				     1 /* uid */ + \
    				     1 /* gid */ + \
    				     1 /* gids.len (0) */)
    #define decode_create_session_maxsz  (op_decode_hdr_maxsz +	\
    				     XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
    				     1 /* csr_sequence */ + \
    				     1 /* csr_flags */ + \
    				     decode_channel_attrs_maxsz + \
    				     decode_channel_attrs_maxsz)
    
    #define encode_destroy_session_maxsz    (op_encode_hdr_maxsz + 4)
    #define decode_destroy_session_maxsz    (op_decode_hdr_maxsz)
    
    Andy Adamson's avatar
    Andy Adamson committed
    #define encode_sequence_maxsz	(op_encode_hdr_maxsz + \
    				XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 4)
    #define decode_sequence_maxsz	(op_decode_hdr_maxsz + \
    				XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5)
    
    #else /* CONFIG_NFS_V4_1 */
    #define encode_sequence_maxsz	0
    #define decode_sequence_maxsz	0
    #endif /* CONFIG_NFS_V4_1 */
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_compound_sz	(1024)  /* XXX: large enough? */
    #define NFS4_dec_compound_sz	(1024)  /* XXX: large enough? */
    #define NFS4_enc_read_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    
    				encode_read_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_read_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    
    				decode_read_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_readlink_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    
    				encode_readlink_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_readlink_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    
    				decode_readlink_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_readdir_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    
    				encode_readdir_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_readdir_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    
    				decode_readdir_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_write_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    
    				encode_write_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_write_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    
    				decode_write_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_commit_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    
    				encode_commit_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_commit_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    
    				decode_commit_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_open_sz        (compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    				encode_putfh_maxsz + \
    				encode_savefh_maxsz + \
    				encode_open_maxsz + \
    				encode_getfh_maxsz + \
    				encode_getattr_maxsz + \
    				encode_restorefh_maxsz + \
    				encode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_open_sz        (compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    				decode_putfh_maxsz + \
    				decode_savefh_maxsz + \
    				decode_open_maxsz + \
    				decode_getfh_maxsz + \
    				decode_getattr_maxsz + \
    				decode_restorefh_maxsz + \
    				decode_getattr_maxsz)
    
    #define NFS4_enc_open_confirm_sz \
    				(compound_encode_hdr_maxsz + \
    				 encode_putfh_maxsz + \
    				 encode_open_confirm_maxsz)
    #define NFS4_dec_open_confirm_sz \
    				(compound_decode_hdr_maxsz + \
    				 decode_putfh_maxsz + \
    				 decode_open_confirm_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_open_noattr_sz	(compound_encode_hdr_maxsz + \
    
    					encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    					encode_putfh_maxsz + \
    
    					encode_open_maxsz + \
    					encode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_open_noattr_sz	(compound_decode_hdr_maxsz + \
    
    					decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    					decode_putfh_maxsz + \
    
    					decode_open_maxsz + \
    					decode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_open_downgrade_sz \
    				(compound_encode_hdr_maxsz + \
    
    				 encode_sequence_maxsz + \
    
    				 encode_putfh_maxsz + \
    				 encode_open_downgrade_maxsz + \
    				 encode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_open_downgrade_sz \
    				(compound_decode_hdr_maxsz + \
    
    				 decode_sequence_maxsz + \
    
    				 decode_putfh_maxsz + \
    				 decode_open_downgrade_maxsz + \
    				 decode_getattr_maxsz)
    #define NFS4_enc_close_sz	(compound_encode_hdr_maxsz + \
    
    				 encode_sequence_maxsz + \
    
    				 encode_putfh_maxsz + \
    				 encode_close_maxsz + \
    				 encode_getattr_maxsz)
    #define NFS4_dec_close_sz	(compound_decode_hdr_maxsz + \
    
    				 decode_sequence_maxsz + \
    
    				 decode_putfh_maxsz + \
    				 decode_close_maxsz + \
    				 decode_getattr_maxsz)
    #define NFS4_enc_setattr_sz	(compound_encode_hdr_maxsz + \
    
    				 encode_sequence_maxsz + \
    
    				 encode_putfh_maxsz + \
    				 encode_setattr_maxsz + \
    				 encode_getattr_maxsz)
    #define NFS4_dec_setattr_sz	(compound_decode_hdr_maxsz + \
    
    				 decode_sequence_maxsz + \
    
    				 decode_putfh_maxsz + \
    				 decode_setattr_maxsz + \
    				 decode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_fsinfo_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    				encode_fsinfo_maxsz)
    #define NFS4_dec_fsinfo_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    				decode_fsinfo_maxsz)
    #define NFS4_enc_renew_sz	(compound_encode_hdr_maxsz + \
    				encode_renew_maxsz)
    #define NFS4_dec_renew_sz	(compound_decode_hdr_maxsz + \
    				decode_renew_maxsz)
    #define NFS4_enc_setclientid_sz	(compound_encode_hdr_maxsz + \
    				encode_setclientid_maxsz)
    #define NFS4_dec_setclientid_sz	(compound_decode_hdr_maxsz + \
    				decode_setclientid_maxsz)
    #define NFS4_enc_setclientid_confirm_sz \
    				(compound_encode_hdr_maxsz + \
    				encode_setclientid_confirm_maxsz + \
    				encode_putrootfh_maxsz + \
    				encode_fsinfo_maxsz)
    #define NFS4_dec_setclientid_confirm_sz \
    				(compound_decode_hdr_maxsz + \
    				decode_setclientid_confirm_maxsz + \
    				decode_putrootfh_maxsz + \
    				decode_fsinfo_maxsz)
    #define NFS4_enc_lock_sz        (compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    
    				encode_lock_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_lock_sz        (compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    
    				decode_lock_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_lockt_sz       (compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    
    				encode_lockt_maxsz)
    #define NFS4_dec_lockt_sz       (compound_decode_hdr_maxsz + \
    
    				 decode_sequence_maxsz + \
    
    				 decode_putfh_maxsz + \
    				 decode_lockt_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_locku_sz       (compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    
    				encode_locku_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_locku_sz       (compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    
    				decode_locku_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_access_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    
    				encode_access_maxsz + \
    				encode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_access_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    
    				decode_access_maxsz + \
    				decode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_getattr_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    				encode_getattr_maxsz)
    #define NFS4_dec_getattr_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    				decode_getattr_maxsz)
    #define NFS4_enc_lookup_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    				encode_lookup_maxsz + \
    				encode_getattr_maxsz + \
    				encode_getfh_maxsz)
    #define NFS4_dec_lookup_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    
    				decode_lookup_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_getattr_maxsz + \
    				decode_getfh_maxsz)
    #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putrootfh_maxsz + \
    				encode_getattr_maxsz + \
    				encode_getfh_maxsz)
    #define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putrootfh_maxsz + \
    				decode_getattr_maxsz + \
    				decode_getfh_maxsz)
    #define NFS4_enc_remove_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    
    				encode_remove_maxsz + \
    				encode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_remove_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_rename_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    				encode_savefh_maxsz + \
    				encode_putfh_maxsz + \
    
    				encode_rename_maxsz + \
    				encode_getattr_maxsz + \
    				encode_restorefh_maxsz + \
    				encode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_rename_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    				decode_savefh_maxsz + \
    				decode_putfh_maxsz + \
    
    				decode_rename_maxsz + \
    				decode_getattr_maxsz + \
    				decode_restorefh_maxsz + \
    				decode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_link_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    				encode_savefh_maxsz + \
    				encode_putfh_maxsz + \
    
    				encode_link_maxsz + \
    				decode_getattr_maxsz + \
    				encode_restorefh_maxsz + \
    				decode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_link_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    				decode_savefh_maxsz + \
    				decode_putfh_maxsz + \
    
    				decode_link_maxsz + \
    				decode_getattr_maxsz + \
    				decode_restorefh_maxsz + \
    				decode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_symlink_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    				encode_symlink_maxsz + \
    				encode_getattr_maxsz + \
    				encode_getfh_maxsz)
    #define NFS4_dec_symlink_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    				decode_symlink_maxsz + \
    				decode_getattr_maxsz + \
    				decode_getfh_maxsz)
    #define NFS4_enc_create_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_create_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_getattr_maxsz + \
    
    				encode_restorefh_maxsz + \
    				encode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_create_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_create_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_getattr_maxsz + \
    
    				decode_restorefh_maxsz + \
    				decode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_pathconf_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    				encode_getattr_maxsz)
    #define NFS4_dec_pathconf_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    				decode_getattr_maxsz)
    #define NFS4_enc_statfs_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    
    				encode_statfs_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_statfs_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_putfh_maxsz + \
    
    				decode_statfs_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_getattr_maxsz)
    #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				decode_getattr_maxsz)
    #define NFS4_enc_delegreturn_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				encode_putfh_maxsz + \
    
    				encode_delegreturn_maxsz + \
    				encode_getattr_maxsz)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    				decode_delegreturn_maxsz + \
    				decode_getattr_maxsz)
    
    #define NFS4_enc_getacl_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    				encode_getacl_maxsz)
    
    #define NFS4_dec_getacl_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    				decode_getacl_maxsz)
    
    #define NFS4_enc_setacl_sz	(compound_encode_hdr_maxsz + \
    
    				encode_sequence_maxsz + \
    
    				encode_setacl_maxsz)
    
    #define NFS4_dec_setacl_sz	(compound_decode_hdr_maxsz + \
    
    				decode_sequence_maxsz + \
    
    				decode_setacl_maxsz)
    
    #define NFS4_enc_fs_locations_sz \
    				(compound_encode_hdr_maxsz + \
    
    				 encode_sequence_maxsz + \
    
    				 encode_putfh_maxsz + \
    
    				 encode_lookup_maxsz + \
    				 encode_fs_locations_maxsz)
    
    #define NFS4_dec_fs_locations_sz \
    				(compound_decode_hdr_maxsz + \
    
    				 decode_sequence_maxsz + \
    
    				 decode_putfh_maxsz + \
    
    				 decode_lookup_maxsz + \
    				 decode_fs_locations_maxsz)
    
    #if defined(CONFIG_NFS_V4_1)
    #define NFS4_enc_exchange_id_sz \
    				(compound_encode_hdr_maxsz + \
    				 encode_exchange_id_maxsz)
    #define NFS4_dec_exchange_id_sz \
    				(compound_decode_hdr_maxsz + \
    				 decode_exchange_id_maxsz)
    
    #define NFS4_enc_create_session_sz \
    				(compound_encode_hdr_maxsz + \
    				 encode_create_session_maxsz)
    #define NFS4_dec_create_session_sz \
    				(compound_decode_hdr_maxsz + \
    				 decode_create_session_maxsz)
    
    #define NFS4_enc_destroy_session_sz	(compound_encode_hdr_maxsz + \
    					 encode_destroy_session_maxsz)
    #define NFS4_dec_destroy_session_sz	(compound_decode_hdr_maxsz + \
    					 decode_destroy_session_maxsz)
    
    Andy Adamson's avatar
    Andy Adamson committed
    #define NFS4_enc_sequence_sz \
    				(compound_decode_hdr_maxsz + \
    				 encode_sequence_maxsz)
    #define NFS4_dec_sequence_sz \
    				(compound_decode_hdr_maxsz + \
    				 decode_sequence_maxsz)
    
    Andy Adamson's avatar
    Andy Adamson committed
    #define NFS4_enc_get_lease_time_sz	(compound_encode_hdr_maxsz + \
    					 encode_sequence_maxsz + \
    					 encode_putrootfh_maxsz + \
    					 encode_fsinfo_maxsz)
    #define NFS4_dec_get_lease_time_sz	(compound_decode_hdr_maxsz + \
    					 decode_sequence_maxsz + \
    					 decode_putrootfh_maxsz + \
    					 decode_fsinfo_maxsz)
    
    #endif /* CONFIG_NFS_V4_1 */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    static const umode_t nfs_type2fmt[] = {
    	[NF4BAD] = 0,
    	[NF4REG] = S_IFREG,
    	[NF4DIR] = S_IFDIR,
    	[NF4BLK] = S_IFBLK,
    	[NF4CHR] = S_IFCHR,
    	[NF4LNK] = S_IFLNK,
    	[NF4SOCK] = S_IFSOCK,
    	[NF4FIFO] = S_IFIFO,
    	[NF4ATTRDIR] = 0,
    	[NF4NAMEDATTR] = 0,
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    };
    
    struct compound_hdr {
    	int32_t		status;
    	uint32_t	nops;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	uint32_t	taglen;
    	char *		tag;
    
    	uint32_t	replen;		/* expected reply words */
    
    	u32		minorversion;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    };
    
    /*
     * START OF "GENERIC" ENCODE ROUTINES.
     *   These may look a little ugly since they are imported from a "generic"
     * set of XDR encode/decode routines which are intended to be shared by
     * all of our NFSv4 implementations (OpenBSD, MacOS X...).
     *
     * If the pain of reading these is too great, it should be a straightforward
     * task to translate them into Linux-specific versions which are more
     * consistent with the style used in NFSv2/v3...
     */
    #define RESERVE_SPACE(nbytes)	do {				\
    	p = xdr_reserve_space(xdr, nbytes);			\
    	BUG_ON(!p);						\
    } while (0)
    
    static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	p = xdr_reserve_space(xdr, 4 + len);
    	BUG_ON(p == NULL);
    	xdr_encode_opaque(p, str, len);
    }
    
    
    static void encode_compound_hdr(struct xdr_stream *xdr,
    				struct rpc_rqst *req,
    				struct compound_hdr *hdr)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    	struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
    
    	/* initialize running count of expected bytes in reply.
    	 * NOTE: the replied tag SHOULD be the same is the one sent,
    	 * but this is not required as a MUST for the server to do so. */
    	hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
    	BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
    
    	*p++ = cpu_to_be32(hdr->taglen);
    
    	p = xdr_encode_opaque_fixed(p, hdr->tag, hdr->taglen);
    
    	*p++ = cpu_to_be32(hdr->minorversion);
    
    	*p++ = cpu_to_be32(hdr->nops);
    
    }
    
    static void encode_nops(struct compound_hdr *hdr)
    {
    
    	BUG_ON(hdr->nops > NFS4_MAX_OPS);
    
    	*hdr->nops_p = htonl(hdr->nops);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
    	BUG_ON(p == NULL);
    	xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE);
    }
    
    
    static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	char owner_name[IDMAP_NAMESZ];
    	char owner_group[IDMAP_NAMESZ];
    	int owner_namelen = 0;
    	int owner_grouplen = 0;
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    	__be32 *q;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int len;
    	uint32_t bmval0 = 0;
    	uint32_t bmval1 = 0;
    
    	/*
    	 * We reserve enough space to write the entire attribute buffer at once.
    	 * In the worst-case, this would be
    	 *   12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
    	 *          = 36 bytes, plus any contribution from variable-length fields
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	 */
    	len = 16;
    
    	/* Sigh */
    	if (iap->ia_valid & ATTR_SIZE)
    		len += 8;
    	if (iap->ia_valid & ATTR_MODE)
    		len += 4;
    	if (iap->ia_valid & ATTR_UID) {
    
    		owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		if (owner_namelen < 0) {
    
    			dprintk("nfs: couldn't resolve uid %d to string\n",
    					iap->ia_uid);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			/* XXX */
    			strcpy(owner_name, "nobody");
    			owner_namelen = sizeof("nobody") - 1;
    			/* goto out; */
    		}
    		len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
    	}
    	if (iap->ia_valid & ATTR_GID) {
    
    		owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		if (owner_grouplen < 0) {
    
    			dprintk("nfs: couldn't resolve gid %d to string\n",
    					iap->ia_gid);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			strcpy(owner_group, "nobody");
    			owner_grouplen = sizeof("nobody") - 1;
    			/* goto out; */
    		}
    		len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
    	}
    	if (iap->ia_valid & ATTR_ATIME_SET)
    		len += 16;
    	else if (iap->ia_valid & ATTR_ATIME)
    		len += 4;
    	if (iap->ia_valid & ATTR_MTIME_SET)
    		len += 16;
    	else if (iap->ia_valid & ATTR_MTIME)
    		len += 4;
    	RESERVE_SPACE(len);
    
    	/*
    	 * We write the bitmap length now, but leave the bitmap and the attribute
    	 * buffer length to be backfilled at the end of this routine.
    	 */
    
    	*p++ = cpu_to_be32(2);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	q = p;
    	p += 3;
    
    	if (iap->ia_valid & ATTR_SIZE) {
    		bmval0 |= FATTR4_WORD0_SIZE;
    
    		p = xdr_encode_hyper(p, iap->ia_size);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    	if (iap->ia_valid & ATTR_MODE) {
    		bmval1 |= FATTR4_WORD1_MODE;
    
    		*p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    	if (iap->ia_valid & ATTR_UID) {
    		bmval1 |= FATTR4_WORD1_OWNER;
    
    		*p++ = cpu_to_be32(owner_namelen);
    
    		p = xdr_encode_opaque_fixed(p, owner_name, owner_namelen);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    	if (iap->ia_valid & ATTR_GID) {
    		bmval1 |= FATTR4_WORD1_OWNER_GROUP;
    
    		*p++ = cpu_to_be32(owner_grouplen);
    
    		p = xdr_encode_opaque_fixed(p, owner_group, owner_grouplen);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    	if (iap->ia_valid & ATTR_ATIME_SET) {
    		bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
    
    		*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
    		*p++ = cpu_to_be32(0);
    		*p++ = cpu_to_be32(iap->ia_mtime.tv_sec);
    		*p++ = cpu_to_be32(iap->ia_mtime.tv_nsec);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    	else if (iap->ia_valid & ATTR_ATIME) {
    		bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
    
    		*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    	if (iap->ia_valid & ATTR_MTIME_SET) {
    		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
    
    		*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
    		*p++ = cpu_to_be32(0);
    		*p++ = cpu_to_be32(iap->ia_mtime.tv_sec);
    		*p++ = cpu_to_be32(iap->ia_mtime.tv_nsec);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    	else if (iap->ia_valid & ATTR_MTIME) {
    		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
    
    		*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	/*
    	 * Now we backfill the bitmap and the attribute buffer length.
    	 */
    	if (len != ((char *)p - (char *)q) + 4) {
    
    		printk(KERN_ERR "nfs: Attr length error, %u != %Zu\n",
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    				len, ((char *)p - (char *)q) + 4);
    		BUG();
    	}
    	len = (char *)p - (char *)q - 12;
    	*q++ = htonl(bmval0);
    	*q++ = htonl(bmval1);
    	*q++ = htonl(len);
    
    /* out: */
    }
    
    
    static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hdr *hdr)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	RESERVE_SPACE(8);
    
    	*p++ = cpu_to_be32(OP_ACCESS);
    	*p++ = cpu_to_be32(access);
    
    	hdr->replen += decode_access_maxsz;
    
    static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	RESERVE_SPACE(8+NFS4_STATEID_SIZE);
    
    	*p++ = cpu_to_be32(OP_CLOSE);
    	*p++ = cpu_to_be32(arg->seqid->sequence->counter);
    
    	p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
    
    	hdr->replen += decode_close_maxsz;
    
    static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Andy Adamson's avatar
    Andy Adamson committed
    	RESERVE_SPACE(16);
    
    	*p++ = cpu_to_be32(OP_COMMIT);
    
    	p = xdr_encode_hyper(p, args->offset);
    
    	*p++ = cpu_to_be32(args->count);
    
    	hdr->replen += decode_commit_maxsz;
    
    static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    Al Viro's avatar
    Al Viro committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	RESERVE_SPACE(8);
    
    	*p++ = cpu_to_be32(OP_CREATE);
    	*p++ = cpu_to_be32(create->ftype);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	switch (create->ftype) {
    	case NF4LNK:
    
    		*p++ = cpu_to_be32(create->u.symlink.len);
    
    		xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		break;
    
    	case NF4BLK: case NF4CHR:
    		RESERVE_SPACE(8);
    
    		*p++ = cpu_to_be32(create->u.device.specdata1);
    		*p++ = cpu_to_be32(create->u.device.specdata2);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		break;
    
    	default:
    		break;
    	}
    
    	RESERVE_SPACE(4 + create->name->len);
    
    	*p++ = cpu_to_be32(create->name->len);
    
    	p = xdr_encode_opaque_fixed(p, create->name->name, create->name->len);
    
    	hdr->replen += decode_create_maxsz;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	encode_attrs(xdr, create->attrs, create->server);
    
    static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    Andy Adamson's avatar
    Andy Adamson committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    Andy Adamson's avatar
    Andy Adamson committed
    	RESERVE_SPACE(12);
    
    	*p++ = cpu_to_be32(OP_GETATTR);
    	*p++ = cpu_to_be32(1);
    	*p++ = cpu_to_be32(bitmap);
    
    	hdr->replen += decode_getattr_maxsz;
    
    static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    Andy Adamson's avatar
    Andy Adamson committed
    	__be32 *p;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    Andy Adamson's avatar
    Andy Adamson committed
    	RESERVE_SPACE(16);
    
    	*p++ = cpu_to_be32(OP_GETATTR);
    	*p++ = cpu_to_be32(2);
    	*p++ = cpu_to_be32(bm0);
    	*p++ = cpu_to_be32(bm1);
    
    	hdr->replen += decode_getattr_maxsz;
    
    static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
    			   bitmask[1] & nfs4_fattr_bitmap[1], hdr);
    
    static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
    			   bitmask[1] & nfs4_fsinfo_bitmap[1], hdr);
    
    static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
    
    	encode_getattr_two(xdr, bitmask[0] & nfs4_fs_locations_bitmap[0],
    			   bitmask[1] & nfs4_fs_locations_bitmap[1], hdr);