nfs4xdr.c 174.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10
/*
 *  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>
11
 *
L
Linus Torvalds 已提交
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
 *  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/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>
48
#include <linux/sunrpc/msg_prot.h>
B
Bryan Schumaker 已提交
49
#include <linux/sunrpc/gss_api.h>
L
Linus Torvalds 已提交
50 51 52 53
#include <linux/nfs.h>
#include <linux/nfs4.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_idmap.h>
54
#include "nfs4_fs.h"
55
#include "internal.h"
56
#include "pnfs.h"
L
Linus Torvalds 已提交
57 58 59 60 61 62

#define NFSDBG_FACILITY		NFSDBG_XDR

/* Mapping from NFS error code to "errno" error code. */
#define errno_NFSERR_IO		EIO

63
static int nfs4_stat_to_errno(int);
L
Linus Torvalds 已提交
64 65 66 67 68 69 70 71

/* NFSv4 COMPOUND tags are only wanted for debugging purposes */
#ifdef DEBUG
#define NFS4_MAXTAGLEN		20
#else
#define NFS4_MAXTAGLEN		0
#endif

72
/* lock,open owner id:
73
 * we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT  >> 2)
L
Linus Torvalds 已提交
74
 */
75 76
#define open_owner_id_maxsz	(1 + 1 + 4)
#define lock_owner_id_maxsz	(1 + 1 + 4)
T
Trond Myklebust 已提交
77
#define decode_lockowner_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
L
Linus Torvalds 已提交
78 79 80 81
#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)
T
Trond Myklebust 已提交
82 83 84 85
#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))
L
Linus Torvalds 已提交
86 87 88 89 90 91 92 93
#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))
94
#define nfs4_fattr_bitmap_maxsz 4
95
#define encode_getattr_maxsz    (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
L
Linus Torvalds 已提交
96 97
#define nfs4_name_maxsz		(1 + ((3 + NFS4_MAXNAMLEN) >> 2))
#define nfs4_path_maxsz		(1 + ((3 + NFS4_MAXPATHLEN) >> 2))
98 99
#define nfs4_owner_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
#define nfs4_group_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
100 101
/* 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 + \
102
				3 + 3 + 3 + nfs4_owner_maxsz + nfs4_group_maxsz))
103 104 105
#define nfs4_fattr_maxsz	(nfs4_fattr_bitmap_maxsz + \
				nfs4_fattr_value_maxsz)
#define decode_getattr_maxsz    (op_decode_hdr_maxsz + nfs4_fattr_maxsz)
T
Trond Myklebust 已提交
106 107 108 109 110
#define encode_attrs_maxsz	(nfs4_fattr_bitmap_maxsz + \
				 1 + 2 + 1 + \
				nfs4_owner_maxsz + \
				nfs4_group_maxsz + \
				4 + 4)
L
Linus Torvalds 已提交
111 112
#define encode_savefh_maxsz     (op_encode_hdr_maxsz)
#define decode_savefh_maxsz     (op_decode_hdr_maxsz)
113 114
#define encode_restorefh_maxsz  (op_encode_hdr_maxsz)
#define decode_restorefh_maxsz  (op_decode_hdr_maxsz)
F
Fred Isaman 已提交
115
#define encode_fsinfo_maxsz	(encode_getattr_maxsz)
116
#define decode_fsinfo_maxsz	(op_decode_hdr_maxsz + 15)
L
Linus Torvalds 已提交
117 118 119 120
#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 + \
121 122 123 124 125 126
				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 */
L
Linus Torvalds 已提交
127 128 129 130 131 132 133 134 135
#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)
136 137
#define encode_lookup_maxsz	(op_encode_hdr_maxsz + nfs4_name_maxsz)
#define decode_lookup_maxsz	(op_decode_hdr_maxsz)
138 139
#define encode_share_access_maxsz \
				(2)
140
#define encode_createmode_maxsz	(1 + encode_attrs_maxsz + encode_verifier_maxsz)
141 142 143 144 145 146 147 148
#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)
T
Trond Myklebust 已提交
149
#define decode_delegation_maxsz	(1 + decode_stateid_maxsz + 1 + \
150 151 152
				decode_ace_maxsz)
#define decode_change_info_maxsz	(5)
#define decode_open_maxsz	(op_decode_hdr_maxsz + \
T
Trond Myklebust 已提交
153
				decode_stateid_maxsz + \
154 155 156
				decode_change_info_maxsz + 1 + \
				nfs4_fattr_bitmap_maxsz + \
				decode_delegation_maxsz)
T
Trond Myklebust 已提交
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
#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)
L
Linus Torvalds 已提交
195 196
#define encode_remove_maxsz	(op_encode_hdr_maxsz + \
				nfs4_name_maxsz)
197 198
#define decode_remove_maxsz	(op_decode_hdr_maxsz + \
				 decode_change_info_maxsz)
L
Linus Torvalds 已提交
199 200
#define encode_rename_maxsz	(op_encode_hdr_maxsz + \
				2 * nfs4_name_maxsz)
201 202 203
#define decode_rename_maxsz	(op_decode_hdr_maxsz + \
				 decode_change_info_maxsz + \
				 decode_change_info_maxsz)
L
Linus Torvalds 已提交
204 205
#define encode_link_maxsz	(op_encode_hdr_maxsz + \
				nfs4_name_maxsz)
206
#define decode_link_maxsz	(op_decode_hdr_maxsz + decode_change_info_maxsz)
207
#define encode_lockowner_maxsz	(7)
T
Trond Myklebust 已提交
208 209
#define encode_lock_maxsz	(op_encode_hdr_maxsz + \
				 7 + \
210 211
				 1 + encode_stateid_maxsz + 1 + \
				 encode_lockowner_maxsz)
T
Trond Myklebust 已提交
212 213 214 215
#define decode_lock_denied_maxsz \
				(8 + decode_lockowner_maxsz)
#define decode_lock_maxsz	(op_decode_hdr_maxsz + \
				 decode_lock_denied_maxsz)
216 217
#define encode_lockt_maxsz	(op_encode_hdr_maxsz + 5 + \
				encode_lockowner_maxsz)
T
Trond Myklebust 已提交
218 219 220 221 222 223 224
#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)
225 226 227 228 229
#define encode_release_lockowner_maxsz \
				(op_encode_hdr_maxsz + \
				 encode_lockowner_maxsz)
#define decode_release_lockowner_maxsz \
				(op_decode_hdr_maxsz)
T
Trond Myklebust 已提交
230 231
#define encode_access_maxsz	(op_encode_hdr_maxsz + 1)
#define decode_access_maxsz	(op_decode_hdr_maxsz + 2)
L
Linus Torvalds 已提交
232 233
#define encode_symlink_maxsz	(op_encode_hdr_maxsz + \
				1 + nfs4_name_maxsz + \
234
				1 + \
235
				nfs4_fattr_maxsz)
L
Linus Torvalds 已提交
236 237
#define decode_symlink_maxsz	(op_decode_hdr_maxsz + 8)
#define encode_create_maxsz	(op_encode_hdr_maxsz + \
T
Trond Myklebust 已提交
238 239
				1 + 2 + nfs4_name_maxsz + \
				encode_attrs_maxsz)
240 241 242
#define decode_create_maxsz	(op_decode_hdr_maxsz + \
				decode_change_info_maxsz + \
				nfs4_fattr_bitmap_maxsz)
T
Trond Myklebust 已提交
243 244
#define encode_statfs_maxsz	(encode_getattr_maxsz)
#define decode_statfs_maxsz	(decode_getattr_maxsz)
L
Linus Torvalds 已提交
245 246
#define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4)
#define decode_delegreturn_maxsz (op_decode_hdr_maxsz)
T
Trond Myklebust 已提交
247 248 249 250 251 252
#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)
253 254 255 256
#define encode_fs_locations_maxsz \
				(encode_getattr_maxsz)
#define decode_fs_locations_maxsz \
				(0)
B
Bryan Schumaker 已提交
257
#define encode_secinfo_maxsz	(op_encode_hdr_maxsz + nfs4_name_maxsz)
B
Bryan Schumaker 已提交
258
#define decode_secinfo_maxsz	(op_decode_hdr_maxsz + 1 + ((NFS_MAX_SECFLAVORS * (16 + GSS_OID_MAX_LEN)) / 4))
259 260

#if defined(CONFIG_NFS_V4_1)
A
Andy Adamson 已提交
261 262
#define NFS4_MAX_MACHINE_NAME_LEN (64)

B
Benny Halevy 已提交
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
#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 */)
A
Andy Adamson 已提交
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
#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)
A
Andy Adamson 已提交
309 310
#define encode_destroy_session_maxsz    (op_encode_hdr_maxsz + 4)
#define decode_destroy_session_maxsz    (op_decode_hdr_maxsz)
A
Andy Adamson 已提交
311 312 313 314
#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)
315 316
#define encode_reclaim_complete_maxsz	(op_encode_hdr_maxsz + 4)
#define decode_reclaim_complete_maxsz	(op_decode_hdr_maxsz + 4)
317 318 319 320 321 322 323 324 325 326 327 328 329
#define encode_getdeviceinfo_maxsz (op_encode_hdr_maxsz + 4 + \
				XDR_QUADLEN(NFS4_DEVICEID4_SIZE))
#define decode_getdeviceinfo_maxsz (op_decode_hdr_maxsz + \
				1 /* layout type */ + \
				1 /* opaque devaddr4 length */ + \
				  /* devaddr4 payload is read into page */ \
				1 /* notification bitmap length */ + \
				1 /* notification bitmap */)
#define encode_layoutget_maxsz	(op_encode_hdr_maxsz + 10 + \
				encode_stateid_maxsz)
#define decode_layoutget_maxsz	(op_decode_hdr_maxsz + 8 + \
				decode_stateid_maxsz + \
				XDR_QUADLEN(PNFS_LAYOUT_MAXSIZE))
A
Andy Adamson 已提交
330 331 332 333 334 335 336 337 338 339 340
#define encode_layoutcommit_maxsz (op_encode_hdr_maxsz +          \
				2 /* offset */ + \
				2 /* length */ + \
				1 /* reclaim */ + \
				encode_stateid_maxsz + \
				1 /* new offset (true) */ + \
				2 /* last byte written */ + \
				1 /* nt_timechanged (false) */ + \
				1 /* layoutupdate4 layout type */ + \
				1 /* NULL filelayout layoutupdate4 payload */)
#define decode_layoutcommit_maxsz (op_decode_hdr_maxsz + 3)
B
Benny Halevy 已提交
341 342 343 344 345
#define encode_layoutreturn_maxsz (8 + op_encode_hdr_maxsz + \
				encode_stateid_maxsz + \
				1 /* FIXME: opaque lrf_body always empty at the moment */)
#define decode_layoutreturn_maxsz (op_decode_hdr_maxsz + \
				1 + decode_stateid_maxsz)
346 347
#define encode_secinfo_no_name_maxsz (op_encode_hdr_maxsz + 1)
#define decode_secinfo_no_name_maxsz decode_secinfo_maxsz
348 349 350 351 352
#else /* CONFIG_NFS_V4_1 */
#define encode_sequence_maxsz	0
#define decode_sequence_maxsz	0
#endif /* CONFIG_NFS_V4_1 */

L
Linus Torvalds 已提交
353 354 355
#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 + \
356
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
357
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
358
				encode_read_maxsz)
L
Linus Torvalds 已提交
359
#define NFS4_dec_read_sz	(compound_decode_hdr_maxsz + \
360
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
361
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
362
				decode_read_maxsz)
L
Linus Torvalds 已提交
363
#define NFS4_enc_readlink_sz	(compound_encode_hdr_maxsz + \
364
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
365
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
366
				encode_readlink_maxsz)
L
Linus Torvalds 已提交
367
#define NFS4_dec_readlink_sz	(compound_decode_hdr_maxsz + \
368
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
369
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
370
				decode_readlink_maxsz)
L
Linus Torvalds 已提交
371
#define NFS4_enc_readdir_sz	(compound_encode_hdr_maxsz + \
372
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
373
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
374
				encode_readdir_maxsz)
L
Linus Torvalds 已提交
375
#define NFS4_dec_readdir_sz	(compound_decode_hdr_maxsz + \
376
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
377
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
378
				decode_readdir_maxsz)
L
Linus Torvalds 已提交
379
#define NFS4_enc_write_sz	(compound_encode_hdr_maxsz + \
380
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
381
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
382
				encode_write_maxsz + \
383
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
384
#define NFS4_dec_write_sz	(compound_decode_hdr_maxsz + \
385
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
386
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
387
				decode_write_maxsz + \
388
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
389
#define NFS4_enc_commit_sz	(compound_encode_hdr_maxsz + \
390
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
391
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
392
				encode_commit_maxsz + \
393
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
394
#define NFS4_dec_commit_sz	(compound_decode_hdr_maxsz + \
395
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
396
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
397
				decode_commit_maxsz + \
398
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
399
#define NFS4_enc_open_sz        (compound_encode_hdr_maxsz + \
400
				encode_sequence_maxsz + \
401 402 403 404 405 406 407
				encode_putfh_maxsz + \
				encode_savefh_maxsz + \
				encode_open_maxsz + \
				encode_getfh_maxsz + \
				encode_getattr_maxsz + \
				encode_restorefh_maxsz + \
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
408
#define NFS4_dec_open_sz        (compound_decode_hdr_maxsz + \
409
				decode_sequence_maxsz + \
410 411 412 413 414 415 416
				decode_putfh_maxsz + \
				decode_savefh_maxsz + \
				decode_open_maxsz + \
				decode_getfh_maxsz + \
				decode_getattr_maxsz + \
				decode_restorefh_maxsz + \
				decode_getattr_maxsz)
T
Trond Myklebust 已提交
417 418 419 420 421 422 423 424
#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)
L
Linus Torvalds 已提交
425
#define NFS4_enc_open_noattr_sz	(compound_encode_hdr_maxsz + \
426
					encode_sequence_maxsz + \
L
Linus Torvalds 已提交
427
					encode_putfh_maxsz + \
428 429
					encode_open_maxsz + \
					encode_getattr_maxsz)
L
Linus Torvalds 已提交
430
#define NFS4_dec_open_noattr_sz	(compound_decode_hdr_maxsz + \
431
					decode_sequence_maxsz + \
L
Linus Torvalds 已提交
432
					decode_putfh_maxsz + \
433 434
					decode_open_maxsz + \
					decode_getattr_maxsz)
L
Linus Torvalds 已提交
435 436
#define NFS4_enc_open_downgrade_sz \
				(compound_encode_hdr_maxsz + \
437
				 encode_sequence_maxsz + \
T
Trond Myklebust 已提交
438 439 440
				 encode_putfh_maxsz + \
				 encode_open_downgrade_maxsz + \
				 encode_getattr_maxsz)
L
Linus Torvalds 已提交
441 442
#define NFS4_dec_open_downgrade_sz \
				(compound_decode_hdr_maxsz + \
443
				 decode_sequence_maxsz + \
T
Trond Myklebust 已提交
444 445 446 447
				 decode_putfh_maxsz + \
				 decode_open_downgrade_maxsz + \
				 decode_getattr_maxsz)
#define NFS4_enc_close_sz	(compound_encode_hdr_maxsz + \
448
				 encode_sequence_maxsz + \
T
Trond Myklebust 已提交
449 450 451 452
				 encode_putfh_maxsz + \
				 encode_close_maxsz + \
				 encode_getattr_maxsz)
#define NFS4_dec_close_sz	(compound_decode_hdr_maxsz + \
453
				 decode_sequence_maxsz + \
T
Trond Myklebust 已提交
454 455 456 457
				 decode_putfh_maxsz + \
				 decode_close_maxsz + \
				 decode_getattr_maxsz)
#define NFS4_enc_setattr_sz	(compound_encode_hdr_maxsz + \
458
				 encode_sequence_maxsz + \
T
Trond Myklebust 已提交
459 460 461 462
				 encode_putfh_maxsz + \
				 encode_setattr_maxsz + \
				 encode_getattr_maxsz)
#define NFS4_dec_setattr_sz	(compound_decode_hdr_maxsz + \
463
				 decode_sequence_maxsz + \
T
Trond Myklebust 已提交
464 465 466
				 decode_putfh_maxsz + \
				 decode_setattr_maxsz + \
				 decode_getattr_maxsz)
L
Linus Torvalds 已提交
467
#define NFS4_enc_fsinfo_sz	(compound_encode_hdr_maxsz + \
468
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
469 470 471
				encode_putfh_maxsz + \
				encode_fsinfo_maxsz)
#define NFS4_dec_fsinfo_sz	(compound_decode_hdr_maxsz + \
472
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
				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 + \
494
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
495
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
496
				encode_lock_maxsz)
L
Linus Torvalds 已提交
497
#define NFS4_dec_lock_sz        (compound_decode_hdr_maxsz + \
498
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
499
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
500
				decode_lock_maxsz)
L
Linus Torvalds 已提交
501
#define NFS4_enc_lockt_sz       (compound_encode_hdr_maxsz + \
502
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
503
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
504 505
				encode_lockt_maxsz)
#define NFS4_dec_lockt_sz       (compound_decode_hdr_maxsz + \
506
				 decode_sequence_maxsz + \
T
Trond Myklebust 已提交
507 508
				 decode_putfh_maxsz + \
				 decode_lockt_maxsz)
L
Linus Torvalds 已提交
509
#define NFS4_enc_locku_sz       (compound_encode_hdr_maxsz + \
510
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
511
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
512
				encode_locku_maxsz)
L
Linus Torvalds 已提交
513
#define NFS4_dec_locku_sz       (compound_decode_hdr_maxsz + \
514
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
515
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
516
				decode_locku_maxsz)
517 518 519 520 521 522
#define NFS4_enc_release_lockowner_sz \
				(compound_encode_hdr_maxsz + \
				 encode_lockowner_maxsz)
#define NFS4_dec_release_lockowner_sz \
				(compound_decode_hdr_maxsz + \
				 decode_lockowner_maxsz)
L
Linus Torvalds 已提交
523
#define NFS4_enc_access_sz	(compound_encode_hdr_maxsz + \
524
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
525
				encode_putfh_maxsz + \
526 527
				encode_access_maxsz + \
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
528
#define NFS4_dec_access_sz	(compound_decode_hdr_maxsz + \
529
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
530
				decode_putfh_maxsz + \
531 532
				decode_access_maxsz + \
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
533
#define NFS4_enc_getattr_sz	(compound_encode_hdr_maxsz + \
534
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
535 536 537
				encode_putfh_maxsz + \
				encode_getattr_maxsz)
#define NFS4_dec_getattr_sz	(compound_decode_hdr_maxsz + \
538
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
539 540 541
				decode_putfh_maxsz + \
				decode_getattr_maxsz)
#define NFS4_enc_lookup_sz	(compound_encode_hdr_maxsz + \
542
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
543 544 545 546 547
				encode_putfh_maxsz + \
				encode_lookup_maxsz + \
				encode_getattr_maxsz + \
				encode_getfh_maxsz)
#define NFS4_dec_lookup_sz	(compound_decode_hdr_maxsz + \
548
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
549
				decode_putfh_maxsz + \
550
				decode_lookup_maxsz + \
L
Linus Torvalds 已提交
551 552 553
				decode_getattr_maxsz + \
				decode_getfh_maxsz)
#define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \
554
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
555 556 557 558
				encode_putrootfh_maxsz + \
				encode_getattr_maxsz + \
				encode_getfh_maxsz)
#define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \
559
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
560 561 562 563
				decode_putrootfh_maxsz + \
				decode_getattr_maxsz + \
				decode_getfh_maxsz)
#define NFS4_enc_remove_sz	(compound_encode_hdr_maxsz + \
564
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
565
				encode_putfh_maxsz + \
566 567
				encode_remove_maxsz + \
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
568
#define NFS4_dec_remove_sz	(compound_decode_hdr_maxsz + \
569
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
570
				decode_putfh_maxsz + \
571
				decode_remove_maxsz + \
572
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
573
#define NFS4_enc_rename_sz	(compound_encode_hdr_maxsz + \
574
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
575 576 577
				encode_putfh_maxsz + \
				encode_savefh_maxsz + \
				encode_putfh_maxsz + \
578 579 580 581
				encode_rename_maxsz + \
				encode_getattr_maxsz + \
				encode_restorefh_maxsz + \
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
582
#define NFS4_dec_rename_sz	(compound_decode_hdr_maxsz + \
583
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
584 585 586
				decode_putfh_maxsz + \
				decode_savefh_maxsz + \
				decode_putfh_maxsz + \
587 588 589 590
				decode_rename_maxsz + \
				decode_getattr_maxsz + \
				decode_restorefh_maxsz + \
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
591
#define NFS4_enc_link_sz	(compound_encode_hdr_maxsz + \
592
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
593 594 595
				encode_putfh_maxsz + \
				encode_savefh_maxsz + \
				encode_putfh_maxsz + \
596 597 598 599
				encode_link_maxsz + \
				decode_getattr_maxsz + \
				encode_restorefh_maxsz + \
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
600
#define NFS4_dec_link_sz	(compound_decode_hdr_maxsz + \
601
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
602 603 604
				decode_putfh_maxsz + \
				decode_savefh_maxsz + \
				decode_putfh_maxsz + \
605 606 607 608
				decode_link_maxsz + \
				decode_getattr_maxsz + \
				decode_restorefh_maxsz + \
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
609
#define NFS4_enc_symlink_sz	(compound_encode_hdr_maxsz + \
610
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
611 612 613 614 615
				encode_putfh_maxsz + \
				encode_symlink_maxsz + \
				encode_getattr_maxsz + \
				encode_getfh_maxsz)
#define NFS4_dec_symlink_sz	(compound_decode_hdr_maxsz + \
616
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
617 618 619 620 621
				decode_putfh_maxsz + \
				decode_symlink_maxsz + \
				decode_getattr_maxsz + \
				decode_getfh_maxsz)
#define NFS4_enc_create_sz	(compound_encode_hdr_maxsz + \
622
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
623
				encode_putfh_maxsz + \
624
				encode_savefh_maxsz + \
L
Linus Torvalds 已提交
625
				encode_create_maxsz + \
626
				encode_getfh_maxsz + \
L
Linus Torvalds 已提交
627
				encode_getattr_maxsz + \
628 629
				encode_restorefh_maxsz + \
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
630
#define NFS4_dec_create_sz	(compound_decode_hdr_maxsz + \
631
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
632
				decode_putfh_maxsz + \
633
				decode_savefh_maxsz + \
L
Linus Torvalds 已提交
634
				decode_create_maxsz + \
635
				decode_getfh_maxsz + \
L
Linus Torvalds 已提交
636
				decode_getattr_maxsz + \
637 638
				decode_restorefh_maxsz + \
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
639
#define NFS4_enc_pathconf_sz	(compound_encode_hdr_maxsz + \
640
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
641 642 643
				encode_putfh_maxsz + \
				encode_getattr_maxsz)
#define NFS4_dec_pathconf_sz	(compound_decode_hdr_maxsz + \
644
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
645 646 647
				decode_putfh_maxsz + \
				decode_getattr_maxsz)
#define NFS4_enc_statfs_sz	(compound_encode_hdr_maxsz + \
648
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
649
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
650
				encode_statfs_maxsz)
L
Linus Torvalds 已提交
651
#define NFS4_dec_statfs_sz	(compound_decode_hdr_maxsz + \
652
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
653
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
654
				decode_statfs_maxsz)
L
Linus Torvalds 已提交
655
#define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \
656
				encode_sequence_maxsz + \
657
				encode_putfh_maxsz + \
L
Linus Torvalds 已提交
658 659
				encode_getattr_maxsz)
#define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \
660
				decode_sequence_maxsz + \
661
				decode_putfh_maxsz + \
L
Linus Torvalds 已提交
662 663
				decode_getattr_maxsz)
#define NFS4_enc_delegreturn_sz	(compound_encode_hdr_maxsz + \
664
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
665
				encode_putfh_maxsz + \
666 667
				encode_delegreturn_maxsz + \
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
668
#define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
669
				decode_sequence_maxsz + \
670 671
				decode_delegreturn_maxsz + \
				decode_getattr_maxsz)
672
#define NFS4_enc_getacl_sz	(compound_encode_hdr_maxsz + \
673
				encode_sequence_maxsz + \
674
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
675
				encode_getacl_maxsz)
676
#define NFS4_dec_getacl_sz	(compound_decode_hdr_maxsz + \
677
				decode_sequence_maxsz + \
678
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
679
				decode_getacl_maxsz)
680
#define NFS4_enc_setacl_sz	(compound_encode_hdr_maxsz + \
681
				encode_sequence_maxsz + \
682
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
683
				encode_setacl_maxsz)
684
#define NFS4_dec_setacl_sz	(compound_decode_hdr_maxsz + \
685
				decode_sequence_maxsz + \
686
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
687
				decode_setacl_maxsz)
688 689
#define NFS4_enc_fs_locations_sz \
				(compound_encode_hdr_maxsz + \
690
				 encode_sequence_maxsz + \
691
				 encode_putfh_maxsz + \
692 693
				 encode_lookup_maxsz + \
				 encode_fs_locations_maxsz)
694 695
#define NFS4_dec_fs_locations_sz \
				(compound_decode_hdr_maxsz + \
696
				 decode_sequence_maxsz + \
697
				 decode_putfh_maxsz + \
698 699
				 decode_lookup_maxsz + \
				 decode_fs_locations_maxsz)
B
Bryan Schumaker 已提交
700 701 702 703 704 705 706 707
#define NFS4_enc_secinfo_sz 	(compound_encode_hdr_maxsz + \
				encode_sequence_maxsz + \
				encode_putfh_maxsz + \
				encode_secinfo_maxsz)
#define NFS4_dec_secinfo_sz	(compound_decode_hdr_maxsz + \
				decode_sequence_maxsz + \
				decode_putfh_maxsz + \
				decode_secinfo_maxsz)
B
Benny Halevy 已提交
708 709 710 711 712 713 714
#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)
A
Andy Adamson 已提交
715 716 717 718 719 720
#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)
A
Andy Adamson 已提交
721 722 723 724
#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)
A
Andy Adamson 已提交
725 726 727 728 729 730
#define NFS4_enc_sequence_sz \
				(compound_decode_hdr_maxsz + \
				 encode_sequence_maxsz)
#define NFS4_dec_sequence_sz \
				(compound_decode_hdr_maxsz + \
				 decode_sequence_maxsz)
A
Andy Adamson 已提交
731 732 733 734 735 736 737 738
#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)
739 740 741 742 743 744
#define NFS4_enc_reclaim_complete_sz	(compound_encode_hdr_maxsz + \
					 encode_sequence_maxsz + \
					 encode_reclaim_complete_maxsz)
#define NFS4_dec_reclaim_complete_sz	(compound_decode_hdr_maxsz + \
					 decode_sequence_maxsz + \
					 decode_reclaim_complete_maxsz)
745 746 747 748 749 750 751 752 753 754 755 756 757 758
#define NFS4_enc_getdeviceinfo_sz (compound_encode_hdr_maxsz +    \
				encode_sequence_maxsz +\
				encode_getdeviceinfo_maxsz)
#define NFS4_dec_getdeviceinfo_sz (compound_decode_hdr_maxsz +    \
				decode_sequence_maxsz + \
				decode_getdeviceinfo_maxsz)
#define NFS4_enc_layoutget_sz	(compound_encode_hdr_maxsz + \
				encode_sequence_maxsz + \
				encode_putfh_maxsz +        \
				encode_layoutget_maxsz)
#define NFS4_dec_layoutget_sz	(compound_decode_hdr_maxsz + \
				decode_sequence_maxsz + \
				decode_putfh_maxsz +        \
				decode_layoutget_maxsz)
A
Andy Adamson 已提交
759 760 761 762 763 764 765 766 767 768
#define NFS4_enc_layoutcommit_sz (compound_encode_hdr_maxsz + \
				encode_sequence_maxsz +\
				encode_putfh_maxsz + \
				encode_layoutcommit_maxsz + \
				encode_getattr_maxsz)
#define NFS4_dec_layoutcommit_sz (compound_decode_hdr_maxsz + \
				decode_sequence_maxsz + \
				decode_putfh_maxsz + \
				decode_layoutcommit_maxsz + \
				decode_getattr_maxsz)
B
Benny Halevy 已提交
769 770 771 772 773 774 775 776
#define NFS4_enc_layoutreturn_sz (compound_encode_hdr_maxsz + \
				encode_sequence_maxsz + \
				encode_putfh_maxsz + \
				encode_layoutreturn_maxsz)
#define NFS4_dec_layoutreturn_sz (compound_decode_hdr_maxsz + \
				decode_sequence_maxsz + \
				decode_putfh_maxsz + \
				decode_layoutreturn_maxsz)
777 778 779 780 781 782 783 784
#define NFS4_enc_secinfo_no_name_sz	(compound_encode_hdr_maxsz + \
					encode_sequence_maxsz + \
					encode_putrootfh_maxsz +\
					encode_secinfo_no_name_maxsz)
#define NFS4_dec_secinfo_no_name_sz	(compound_decode_hdr_maxsz + \
					decode_sequence_maxsz + \
					decode_putrootfh_maxsz + \
					decode_secinfo_no_name_maxsz)
785 786 787 788 789 790 791 792 793 794 795 796 797

const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
				      compound_encode_hdr_maxsz +
				      encode_sequence_maxsz +
				      encode_putfh_maxsz +
				      encode_getattr_maxsz) *
				     XDR_UNIT);

const u32 nfs41_maxread_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
				     compound_decode_hdr_maxsz +
				     decode_sequence_maxsz +
				     decode_putfh_maxsz) *
				    XDR_UNIT);
B
Benny Halevy 已提交
798
#endif /* CONFIG_NFS_V4_1 */
L
Linus Torvalds 已提交
799

800 801 802 803 804 805 806 807 808 809 810
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,
L
Linus Torvalds 已提交
811 812 813 814 815
};

struct compound_hdr {
	int32_t		status;
	uint32_t	nops;
816
	__be32 *	nops_p;
L
Linus Torvalds 已提交
817 818
	uint32_t	taglen;
	char *		tag;
819
	uint32_t	replen;		/* expected reply words */
820
	u32		minorversion;
L
Linus Torvalds 已提交
821 822
};

823 824 825 826 827 828
static __be32 *reserve_space(struct xdr_stream *xdr, size_t nbytes)
{
	__be32 *p = xdr_reserve_space(xdr, nbytes);
	BUG_ON(!p);
	return p;
}
L
Linus Torvalds 已提交
829 830 831

static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
{
A
Al Viro 已提交
832
	__be32 *p;
L
Linus Torvalds 已提交
833 834 835 836 837 838

	p = xdr_reserve_space(xdr, 4 + len);
	BUG_ON(p == NULL);
	xdr_encode_opaque(p, str, len);
}

839 840 841
static void encode_compound_hdr(struct xdr_stream *xdr,
				struct rpc_rqst *req,
				struct compound_hdr *hdr)
L
Linus Torvalds 已提交
842
{
A
Al Viro 已提交
843
	__be32 *p;
844
	struct rpc_auth *auth = req->rq_cred->cr_auth;
845 846 847 848 849

	/* 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;
L
Linus Torvalds 已提交
850 851 852

	dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
	BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
853 854
	p = reserve_space(xdr, 4 + hdr->taglen + 8);
	p = xdr_encode_opaque(p, hdr->tag, hdr->taglen);
B
Benny Halevy 已提交
855
	*p++ = cpu_to_be32(hdr->minorversion);
856
	hdr->nops_p = p;
857
	*p = cpu_to_be32(hdr->nops);
858 859 860 861
}

static void encode_nops(struct compound_hdr *hdr)
{
A
Andy Adamson 已提交
862
	BUG_ON(hdr->nops > NFS4_MAX_OPS);
863
	*hdr->nops_p = htonl(hdr->nops);
L
Linus Torvalds 已提交
864 865 866 867
}

static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
{
A
Al Viro 已提交
868
	__be32 *p;
L
Linus Torvalds 已提交
869 870 871 872 873 874

	p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
	BUG_ON(p == NULL);
	xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE);
}

875
static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
L
Linus Torvalds 已提交
876 877 878 879 880
{
	char owner_name[IDMAP_NAMESZ];
	char owner_group[IDMAP_NAMESZ];
	int owner_namelen = 0;
	int owner_grouplen = 0;
A
Al Viro 已提交
881 882
	__be32 *p;
	__be32 *q;
L
Linus Torvalds 已提交
883 884 885 886 887 888 889 890 891
	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
892
	 *            such as owner/group.
L
Linus Torvalds 已提交
893 894 895 896 897 898 899 900 901
	 */
	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) {
902
		owner_namelen = nfs_map_uid_to_name(server, iap->ia_uid, owner_name, IDMAP_NAMESZ);
L
Linus Torvalds 已提交
903
		if (owner_namelen < 0) {
904 905
			dprintk("nfs: couldn't resolve uid %d to string\n",
					iap->ia_uid);
L
Linus Torvalds 已提交
906 907 908 909 910 911 912 913
			/* 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) {
914
		owner_grouplen = nfs_map_gid_to_group(server, iap->ia_gid, owner_group, IDMAP_NAMESZ);
L
Linus Torvalds 已提交
915
		if (owner_grouplen < 0) {
916 917
			dprintk("nfs: couldn't resolve gid %d to string\n",
					iap->ia_gid);
L
Linus Torvalds 已提交
918 919 920 921 922 923 924 925 926 927 928 929 930 931
			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;
932
	p = reserve_space(xdr, len);
L
Linus Torvalds 已提交
933 934 935 936 937

	/*
	 * We write the bitmap length now, but leave the bitmap and the attribute
	 * buffer length to be backfilled at the end of this routine.
	 */
B
Benny Halevy 已提交
938
	*p++ = cpu_to_be32(2);
L
Linus Torvalds 已提交
939 940 941 942 943
	q = p;
	p += 3;

	if (iap->ia_valid & ATTR_SIZE) {
		bmval0 |= FATTR4_WORD0_SIZE;
B
Benny Halevy 已提交
944
		p = xdr_encode_hyper(p, iap->ia_size);
L
Linus Torvalds 已提交
945 946 947
	}
	if (iap->ia_valid & ATTR_MODE) {
		bmval1 |= FATTR4_WORD1_MODE;
B
Benny Halevy 已提交
948
		*p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO);
L
Linus Torvalds 已提交
949 950 951
	}
	if (iap->ia_valid & ATTR_UID) {
		bmval1 |= FATTR4_WORD1_OWNER;
952
		p = xdr_encode_opaque(p, owner_name, owner_namelen);
L
Linus Torvalds 已提交
953 954 955
	}
	if (iap->ia_valid & ATTR_GID) {
		bmval1 |= FATTR4_WORD1_OWNER_GROUP;
956
		p = xdr_encode_opaque(p, owner_group, owner_grouplen);
L
Linus Torvalds 已提交
957 958 959
	}
	if (iap->ia_valid & ATTR_ATIME_SET) {
		bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
B
Benny Halevy 已提交
960 961
		*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
		*p++ = cpu_to_be32(0);
962 963
		*p++ = cpu_to_be32(iap->ia_atime.tv_sec);
		*p++ = cpu_to_be32(iap->ia_atime.tv_nsec);
L
Linus Torvalds 已提交
964 965 966
	}
	else if (iap->ia_valid & ATTR_ATIME) {
		bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
B
Benny Halevy 已提交
967
		*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
L
Linus Torvalds 已提交
968 969 970
	}
	if (iap->ia_valid & ATTR_MTIME_SET) {
		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
B
Benny Halevy 已提交
971 972 973 974
		*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);
L
Linus Torvalds 已提交
975 976 977
	}
	else if (iap->ia_valid & ATTR_MTIME) {
		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
B
Benny Halevy 已提交
978
		*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
L
Linus Torvalds 已提交
979
	}
980

L
Linus Torvalds 已提交
981 982 983 984
	/*
	 * Now we backfill the bitmap and the attribute buffer length.
	 */
	if (len != ((char *)p - (char *)q) + 4) {
985
		printk(KERN_ERR "nfs: Attr length error, %u != %Zu\n",
L
Linus Torvalds 已提交
986 987 988 989 990 991
				len, ((char *)p - (char *)q) + 4);
		BUG();
	}
	len = (char *)p - (char *)q - 12;
	*q++ = htonl(bmval0);
	*q++ = htonl(bmval1);
992
	*q = htonl(len);
L
Linus Torvalds 已提交
993 994 995 996

/* out: */
}

997
static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
998
{
A
Al Viro 已提交
999
	__be32 *p;
L
Linus Torvalds 已提交
1000

1001
	p = reserve_space(xdr, 8);
B
Benny Halevy 已提交
1002
	*p++ = cpu_to_be32(OP_ACCESS);
1003
	*p = cpu_to_be32(access);
1004
	hdr->nops++;
1005
	hdr->replen += decode_access_maxsz;
L
Linus Torvalds 已提交
1006 1007
}

1008
static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1009
{
A
Al Viro 已提交
1010
	__be32 *p;
L
Linus Torvalds 已提交
1011

1012
	p = reserve_space(xdr, 8+NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1013 1014
	*p++ = cpu_to_be32(OP_CLOSE);
	*p++ = cpu_to_be32(arg->seqid->sequence->counter);
1015
	xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
1016
	hdr->nops++;
1017
	hdr->replen += decode_close_maxsz;
L
Linus Torvalds 已提交
1018 1019
}

1020
static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1021
{
A
Al Viro 已提交
1022
	__be32 *p;
1023

1024
	p = reserve_space(xdr, 16);
B
Benny Halevy 已提交
1025
	*p++ = cpu_to_be32(OP_COMMIT);
B
Benny Halevy 已提交
1026
	p = xdr_encode_hyper(p, args->offset);
1027
	*p = cpu_to_be32(args->count);
1028
	hdr->nops++;
1029
	hdr->replen += decode_commit_maxsz;
L
Linus Torvalds 已提交
1030 1031
}

1032
static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1033
{
A
Al Viro 已提交
1034
	__be32 *p;
1035

1036
	p = reserve_space(xdr, 8);
B
Benny Halevy 已提交
1037
	*p++ = cpu_to_be32(OP_CREATE);
1038
	*p = cpu_to_be32(create->ftype);
L
Linus Torvalds 已提交
1039 1040 1041

	switch (create->ftype) {
	case NF4LNK:
1042
		p = reserve_space(xdr, 4);
1043
		*p = cpu_to_be32(create->u.symlink.len);
1044
		xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len);
L
Linus Torvalds 已提交
1045 1046 1047
		break;

	case NF4BLK: case NF4CHR:
1048
		p = reserve_space(xdr, 8);
B
Benny Halevy 已提交
1049
		*p++ = cpu_to_be32(create->u.device.specdata1);
1050
		*p = cpu_to_be32(create->u.device.specdata2);
L
Linus Torvalds 已提交
1051 1052 1053 1054 1055 1056
		break;

	default:
		break;
	}

1057
	encode_string(xdr, create->name->len, create->name->name);
1058
	hdr->nops++;
1059
	hdr->replen += decode_create_maxsz;
L
Linus Torvalds 已提交
1060

1061
	encode_attrs(xdr, create->attrs, create->server);
L
Linus Torvalds 已提交
1062 1063
}

1064
static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1065
{
A
Andy Adamson 已提交
1066
	__be32 *p;
L
Linus Torvalds 已提交
1067

1068
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
1069 1070
	*p++ = cpu_to_be32(OP_GETATTR);
	*p++ = cpu_to_be32(1);
1071
	*p = cpu_to_be32(bitmap);
1072
	hdr->nops++;
1073
	hdr->replen += decode_getattr_maxsz;
L
Linus Torvalds 已提交
1074 1075
}

1076
static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1077
{
A
Andy Adamson 已提交
1078
	__be32 *p;
L
Linus Torvalds 已提交
1079

1080
	p = reserve_space(xdr, 16);
B
Benny Halevy 已提交
1081 1082 1083
	*p++ = cpu_to_be32(OP_GETATTR);
	*p++ = cpu_to_be32(2);
	*p++ = cpu_to_be32(bm0);
1084
	*p = cpu_to_be32(bm1);
1085
	hdr->nops++;
1086
	hdr->replen += decode_getattr_maxsz;
L
Linus Torvalds 已提交
1087 1088
}

1089
static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1090
{
1091 1092
	encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
			   bitmask[1] & nfs4_fattr_bitmap[1], hdr);
L
Linus Torvalds 已提交
1093 1094
}

1095
static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1096
{
1097 1098
	encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
			   bitmask[1] & nfs4_fsinfo_bitmap[1], hdr);
L
Linus Torvalds 已提交
1099 1100
}

1101
static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
1102
{
1103 1104
	encode_getattr_two(xdr, bitmask[0] & nfs4_fs_locations_bitmap[0],
			   bitmask[1] & nfs4_fs_locations_bitmap[1], hdr);
1105 1106
}

1107
static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1108
{
A
Al Viro 已提交
1109
	__be32 *p;
L
Linus Torvalds 已提交
1110

1111
	p = reserve_space(xdr, 4);
1112
	*p = cpu_to_be32(OP_GETFH);
1113
	hdr->nops++;
1114
	hdr->replen += decode_getfh_maxsz;
L
Linus Torvalds 已提交
1115 1116
}

1117
static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1118
{
A
Al Viro 已提交
1119
	__be32 *p;
L
Linus Torvalds 已提交
1120

1121
	p = reserve_space(xdr, 8 + name->len);
B
Benny Halevy 已提交
1122
	*p++ = cpu_to_be32(OP_LINK);
1123
	xdr_encode_opaque(p, name->name, name->len);
1124
	hdr->nops++;
1125
	hdr->replen += decode_link_maxsz;
L
Linus Torvalds 已提交
1126 1127
}

T
Trond Myklebust 已提交
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
static inline int nfs4_lock_type(struct file_lock *fl, int block)
{
	if ((fl->fl_type & (F_RDLCK|F_WRLCK|F_UNLCK)) == F_RDLCK)
		return block ? NFS4_READW_LT : NFS4_READ_LT;
	return block ? NFS4_WRITEW_LT : NFS4_WRITE_LT;
}

static inline uint64_t nfs4_lock_length(struct file_lock *fl)
{
	if (fl->fl_end == OFFSET_MAX)
		return ~(uint64_t)0;
	return fl->fl_end - fl->fl_start + 1;
}

1142 1143 1144 1145
static void encode_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner)
{
	__be32 *p;

1146
	p = reserve_space(xdr, 32);
1147
	p = xdr_encode_hyper(p, lowner->clientid);
1148
	*p++ = cpu_to_be32(20);
1149
	p = xdr_encode_opaque_fixed(p, "lock id:", 8);
1150
	*p++ = cpu_to_be32(lowner->s_dev);
1151 1152 1153
	xdr_encode_hyper(p, lowner->id);
}

L
Linus Torvalds 已提交
1154 1155 1156 1157
/*
 * opcode,type,reclaim,offset,length,new_lock_owner = 32
 * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
 */
1158
static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1159
{
A
Al Viro 已提交
1160
	__be32 *p;
L
Linus Torvalds 已提交
1161

1162
	p = reserve_space(xdr, 32);
B
Benny Halevy 已提交
1163 1164 1165
	*p++ = cpu_to_be32(OP_LOCK);
	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, args->block));
	*p++ = cpu_to_be32(args->reclaim);
B
Benny Halevy 已提交
1166 1167
	p = xdr_encode_hyper(p, args->fl->fl_start);
	p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
1168
	*p = cpu_to_be32(args->new_lock_owner);
T
Trond Myklebust 已提交
1169
	if (args->new_lock_owner){
1170
		p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
B
Benny Halevy 已提交
1171
		*p++ = cpu_to_be32(args->open_seqid->sequence->counter);
B
Benny Halevy 已提交
1172
		p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1173
		*p++ = cpu_to_be32(args->lock_seqid->sequence->counter);
1174
		encode_lockowner(xdr, &args->lock_owner);
L
Linus Torvalds 已提交
1175 1176
	}
	else {
1177
		p = reserve_space(xdr, NFS4_STATEID_SIZE+4);
B
Benny Halevy 已提交
1178
		p = xdr_encode_opaque_fixed(p, args->lock_stateid->data, NFS4_STATEID_SIZE);
1179
		*p = cpu_to_be32(args->lock_seqid->sequence->counter);
L
Linus Torvalds 已提交
1180
	}
1181
	hdr->nops++;
1182
	hdr->replen += decode_lock_maxsz;
L
Linus Torvalds 已提交
1183 1184
}

1185
static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1186
{
A
Al Viro 已提交
1187
	__be32 *p;
L
Linus Torvalds 已提交
1188

1189
	p = reserve_space(xdr, 24);
B
Benny Halevy 已提交
1190 1191
	*p++ = cpu_to_be32(OP_LOCKT);
	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
B
Benny Halevy 已提交
1192 1193
	p = xdr_encode_hyper(p, args->fl->fl_start);
	p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
1194
	encode_lockowner(xdr, &args->lock_owner);
1195
	hdr->nops++;
1196
	hdr->replen += decode_lockt_maxsz;
L
Linus Torvalds 已提交
1197 1198
}

1199
static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1200
{
A
Al Viro 已提交
1201
	__be32 *p;
L
Linus Torvalds 已提交
1202

1203
	p = reserve_space(xdr, 12+NFS4_STATEID_SIZE+16);
B
Benny Halevy 已提交
1204 1205 1206
	*p++ = cpu_to_be32(OP_LOCKU);
	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
	*p++ = cpu_to_be32(args->seqid->sequence->counter);
B
Benny Halevy 已提交
1207
	p = xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1208
	p = xdr_encode_hyper(p, args->fl->fl_start);
1209
	xdr_encode_hyper(p, nfs4_lock_length(args->fl));
1210
	hdr->nops++;
1211
	hdr->replen += decode_locku_maxsz;
L
Linus Torvalds 已提交
1212 1213
}

1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
static void encode_release_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner, struct compound_hdr *hdr)
{
	__be32 *p;

	p = reserve_space(xdr, 4);
	*p = cpu_to_be32(OP_RELEASE_LOCKOWNER);
	encode_lockowner(xdr, lowner);
	hdr->nops++;
	hdr->replen += decode_release_lockowner_maxsz;
}

1225
static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1226 1227
{
	int len = name->len;
A
Al Viro 已提交
1228
	__be32 *p;
L
Linus Torvalds 已提交
1229

1230
	p = reserve_space(xdr, 8 + len);
B
Benny Halevy 已提交
1231
	*p++ = cpu_to_be32(OP_LOOKUP);
1232
	xdr_encode_opaque(p, name->name, len);
1233
	hdr->nops++;
1234
	hdr->replen += decode_lookup_maxsz;
L
Linus Torvalds 已提交
1235 1236
}

1237
static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode)
L
Linus Torvalds 已提交
1238
{
A
Al Viro 已提交
1239
	__be32 *p;
L
Linus Torvalds 已提交
1240

1241
	p = reserve_space(xdr, 8);
1242
	switch (fmode & (FMODE_READ|FMODE_WRITE)) {
A
Andy Adamson 已提交
1243
	case FMODE_READ:
B
Benny Halevy 已提交
1244
		*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_READ);
A
Andy Adamson 已提交
1245 1246
		break;
	case FMODE_WRITE:
B
Benny Halevy 已提交
1247
		*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_WRITE);
A
Andy Adamson 已提交
1248 1249
		break;
	case FMODE_READ|FMODE_WRITE:
B
Benny Halevy 已提交
1250
		*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_BOTH);
A
Andy Adamson 已提交
1251 1252
		break;
	default:
B
Benny Halevy 已提交
1253
		*p++ = cpu_to_be32(0);
L
Linus Torvalds 已提交
1254
	}
1255
	*p = cpu_to_be32(0);		/* for linux, share_deny = 0 always */
L
Linus Torvalds 已提交
1256 1257 1258 1259
}

static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg)
{
A
Al Viro 已提交
1260
	__be32 *p;
L
Linus Torvalds 已提交
1261 1262 1263 1264
 /*
 * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
 * owner 4 = 32
 */
1265
	p = reserve_space(xdr, 8);
B
Benny Halevy 已提交
1266
	*p++ = cpu_to_be32(OP_OPEN);
1267
	*p = cpu_to_be32(arg->seqid->sequence->counter);
1268
	encode_share_access(xdr, arg->fmode);
1269
	p = reserve_space(xdr, 32);
B
Benny Halevy 已提交
1270
	p = xdr_encode_hyper(p, arg->clientid);
1271
	*p++ = cpu_to_be32(20);
B
Benny Halevy 已提交
1272
	p = xdr_encode_opaque_fixed(p, "open id:", 8);
1273
	*p++ = cpu_to_be32(arg->server->s_dev);
1274
	xdr_encode_hyper(p, arg->id);
L
Linus Torvalds 已提交
1275 1276 1277 1278
}

static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
{
A
Al Viro 已提交
1279
	__be32 *p;
1280
	struct nfs_client *clp;
L
Linus Torvalds 已提交
1281

1282
	p = reserve_space(xdr, 4);
L
Linus Torvalds 已提交
1283
	switch(arg->open_flags & O_EXCL) {
A
Andy Adamson 已提交
1284
	case 0:
1285
		*p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
A
Andy Adamson 已提交
1286 1287 1288
		encode_attrs(xdr, arg->u.attrs, arg->server);
		break;
	default:
1289
		clp = arg->server->nfs_client;
1290
		if (clp->cl_mvops->minor_version > 0) {
1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305
			if (nfs4_has_persistent_session(clp)) {
				*p = cpu_to_be32(NFS4_CREATE_GUARDED);
				encode_attrs(xdr, arg->u.attrs, arg->server);
			} else {
				struct iattr dummy;

				*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
				encode_nfs4_verifier(xdr, &arg->u.verifier);
				dummy.ia_valid = 0;
				encode_attrs(xdr, &dummy, arg->server);
			}
		} else {
			*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
			encode_nfs4_verifier(xdr, &arg->u.verifier);
		}
L
Linus Torvalds 已提交
1306 1307 1308 1309 1310
	}
}

static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *arg)
{
A
Al Viro 已提交
1311
	__be32 *p;
L
Linus Torvalds 已提交
1312

1313
	p = reserve_space(xdr, 4);
L
Linus Torvalds 已提交
1314
	switch (arg->open_flags & O_CREAT) {
A
Andy Adamson 已提交
1315
	case 0:
1316
		*p = cpu_to_be32(NFS4_OPEN_NOCREATE);
A
Andy Adamson 已提交
1317 1318 1319
		break;
	default:
		BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL);
1320
		*p = cpu_to_be32(NFS4_OPEN_CREATE);
A
Andy Adamson 已提交
1321
		encode_createmode(xdr, arg);
L
Linus Torvalds 已提交
1322 1323 1324
	}
}

1325
static inline void encode_delegation_type(struct xdr_stream *xdr, fmode_t delegation_type)
L
Linus Torvalds 已提交
1326
{
A
Al Viro 已提交
1327
	__be32 *p;
L
Linus Torvalds 已提交
1328

1329
	p = reserve_space(xdr, 4);
L
Linus Torvalds 已提交
1330
	switch (delegation_type) {
A
Andy Adamson 已提交
1331
	case 0:
1332
		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_NONE);
A
Andy Adamson 已提交
1333 1334
		break;
	case FMODE_READ:
1335
		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_READ);
A
Andy Adamson 已提交
1336 1337
		break;
	case FMODE_WRITE|FMODE_READ:
1338
		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_WRITE);
A
Andy Adamson 已提交
1339 1340 1341
		break;
	default:
		BUG();
L
Linus Torvalds 已提交
1342 1343 1344 1345 1346
	}
}

static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr *name)
{
A
Al Viro 已提交
1347
	__be32 *p;
L
Linus Torvalds 已提交
1348

1349
	p = reserve_space(xdr, 4);
1350
	*p = cpu_to_be32(NFS4_OPEN_CLAIM_NULL);
L
Linus Torvalds 已提交
1351 1352 1353
	encode_string(xdr, name->len, name->name);
}

1354
static inline void encode_claim_previous(struct xdr_stream *xdr, fmode_t type)
L
Linus Torvalds 已提交
1355
{
A
Al Viro 已提交
1356
	__be32 *p;
L
Linus Torvalds 已提交
1357

1358
	p = reserve_space(xdr, 4);
1359
	*p = cpu_to_be32(NFS4_OPEN_CLAIM_PREVIOUS);
L
Linus Torvalds 已提交
1360 1361 1362 1363 1364
	encode_delegation_type(xdr, type);
}

static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struct qstr *name, const nfs4_stateid *stateid)
{
A
Al Viro 已提交
1365
	__be32 *p;
L
Linus Torvalds 已提交
1366

1367
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1368
	*p++ = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
1369
	xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1370 1371 1372
	encode_string(xdr, name->len, name->name);
}

1373
static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1374 1375 1376 1377
{
	encode_openhdr(xdr, arg);
	encode_opentype(xdr, arg);
	switch (arg->claim) {
A
Andy Adamson 已提交
1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388
	case NFS4_OPEN_CLAIM_NULL:
		encode_claim_null(xdr, arg->name);
		break;
	case NFS4_OPEN_CLAIM_PREVIOUS:
		encode_claim_previous(xdr, arg->u.delegation_type);
		break;
	case NFS4_OPEN_CLAIM_DELEGATE_CUR:
		encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation);
		break;
	default:
		BUG();
L
Linus Torvalds 已提交
1389
	}
1390
	hdr->nops++;
1391
	hdr->replen += decode_open_maxsz;
L
Linus Torvalds 已提交
1392 1393
}

1394
static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1395
{
A
Al Viro 已提交
1396
	__be32 *p;
L
Linus Torvalds 已提交
1397

1398
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
B
Benny Halevy 已提交
1399
	*p++ = cpu_to_be32(OP_OPEN_CONFIRM);
B
Benny Halevy 已提交
1400
	p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
1401
	*p = cpu_to_be32(arg->seqid->sequence->counter);
1402
	hdr->nops++;
1403
	hdr->replen += decode_open_confirm_maxsz;
L
Linus Torvalds 已提交
1404 1405
}

1406
static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1407
{
A
Al Viro 已提交
1408
	__be32 *p;
L
Linus Torvalds 已提交
1409

1410
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
B
Benny Halevy 已提交
1411
	*p++ = cpu_to_be32(OP_OPEN_DOWNGRADE);
B
Benny Halevy 已提交
1412
	p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
1413
	*p = cpu_to_be32(arg->seqid->sequence->counter);
1414
	encode_share_access(xdr, arg->fmode);
1415
	hdr->nops++;
1416
	hdr->replen += decode_open_downgrade_maxsz;
L
Linus Torvalds 已提交
1417 1418
}

1419
static void
1420
encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1421 1422
{
	int len = fh->size;
A
Al Viro 已提交
1423
	__be32 *p;
L
Linus Torvalds 已提交
1424

1425
	p = reserve_space(xdr, 8 + len);
B
Benny Halevy 已提交
1426
	*p++ = cpu_to_be32(OP_PUTFH);
1427
	xdr_encode_opaque(p, fh->data, len);
1428
	hdr->nops++;
1429
	hdr->replen += decode_putfh_maxsz;
L
Linus Torvalds 已提交
1430 1431
}

1432
static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1433
{
A
Andy Adamson 已提交
1434
	__be32 *p;
1435

1436
	p = reserve_space(xdr, 4);
1437
	*p = cpu_to_be32(OP_PUTROOTFH);
1438
	hdr->nops++;
1439
	hdr->replen += decode_putrootfh_maxsz;
L
Linus Torvalds 已提交
1440 1441
}

1442
static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx, const struct nfs_lock_context *l_ctx, int zero_seqid)
L
Linus Torvalds 已提交
1443 1444
{
	nfs4_stateid stateid;
A
Al Viro 已提交
1445
	__be32 *p;
L
Linus Torvalds 已提交
1446

1447
	p = reserve_space(xdr, NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1448
	if (ctx->state != NULL) {
1449
		nfs4_copy_stateid(&stateid, ctx->state, l_ctx->lockowner, l_ctx->pid);
1450 1451
		if (zero_seqid)
			stateid.stateid.seqid = 0;
1452
		xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1453
	} else
1454
		xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1455 1456
}

1457
static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1458
{
A
Al Viro 已提交
1459
	__be32 *p;
L
Linus Torvalds 已提交
1460

1461
	p = reserve_space(xdr, 4);
1462
	*p = cpu_to_be32(OP_READ);
L
Linus Torvalds 已提交
1463

1464 1465
	encode_stateid(xdr, args->context, args->lock_context,
		       hdr->minorversion);
L
Linus Torvalds 已提交
1466

1467
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
1468
	p = xdr_encode_hyper(p, args->offset);
1469
	*p = cpu_to_be32(args->count);
1470
	hdr->nops++;
1471
	hdr->replen += decode_read_maxsz;
L
Linus Torvalds 已提交
1472 1473
}

1474
static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1475
{
1476 1477 1478 1479
	uint32_t attrs[2] = {
		FATTR4_WORD0_RDATTR_ERROR,
		FATTR4_WORD1_MOUNTED_ON_FILEID,
	};
1480
	uint32_t dircount = readdir->count >> 1;
A
Al Viro 已提交
1481
	__be32 *p;
L
Linus Torvalds 已提交
1482

B
Bryan Schumaker 已提交
1483 1484
	if (readdir->plus) {
		attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
1485
			FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE|FATTR4_WORD0_FILEID;
B
Bryan Schumaker 已提交
1486 1487 1488 1489
		attrs[1] |= FATTR4_WORD1_MODE|FATTR4_WORD1_NUMLINKS|FATTR4_WORD1_OWNER|
			FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV|
			FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|
			FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
1490
		dircount >>= 1;
B
Bryan Schumaker 已提交
1491
	}
1492 1493 1494
	/* Use mounted_on_fileid only if the server supports it */
	if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))
		attrs[0] |= FATTR4_WORD0_FILEID;
B
Bryan Schumaker 已提交
1495

1496
	p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
B
Benny Halevy 已提交
1497
	*p++ = cpu_to_be32(OP_READDIR);
B
Benny Halevy 已提交
1498
	p = xdr_encode_hyper(p, readdir->cookie);
B
Benny Halevy 已提交
1499
	p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE);
1500
	*p++ = cpu_to_be32(dircount);
B
Benny Halevy 已提交
1501 1502
	*p++ = cpu_to_be32(readdir->count);
	*p++ = cpu_to_be32(2);
B
Bryan Schumaker 已提交
1503

B
Benny Halevy 已提交
1504
	*p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]);
1505
	*p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
1506
	hdr->nops++;
1507
	hdr->replen += decode_readdir_maxsz;
1508 1509
	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
			__func__,
1510 1511 1512 1513 1514
			(unsigned long long)readdir->cookie,
			((u32 *)readdir->verifier.data)[0],
			((u32 *)readdir->verifier.data)[1],
			attrs[0] & readdir->bitmask[0],
			attrs[1] & readdir->bitmask[1]);
L
Linus Torvalds 已提交
1515 1516
}

1517
static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1518
{
A
Al Viro 已提交
1519
	__be32 *p;
L
Linus Torvalds 已提交
1520

1521
	p = reserve_space(xdr, 4);
1522
	*p = cpu_to_be32(OP_READLINK);
1523
	hdr->nops++;
1524
	hdr->replen += decode_readlink_maxsz;
L
Linus Torvalds 已提交
1525 1526
}

1527
static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1528
{
A
Al Viro 已提交
1529
	__be32 *p;
L
Linus Torvalds 已提交
1530

1531
	p = reserve_space(xdr, 8 + name->len);
B
Benny Halevy 已提交
1532
	*p++ = cpu_to_be32(OP_REMOVE);
1533
	xdr_encode_opaque(p, name->name, name->len);
1534
	hdr->nops++;
1535
	hdr->replen += decode_remove_maxsz;
L
Linus Torvalds 已提交
1536 1537
}

1538
static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1539
{
A
Al Viro 已提交
1540
	__be32 *p;
L
Linus Torvalds 已提交
1541

1542 1543 1544 1545
	p = reserve_space(xdr, 4);
	*p = cpu_to_be32(OP_RENAME);
	encode_string(xdr, oldname->len, oldname->name);
	encode_string(xdr, newname->len, newname->name);
1546
	hdr->nops++;
1547
	hdr->replen += decode_rename_maxsz;
L
Linus Torvalds 已提交
1548 1549
}

1550
static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1551
{
A
Al Viro 已提交
1552
	__be32 *p;
L
Linus Torvalds 已提交
1553

1554
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
1555
	*p++ = cpu_to_be32(OP_RENEW);
1556
	xdr_encode_hyper(p, client_stateid->cl_clientid);
1557
	hdr->nops++;
1558
	hdr->replen += decode_renew_maxsz;
L
Linus Torvalds 已提交
1559 1560
}

1561
static void
1562
encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
1563
{
A
Al Viro 已提交
1564
	__be32 *p;
1565

1566
	p = reserve_space(xdr, 4);
1567
	*p = cpu_to_be32(OP_RESTOREFH);
1568
	hdr->nops++;
1569
	hdr->replen += decode_restorefh_maxsz;
1570 1571
}

1572
static void
1573
encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compound_hdr *hdr)
1574
{
A
Al Viro 已提交
1575
	__be32 *p;
1576

1577
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1578
	*p++ = cpu_to_be32(OP_SETATTR);
1579
	xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
1580
	p = reserve_space(xdr, 2*4);
B
Benny Halevy 已提交
1581
	*p++ = cpu_to_be32(1);
1582
	*p = cpu_to_be32(FATTR4_WORD0_ACL);
1583
	BUG_ON(arg->acl_len % 4);
1584
	p = reserve_space(xdr, 4);
1585
	*p = cpu_to_be32(arg->acl_len);
1586
	xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
1587
	hdr->nops++;
1588
	hdr->replen += decode_setacl_maxsz;
1589 1590
}

1591
static void
1592
encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1593
{
A
Al Viro 已提交
1594
	__be32 *p;
L
Linus Torvalds 已提交
1595

1596
	p = reserve_space(xdr, 4);
1597
	*p = cpu_to_be32(OP_SAVEFH);
1598
	hdr->nops++;
1599
	hdr->replen += decode_savefh_maxsz;
L
Linus Torvalds 已提交
1600 1601
}

1602
static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1603
{
A
Al Viro 已提交
1604
	__be32 *p;
1605

1606
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1607
	*p++ = cpu_to_be32(OP_SETATTR);
1608
	xdr_encode_opaque_fixed(p, arg->stateid.data, NFS4_STATEID_SIZE);
1609
	hdr->nops++;
1610
	hdr->replen += decode_setattr_maxsz;
1611
	encode_attrs(xdr, arg->iap, server);
L
Linus Torvalds 已提交
1612 1613
}

1614
static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1615
{
A
Al Viro 已提交
1616
	__be32 *p;
L
Linus Torvalds 已提交
1617

1618
	p = reserve_space(xdr, 4 + NFS4_VERIFIER_SIZE);
B
Benny Halevy 已提交
1619
	*p++ = cpu_to_be32(OP_SETCLIENTID);
1620
	xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE);
L
Linus Torvalds 已提交
1621 1622

	encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
1623
	p = reserve_space(xdr, 4);
1624
	*p = cpu_to_be32(setclientid->sc_prog);
L
Linus Torvalds 已提交
1625 1626
	encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid);
	encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
1627
	p = reserve_space(xdr, 4);
1628
	*p = cpu_to_be32(setclientid->sc_cb_ident);
1629
	hdr->nops++;
1630
	hdr->replen += decode_setclientid_maxsz;
L
Linus Torvalds 已提交
1631 1632
}

1633
static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_setclientid_res *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1634
{
A
Andy Adamson 已提交
1635
	__be32 *p;
L
Linus Torvalds 已提交
1636

1637
	p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE);
B
Benny Halevy 已提交
1638
	*p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM);
1639 1640
	p = xdr_encode_hyper(p, arg->clientid);
	xdr_encode_opaque_fixed(p, arg->confirm.data, NFS4_VERIFIER_SIZE);
1641
	hdr->nops++;
1642
	hdr->replen += decode_setclientid_confirm_maxsz;
L
Linus Torvalds 已提交
1643 1644
}

1645
static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1646
{
A
Al Viro 已提交
1647
	__be32 *p;
L
Linus Torvalds 已提交
1648

1649
	p = reserve_space(xdr, 4);
1650
	*p = cpu_to_be32(OP_WRITE);
L
Linus Torvalds 已提交
1651

1652 1653
	encode_stateid(xdr, args->context, args->lock_context,
		       hdr->minorversion);
L
Linus Torvalds 已提交
1654

1655
	p = reserve_space(xdr, 16);
B
Benny Halevy 已提交
1656
	p = xdr_encode_hyper(p, args->offset);
B
Benny Halevy 已提交
1657
	*p++ = cpu_to_be32(args->stable);
1658
	*p = cpu_to_be32(args->count);
L
Linus Torvalds 已提交
1659 1660

	xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
1661
	hdr->nops++;
1662
	hdr->replen += decode_write_maxsz;
L
Linus Torvalds 已提交
1663 1664
}

1665
static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1666
{
A
Al Viro 已提交
1667
	__be32 *p;
L
Linus Torvalds 已提交
1668

1669
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1670

B
Benny Halevy 已提交
1671
	*p++ = cpu_to_be32(OP_DELEGRETURN);
1672
	xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
1673
	hdr->nops++;
1674
	hdr->replen += decode_delegreturn_maxsz;
L
Linus Torvalds 已提交
1675
}
1676

B
Bryan Schumaker 已提交
1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688
static void encode_secinfo(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
{
	int len = name->len;
	__be32 *p;

	p = reserve_space(xdr, 8 + len);
	*p++ = cpu_to_be32(OP_SECINFO);
	xdr_encode_opaque(p, name->name, len);
	hdr->nops++;
	hdr->replen += decode_secinfo_maxsz;
}

B
Benny Halevy 已提交
1689
#if defined(CONFIG_NFS_V4_1)
1690
/* NFSv4.1 operations */
B
Benny Halevy 已提交
1691 1692 1693 1694 1695 1696
static void encode_exchange_id(struct xdr_stream *xdr,
			       struct nfs41_exchange_id_args *args,
			       struct compound_hdr *hdr)
{
	__be32 *p;

1697
	p = reserve_space(xdr, 4 + sizeof(args->verifier->data));
B
Benny Halevy 已提交
1698
	*p++ = cpu_to_be32(OP_EXCHANGE_ID);
1699
	xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data));
B
Benny Halevy 已提交
1700 1701 1702

	encode_string(xdr, args->id_len, args->id);

1703
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
1704 1705
	*p++ = cpu_to_be32(args->flags);
	*p++ = cpu_to_be32(0);	/* zero length state_protect4_a */
1706
	*p = cpu_to_be32(0);	/* zero length implementation id array */
B
Benny Halevy 已提交
1707 1708 1709
	hdr->nops++;
	hdr->replen += decode_exchange_id_maxsz;
}
A
Andy Adamson 已提交
1710 1711 1712 1713 1714 1715 1716 1717 1718

static void encode_create_session(struct xdr_stream *xdr,
				  struct nfs41_create_session_args *args,
				  struct compound_hdr *hdr)
{
	__be32 *p;
	char machine_name[NFS4_MAX_MACHINE_NAME_LEN];
	uint32_t len;
	struct nfs_client *clp = args->client;
1719 1720 1721 1722 1723 1724 1725 1726
	u32 max_resp_sz_cached;

	/*
	 * Assumes OPEN is the biggest non-idempotent compound.
	 * 2 is the verifier.
	 */
	max_resp_sz_cached = (NFS4_dec_open_sz + RPC_REPHDRSIZE +
			      RPC_MAX_AUTH_SIZE + 2) * XDR_UNIT;
A
Andy Adamson 已提交
1727

1728 1729
	len = scnprintf(machine_name, sizeof(machine_name), "%s",
			clp->cl_ipaddr);
A
Andy Adamson 已提交
1730

1731
	p = reserve_space(xdr, 20 + 2*28 + 20 + len + 12);
1732
	*p++ = cpu_to_be32(OP_CREATE_SESSION);
1733
	p = xdr_encode_hyper(p, clp->cl_clientid);
B
Benny Halevy 已提交
1734 1735
	*p++ = cpu_to_be32(clp->cl_seqid);			/*Sequence id */
	*p++ = cpu_to_be32(args->flags);			/*flags */
A
Andy Adamson 已提交
1736 1737

	/* Fore Channel */
1738
	*p++ = cpu_to_be32(0);				/* header padding size */
B
Benny Halevy 已提交
1739 1740
	*p++ = cpu_to_be32(args->fc_attrs.max_rqst_sz);	/* max req size */
	*p++ = cpu_to_be32(args->fc_attrs.max_resp_sz);	/* max resp size */
1741
	*p++ = cpu_to_be32(max_resp_sz_cached);		/* Max resp sz cached */
B
Benny Halevy 已提交
1742 1743 1744
	*p++ = cpu_to_be32(args->fc_attrs.max_ops);	/* max operations */
	*p++ = cpu_to_be32(args->fc_attrs.max_reqs);	/* max requests */
	*p++ = cpu_to_be32(0);				/* rdmachannel_attrs */
A
Andy Adamson 已提交
1745 1746

	/* Back Channel */
1747
	*p++ = cpu_to_be32(0);				/* header padding size */
B
Benny Halevy 已提交
1748 1749 1750 1751 1752 1753
	*p++ = cpu_to_be32(args->bc_attrs.max_rqst_sz);	/* max req size */
	*p++ = cpu_to_be32(args->bc_attrs.max_resp_sz);	/* max resp size */
	*p++ = cpu_to_be32(args->bc_attrs.max_resp_sz_cached);	/* Max resp sz cached */
	*p++ = cpu_to_be32(args->bc_attrs.max_ops);	/* max operations */
	*p++ = cpu_to_be32(args->bc_attrs.max_reqs);	/* max requests */
	*p++ = cpu_to_be32(0);				/* rdmachannel_attrs */
A
Andy Adamson 已提交
1754

B
Benny Halevy 已提交
1755 1756 1757
	*p++ = cpu_to_be32(args->cb_program);		/* cb_program */
	*p++ = cpu_to_be32(1);
	*p++ = cpu_to_be32(RPC_AUTH_UNIX);			/* auth_sys */
A
Andy Adamson 已提交
1758 1759

	/* authsys_parms rfc1831 */
B
Benny Halevy 已提交
1760
	*p++ = cpu_to_be32((u32)clp->cl_boot_time.tv_nsec);	/* stamp */
1761
	p = xdr_encode_opaque(p, machine_name, len);
B
Benny Halevy 已提交
1762 1763
	*p++ = cpu_to_be32(0);				/* UID */
	*p++ = cpu_to_be32(0);				/* GID */
1764
	*p = cpu_to_be32(0);				/* No more gids */
A
Andy Adamson 已提交
1765 1766 1767
	hdr->nops++;
	hdr->replen += decode_create_session_maxsz;
}
A
Andy Adamson 已提交
1768 1769 1770 1771 1772 1773

static void encode_destroy_session(struct xdr_stream *xdr,
				   struct nfs4_session *session,
				   struct compound_hdr *hdr)
{
	__be32 *p;
1774
	p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN);
B
Benny Halevy 已提交
1775
	*p++ = cpu_to_be32(OP_DESTROY_SESSION);
1776
	xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
A
Andy Adamson 已提交
1777 1778 1779
	hdr->nops++;
	hdr->replen += decode_destroy_session_maxsz;
}
1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792

static void encode_reclaim_complete(struct xdr_stream *xdr,
				    struct nfs41_reclaim_complete_args *args,
				    struct compound_hdr *hdr)
{
	__be32 *p;

	p = reserve_space(xdr, 8);
	*p++ = cpu_to_be32(OP_RECLAIM_COMPLETE);
	*p++ = cpu_to_be32(args->one_fs);
	hdr->nops++;
	hdr->replen += decode_reclaim_complete_maxsz;
}
B
Benny Halevy 已提交
1793 1794
#endif /* CONFIG_NFS_V4_1 */

1795 1796 1797 1798 1799 1800
static void encode_sequence(struct xdr_stream *xdr,
			    const struct nfs4_sequence_args *args,
			    struct compound_hdr *hdr)
{
#if defined(CONFIG_NFS_V4_1)
	struct nfs4_session *session = args->sa_session;
A
Andy Adamson 已提交
1801 1802 1803
	struct nfs4_slot_table *tp;
	struct nfs4_slot *slot;
	__be32 *p;
1804 1805 1806 1807

	if (!session)
		return;

A
Andy Adamson 已提交
1808 1809 1810 1811 1812
	tp = &session->fc_slot_table;

	WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE);
	slot = tp->slots + args->sa_slotid;

1813
	p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN + 16);
B
Benny Halevy 已提交
1814
	*p++ = cpu_to_be32(OP_SEQUENCE);
A
Andy Adamson 已提交
1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827

	/*
	 * Sessionid + seqid + slotid + max slotid + cache_this
	 */
	dprintk("%s: sessionid=%u:%u:%u:%u seqid=%d slotid=%d "
		"max_slotid=%d cache_this=%d\n",
		__func__,
		((u32 *)session->sess_id.data)[0],
		((u32 *)session->sess_id.data)[1],
		((u32 *)session->sess_id.data)[2],
		((u32 *)session->sess_id.data)[3],
		slot->seq_nr, args->sa_slotid,
		tp->highest_used_slotid, args->sa_cache_this);
B
Benny Halevy 已提交
1828
	p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
B
Benny Halevy 已提交
1829 1830 1831
	*p++ = cpu_to_be32(slot->seq_nr);
	*p++ = cpu_to_be32(args->sa_slotid);
	*p++ = cpu_to_be32(tp->highest_used_slotid);
1832
	*p = cpu_to_be32(args->sa_cache_this);
1833 1834 1835 1836 1837
	hdr->nops++;
	hdr->replen += decode_sequence_maxsz;
#endif /* CONFIG_NFS_V4_1 */
}

1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871
#ifdef CONFIG_NFS_V4_1
static void
encode_getdeviceinfo(struct xdr_stream *xdr,
		     const struct nfs4_getdeviceinfo_args *args,
		     struct compound_hdr *hdr)
{
	__be32 *p;

	p = reserve_space(xdr, 16 + NFS4_DEVICEID4_SIZE);
	*p++ = cpu_to_be32(OP_GETDEVICEINFO);
	p = xdr_encode_opaque_fixed(p, args->pdev->dev_id.data,
				    NFS4_DEVICEID4_SIZE);
	*p++ = cpu_to_be32(args->pdev->layout_type);
	*p++ = cpu_to_be32(args->pdev->pglen);		/* gdia_maxcount */
	*p++ = cpu_to_be32(0);				/* bitmap length 0 */
	hdr->nops++;
	hdr->replen += decode_getdeviceinfo_maxsz;
}

static void
encode_layoutget(struct xdr_stream *xdr,
		      const struct nfs4_layoutget_args *args,
		      struct compound_hdr *hdr)
{
	__be32 *p;

	p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE);
	*p++ = cpu_to_be32(OP_LAYOUTGET);
	*p++ = cpu_to_be32(0);     /* Signal layout available */
	*p++ = cpu_to_be32(args->type);
	*p++ = cpu_to_be32(args->range.iomode);
	p = xdr_encode_hyper(p, args->range.offset);
	p = xdr_encode_hyper(p, args->range.length);
	p = xdr_encode_hyper(p, args->minlength);
1872
	p = xdr_encode_opaque_fixed(p, &args->stateid.data, NFS4_STATEID_SIZE);
1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884
	*p = cpu_to_be32(args->maxcount);

	dprintk("%s: 1st type:0x%x iomode:%d off:%lu len:%lu mc:%d\n",
		__func__,
		args->type,
		args->range.iomode,
		(unsigned long)args->range.offset,
		(unsigned long)args->range.length,
		args->maxcount);
	hdr->nops++;
	hdr->replen += decode_layoutget_maxsz;
}
A
Andy Adamson 已提交
1885 1886 1887

static int
encode_layoutcommit(struct xdr_stream *xdr,
B
Benny Halevy 已提交
1888
		    struct inode *inode,
A
Andy Adamson 已提交
1889 1890 1891 1892 1893 1894 1895 1896
		    const struct nfs4_layoutcommit_args *args,
		    struct compound_hdr *hdr)
{
	__be32 *p;

	dprintk("%s: lbw: %llu type: %d\n", __func__, args->lastbytewritten,
		NFS_SERVER(args->inode)->pnfs_curr_ld->id);

B
Benny Halevy 已提交
1897
	p = reserve_space(xdr, 44 + NFS4_STATEID_SIZE);
A
Andy Adamson 已提交
1898 1899 1900 1901 1902 1903 1904 1905 1906 1907
	*p++ = cpu_to_be32(OP_LAYOUTCOMMIT);
	/* Only whole file layouts */
	p = xdr_encode_hyper(p, 0); /* offset */
	p = xdr_encode_hyper(p, NFS4_MAX_UINT64); /* length */
	*p++ = cpu_to_be32(0); /* reclaim */
	p = xdr_encode_opaque_fixed(p, args->stateid.data, NFS4_STATEID_SIZE);
	*p++ = cpu_to_be32(1); /* newoffset = TRUE */
	p = xdr_encode_hyper(p, args->lastbytewritten);
	*p++ = cpu_to_be32(0); /* Never send time_modify_changed */
	*p++ = cpu_to_be32(NFS_SERVER(args->inode)->pnfs_curr_ld->id);/* type */
B
Benny Halevy 已提交
1908 1909 1910 1911 1912 1913 1914 1915

	if (NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit)
		NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit(
			NFS_I(inode)->layout, xdr, args);
	else {
		p = reserve_space(xdr, 4);
		*p = cpu_to_be32(0); /* no layout-type payload */
	}
A
Andy Adamson 已提交
1916 1917 1918 1919 1920

	hdr->nops++;
	hdr->replen += decode_layoutcommit_maxsz;
	return 0;
}
B
Benny Halevy 已提交
1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940

static void
encode_layoutreturn(struct xdr_stream *xdr,
		    const struct nfs4_layoutreturn_args *args,
		    struct compound_hdr *hdr)
{
	__be32 *p;

	p = reserve_space(xdr, 20);
	*p++ = cpu_to_be32(OP_LAYOUTRETURN);
	*p++ = cpu_to_be32(0);		/* reclaim. always 0 for now */
	*p++ = cpu_to_be32(args->layout_type);
	*p++ = cpu_to_be32(IOMODE_ANY);
	*p = cpu_to_be32(RETURN_FILE);
	p = reserve_space(xdr, 16 + NFS4_STATEID_SIZE);
	p = xdr_encode_hyper(p, 0);
	p = xdr_encode_hyper(p, NFS4_MAX_UINT64);
	spin_lock(&args->inode->i_lock);
	xdr_encode_opaque_fixed(p, &args->stateid.data, NFS4_STATEID_SIZE);
	spin_unlock(&args->inode->i_lock);
A
Andy Adamson 已提交
1941 1942 1943 1944 1945 1946 1947
	if (NFS_SERVER(args->inode)->pnfs_curr_ld->encode_layoutreturn) {
		NFS_SERVER(args->inode)->pnfs_curr_ld->encode_layoutreturn(
			NFS_I(args->inode)->layout, xdr, args);
	} else {
		p = reserve_space(xdr, 4);
		*p = cpu_to_be32(0);
	}
B
Benny Halevy 已提交
1948 1949 1950
	hdr->nops++;
	hdr->replen += decode_layoutreturn_maxsz;
}
1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964

static int
encode_secinfo_no_name(struct xdr_stream *xdr,
		       const struct nfs41_secinfo_no_name_args *args,
		       struct compound_hdr *hdr)
{
	__be32 *p;
	p = reserve_space(xdr, 8);
	*p++ = cpu_to_be32(OP_SECINFO_NO_NAME);
	*p++ = cpu_to_be32(args->style);
	hdr->nops++;
	hdr->replen += decode_secinfo_no_name_maxsz;
	return 0;
}
1965 1966
#endif /* CONFIG_NFS_V4_1 */

L
Linus Torvalds 已提交
1967 1968 1969 1970
/*
 * END OF "GENERIC" ENCODE ROUTINES.
 */

1971 1972 1973 1974
static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args)
{
#if defined(CONFIG_NFS_V4_1)
	if (args->sa_session)
1975
		return args->sa_session->clp->cl_mvops->minor_version;
1976 1977 1978 1979
#endif /* CONFIG_NFS_V4_1 */
	return 0;
}

L
Linus Torvalds 已提交
1980 1981 1982
/*
 * Encode an ACCESS request
 */
1983 1984
static void nfs4_xdr_enc_access(struct rpc_rqst *req, struct xdr_stream *xdr,
				const struct nfs4_accessargs *args)
L
Linus Torvalds 已提交
1985 1986
{
	struct compound_hdr hdr = {
1987
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1988 1989
	};

1990 1991 1992 1993 1994
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_access(xdr, args->access, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
1995
	encode_nops(&hdr);
L
Linus Torvalds 已提交
1996 1997 1998 1999 2000
}

/*
 * Encode LOOKUP request
 */
2001 2002
static void nfs4_xdr_enc_lookup(struct rpc_rqst *req, struct xdr_stream *xdr,
				const struct nfs4_lookup_arg *args)
L
Linus Torvalds 已提交
2003 2004
{
	struct compound_hdr hdr = {
2005
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2006 2007
	};

2008 2009 2010 2011 2012 2013
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->dir_fh, &hdr);
	encode_lookup(xdr, args->name, &hdr);
	encode_getfh(xdr, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
2014
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2015 2016 2017 2018 2019
}

/*
 * Encode LOOKUP_ROOT request
 */
2020 2021 2022
static void nfs4_xdr_enc_lookup_root(struct rpc_rqst *req,
				     struct xdr_stream *xdr,
				     const struct nfs4_lookup_root_arg *args)
L
Linus Torvalds 已提交
2023 2024
{
	struct compound_hdr hdr = {
2025
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2026 2027
	};

2028 2029 2030 2031 2032
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putrootfh(xdr, &hdr);
	encode_getfh(xdr, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
2033
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2034 2035 2036 2037 2038
}

/*
 * Encode REMOVE request
 */
2039 2040
static void nfs4_xdr_enc_remove(struct rpc_rqst *req, struct xdr_stream *xdr,
				const struct nfs_removeargs *args)
L
Linus Torvalds 已提交
2041 2042
{
	struct compound_hdr hdr = {
2043
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2044 2045
	};

2046 2047 2048 2049 2050
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_remove(xdr, &args->name, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
2051
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2052 2053 2054 2055 2056
}

/*
 * Encode RENAME request
 */
2057 2058
static void nfs4_xdr_enc_rename(struct rpc_rqst *req, struct xdr_stream *xdr,
				const struct nfs_renameargs *args)
L
Linus Torvalds 已提交
2059 2060
{
	struct compound_hdr hdr = {
2061
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2062 2063
	};

2064 2065 2066 2067 2068 2069 2070 2071 2072
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->old_dir, &hdr);
	encode_savefh(xdr, &hdr);
	encode_putfh(xdr, args->new_dir, &hdr);
	encode_rename(xdr, args->old_name, args->new_name, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
	encode_restorefh(xdr, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
2073
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2074 2075 2076 2077 2078
}

/*
 * Encode LINK request
 */
2079 2080
static void nfs4_xdr_enc_link(struct rpc_rqst *req, struct xdr_stream *xdr,
			     const struct nfs4_link_arg *args)
L
Linus Torvalds 已提交
2081 2082
{
	struct compound_hdr hdr = {
2083
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2084 2085
	};

2086 2087 2088 2089 2090 2091 2092 2093 2094
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_savefh(xdr, &hdr);
	encode_putfh(xdr, args->dir_fh, &hdr);
	encode_link(xdr, args->name, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
	encode_restorefh(xdr, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
2095
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2096 2097 2098 2099 2100
}

/*
 * Encode CREATE request
 */
2101 2102
static void nfs4_xdr_enc_create(struct rpc_rqst *req, struct xdr_stream *xdr,
				const struct nfs4_create_arg *args)
L
Linus Torvalds 已提交
2103 2104
{
	struct compound_hdr hdr = {
2105
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2106 2107
	};

2108 2109 2110 2111 2112 2113 2114 2115 2116
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->dir_fh, &hdr);
	encode_savefh(xdr, &hdr);
	encode_create(xdr, args, &hdr);
	encode_getfh(xdr, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
	encode_restorefh(xdr, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
2117
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2118 2119 2120 2121 2122
}

/*
 * Encode SYMLINK request
 */
2123 2124
static void nfs4_xdr_enc_symlink(struct rpc_rqst *req, struct xdr_stream *xdr,
				 const struct nfs4_create_arg *args)
L
Linus Torvalds 已提交
2125
{
2126
	nfs4_xdr_enc_create(req, xdr, args);
L
Linus Torvalds 已提交
2127 2128 2129 2130 2131
}

/*
 * Encode GETATTR request
 */
2132 2133
static void nfs4_xdr_enc_getattr(struct rpc_rqst *req, struct xdr_stream *xdr,
				 const struct nfs4_getattr_arg *args)
L
Linus Torvalds 已提交
2134 2135
{
	struct compound_hdr hdr = {
2136
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2137 2138
	};

2139 2140 2141 2142
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
2143
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2144 2145 2146 2147 2148
}

/*
 * Encode a CLOSE request
 */
2149 2150
static void nfs4_xdr_enc_close(struct rpc_rqst *req, struct xdr_stream *xdr,
			       struct nfs_closeargs *args)
L
Linus Torvalds 已提交
2151
{
A
Andy Adamson 已提交
2152
	struct compound_hdr hdr = {
2153
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
A
Andy Adamson 已提交
2154 2155
	};

2156 2157 2158 2159 2160
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_close(xdr, args, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
2161
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2162 2163 2164 2165 2166
}

/*
 * Encode an OPEN request
 */
2167 2168
static void nfs4_xdr_enc_open(struct rpc_rqst *req, struct xdr_stream *xdr,
			      struct nfs_openargs *args)
L
Linus Torvalds 已提交
2169 2170
{
	struct compound_hdr hdr = {
2171
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2172 2173
	};

2174 2175 2176 2177 2178 2179 2180 2181 2182
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_savefh(xdr, &hdr);
	encode_open(xdr, args, &hdr);
	encode_getfh(xdr, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
	encode_restorefh(xdr, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
2183
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2184 2185 2186 2187 2188
}

/*
 * Encode an OPEN_CONFIRM request
 */
2189 2190 2191
static void nfs4_xdr_enc_open_confirm(struct rpc_rqst *req,
				      struct xdr_stream *xdr,
				      struct nfs_open_confirmargs *args)
L
Linus Torvalds 已提交
2192 2193
{
	struct compound_hdr hdr = {
2194
		.nops   = 0,
L
Linus Torvalds 已提交
2195 2196
	};

2197 2198 2199
	encode_compound_hdr(xdr, req, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_open_confirm(xdr, args, &hdr);
2200
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2201 2202 2203 2204 2205
}

/*
 * Encode an OPEN request with no attributes.
 */
2206 2207 2208
static void nfs4_xdr_enc_open_noattr(struct rpc_rqst *req,
				     struct xdr_stream *xdr,
				     struct nfs_openargs *args)
L
Linus Torvalds 已提交
2209 2210
{
	struct compound_hdr hdr = {
2211
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2212 2213
	};

2214 2215 2216 2217 2218
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_open(xdr, args, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
2219
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2220 2221 2222 2223 2224
}

/*
 * Encode an OPEN_DOWNGRADE request
 */
2225 2226 2227
static void nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req,
					struct xdr_stream *xdr,
					struct nfs_closeargs *args)
L
Linus Torvalds 已提交
2228 2229
{
	struct compound_hdr hdr = {
2230
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2231 2232
	};

2233 2234 2235 2236 2237
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_open_downgrade(xdr, args, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
2238
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2239 2240 2241 2242 2243
}

/*
 * Encode a LOCK request
 */
2244 2245
static void nfs4_xdr_enc_lock(struct rpc_rqst *req, struct xdr_stream *xdr,
			      struct nfs_lock_args *args)
L
Linus Torvalds 已提交
2246 2247
{
	struct compound_hdr hdr = {
2248
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2249 2250
	};

2251 2252 2253 2254
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_lock(xdr, args, &hdr);
2255
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2256 2257 2258 2259 2260
}

/*
 * Encode a LOCKT request
 */
2261 2262
static void nfs4_xdr_enc_lockt(struct rpc_rqst *req, struct xdr_stream *xdr,
			       struct nfs_lockt_args *args)
L
Linus Torvalds 已提交
2263 2264
{
	struct compound_hdr hdr = {
2265
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2266 2267
	};

2268 2269 2270 2271
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_lockt(xdr, args, &hdr);
2272
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2273 2274 2275 2276 2277
}

/*
 * Encode a LOCKU request
 */
2278 2279
static void nfs4_xdr_enc_locku(struct rpc_rqst *req, struct xdr_stream *xdr,
			       struct nfs_locku_args *args)
L
Linus Torvalds 已提交
2280 2281
{
	struct compound_hdr hdr = {
2282
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2283 2284
	};

2285 2286 2287 2288
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_locku(xdr, args, &hdr);
2289
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2290 2291
}

2292 2293 2294
static void nfs4_xdr_enc_release_lockowner(struct rpc_rqst *req,
					   struct xdr_stream *xdr,
					struct nfs_release_lockowner_args *args)
2295 2296 2297 2298 2299
{
	struct compound_hdr hdr = {
		.minorversion = 0,
	};

2300 2301
	encode_compound_hdr(xdr, req, &hdr);
	encode_release_lockowner(xdr, &args->lock_owner, &hdr);
2302 2303 2304
	encode_nops(&hdr);
}

L
Linus Torvalds 已提交
2305 2306 2307
/*
 * Encode a READLINK request
 */
2308 2309
static void nfs4_xdr_enc_readlink(struct rpc_rqst *req, struct xdr_stream *xdr,
				  const struct nfs4_readlink *args)
L
Linus Torvalds 已提交
2310 2311
{
	struct compound_hdr hdr = {
2312
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2313 2314
	};

2315 2316 2317 2318
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_readlink(xdr, args, req, &hdr);
2319

2320
	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
2321
			args->pgbase, args->pglen);
2322
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2323 2324 2325 2326 2327
}

/*
 * Encode a READDIR request
 */
2328 2329
static void nfs4_xdr_enc_readdir(struct rpc_rqst *req, struct xdr_stream *xdr,
				 const struct nfs4_readdir_arg *args)
L
Linus Torvalds 已提交
2330 2331
{
	struct compound_hdr hdr = {
2332
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2333 2334
	};

2335 2336 2337 2338
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_readdir(xdr, args, req, &hdr);
2339

2340
	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
2341 2342
			 args->pgbase, args->count);
	dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
2343
			__func__, hdr.replen << 2, args->pages,
2344
			args->pgbase, args->count);
2345
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2346 2347 2348 2349 2350
}

/*
 * Encode a READ request
 */
2351 2352
static void nfs4_xdr_enc_read(struct rpc_rqst *req, struct xdr_stream *xdr,
			      struct nfs_readargs *args)
L
Linus Torvalds 已提交
2353 2354
{
	struct compound_hdr hdr = {
2355
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2356 2357
	};

2358 2359 2360 2361
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_read(xdr, args, &hdr);
L
Linus Torvalds 已提交
2362

2363
	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2,
L
Linus Torvalds 已提交
2364
			 args->pages, args->pgbase, args->count);
2365
	req->rq_rcv_buf.flags |= XDRBUF_READ;
2366
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2367 2368 2369 2370 2371
}

/*
 * Encode an SETATTR request
 */
2372 2373
static void nfs4_xdr_enc_setattr(struct rpc_rqst *req, struct xdr_stream *xdr,
				 struct nfs_setattrargs *args)
L
Linus Torvalds 已提交
2374
{
A
Andy Adamson 已提交
2375
	struct compound_hdr hdr = {
2376
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
A
Andy Adamson 已提交
2377 2378
	};

2379 2380 2381 2382 2383
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_setattr(xdr, args, args->server, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
2384
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2385 2386
}

2387 2388 2389
/*
 * Encode a GETACL request
 */
2390 2391
static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
				struct nfs_getaclargs *args)
2392 2393
{
	struct compound_hdr hdr = {
2394
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
2395
	};
2396
	uint32_t replen;
2397

2398 2399 2400
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
2401
	replen = hdr.replen + op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz + 1;
2402
	encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr);
2403

2404
	xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
2405
		args->acl_pages, args->acl_pgbase, args->acl_len);
2406
	encode_nops(&hdr);
2407 2408
}

L
Linus Torvalds 已提交
2409 2410 2411
/*
 * Encode a WRITE request
 */
2412 2413
static void nfs4_xdr_enc_write(struct rpc_rqst *req, struct xdr_stream *xdr,
			       struct nfs_writeargs *args)
L
Linus Torvalds 已提交
2414 2415
{
	struct compound_hdr hdr = {
2416
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2417 2418
	};

2419 2420 2421 2422
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_write(xdr, args, &hdr);
2423
	req->rq_snd_buf.flags |= XDRBUF_WRITE;
2424 2425
	if (args->bitmask)
		encode_getfattr(xdr, args->bitmask, &hdr);
2426
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2427 2428 2429 2430 2431
}

/*
 *  a COMMIT request
 */
2432 2433
static void nfs4_xdr_enc_commit(struct rpc_rqst *req, struct xdr_stream *xdr,
				struct nfs_writeargs *args)
L
Linus Torvalds 已提交
2434 2435
{
	struct compound_hdr hdr = {
2436
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2437 2438
	};

2439 2440 2441 2442
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_commit(xdr, args, &hdr);
2443 2444
	if (args->bitmask)
		encode_getfattr(xdr, args->bitmask, &hdr);
2445
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2446 2447 2448 2449 2450
}

/*
 * FSINFO request
 */
2451 2452
static void nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, struct xdr_stream *xdr,
				struct nfs4_fsinfo_arg *args)
L
Linus Torvalds 已提交
2453 2454
{
	struct compound_hdr hdr = {
2455
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2456 2457
	};

2458 2459 2460 2461
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_fsinfo(xdr, args->bitmask, &hdr);
2462
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2463 2464 2465 2466 2467
}

/*
 * a PATHCONF request
 */
2468 2469
static void nfs4_xdr_enc_pathconf(struct rpc_rqst *req, struct xdr_stream *xdr,
				  const struct nfs4_pathconf_arg *args)
L
Linus Torvalds 已提交
2470 2471
{
	struct compound_hdr hdr = {
2472
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2473 2474
	};

2475 2476 2477 2478
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_getattr_one(xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0],
2479
			   &hdr);
2480
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2481 2482 2483 2484 2485
}

/*
 * a STATFS request
 */
2486 2487
static void nfs4_xdr_enc_statfs(struct rpc_rqst *req, struct xdr_stream *xdr,
				const struct nfs4_statfs_arg *args)
L
Linus Torvalds 已提交
2488 2489
{
	struct compound_hdr hdr = {
2490
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2491 2492
	};

2493 2494 2495 2496
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_getattr_two(xdr, args->bitmask[0] & nfs4_statfs_bitmap[0],
2497
			   args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr);
2498
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2499 2500 2501 2502 2503
}

/*
 * GETATTR_BITMAP request
 */
2504 2505 2506
static void nfs4_xdr_enc_server_caps(struct rpc_rqst *req,
				     struct xdr_stream *xdr,
				     struct nfs4_server_caps_arg *args)
L
Linus Torvalds 已提交
2507 2508
{
	struct compound_hdr hdr = {
2509
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2510 2511
	};

2512 2513 2514 2515
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fhandle, &hdr);
	encode_getattr_one(xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
2516 2517 2518
			   FATTR4_WORD0_LINK_SUPPORT|
			   FATTR4_WORD0_SYMLINK_SUPPORT|
			   FATTR4_WORD0_ACLSUPPORT, &hdr);
2519
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2520 2521 2522 2523 2524
}

/*
 * a RENEW request
 */
2525 2526
static void nfs4_xdr_enc_renew(struct rpc_rqst *req, struct xdr_stream *xdr,
			       struct nfs_client *clp)
L
Linus Torvalds 已提交
2527 2528
{
	struct compound_hdr hdr = {
2529
		.nops	= 0,
L
Linus Torvalds 已提交
2530 2531
	};

2532 2533
	encode_compound_hdr(xdr, req, &hdr);
	encode_renew(xdr, clp, &hdr);
2534
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2535 2536 2537 2538 2539
}

/*
 * a SETCLIENTID request
 */
2540 2541 2542
static void nfs4_xdr_enc_setclientid(struct rpc_rqst *req,
				     struct xdr_stream *xdr,
				     struct nfs4_setclientid *sc)
L
Linus Torvalds 已提交
2543 2544
{
	struct compound_hdr hdr = {
2545
		.nops	= 0,
L
Linus Torvalds 已提交
2546 2547
	};

2548 2549
	encode_compound_hdr(xdr, req, &hdr);
	encode_setclientid(xdr, sc, &hdr);
2550
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2551 2552 2553 2554 2555
}

/*
 * a SETCLIENTID_CONFIRM request
 */
2556 2557 2558
static void nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req,
					     struct xdr_stream *xdr,
					     struct nfs4_setclientid_res *arg)
L
Linus Torvalds 已提交
2559 2560
{
	struct compound_hdr hdr = {
2561
		.nops	= 0,
L
Linus Torvalds 已提交
2562 2563 2564
	};
	const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };

2565 2566 2567 2568
	encode_compound_hdr(xdr, req, &hdr);
	encode_setclientid_confirm(xdr, arg, &hdr);
	encode_putrootfh(xdr, &hdr);
	encode_fsinfo(xdr, lease_bitmap, &hdr);
2569
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2570 2571 2572 2573 2574
}

/*
 * DELEGRETURN request
 */
2575 2576 2577
static void nfs4_xdr_enc_delegreturn(struct rpc_rqst *req,
				     struct xdr_stream *xdr,
				     const struct nfs4_delegreturnargs *args)
L
Linus Torvalds 已提交
2578 2579
{
	struct compound_hdr hdr = {
2580
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2581 2582
	};

2583 2584 2585 2586 2587
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fhandle, &hdr);
	encode_delegreturn(xdr, args->stateid, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
2588
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2589 2590
}

2591 2592 2593
/*
 * Encode FS_LOCATIONS request
 */
2594 2595 2596
static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req,
				      struct xdr_stream *xdr,
				      struct nfs4_fs_locations_arg *args)
2597 2598
{
	struct compound_hdr hdr = {
2599
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
2600
	};
2601
	uint32_t replen;
2602

2603 2604 2605 2606
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->dir_fh, &hdr);
	encode_lookup(xdr, args->name, &hdr);
2607
	replen = hdr.replen;	/* get the attribute into args->page */
2608
	encode_fs_locations(xdr, args->bitmask, &hdr);
2609

2610
	xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page,
2611
			0, PAGE_SIZE);
2612
	encode_nops(&hdr);
2613 2614
}

B
Bryan Schumaker 已提交
2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632
/*
 * Encode SECINFO request
 */
static void nfs4_xdr_enc_secinfo(struct rpc_rqst *req,
				struct xdr_stream *xdr,
				struct nfs4_secinfo_arg *args)
{
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->dir_fh, &hdr);
	encode_secinfo(xdr, args->name, &hdr);
	encode_nops(&hdr);
}

B
Benny Halevy 已提交
2633 2634 2635 2636
#if defined(CONFIG_NFS_V4_1)
/*
 * EXCHANGE_ID request
 */
2637 2638 2639
static void nfs4_xdr_enc_exchange_id(struct rpc_rqst *req,
				     struct xdr_stream *xdr,
				     struct nfs41_exchange_id_args *args)
B
Benny Halevy 已提交
2640 2641
{
	struct compound_hdr hdr = {
2642
		.minorversion = args->client->cl_mvops->minor_version,
B
Benny Halevy 已提交
2643 2644
	};

2645 2646
	encode_compound_hdr(xdr, req, &hdr);
	encode_exchange_id(xdr, args, &hdr);
B
Benny Halevy 已提交
2647 2648
	encode_nops(&hdr);
}
A
Andy Adamson 已提交
2649

A
Andy Adamson 已提交
2650 2651 2652
/*
 * a CREATE_SESSION request
 */
2653 2654 2655
static void nfs4_xdr_enc_create_session(struct rpc_rqst *req,
					struct xdr_stream *xdr,
					struct nfs41_create_session_args *args)
A
Andy Adamson 已提交
2656 2657
{
	struct compound_hdr hdr = {
2658
		.minorversion = args->client->cl_mvops->minor_version,
A
Andy Adamson 已提交
2659 2660
	};

2661 2662
	encode_compound_hdr(xdr, req, &hdr);
	encode_create_session(xdr, args, &hdr);
A
Andy Adamson 已提交
2663 2664 2665
	encode_nops(&hdr);
}

A
Andy Adamson 已提交
2666 2667 2668
/*
 * a DESTROY_SESSION request
 */
2669 2670 2671
static void nfs4_xdr_enc_destroy_session(struct rpc_rqst *req,
					 struct xdr_stream *xdr,
					 struct nfs4_session *session)
A
Andy Adamson 已提交
2672 2673
{
	struct compound_hdr hdr = {
2674
		.minorversion = session->clp->cl_mvops->minor_version,
A
Andy Adamson 已提交
2675 2676
	};

2677 2678
	encode_compound_hdr(xdr, req, &hdr);
	encode_destroy_session(xdr, session, &hdr);
A
Andy Adamson 已提交
2679 2680 2681
	encode_nops(&hdr);
}

A
Andy Adamson 已提交
2682 2683 2684
/*
 * a SEQUENCE request
 */
2685 2686
static void nfs4_xdr_enc_sequence(struct rpc_rqst *req, struct xdr_stream *xdr,
				  struct nfs4_sequence_args *args)
A
Andy Adamson 已提交
2687 2688 2689 2690 2691
{
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(args),
	};

2692 2693
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, args, &hdr);
A
Andy Adamson 已提交
2694 2695 2696
	encode_nops(&hdr);
}

A
Andy Adamson 已提交
2697 2698 2699
/*
 * a GET_LEASE_TIME request
 */
2700 2701 2702
static void nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req,
					struct xdr_stream *xdr,
					struct nfs4_get_lease_time_args *args)
A
Andy Adamson 已提交
2703 2704 2705 2706 2707 2708
{
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->la_seq_args),
	};
	const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };

2709 2710 2711 2712
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->la_seq_args, &hdr);
	encode_putrootfh(xdr, &hdr);
	encode_fsinfo(xdr, lease_bitmap, &hdr);
A
Andy Adamson 已提交
2713 2714
	encode_nops(&hdr);
}
2715 2716 2717 2718

/*
 * a RECLAIM_COMPLETE request
 */
2719 2720 2721
static void nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req,
					  struct xdr_stream *xdr,
				struct nfs41_reclaim_complete_args *args)
2722 2723 2724 2725 2726
{
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args)
	};

2727 2728 2729
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_reclaim_complete(xdr, args, &hdr);
2730 2731 2732
	encode_nops(&hdr);
}

2733 2734 2735
/*
 * Encode GETDEVICEINFO request
 */
2736 2737 2738
static void nfs4_xdr_enc_getdeviceinfo(struct rpc_rqst *req,
				       struct xdr_stream *xdr,
				       struct nfs4_getdeviceinfo_args *args)
2739 2740 2741 2742 2743
{
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

2744 2745 2746
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_getdeviceinfo(xdr, args, &hdr);
2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759

	/* set up reply kvec. Subtract notification bitmap max size (2)
	 * so that notification bitmap is put in xdr_buf tail */
	xdr_inline_pages(&req->rq_rcv_buf, (hdr.replen - 2) << 2,
			 args->pdev->pages, args->pdev->pgbase,
			 args->pdev->pglen);

	encode_nops(&hdr);
}

/*
 *  Encode LAYOUTGET request
 */
2760 2761 2762
static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req,
				   struct xdr_stream *xdr,
				   struct nfs4_layoutget_args *args)
2763 2764 2765 2766 2767
{
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

2768 2769 2770 2771
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, NFS_FH(args->inode), &hdr);
	encode_layoutget(xdr, args, &hdr);
2772 2773 2774 2775

	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2,
	    args->layout.pages, 0, args->layout.pglen);

2776 2777
	encode_nops(&hdr);
}
A
Andy Adamson 已提交
2778 2779 2780 2781

/*
 *  Encode LAYOUTCOMMIT request
 */
B
Benny Halevy 已提交
2782 2783 2784
static void nfs4_xdr_enc_layoutcommit(struct rpc_rqst *req,
				      struct xdr_stream *xdr,
				      struct nfs4_layoutcommit_args *args)
A
Andy Adamson 已提交
2785
{
B
Benny Halevy 已提交
2786 2787
	struct nfs4_layoutcommit_data *data =
		container_of(args, struct nfs4_layoutcommit_data, args);
A
Andy Adamson 已提交
2788 2789 2790 2791 2792 2793 2794
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, NFS_FH(args->inode), &hdr);
B
Benny Halevy 已提交
2795
	encode_layoutcommit(xdr, data->args.inode, args, &hdr);
A
Andy Adamson 已提交
2796
	encode_getfattr(xdr, args->bitmask, &hdr);
2797
	encode_nops(&hdr);
B
Benny Halevy 已提交
2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815
}

/*
 * Encode LAYOUTRETURN request
 */
static void nfs4_xdr_enc_layoutreturn(struct rpc_rqst *req,
				      struct xdr_stream *xdr,
				      struct nfs4_layoutreturn_args *args)
{
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, NFS_FH(args->inode), &hdr);
	encode_layoutreturn(xdr, args, &hdr);
	encode_nops(&hdr);
2816
}
2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835

/*
 * Encode SECINFO_NO_NAME request
 */
static int nfs4_xdr_enc_secinfo_no_name(struct rpc_rqst *req,
					struct xdr_stream *xdr,
					struct nfs41_secinfo_no_name_args *args)
{
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putrootfh(xdr, &hdr);
	encode_secinfo_no_name(xdr, args, &hdr);
	encode_nops(&hdr);
	return 0;
}
B
Benny Halevy 已提交
2836 2837
#endif /* CONFIG_NFS_V4_1 */

2838 2839 2840 2841 2842 2843
static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
{
	dprintk("nfs: %s: prematurely hit end of receive buffer. "
		"Remaining buffer length is %tu words.\n",
		func, xdr->end - xdr->p);
}
L
Linus Torvalds 已提交
2844

2845
static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
L
Linus Torvalds 已提交
2846
{
A
Al Viro 已提交
2847
	__be32 *p;
L
Linus Torvalds 已提交
2848

B
Benny Halevy 已提交
2849 2850 2851
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
2852
	*len = be32_to_cpup(p);
B
Benny Halevy 已提交
2853 2854 2855
	p = xdr_inline_decode(xdr, *len);
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
2856 2857
	*string = (char *)p;
	return 0;
B
Benny Halevy 已提交
2858 2859 2860
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2861 2862 2863 2864
}

static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
{
A
Al Viro 已提交
2865
	__be32 *p;
L
Linus Torvalds 已提交
2866

B
Benny Halevy 已提交
2867 2868 2869
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
2870
	hdr->status = be32_to_cpup(p++);
2871
	hdr->taglen = be32_to_cpup(p);
2872

B
Benny Halevy 已提交
2873 2874 2875
	p = xdr_inline_decode(xdr, hdr->taglen + 4);
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
2876 2877
	hdr->tag = (char *)p;
	p += XDR_QUADLEN(hdr->taglen);
2878
	hdr->nops = be32_to_cpup(p);
2879 2880
	if (unlikely(hdr->nops < 1))
		return nfs4_stat_to_errno(hdr->status);
L
Linus Torvalds 已提交
2881
	return 0;
B
Benny Halevy 已提交
2882 2883 2884
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2885 2886 2887 2888
}

static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
{
A
Al Viro 已提交
2889
	__be32 *p;
L
Linus Torvalds 已提交
2890 2891 2892
	uint32_t opnum;
	int32_t nfserr;

B
Benny Halevy 已提交
2893 2894 2895
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
2896
	opnum = be32_to_cpup(p++);
L
Linus Torvalds 已提交
2897
	if (opnum != expected) {
2898 2899
		dprintk("nfs: Server returned operation"
			" %d but we issued a request for %d\n",
L
Linus Torvalds 已提交
2900 2901 2902
				opnum, expected);
		return -EIO;
	}
2903
	nfserr = be32_to_cpup(p);
L
Linus Torvalds 已提交
2904
	if (nfserr != NFS_OK)
2905
		return nfs4_stat_to_errno(nfserr);
L
Linus Torvalds 已提交
2906
	return 0;
B
Benny Halevy 已提交
2907 2908 2909
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2910 2911 2912
}

/* Dummy routine */
2913
static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp)
L
Linus Torvalds 已提交
2914
{
A
Al Viro 已提交
2915
	__be32 *p;
2916
	unsigned int strlen;
L
Linus Torvalds 已提交
2917 2918
	char *str;

B
Benny Halevy 已提交
2919 2920 2921 2922 2923
	p = xdr_inline_decode(xdr, 12);
	if (likely(p))
		return decode_opaque_inline(xdr, &strlen, &str);
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2924 2925 2926 2927
}

static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
{
A
Al Viro 已提交
2928 2929
	uint32_t bmlen;
	__be32 *p;
L
Linus Torvalds 已提交
2930

B
Benny Halevy 已提交
2931 2932 2933
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
2934
	bmlen = be32_to_cpup(p);
L
Linus Torvalds 已提交
2935 2936

	bitmap[0] = bitmap[1] = 0;
B
Benny Halevy 已提交
2937 2938 2939
	p = xdr_inline_decode(xdr, (bmlen << 2));
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
2940
	if (bmlen > 0) {
B
Benny Halevy 已提交
2941
		bitmap[0] = be32_to_cpup(p++);
L
Linus Torvalds 已提交
2942
		if (bmlen > 1)
2943
			bitmap[1] = be32_to_cpup(p);
L
Linus Torvalds 已提交
2944 2945
	}
	return 0;
B
Benny Halevy 已提交
2946 2947 2948
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2949 2950
}

A
Al Viro 已提交
2951
static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep)
L
Linus Torvalds 已提交
2952
{
A
Al Viro 已提交
2953
	__be32 *p;
L
Linus Torvalds 已提交
2954

B
Benny Halevy 已提交
2955 2956 2957
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
2958
	*attrlen = be32_to_cpup(p);
L
Linus Torvalds 已提交
2959 2960
	*savep = xdr->p;
	return 0;
B
Benny Halevy 已提交
2961 2962 2963
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2964 2965 2966 2967 2968
}

static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask)
{
	if (likely(bitmap[0] & FATTR4_WORD0_SUPPORTED_ATTRS)) {
R
Roman Borisov 已提交
2969 2970 2971 2972
		int ret;
		ret = decode_attr_bitmap(xdr, bitmask);
		if (unlikely(ret < 0))
			return ret;
L
Linus Torvalds 已提交
2973 2974 2975
		bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS;
	} else
		bitmask[0] = bitmask[1] = 0;
2976
	dprintk("%s: bitmask=%08x:%08x\n", __func__, bitmask[0], bitmask[1]);
L
Linus Torvalds 已提交
2977 2978 2979 2980 2981
	return 0;
}

static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
{
A
Al Viro 已提交
2982
	__be32 *p;
2983
	int ret = 0;
L
Linus Torvalds 已提交
2984 2985 2986 2987 2988

	*type = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_TYPE)) {
B
Benny Halevy 已提交
2989 2990 2991
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
2992
		*type = be32_to_cpup(p);
L
Linus Torvalds 已提交
2993
		if (*type < NF4REG || *type > NF4NAMEDATTR) {
2994
			dprintk("%s: bad type %d\n", __func__, *type);
L
Linus Torvalds 已提交
2995 2996 2997
			return -EIO;
		}
		bitmap[0] &= ~FATTR4_WORD0_TYPE;
2998
		ret = NFS_ATTR_FATTR_TYPE;
L
Linus Torvalds 已提交
2999
	}
3000
	dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type]);
3001
	return ret;
B
Benny Halevy 已提交
3002 3003 3004
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3005 3006 3007 3008
}

static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
{
A
Al Viro 已提交
3009
	__be32 *p;
3010
	int ret = 0;
L
Linus Torvalds 已提交
3011 3012 3013 3014 3015

	*change = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) {
B
Benny Halevy 已提交
3016 3017 3018
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3019
		xdr_decode_hyper(p, change);
L
Linus Torvalds 已提交
3020
		bitmap[0] &= ~FATTR4_WORD0_CHANGE;
3021
		ret = NFS_ATTR_FATTR_CHANGE;
L
Linus Torvalds 已提交
3022
	}
3023
	dprintk("%s: change attribute=%Lu\n", __func__,
L
Linus Torvalds 已提交
3024
			(unsigned long long)*change);
3025
	return ret;
B
Benny Halevy 已提交
3026 3027 3028
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3029 3030 3031 3032
}

static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
{
A
Al Viro 已提交
3033
	__be32 *p;
3034
	int ret = 0;
L
Linus Torvalds 已提交
3035 3036 3037 3038 3039

	*size = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) {
B
Benny Halevy 已提交
3040 3041 3042
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3043
		xdr_decode_hyper(p, size);
L
Linus Torvalds 已提交
3044
		bitmap[0] &= ~FATTR4_WORD0_SIZE;
3045
		ret = NFS_ATTR_FATTR_SIZE;
L
Linus Torvalds 已提交
3046
	}
3047
	dprintk("%s: file size=%Lu\n", __func__, (unsigned long long)*size);
3048
	return ret;
B
Benny Halevy 已提交
3049 3050 3051
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3052 3053 3054 3055
}

static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
3056
	__be32 *p;
L
Linus Torvalds 已提交
3057 3058 3059 3060 3061

	*res = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) {
B
Benny Halevy 已提交
3062 3063 3064
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3065
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
3066 3067
		bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT;
	}
3068
	dprintk("%s: link support=%s\n", __func__, *res == 0 ? "false" : "true");
L
Linus Torvalds 已提交
3069
	return 0;
B
Benny Halevy 已提交
3070 3071 3072
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3073 3074 3075 3076
}

static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
3077
	__be32 *p;
L
Linus Torvalds 已提交
3078 3079 3080 3081 3082

	*res = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) {
B
Benny Halevy 已提交
3083 3084 3085
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3086
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
3087 3088
		bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT;
	}
3089
	dprintk("%s: symlink support=%s\n", __func__, *res == 0 ? "false" : "true");
L
Linus Torvalds 已提交
3090
	return 0;
B
Benny Halevy 已提交
3091 3092 3093
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3094 3095
}

3096
static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
L
Linus Torvalds 已提交
3097
{
A
Al Viro 已提交
3098
	__be32 *p;
3099
	int ret = 0;
L
Linus Torvalds 已提交
3100 3101 3102 3103 3104 3105

	fsid->major = 0;
	fsid->minor = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_FSID - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_FSID)) {
B
Benny Halevy 已提交
3106 3107 3108
		p = xdr_inline_decode(xdr, 16);
		if (unlikely(!p))
			goto out_overflow;
B
Benny Halevy 已提交
3109
		p = xdr_decode_hyper(p, &fsid->major);
3110
		xdr_decode_hyper(p, &fsid->minor);
L
Linus Torvalds 已提交
3111
		bitmap[0] &= ~FATTR4_WORD0_FSID;
3112
		ret = NFS_ATTR_FATTR_FSID;
L
Linus Torvalds 已提交
3113
	}
3114
	dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __func__,
L
Linus Torvalds 已提交
3115 3116
			(unsigned long long)fsid->major,
			(unsigned long long)fsid->minor);
3117
	return ret;
B
Benny Halevy 已提交
3118 3119 3120
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3121 3122 3123 3124
}

static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
3125
	__be32 *p;
L
Linus Torvalds 已提交
3126 3127 3128 3129 3130

	*res = 60;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) {
B
Benny Halevy 已提交
3131 3132 3133
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3134
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
3135 3136
		bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME;
	}
3137
	dprintk("%s: file size=%u\n", __func__, (unsigned int)*res);
L
Linus Torvalds 已提交
3138
	return 0;
B
Benny Halevy 已提交
3139 3140 3141
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3142 3143
}

3144
static int decode_attr_error(struct xdr_stream *xdr, uint32_t *bitmap, int32_t *res)
3145 3146 3147 3148 3149 3150 3151 3152 3153 3154
{
	__be32 *p;

	if (unlikely(bitmap[0] & (FATTR4_WORD0_RDATTR_ERROR - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_RDATTR_ERROR)) {
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
		bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR;
3155
		*res = -be32_to_cpup(p);
3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167
	}
	return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}

static int decode_attr_filehandle(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fh *fh)
{
	__be32 *p;
	int len;

3168 3169
	if (fh != NULL)
		memset(fh, 0, sizeof(*fh));
3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182

	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEHANDLE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_FILEHANDLE)) {
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
		len = be32_to_cpup(p);
		if (len > NFS4_FHSIZE)
			return -EIO;
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
3183 3184 3185 3186
		if (fh != NULL) {
			memcpy(fh->data, p, len);
			fh->size = len;
		}
3187 3188 3189 3190 3191 3192 3193 3194
		bitmap[0] &= ~FATTR4_WORD0_FILEHANDLE;
	}
	return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}

L
Linus Torvalds 已提交
3195 3196
static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
3197
	__be32 *p;
L
Linus Torvalds 已提交
3198 3199 3200 3201 3202

	*res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) {
B
Benny Halevy 已提交
3203 3204 3205
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3206
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
3207 3208
		bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT;
	}
3209
	dprintk("%s: ACLs supported=%u\n", __func__, (unsigned int)*res);
L
Linus Torvalds 已提交
3210
	return 0;
B
Benny Halevy 已提交
3211 3212 3213
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3214 3215 3216 3217
}

static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
{
A
Al Viro 已提交
3218
	__be32 *p;
3219
	int ret = 0;
L
Linus Torvalds 已提交
3220 3221 3222 3223 3224

	*fileid = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) {
B
Benny Halevy 已提交
3225 3226 3227
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3228
		xdr_decode_hyper(p, fileid);
L
Linus Torvalds 已提交
3229
		bitmap[0] &= ~FATTR4_WORD0_FILEID;
3230
		ret = NFS_ATTR_FATTR_FILEID;
L
Linus Torvalds 已提交
3231
	}
3232
	dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
3233
	return ret;
B
Benny Halevy 已提交
3234 3235 3236
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3237 3238
}

3239 3240
static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
{
A
Al Viro 已提交
3241
	__be32 *p;
3242
	int ret = 0;
3243 3244 3245 3246 3247

	*fileid = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)) {
B
Benny Halevy 已提交
3248 3249 3250
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3251
		xdr_decode_hyper(p, fileid);
3252
		bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
3253
		ret = NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
3254
	}
3255
	dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
3256
	return ret;
B
Benny Halevy 已提交
3257 3258 3259
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
3260 3261
}

L
Linus Torvalds 已提交
3262 3263
static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3264
	__be32 *p;
L
Linus Torvalds 已提交
3265 3266 3267 3268 3269 3270
	int status = 0;

	*res = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_AVAIL - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_FILES_AVAIL)) {
B
Benny Halevy 已提交
3271 3272 3273
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3274
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3275 3276
		bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL;
	}
3277
	dprintk("%s: files avail=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3278
	return status;
B
Benny Halevy 已提交
3279 3280 3281
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3282 3283 3284 3285
}

static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3286
	__be32 *p;
L
Linus Torvalds 已提交
3287 3288 3289 3290 3291 3292
	int status = 0;

	*res = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_FREE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_FILES_FREE)) {
B
Benny Halevy 已提交
3293 3294 3295
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3296
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3297 3298
		bitmap[0] &= ~FATTR4_WORD0_FILES_FREE;
	}
3299
	dprintk("%s: files free=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3300
	return status;
B
Benny Halevy 已提交
3301 3302 3303
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3304 3305 3306 3307
}

static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3308
	__be32 *p;
L
Linus Torvalds 已提交
3309 3310 3311 3312 3313 3314
	int status = 0;

	*res = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILES_TOTAL - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_FILES_TOTAL)) {
B
Benny Halevy 已提交
3315 3316 3317
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3318
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3319 3320
		bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL;
	}
3321
	dprintk("%s: files total=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3322
	return status;
B
Benny Halevy 已提交
3323 3324 3325
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3326 3327
}

3328 3329
static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
{
3330
	u32 n;
A
Al Viro 已提交
3331
	__be32 *p;
3332 3333
	int status = 0;

B
Benny Halevy 已提交
3334 3335 3336
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
3337
	n = be32_to_cpup(p);
3338 3339
	if (n == 0)
		goto root_path;
3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359
	dprintk("path ");
	path->ncomponents = 0;
	while (path->ncomponents < n) {
		struct nfs4_string *component = &path->components[path->ncomponents];
		status = decode_opaque_inline(xdr, &component->len, &component->data);
		if (unlikely(status != 0))
			goto out_eio;
		if (path->ncomponents != n)
			dprintk("/");
		dprintk("%s", component->data);
		if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS)
			path->ncomponents++;
		else {
			dprintk("cannot parse %d components in path\n", n);
			goto out_eio;
		}
	}
out:
	dprintk("\n");
	return status;
3360 3361 3362 3363 3364 3365 3366
root_path:
/* a root pathname is sent as a zero component4 */
	path->ncomponents = 1;
	path->components[0].len=0;
	path->components[0].data=NULL;
	dprintk("path /\n");
	goto out;
3367 3368 3369 3370
out_eio:
	dprintk(" status %d", status);
	status = -EIO;
	goto out;
B
Benny Halevy 已提交
3371 3372 3373
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
3374 3375 3376
}

static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res)
3377 3378
{
	int n;
A
Al Viro 已提交
3379
	__be32 *p;
3380 3381 3382 3383 3384 3385 3386
	int status = -EIO;

	if (unlikely(bitmap[0] & (FATTR4_WORD0_FS_LOCATIONS -1U)))
		goto out;
	status = 0;
	if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
		goto out;
3387
	dprintk("%s: fsroot ", __func__);
3388
	status = decode_pathname(xdr, &res->fs_path);
3389 3390
	if (unlikely(status != 0))
		goto out;
B
Benny Halevy 已提交
3391 3392 3393
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
3394
	n = be32_to_cpup(p);
3395 3396 3397 3398
	if (n <= 0)
		goto out_eio;
	res->nlocations = 0;
	while (res->nlocations < n) {
3399
		u32 m;
3400
		struct nfs4_fs_location *loc = &res->locations[res->nlocations];
3401

B
Benny Halevy 已提交
3402 3403 3404
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3405
		m = be32_to_cpup(p);
3406 3407

		loc->nservers = 0;
3408
		dprintk("%s: servers ", __func__);
3409 3410 3411 3412 3413 3414 3415 3416 3417
		while (loc->nservers < m) {
			struct nfs4_string *server = &loc->servers[loc->nservers];
			status = decode_opaque_inline(xdr, &server->len, &server->data);
			if (unlikely(status != 0))
				goto out_eio;
			dprintk("%s ", server->data);
			if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS)
				loc->nservers++;
			else {
3418 3419 3420
				unsigned int i;
				dprintk("%s: using first %u of %u servers "
					"returned for location %u\n",
3421
						__func__,
3422 3423
						NFS4_FS_LOCATION_MAXSERVERS,
						m, res->nlocations);
3424
				for (i = loc->nservers; i < m; i++) {
T
Trond Myklebust 已提交
3425
					unsigned int len;
3426 3427 3428 3429 3430 3431 3432 3433
					char *data;
					status = decode_opaque_inline(xdr, &len, &data);
					if (unlikely(status != 0))
						goto out_eio;
				}
			}
		}
		status = decode_pathname(xdr, &loc->rootpath);
3434 3435
		if (unlikely(status != 0))
			goto out_eio;
3436
		if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
3437 3438
			res->nlocations++;
	}
3439 3440
	if (res->nlocations != 0)
		status = NFS_ATTR_FATTR_V4_REFERRAL;
3441
out:
3442
	dprintk("%s: fs_locations done, error = %d\n", __func__, status);
3443
	return status;
B
Benny Halevy 已提交
3444 3445
out_overflow:
	print_overflow_msg(__func__, xdr);
3446 3447 3448 3449 3450
out_eio:
	status = -EIO;
	goto out;
}

L
Linus Torvalds 已提交
3451 3452
static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3453
	__be32 *p;
L
Linus Torvalds 已提交
3454 3455 3456 3457 3458 3459
	int status = 0;

	*res = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXFILESIZE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_MAXFILESIZE)) {
B
Benny Halevy 已提交
3460 3461 3462
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3463
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3464 3465
		bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE;
	}
3466
	dprintk("%s: maxfilesize=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3467
	return status;
B
Benny Halevy 已提交
3468 3469 3470
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3471 3472 3473 3474
}

static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink)
{
A
Al Viro 已提交
3475
	__be32 *p;
L
Linus Torvalds 已提交
3476 3477 3478 3479 3480 3481
	int status = 0;

	*maxlink = 1;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXLINK - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_MAXLINK)) {
B
Benny Halevy 已提交
3482 3483 3484
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3485
		*maxlink = be32_to_cpup(p);
L
Linus Torvalds 已提交
3486 3487
		bitmap[0] &= ~FATTR4_WORD0_MAXLINK;
	}
3488
	dprintk("%s: maxlink=%u\n", __func__, *maxlink);
L
Linus Torvalds 已提交
3489
	return status;
B
Benny Halevy 已提交
3490 3491 3492
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3493 3494 3495 3496
}

static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname)
{
A
Al Viro 已提交
3497
	__be32 *p;
L
Linus Torvalds 已提交
3498 3499 3500 3501 3502 3503
	int status = 0;

	*maxname = 1024;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXNAME - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_MAXNAME)) {
B
Benny Halevy 已提交
3504 3505 3506
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3507
		*maxname = be32_to_cpup(p);
L
Linus Torvalds 已提交
3508 3509
		bitmap[0] &= ~FATTR4_WORD0_MAXNAME;
	}
3510
	dprintk("%s: maxname=%u\n", __func__, *maxname);
L
Linus Torvalds 已提交
3511
	return status;
B
Benny Halevy 已提交
3512 3513 3514
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3515 3516 3517 3518
}

static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
3519
	__be32 *p;
L
Linus Torvalds 已提交
3520 3521 3522 3523 3524 3525 3526
	int status = 0;

	*res = 1024;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXREAD - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_MAXREAD)) {
		uint64_t maxread;
B
Benny Halevy 已提交
3527 3528 3529
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3530
		xdr_decode_hyper(p, &maxread);
L
Linus Torvalds 已提交
3531 3532 3533 3534 3535
		if (maxread > 0x7FFFFFFF)
			maxread = 0x7FFFFFFF;
		*res = (uint32_t)maxread;
		bitmap[0] &= ~FATTR4_WORD0_MAXREAD;
	}
3536
	dprintk("%s: maxread=%lu\n", __func__, (unsigned long)*res);
L
Linus Torvalds 已提交
3537
	return status;
B
Benny Halevy 已提交
3538 3539 3540
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3541 3542 3543 3544
}

static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
3545
	__be32 *p;
L
Linus Torvalds 已提交
3546 3547 3548 3549 3550 3551 3552
	int status = 0;

	*res = 1024;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_MAXWRITE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_MAXWRITE)) {
		uint64_t maxwrite;
B
Benny Halevy 已提交
3553 3554 3555
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3556
		xdr_decode_hyper(p, &maxwrite);
L
Linus Torvalds 已提交
3557 3558 3559 3560 3561
		if (maxwrite > 0x7FFFFFFF)
			maxwrite = 0x7FFFFFFF;
		*res = (uint32_t)maxwrite;
		bitmap[0] &= ~FATTR4_WORD0_MAXWRITE;
	}
3562
	dprintk("%s: maxwrite=%lu\n", __func__, (unsigned long)*res);
L
Linus Torvalds 已提交
3563
	return status;
B
Benny Halevy 已提交
3564 3565 3566
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3567 3568
}

3569
static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *mode)
L
Linus Torvalds 已提交
3570
{
3571
	uint32_t tmp;
A
Al Viro 已提交
3572
	__be32 *p;
3573
	int ret = 0;
L
Linus Torvalds 已提交
3574 3575 3576 3577 3578

	*mode = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_MODE)) {
B
Benny Halevy 已提交
3579 3580 3581
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3582
		tmp = be32_to_cpup(p);
3583
		*mode = tmp & ~S_IFMT;
L
Linus Torvalds 已提交
3584
		bitmap[1] &= ~FATTR4_WORD1_MODE;
3585
		ret = NFS_ATTR_FATTR_MODE;
L
Linus Torvalds 已提交
3586
	}
3587
	dprintk("%s: file mode=0%o\n", __func__, (unsigned int)*mode);
3588
	return ret;
B
Benny Halevy 已提交
3589 3590 3591
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3592 3593 3594 3595
}

static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
{
A
Al Viro 已提交
3596
	__be32 *p;
3597
	int ret = 0;
L
Linus Torvalds 已提交
3598 3599 3600 3601 3602

	*nlink = 1;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) {
B
Benny Halevy 已提交
3603 3604 3605
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3606
		*nlink = be32_to_cpup(p);
L
Linus Torvalds 已提交
3607
		bitmap[1] &= ~FATTR4_WORD1_NUMLINKS;
3608
		ret = NFS_ATTR_FATTR_NLINK;
L
Linus Torvalds 已提交
3609
	}
3610
	dprintk("%s: nlink=%u\n", __func__, (unsigned int)*nlink);
3611
	return ret;
B
Benny Halevy 已提交
3612 3613 3614
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3615 3616
}

3617
static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap,
3618
		const struct nfs_server *server, uint32_t *uid, int may_sleep)
L
Linus Torvalds 已提交
3619
{
A
Al Viro 已提交
3620 3621
	uint32_t len;
	__be32 *p;
3622
	int ret = 0;
L
Linus Torvalds 已提交
3623 3624 3625 3626 3627

	*uid = -2;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) {
B
Benny Halevy 已提交
3628 3629 3630
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3631
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
3632 3633 3634
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
3635 3636 3637
		if (!may_sleep) {
			/* do nothing */
		} else if (len < XDR_MAX_NETOBJ) {
3638
			if (nfs_map_name_to_uid(server, (char *)p, len, uid) == 0)
3639 3640
				ret = NFS_ATTR_FATTR_OWNER;
			else
L
Linus Torvalds 已提交
3641
				dprintk("%s: nfs_map_name_to_uid failed!\n",
3642
						__func__);
L
Linus Torvalds 已提交
3643
		} else
3644
			dprintk("%s: name too long (%u)!\n",
3645
					__func__, len);
L
Linus Torvalds 已提交
3646 3647
		bitmap[1] &= ~FATTR4_WORD1_OWNER;
	}
3648
	dprintk("%s: uid=%d\n", __func__, (int)*uid);
3649
	return ret;
B
Benny Halevy 已提交
3650 3651 3652
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3653 3654
}

3655
static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap,
3656
		const struct nfs_server *server, uint32_t *gid, int may_sleep)
L
Linus Torvalds 已提交
3657
{
A
Al Viro 已提交
3658 3659
	uint32_t len;
	__be32 *p;
3660
	int ret = 0;
L
Linus Torvalds 已提交
3661 3662 3663 3664 3665

	*gid = -2;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) {
B
Benny Halevy 已提交
3666 3667 3668
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3669
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
3670 3671 3672
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
3673 3674 3675
		if (!may_sleep) {
			/* do nothing */
		} else if (len < XDR_MAX_NETOBJ) {
3676
			if (nfs_map_group_to_gid(server, (char *)p, len, gid) == 0)
3677 3678
				ret = NFS_ATTR_FATTR_GROUP;
			else
L
Linus Torvalds 已提交
3679
				dprintk("%s: nfs_map_group_to_gid failed!\n",
3680
						__func__);
L
Linus Torvalds 已提交
3681
		} else
3682
			dprintk("%s: name too long (%u)!\n",
3683
					__func__, len);
L
Linus Torvalds 已提交
3684 3685
		bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
	}
3686
	dprintk("%s: gid=%d\n", __func__, (int)*gid);
3687
	return ret;
B
Benny Halevy 已提交
3688 3689 3690
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3691 3692 3693 3694
}

static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
{
A
Al Viro 已提交
3695 3696
	uint32_t major = 0, minor = 0;
	__be32 *p;
3697
	int ret = 0;
L
Linus Torvalds 已提交
3698 3699 3700 3701 3702 3703 3704

	*rdev = MKDEV(0,0);
	if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_RAWDEV)) {
		dev_t tmp;

B
Benny Halevy 已提交
3705 3706 3707
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
B
Benny Halevy 已提交
3708
		major = be32_to_cpup(p++);
3709
		minor = be32_to_cpup(p);
L
Linus Torvalds 已提交
3710 3711 3712 3713
		tmp = MKDEV(major, minor);
		if (MAJOR(tmp) == major && MINOR(tmp) == minor)
			*rdev = tmp;
		bitmap[1] &= ~ FATTR4_WORD1_RAWDEV;
3714
		ret = NFS_ATTR_FATTR_RDEV;
L
Linus Torvalds 已提交
3715
	}
3716
	dprintk("%s: rdev=(0x%x:0x%x)\n", __func__, major, minor);
3717
	return ret;
B
Benny Halevy 已提交
3718 3719 3720
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3721 3722 3723 3724
}

static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3725
	__be32 *p;
L
Linus Torvalds 已提交
3726 3727 3728 3729 3730 3731
	int status = 0;

	*res = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_AVAIL - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_AVAIL)) {
B
Benny Halevy 已提交
3732 3733 3734
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3735
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3736 3737
		bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL;
	}
3738
	dprintk("%s: space avail=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3739
	return status;
B
Benny Halevy 已提交
3740 3741 3742
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3743 3744 3745 3746
}

static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3747
	__be32 *p;
L
Linus Torvalds 已提交
3748 3749 3750 3751 3752 3753
	int status = 0;

	*res = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_FREE - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_FREE)) {
B
Benny Halevy 已提交
3754 3755 3756
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3757
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3758 3759
		bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE;
	}
3760
	dprintk("%s: space free=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3761
	return status;
B
Benny Halevy 已提交
3762 3763 3764
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3765 3766 3767 3768
}

static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3769
	__be32 *p;
L
Linus Torvalds 已提交
3770 3771 3772 3773 3774 3775
	int status = 0;

	*res = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_TOTAL - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_TOTAL)) {
B
Benny Halevy 已提交
3776 3777 3778
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3779
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3780 3781
		bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL;
	}
3782
	dprintk("%s: space total=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3783
	return status;
B
Benny Halevy 已提交
3784 3785 3786
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3787 3788 3789 3790
}

static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
{
A
Al Viro 已提交
3791
	__be32 *p;
3792
	int ret = 0;
L
Linus Torvalds 已提交
3793 3794 3795 3796 3797

	*used = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) {
B
Benny Halevy 已提交
3798 3799 3800
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3801
		xdr_decode_hyper(p, used);
L
Linus Torvalds 已提交
3802
		bitmap[1] &= ~FATTR4_WORD1_SPACE_USED;
3803
		ret = NFS_ATTR_FATTR_SPACE_USED;
L
Linus Torvalds 已提交
3804
	}
3805
	dprintk("%s: space used=%Lu\n", __func__,
L
Linus Torvalds 已提交
3806
			(unsigned long long)*used);
3807
	return ret;
B
Benny Halevy 已提交
3808 3809 3810
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3811 3812 3813 3814
}

static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
{
A
Al Viro 已提交
3815
	__be32 *p;
L
Linus Torvalds 已提交
3816 3817 3818
	uint64_t sec;
	uint32_t nsec;

B
Benny Halevy 已提交
3819 3820 3821
	p = xdr_inline_decode(xdr, 12);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3822
	p = xdr_decode_hyper(p, &sec);
3823
	nsec = be32_to_cpup(p);
L
Linus Torvalds 已提交
3824 3825 3826
	time->tv_sec = (time_t)sec;
	time->tv_nsec = (long)nsec;
	return 0;
B
Benny Halevy 已提交
3827 3828 3829
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841
}

static int decode_attr_time_access(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
{
	int status = 0;

	time->tv_sec = 0;
	time->tv_nsec = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_ACCESS - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_TIME_ACCESS)) {
		status = decode_attr_time(xdr, time);
3842 3843
		if (status == 0)
			status = NFS_ATTR_FATTR_ATIME;
L
Linus Torvalds 已提交
3844 3845
		bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS;
	}
3846
	dprintk("%s: atime=%ld\n", __func__, (long)time->tv_sec);
L
Linus Torvalds 已提交
3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859
	return status;
}

static int decode_attr_time_metadata(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
{
	int status = 0;

	time->tv_sec = 0;
	time->tv_nsec = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_METADATA - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) {
		status = decode_attr_time(xdr, time);
3860 3861
		if (status == 0)
			status = NFS_ATTR_FATTR_CTIME;
L
Linus Torvalds 已提交
3862 3863
		bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
	}
3864
	dprintk("%s: ctime=%ld\n", __func__, (long)time->tv_sec);
L
Linus Torvalds 已提交
3865 3866 3867
	return status;
}

3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885
static int decode_attr_time_delta(struct xdr_stream *xdr, uint32_t *bitmap,
				  struct timespec *time)
{
	int status = 0;

	time->tv_sec = 0;
	time->tv_nsec = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_DELTA - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_TIME_DELTA)) {
		status = decode_attr_time(xdr, time);
		bitmap[1] &= ~FATTR4_WORD1_TIME_DELTA;
	}
	dprintk("%s: time_delta=%ld %ld\n", __func__, (long)time->tv_sec,
		(long)time->tv_nsec);
	return status;
}

L
Linus Torvalds 已提交
3886 3887 3888 3889 3890 3891 3892 3893 3894 3895
static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, struct timespec *time)
{
	int status = 0;

	time->tv_sec = 0;
	time->tv_nsec = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_TIME_MODIFY - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) {
		status = decode_attr_time(xdr, time);
3896 3897
		if (status == 0)
			status = NFS_ATTR_FATTR_MTIME;
L
Linus Torvalds 已提交
3898 3899
		bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
	}
3900
	dprintk("%s: mtime=%ld\n", __func__, (long)time->tv_sec);
L
Linus Torvalds 已提交
3901 3902 3903
	return status;
}

A
Al Viro 已提交
3904
static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
L
Linus Torvalds 已提交
3905 3906 3907 3908 3909
{
	unsigned int attrwords = XDR_QUADLEN(attrlen);
	unsigned int nwords = xdr->p - savep;

	if (unlikely(attrwords != nwords)) {
3910 3911
		dprintk("%s: server returned incorrect attribute length: "
			"%u %c %u\n",
3912
				__func__,
L
Linus Torvalds 已提交
3913 3914 3915 3916 3917 3918 3919 3920 3921 3922
				attrwords << 2,
				(attrwords < nwords) ? '<' : '>',
				nwords << 2);
		return -EIO;
	}
	return 0;
}

static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
A
Al Viro 已提交
3923
	__be32 *p;
L
Linus Torvalds 已提交
3924

B
Benny Halevy 已提交
3925 3926 3927
	p = xdr_inline_decode(xdr, 20);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3928
	cinfo->atomic = be32_to_cpup(p++);
B
Benny Halevy 已提交
3929
	p = xdr_decode_hyper(p, &cinfo->before);
3930
	xdr_decode_hyper(p, &cinfo->after);
L
Linus Torvalds 已提交
3931
	return 0;
B
Benny Halevy 已提交
3932 3933 3934
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3935 3936 3937 3938
}

static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
{
A
Al Viro 已提交
3939
	__be32 *p;
L
Linus Torvalds 已提交
3940 3941 3942 3943 3944 3945
	uint32_t supp, acc;
	int status;

	status = decode_op_hdr(xdr, OP_ACCESS);
	if (status)
		return status;
B
Benny Halevy 已提交
3946 3947 3948
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3949
	supp = be32_to_cpup(p++);
3950
	acc = be32_to_cpup(p);
L
Linus Torvalds 已提交
3951 3952 3953
	access->supported = supp;
	access->access = acc;
	return 0;
B
Benny Halevy 已提交
3954 3955 3956
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3957 3958
}

3959
static int decode_opaque_fixed(struct xdr_stream *xdr, void *buf, size_t len)
L
Linus Torvalds 已提交
3960
{
A
Al Viro 已提交
3961
	__be32 *p;
3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978

	p = xdr_inline_decode(xdr, len);
	if (likely(p)) {
		memcpy(buf, p, len);
		return 0;
	}
	print_overflow_msg(__func__, xdr);
	return -EIO;
}

static int decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
{
	return decode_opaque_fixed(xdr, stateid->data, NFS4_STATEID_SIZE);
}

static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
{
L
Linus Torvalds 已提交
3979 3980 3981
	int status;

	status = decode_op_hdr(xdr, OP_CLOSE);
3982 3983
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
3984 3985 3986
	if (!status)
		status = decode_stateid(xdr, &res->stateid);
	return status;
L
Linus Torvalds 已提交
3987 3988
}

3989 3990 3991
static int decode_verifier(struct xdr_stream *xdr, void *verifier)
{
	return decode_opaque_fixed(xdr, verifier, 8);
L
Linus Torvalds 已提交
3992 3993 3994 3995 3996 3997 3998
}

static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
{
	int status;

	status = decode_op_hdr(xdr, OP_COMMIT);
3999 4000 4001
	if (!status)
		status = decode_verifier(xdr, res->verf->verifier);
	return status;
L
Linus Torvalds 已提交
4002 4003 4004 4005
}

static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
A
Al Viro 已提交
4006
	__be32 *p;
L
Linus Torvalds 已提交
4007 4008 4009 4010 4011 4012 4013 4014
	uint32_t bmlen;
	int status;

	status = decode_op_hdr(xdr, OP_CREATE);
	if (status)
		return status;
	if ((status = decode_change_info(xdr, cinfo)))
		return status;
B
Benny Halevy 已提交
4015 4016 4017
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4018
	bmlen = be32_to_cpup(p);
B
Benny Halevy 已提交
4019 4020 4021 4022 4023 4024
	p = xdr_inline_decode(xdr, bmlen << 2);
	if (likely(p))
		return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4025 4026 4027 4028
}

static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
{
A
Al Viro 已提交
4029
	__be32 *savep;
4030
	uint32_t attrlen, bitmap[2] = {0};
L
Linus Torvalds 已提交
4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048
	int status;

	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
		goto xdr_error;
	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
		goto xdr_error;
	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
		goto xdr_error;
	if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0)
		goto xdr_error;
	if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0)
		goto xdr_error;
	if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0)
		goto xdr_error;
	if ((status = decode_attr_aclsupport(xdr, bitmap, &res->acl_bitmask)) != 0)
		goto xdr_error;
	status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
4049
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
4050 4051
	return status;
}
4052

L
Linus Torvalds 已提交
4053 4054
static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
{
A
Al Viro 已提交
4055
	__be32 *savep;
4056
	uint32_t attrlen, bitmap[2] = {0};
L
Linus Torvalds 已提交
4057
	int status;
4058

L
Linus Torvalds 已提交
4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080
	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
		goto xdr_error;
	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
		goto xdr_error;
	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
		goto xdr_error;

	if ((status = decode_attr_files_avail(xdr, bitmap, &fsstat->afiles)) != 0)
		goto xdr_error;
	if ((status = decode_attr_files_free(xdr, bitmap, &fsstat->ffiles)) != 0)
		goto xdr_error;
	if ((status = decode_attr_files_total(xdr, bitmap, &fsstat->tfiles)) != 0)
		goto xdr_error;
	if ((status = decode_attr_space_avail(xdr, bitmap, &fsstat->abytes)) != 0)
		goto xdr_error;
	if ((status = decode_attr_space_free(xdr, bitmap, &fsstat->fbytes)) != 0)
		goto xdr_error;
	if ((status = decode_attr_space_total(xdr, bitmap, &fsstat->tbytes)) != 0)
		goto xdr_error;

	status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
4081
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
4082 4083 4084 4085 4086
	return status;
}

static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
{
A
Al Viro 已提交
4087
	__be32 *savep;
4088
	uint32_t attrlen, bitmap[2] = {0};
L
Linus Torvalds 已提交
4089
	int status;
4090

L
Linus Torvalds 已提交
4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104
	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
		goto xdr_error;
	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
		goto xdr_error;
	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
		goto xdr_error;

	if ((status = decode_attr_maxlink(xdr, bitmap, &pathconf->max_link)) != 0)
		goto xdr_error;
	if ((status = decode_attr_maxname(xdr, bitmap, &pathconf->max_namelen)) != 0)
		goto xdr_error;

	status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
4105
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
4106 4107 4108
	return status;
}

4109 4110
static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
		struct nfs_fattr *fattr, struct nfs_fh *fh,
4111
		const struct nfs_server *server, int may_sleep)
L
Linus Torvalds 已提交
4112
{
4113 4114
	int status;
	umode_t fmode = 0;
4115
	uint32_t type;
4116
	int32_t err;
L
Linus Torvalds 已提交
4117

4118 4119
	status = decode_attr_type(xdr, bitmap, &type);
	if (status < 0)
L
Linus Torvalds 已提交
4120
		goto xdr_error;
4121 4122 4123 4124 4125
	fattr->mode = 0;
	if (status != 0) {
		fattr->mode |= nfs_type2fmt[type];
		fattr->valid |= status;
	}
L
Linus Torvalds 已提交
4126

4127 4128
	status = decode_attr_change(xdr, bitmap, &fattr->change_attr);
	if (status < 0)
L
Linus Torvalds 已提交
4129
		goto xdr_error;
4130
	fattr->valid |= status;
4131 4132 4133

	status = decode_attr_size(xdr, bitmap, &fattr->size);
	if (status < 0)
L
Linus Torvalds 已提交
4134
		goto xdr_error;
4135
	fattr->valid |= status;
4136 4137 4138

	status = decode_attr_fsid(xdr, bitmap, &fattr->fsid);
	if (status < 0)
L
Linus Torvalds 已提交
4139
		goto xdr_error;
4140
	fattr->valid |= status;
4141

4142 4143
	err = 0;
	status = decode_attr_error(xdr, bitmap, &err);
4144 4145
	if (status < 0)
		goto xdr_error;
4146 4147
	if (err == -NFS4ERR_WRONGSEC)
		nfs_fixup_secinfo_attributes(fattr, fh);
4148 4149 4150 4151 4152

	status = decode_attr_filehandle(xdr, bitmap, fh);
	if (status < 0)
		goto xdr_error;

4153 4154
	status = decode_attr_fileid(xdr, bitmap, &fattr->fileid);
	if (status < 0)
L
Linus Torvalds 已提交
4155
		goto xdr_error;
4156
	fattr->valid |= status;
4157 4158

	status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
4159
						struct nfs4_fs_locations,
4160 4161
						fattr));
	if (status < 0)
4162
		goto xdr_error;
4163
	fattr->valid |= status;
4164 4165 4166

	status = decode_attr_mode(xdr, bitmap, &fmode);
	if (status < 0)
L
Linus Torvalds 已提交
4167
		goto xdr_error;
4168 4169 4170 4171
	if (status != 0) {
		fattr->mode |= fmode;
		fattr->valid |= status;
	}
4172 4173 4174

	status = decode_attr_nlink(xdr, bitmap, &fattr->nlink);
	if (status < 0)
L
Linus Torvalds 已提交
4175
		goto xdr_error;
4176
	fattr->valid |= status;
4177

4178
	status = decode_attr_owner(xdr, bitmap, server, &fattr->uid, may_sleep);
4179
	if (status < 0)
L
Linus Torvalds 已提交
4180
		goto xdr_error;
4181
	fattr->valid |= status;
4182

4183
	status = decode_attr_group(xdr, bitmap, server, &fattr->gid, may_sleep);
4184
	if (status < 0)
L
Linus Torvalds 已提交
4185
		goto xdr_error;
4186
	fattr->valid |= status;
4187 4188 4189

	status = decode_attr_rdev(xdr, bitmap, &fattr->rdev);
	if (status < 0)
L
Linus Torvalds 已提交
4190
		goto xdr_error;
4191
	fattr->valid |= status;
4192 4193 4194

	status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used);
	if (status < 0)
L
Linus Torvalds 已提交
4195
		goto xdr_error;
4196
	fattr->valid |= status;
4197 4198 4199

	status = decode_attr_time_access(xdr, bitmap, &fattr->atime);
	if (status < 0)
L
Linus Torvalds 已提交
4200
		goto xdr_error;
4201
	fattr->valid |= status;
4202 4203 4204

	status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
	if (status < 0)
L
Linus Torvalds 已提交
4205
		goto xdr_error;
4206
	fattr->valid |= status;
4207 4208 4209

	status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime);
	if (status < 0)
L
Linus Torvalds 已提交
4210
		goto xdr_error;
4211
	fattr->valid |= status;
4212

4213
	status = decode_attr_mounted_on_fileid(xdr, bitmap, &fattr->mounted_on_fileid);
4214
	if (status < 0)
4215
		goto xdr_error;
4216
	fattr->valid |= status;
4217

4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246
xdr_error:
	dprintk("%s: xdr returned %d\n", __func__, -status);
	return status;
}

static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr,
		struct nfs_fh *fh, const struct nfs_server *server, int may_sleep)
{
	__be32 *savep;
	uint32_t attrlen,
		 bitmap[2] = {0};
	int status;

	status = decode_op_hdr(xdr, OP_GETATTR);
	if (status < 0)
		goto xdr_error;

	status = decode_attr_bitmap(xdr, bitmap);
	if (status < 0)
		goto xdr_error;

	status = decode_attr_length(xdr, &attrlen, &savep);
	if (status < 0)
		goto xdr_error;

	status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, server, may_sleep);
	if (status < 0)
		goto xdr_error;

4247
	status = verify_attr_len(xdr, savep, attrlen);
L
Linus Torvalds 已提交
4248
xdr_error:
4249
	dprintk("%s: xdr returned %d\n", __func__, -status);
L
Linus Torvalds 已提交
4250 4251 4252
	return status;
}

4253 4254 4255 4256 4257
static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
		const struct nfs_server *server, int may_sleep)
{
	return decode_getfattr_generic(xdr, fattr, NULL, server, may_sleep);
}
L
Linus Torvalds 已提交
4258

4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313
/*
 * Decode potentially multiple layout types. Currently we only support
 * one layout driver per file system.
 */
static int decode_first_pnfs_layout_type(struct xdr_stream *xdr,
					 uint32_t *layouttype)
{
	uint32_t *p;
	int num;

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
	num = be32_to_cpup(p);

	/* pNFS is not supported by the underlying file system */
	if (num == 0) {
		*layouttype = 0;
		return 0;
	}
	if (num > 1)
		printk(KERN_INFO "%s: Warning: Multiple pNFS layout drivers "
			"per filesystem not supported\n", __func__);

	/* Decode and set first layout type, move xdr->p past unused types */
	p = xdr_inline_decode(xdr, num * 4);
	if (unlikely(!p))
		goto out_overflow;
	*layouttype = be32_to_cpup(p);
	return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}

/*
 * The type of file system exported.
 * Note we must ensure that layouttype is set in any non-error case.
 */
static int decode_attr_pnfstype(struct xdr_stream *xdr, uint32_t *bitmap,
				uint32_t *layouttype)
{
	int status = 0;

	dprintk("%s: bitmap is %x\n", __func__, bitmap[1]);
	if (unlikely(bitmap[1] & (FATTR4_WORD1_FS_LAYOUT_TYPES - 1U)))
		return -EIO;
	if (bitmap[1] & FATTR4_WORD1_FS_LAYOUT_TYPES) {
		status = decode_first_pnfs_layout_type(xdr, layouttype);
		bitmap[1] &= ~FATTR4_WORD1_FS_LAYOUT_TYPES;
	} else
		*layouttype = 0;
	return status;
}

L
Linus Torvalds 已提交
4314 4315
static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
{
A
Al Viro 已提交
4316
	__be32 *savep;
L
Linus Torvalds 已提交
4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338
	uint32_t attrlen, bitmap[2];
	int status;

	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
		goto xdr_error;
	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
		goto xdr_error;
	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
		goto xdr_error;

	fsinfo->rtmult = fsinfo->wtmult = 512;	/* ??? */

	if ((status = decode_attr_lease_time(xdr, bitmap, &fsinfo->lease_time)) != 0)
		goto xdr_error;
	if ((status = decode_attr_maxfilesize(xdr, bitmap, &fsinfo->maxfilesize)) != 0)
		goto xdr_error;
	if ((status = decode_attr_maxread(xdr, bitmap, &fsinfo->rtmax)) != 0)
		goto xdr_error;
	fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax;
	if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0)
		goto xdr_error;
	fsinfo->wtpref = fsinfo->wtmax;
4339
	status = decode_attr_time_delta(xdr, bitmap, &fsinfo->time_delta);
4340 4341 4342
	if (status != 0)
		goto xdr_error;
	status = decode_attr_pnfstype(xdr, bitmap, &fsinfo->layouttype);
4343 4344
	if (status != 0)
		goto xdr_error;
L
Linus Torvalds 已提交
4345 4346 4347

	status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
4348
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
4349 4350 4351 4352 4353
	return status;
}

static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
{
A
Al Viro 已提交
4354
	__be32 *p;
L
Linus Torvalds 已提交
4355 4356 4357
	uint32_t len;
	int status;

4358 4359 4360
	/* Zero handle first to allow comparisons */
	memset(fh, 0, sizeof(*fh));

L
Linus Torvalds 已提交
4361 4362 4363 4364
	status = decode_op_hdr(xdr, OP_GETFH);
	if (status)
		return status;

B
Benny Halevy 已提交
4365 4366 4367
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4368
	len = be32_to_cpup(p);
L
Linus Torvalds 已提交
4369 4370 4371
	if (len > NFS4_FHSIZE)
		return -EIO;
	fh->size = len;
B
Benny Halevy 已提交
4372 4373 4374
	p = xdr_inline_decode(xdr, len);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4375
	memcpy(fh->data, p, len);
L
Linus Torvalds 已提交
4376
	return 0;
B
Benny Halevy 已提交
4377 4378 4379
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4380 4381 4382 4383 4384
}

static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
	int status;
4385

L
Linus Torvalds 已提交
4386 4387 4388 4389 4390 4391 4392 4393 4394
	status = decode_op_hdr(xdr, OP_LINK);
	if (status)
		return status;
	return decode_change_info(xdr, cinfo);
}

/*
 * We create the owner, so we know a proper owner.id length is 4.
 */
T
Trond Myklebust 已提交
4395
static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
L
Linus Torvalds 已提交
4396
{
T
Trond Myklebust 已提交
4397
	uint64_t offset, length, clientid;
A
Al Viro 已提交
4398
	__be32 *p;
T
Trond Myklebust 已提交
4399
	uint32_t namelen, type;
L
Linus Torvalds 已提交
4400

4401
	p = xdr_inline_decode(xdr, 32); /* read 32 bytes */
B
Benny Halevy 已提交
4402 4403
	if (unlikely(!p))
		goto out_overflow;
4404
	p = xdr_decode_hyper(p, &offset); /* read 2 8-byte long words */
B
Benny Halevy 已提交
4405
	p = xdr_decode_hyper(p, &length);
4406 4407
	type = be32_to_cpup(p++); /* 4 byte read */
	if (fl != NULL) { /* manipulate file lock */
T
Trond Myklebust 已提交
4408 4409 4410 4411 4412 4413 4414 4415 4416
		fl->fl_start = (loff_t)offset;
		fl->fl_end = fl->fl_start + (loff_t)length - 1;
		if (length == ~(uint64_t)0)
			fl->fl_end = OFFSET_MAX;
		fl->fl_type = F_WRLCK;
		if (type & 1)
			fl->fl_type = F_RDLCK;
		fl->fl_pid = 0;
	}
4417 4418 4419
	p = xdr_decode_hyper(p, &clientid); /* read 8 bytes */
	namelen = be32_to_cpup(p); /* read 4 bytes */  /* have read all 32 bytes now */
	p = xdr_inline_decode(xdr, namelen); /* variable size field */
B
Benny Halevy 已提交
4420 4421 4422 4423 4424
	if (likely(p))
		return -NFS4ERR_DENIED;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4425 4426
}

T
Trond Myklebust 已提交
4427
static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
L
Linus Torvalds 已提交
4428 4429 4430 4431
{
	int status;

	status = decode_op_hdr(xdr, OP_LOCK);
4432 4433
	if (status == -EIO)
		goto out;
L
Linus Torvalds 已提交
4434
	if (status == 0) {
4435 4436 4437
		status = decode_stateid(xdr, &res->stateid);
		if (unlikely(status))
			goto out;
L
Linus Torvalds 已提交
4438
	} else if (status == -NFS4ERR_DENIED)
4439 4440 4441 4442 4443
		status = decode_lock_denied(xdr, NULL);
	if (res->open_seqid != NULL)
		nfs_increment_open_seqid(status, res->open_seqid);
	nfs_increment_lock_seqid(status, res->lock_seqid);
out:
L
Linus Torvalds 已提交
4444 4445 4446
	return status;
}

T
Trond Myklebust 已提交
4447
static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res)
L
Linus Torvalds 已提交
4448 4449 4450 4451
{
	int status;
	status = decode_op_hdr(xdr, OP_LOCKT);
	if (status == -NFS4ERR_DENIED)
T
Trond Myklebust 已提交
4452
		return decode_lock_denied(xdr, res->denied);
L
Linus Torvalds 已提交
4453 4454 4455
	return status;
}

T
Trond Myklebust 已提交
4456
static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
L
Linus Torvalds 已提交
4457 4458 4459 4460
{
	int status;

	status = decode_op_hdr(xdr, OP_LOCKU);
4461 4462
	if (status != -EIO)
		nfs_increment_lock_seqid(status, res->seqid);
4463 4464
	if (status == 0)
		status = decode_stateid(xdr, &res->stateid);
L
Linus Torvalds 已提交
4465 4466 4467
	return status;
}

4468 4469 4470 4471 4472
static int decode_release_lockowner(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_RELEASE_LOCKOWNER);
}

L
Linus Torvalds 已提交
4473 4474 4475 4476 4477 4478 4479 4480
static int decode_lookup(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_LOOKUP);
}

/* This is too sick! */
static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
{
A
Andy Adamson 已提交
4481
	__be32 *p;
L
Linus Torvalds 已提交
4482 4483
	uint32_t limit_type, nblocks, blocksize;

B
Benny Halevy 已提交
4484 4485 4486
	p = xdr_inline_decode(xdr, 12);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4487
	limit_type = be32_to_cpup(p++);
L
Linus Torvalds 已提交
4488
	switch (limit_type) {
A
Andy Adamson 已提交
4489
	case 1:
4490
		xdr_decode_hyper(p, maxsize);
A
Andy Adamson 已提交
4491 4492
		break;
	case 2:
B
Benny Halevy 已提交
4493
		nblocks = be32_to_cpup(p++);
4494
		blocksize = be32_to_cpup(p);
A
Andy Adamson 已提交
4495
		*maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
L
Linus Torvalds 已提交
4496 4497
	}
	return 0;
B
Benny Halevy 已提交
4498 4499 4500
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4501 4502 4503 4504
}

static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
{
A
Andy Adamson 已提交
4505 4506
	__be32 *p;
	uint32_t delegation_type;
4507
	int status;
L
Linus Torvalds 已提交
4508

B
Benny Halevy 已提交
4509 4510 4511
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4512
	delegation_type = be32_to_cpup(p);
L
Linus Torvalds 已提交
4513 4514 4515 4516
	if (delegation_type == NFS4_OPEN_DELEGATE_NONE) {
		res->delegation_type = 0;
		return 0;
	}
4517 4518 4519
	status = decode_stateid(xdr, &res->delegation);
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
4520 4521 4522
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4523
	res->do_recall = be32_to_cpup(p);
A
Andy Adamson 已提交
4524

L
Linus Torvalds 已提交
4525
	switch (delegation_type) {
A
Andy Adamson 已提交
4526 4527 4528 4529 4530 4531
	case NFS4_OPEN_DELEGATE_READ:
		res->delegation_type = FMODE_READ;
		break;
	case NFS4_OPEN_DELEGATE_WRITE:
		res->delegation_type = FMODE_WRITE|FMODE_READ;
		if (decode_space_limit(xdr, &res->maxsize) < 0)
L
Linus Torvalds 已提交
4532 4533
				return -EIO;
	}
4534
	return decode_ace(xdr, NULL, res->server->nfs_client);
B
Benny Halevy 已提交
4535 4536 4537
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4538 4539 4540 4541
}

static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
{
A
Andy Adamson 已提交
4542
	__be32 *p;
4543
	uint32_t savewords, bmlen, i;
A
Andy Adamson 已提交
4544
	int status;
L
Linus Torvalds 已提交
4545

A
Andy Adamson 已提交
4546
	status = decode_op_hdr(xdr, OP_OPEN);
4547 4548
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
4549 4550 4551
	if (!status)
		status = decode_stateid(xdr, &res->stateid);
	if (unlikely(status))
A
Andy Adamson 已提交
4552
		return status;
L
Linus Torvalds 已提交
4553

A
Andy Adamson 已提交
4554
	decode_change_info(xdr, &res->cinfo);
L
Linus Torvalds 已提交
4555

B
Benny Halevy 已提交
4556 4557 4558
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4559
	res->rflags = be32_to_cpup(p++);
4560
	bmlen = be32_to_cpup(p);
A
Andy Adamson 已提交
4561 4562
	if (bmlen > 10)
		goto xdr_error;
L
Linus Torvalds 已提交
4563

B
Benny Halevy 已提交
4564 4565 4566
	p = xdr_inline_decode(xdr, bmlen << 2);
	if (unlikely(!p))
		goto out_overflow;
4567 4568
	savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE);
	for (i = 0; i < savewords; ++i)
B
Benny Halevy 已提交
4569
		res->attrset[i] = be32_to_cpup(p++);
4570 4571 4572
	for (; i < NFS4_BITMAP_SIZE; i++)
		res->attrset[i] = 0;

L
Linus Torvalds 已提交
4573 4574
	return decode_delegation(xdr, res);
xdr_error:
4575
	dprintk("%s: Bitmap too large! Length = %u\n", __func__, bmlen);
L
Linus Torvalds 已提交
4576
	return -EIO;
B
Benny Halevy 已提交
4577 4578 4579
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4580 4581 4582 4583 4584 4585
}

static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
{
	int status;

A
Andy Adamson 已提交
4586
	status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
4587 4588
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
4589 4590 4591
	if (!status)
		status = decode_stateid(xdr, &res->stateid);
	return status;
L
Linus Torvalds 已提交
4592 4593 4594 4595 4596 4597 4598
}

static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
{
	int status;

	status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE);
4599 4600
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
4601 4602 4603
	if (!status)
		status = decode_stateid(xdr, &res->stateid);
	return status;
L
Linus Torvalds 已提交
4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618
}

static int decode_putfh(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_PUTFH);
}

static int decode_putrootfh(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_PUTROOTFH);
}

static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
{
	struct kvec *iov = req->rq_rcv_buf.head;
A
Al Viro 已提交
4619
	__be32 *p;
L
Linus Torvalds 已提交
4620 4621 4622 4623 4624 4625
	uint32_t count, eof, recvd, hdrlen;
	int status;

	status = decode_op_hdr(xdr, OP_READ);
	if (status)
		return status;
B
Benny Halevy 已提交
4626 4627 4628
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4629
	eof = be32_to_cpup(p++);
4630
	count = be32_to_cpup(p);
4631
	hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base;
L
Linus Torvalds 已提交
4632 4633
	recvd = req->rq_rcv_buf.len - hdrlen;
	if (count > recvd) {
4634
		dprintk("NFS: server cheating in read reply: "
L
Linus Torvalds 已提交
4635 4636 4637 4638 4639 4640 4641 4642
				"count %u > recvd %u\n", count, recvd);
		count = recvd;
		eof = 0;
	}
	xdr_read_pages(xdr, count);
	res->eof = eof;
	res->count = count;
	return 0;
B
Benny Halevy 已提交
4643 4644 4645
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4646 4647 4648 4649 4650 4651
}

static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
{
	struct xdr_buf	*rcvbuf = &req->rq_rcv_buf;
	struct kvec	*iov = rcvbuf->head;
4652 4653 4654
	size_t		hdrlen;
	u32		recvd, pglen = rcvbuf->page_len;
	int		status;
L
Linus Torvalds 已提交
4655 4656

	status = decode_op_hdr(xdr, OP_READDIR);
4657 4658 4659
	if (!status)
		status = decode_verifier(xdr, readdir->verifier.data);
	if (unlikely(status))
L
Linus Torvalds 已提交
4660
		return status;
4661 4662
	dprintk("%s: verifier = %08x:%08x\n",
			__func__,
4663 4664 4665
			((u32 *)readdir->verifier.data)[0],
			((u32 *)readdir->verifier.data)[1]);

L
Linus Torvalds 已提交
4666

4667
	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
L
Linus Torvalds 已提交
4668 4669 4670 4671 4672
	recvd = rcvbuf->len - hdrlen;
	if (pglen > recvd)
		pglen = recvd;
	xdr_read_pages(xdr, pglen);

4673

4674
	return pglen;
L
Linus Torvalds 已提交
4675 4676 4677 4678 4679 4680
}

static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
{
	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
	struct kvec *iov = rcvbuf->head;
4681 4682
	size_t hdrlen;
	u32 len, recvd;
A
Al Viro 已提交
4683
	__be32 *p;
L
Linus Torvalds 已提交
4684 4685 4686 4687 4688 4689 4690
	int status;

	status = decode_op_hdr(xdr, OP_READLINK);
	if (status)
		return status;

	/* Convert length of symlink */
B
Benny Halevy 已提交
4691 4692 4693
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4694
	len = be32_to_cpup(p);
L
Linus Torvalds 已提交
4695
	if (len >= rcvbuf->page_len || len <= 0) {
4696
		dprintk("nfs: server returned giant symlink!\n");
L
Linus Torvalds 已提交
4697 4698 4699 4700 4701
		return -ENAMETOOLONG;
	}
	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
	recvd = req->rq_rcv_buf.len - hdrlen;
	if (recvd < len) {
4702
		dprintk("NFS: server cheating in readlink reply: "
L
Linus Torvalds 已提交
4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713
				"count %u > recvd %u\n", len, recvd);
		return -EIO;
	}
	xdr_read_pages(xdr, len);
	/*
	 * The XDR encode routine has set things up so that
	 * the link text will be copied directly into the
	 * buffer.  We just have to do overflow-checking,
	 * and and null-terminate the text (the VFS expects
	 * null-termination).
	 */
4714
	xdr_terminate_string(rcvbuf, len);
L
Linus Torvalds 已提交
4715
	return 0;
B
Benny Halevy 已提交
4716 4717 4718
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752
}

static int decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
	int status;

	status = decode_op_hdr(xdr, OP_REMOVE);
	if (status)
		goto out;
	status = decode_change_info(xdr, cinfo);
out:
	return status;
}

static int decode_rename(struct xdr_stream *xdr, struct nfs4_change_info *old_cinfo,
	      struct nfs4_change_info *new_cinfo)
{
	int status;

	status = decode_op_hdr(xdr, OP_RENAME);
	if (status)
		goto out;
	if ((status = decode_change_info(xdr, old_cinfo)))
		goto out;
	status = decode_change_info(xdr, new_cinfo);
out:
	return status;
}

static int decode_renew(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_RENEW);
}

4753 4754 4755 4756 4757 4758
static int
decode_restorefh(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_RESTOREFH);
}

4759 4760 4761
static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
		size_t *acl_len)
{
A
Al Viro 已提交
4762
	__be32 *savep;
4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778
	uint32_t attrlen,
		 bitmap[2] = {0};
	struct kvec *iov = req->rq_rcv_buf.head;
	int status;

	*acl_len = 0;
	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
		goto out;
	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
		goto out;
	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
		goto out;

	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
4779 4780
		size_t hdrlen;
		u32 recvd;
4781 4782 4783 4784 4785 4786

		/* We ignore &savep and don't do consistency checks on
		 * the attr length.  Let userspace figure it out.... */
		hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
		recvd = req->rq_rcv_buf.len - hdrlen;
		if (attrlen > recvd) {
4787
			dprintk("NFS: server cheating in getattr"
4788 4789 4790 4791
					" acl reply: attrlen %u > recvd %u\n",
					attrlen, recvd);
			return -EINVAL;
		}
4792
		xdr_read_pages(xdr, attrlen);
4793
		*acl_len = attrlen;
J
J. Bruce Fields 已提交
4794 4795
	} else
		status = -EOPNOTSUPP;
4796 4797 4798 4799 4800

out:
	return status;
}

L
Linus Torvalds 已提交
4801 4802 4803 4804 4805 4806
static int
decode_savefh(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_SAVEFH);
}

4807
static int decode_setattr(struct xdr_stream *xdr)
L
Linus Torvalds 已提交
4808
{
A
Al Viro 已提交
4809
	__be32 *p;
L
Linus Torvalds 已提交
4810 4811 4812 4813 4814 4815
	uint32_t bmlen;
	int status;

	status = decode_op_hdr(xdr, OP_SETATTR);
	if (status)
		return status;
B
Benny Halevy 已提交
4816 4817 4818
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4819
	bmlen = be32_to_cpup(p);
B
Benny Halevy 已提交
4820 4821 4822 4823 4824 4825
	p = xdr_inline_decode(xdr, bmlen << 2);
	if (likely(p))
		return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4826 4827
}

4828
static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid_res *res)
L
Linus Torvalds 已提交
4829
{
A
Al Viro 已提交
4830
	__be32 *p;
L
Linus Torvalds 已提交
4831 4832 4833
	uint32_t opnum;
	int32_t nfserr;

B
Benny Halevy 已提交
4834 4835 4836
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4837
	opnum = be32_to_cpup(p++);
L
Linus Torvalds 已提交
4838
	if (opnum != OP_SETCLIENTID) {
4839
		dprintk("nfs: decode_setclientid: Server returned operation"
4840
			" %d\n", opnum);
L
Linus Torvalds 已提交
4841 4842
		return -EIO;
	}
4843
	nfserr = be32_to_cpup(p);
L
Linus Torvalds 已提交
4844
	if (nfserr == NFS_OK) {
B
Benny Halevy 已提交
4845 4846 4847
		p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE);
		if (unlikely(!p))
			goto out_overflow;
4848 4849
		p = xdr_decode_hyper(p, &res->clientid);
		memcpy(res->confirm.data, p, NFS4_VERIFIER_SIZE);
L
Linus Torvalds 已提交
4850 4851 4852 4853
	} else if (nfserr == NFSERR_CLID_INUSE) {
		uint32_t len;

		/* skip netid string */
B
Benny Halevy 已提交
4854 4855 4856
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
4857
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
4858 4859 4860
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
L
Linus Torvalds 已提交
4861 4862

		/* skip uaddr string */
B
Benny Halevy 已提交
4863 4864 4865
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
4866
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
4867 4868 4869
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
L
Linus Torvalds 已提交
4870 4871
		return -NFSERR_CLID_INUSE;
	} else
4872
		return nfs4_stat_to_errno(nfserr);
L
Linus Torvalds 已提交
4873 4874

	return 0;
B
Benny Halevy 已提交
4875 4876 4877
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4878 4879 4880 4881 4882 4883 4884 4885 4886
}

static int decode_setclientid_confirm(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM);
}

static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
{
A
Al Viro 已提交
4887
	__be32 *p;
L
Linus Torvalds 已提交
4888 4889 4890 4891 4892 4893
	int status;

	status = decode_op_hdr(xdr, OP_WRITE);
	if (status)
		return status;

B
Benny Halevy 已提交
4894 4895 4896
	p = xdr_inline_decode(xdr, 16);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4897 4898
	res->count = be32_to_cpup(p++);
	res->verf->committed = be32_to_cpup(p++);
B
Benny Halevy 已提交
4899
	memcpy(res->verf->verifier, p, 8);
L
Linus Torvalds 已提交
4900
	return 0;
B
Benny Halevy 已提交
4901 4902 4903
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4904 4905 4906 4907 4908 4909 4910
}

static int decode_delegreturn(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_DELEGRETURN);
}

B
Bryan Schumaker 已提交
4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946
static int decode_secinfo_gss(struct xdr_stream *xdr, struct nfs4_secinfo_flavor *flavor)
{
	__be32 *p;

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
	flavor->gss.sec_oid4.len = be32_to_cpup(p);
	if (flavor->gss.sec_oid4.len > GSS_OID_MAX_LEN)
		goto out_err;

	p = xdr_inline_decode(xdr, flavor->gss.sec_oid4.len);
	if (unlikely(!p))
		goto out_overflow;
	memcpy(flavor->gss.sec_oid4.data, p, flavor->gss.sec_oid4.len);

	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
	flavor->gss.qop4 = be32_to_cpup(p++);
	flavor->gss.service = be32_to_cpup(p);

	return 0;

out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
out_err:
	return -EINVAL;
}

static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
{
	struct nfs4_secinfo_flavor *sec_flavor;
	int status;
	__be32 *p;
4947
	int i, num_flavors;
B
Bryan Schumaker 已提交
4948 4949

	status = decode_op_hdr(xdr, OP_SECINFO);
4950 4951
	if (status)
		goto out;
B
Bryan Schumaker 已提交
4952 4953 4954 4955
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;

4956 4957 4958 4959
	res->flavors->num_flavors = 0;
	num_flavors = be32_to_cpup(p);

	for (i = 0; i < num_flavors; i++) {
B
Bryan Schumaker 已提交
4960
		sec_flavor = &res->flavors->flavors[i];
4961
		if ((char *)&sec_flavor[1] - (char *)res->flavors > PAGE_SIZE)
B
Bryan Schumaker 已提交
4962 4963 4964 4965 4966 4967 4968 4969
			break;

		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
		sec_flavor->flavor = be32_to_cpup(p);

		if (sec_flavor->flavor == RPC_AUTH_GSS) {
4970 4971 4972
			status = decode_secinfo_gss(xdr, sec_flavor);
			if (status)
				goto out;
B
Bryan Schumaker 已提交
4973
		}
4974
		res->flavors->num_flavors++;
B
Bryan Schumaker 已提交
4975 4976
	}

4977 4978
out:
	return status;
B
Bryan Schumaker 已提交
4979 4980 4981 4982 4983
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}

B
Benny Halevy 已提交
4984 4985 4986 4987 4988 4989
#if defined(CONFIG_NFS_V4_1)
static int decode_exchange_id(struct xdr_stream *xdr,
			      struct nfs41_exchange_id_res *res)
{
	__be32 *p;
	uint32_t dummy;
4990
	char *dummy_str;
B
Benny Halevy 已提交
4991 4992 4993 4994 4995 4996 4997
	int status;
	struct nfs_client *clp = res->client;

	status = decode_op_hdr(xdr, OP_EXCHANGE_ID);
	if (status)
		return status;

B
Benny Halevy 已提交
4998 4999 5000
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
5001
	xdr_decode_hyper(p, &clp->cl_clientid);
B
Benny Halevy 已提交
5002 5003 5004
	p = xdr_inline_decode(xdr, 12);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
5005 5006
	clp->cl_seqid = be32_to_cpup(p++);
	clp->cl_exchange_flags = be32_to_cpup(p++);
B
Benny Halevy 已提交
5007 5008

	/* We ask for SP4_NONE */
5009
	dummy = be32_to_cpup(p);
B
Benny Halevy 已提交
5010 5011 5012 5013
	if (dummy != SP4_NONE)
		return -EIO;

	/* Throw away minor_id */
B
Benny Halevy 已提交
5014 5015 5016
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
5017 5018

	/* Throw away Major id */
5019 5020 5021
	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
5022

5023
	/* Save server_scope */
5024 5025 5026
	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
5027

5028 5029 5030 5031 5032 5033
	if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
		return -EIO;

	memcpy(res->server_scope->server_scope, dummy_str, dummy);
	res->server_scope->server_scope_sz = dummy;

B
Benny Halevy 已提交
5034
	/* Throw away Implementation id array */
5035 5036 5037
	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
5038 5039

	return 0;
B
Benny Halevy 已提交
5040 5041 5042
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
B
Benny Halevy 已提交
5043
}
A
Andy Adamson 已提交
5044 5045 5046 5047 5048

static int decode_chan_attrs(struct xdr_stream *xdr,
			     struct nfs4_channel_attrs *attrs)
{
	__be32 *p;
5049
	u32 nr_attrs, val;
A
Andy Adamson 已提交
5050

B
Benny Halevy 已提交
5051 5052 5053
	p = xdr_inline_decode(xdr, 28);
	if (unlikely(!p))
		goto out_overflow;
5054 5055 5056
	val = be32_to_cpup(p++);	/* headerpadsz */
	if (val)
		return -EINVAL;		/* no support for header padding yet */
B
Benny Halevy 已提交
5057 5058 5059 5060 5061
	attrs->max_rqst_sz = be32_to_cpup(p++);
	attrs->max_resp_sz = be32_to_cpup(p++);
	attrs->max_resp_sz_cached = be32_to_cpup(p++);
	attrs->max_ops = be32_to_cpup(p++);
	attrs->max_reqs = be32_to_cpup(p++);
5062
	nr_attrs = be32_to_cpup(p);
A
Andy Adamson 已提交
5063 5064 5065 5066 5067
	if (unlikely(nr_attrs > 1)) {
		printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n",
			__func__, nr_attrs);
		return -EINVAL;
	}
B
Benny Halevy 已提交
5068 5069 5070 5071 5072
	if (nr_attrs == 1) {
		p = xdr_inline_decode(xdr, 4); /* skip rdma_attrs */
		if (unlikely(!p))
			goto out_overflow;
	}
A
Andy Adamson 已提交
5073
	return 0;
B
Benny Halevy 已提交
5074 5075 5076
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
A
Andy Adamson 已提交
5077 5078
}

5079 5080 5081
static int decode_sessionid(struct xdr_stream *xdr, struct nfs4_sessionid *sid)
{
	return decode_opaque_fixed(xdr, sid->data, NFS4_MAX_SESSIONID_LEN);
A
Andy Adamson 已提交
5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092
}

static int decode_create_session(struct xdr_stream *xdr,
				 struct nfs41_create_session_res *res)
{
	__be32 *p;
	int status;
	struct nfs_client *clp = res->client;
	struct nfs4_session *session = clp->cl_session;

	status = decode_op_hdr(xdr, OP_CREATE_SESSION);
5093 5094 5095
	if (!status)
		status = decode_sessionid(xdr, &session->sess_id);
	if (unlikely(status))
A
Andy Adamson 已提交
5096 5097 5098
		return status;

	/* seqid, flags */
B
Benny Halevy 已提交
5099 5100 5101
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
5102
	clp->cl_seqid = be32_to_cpup(p++);
5103
	session->flags = be32_to_cpup(p);
A
Andy Adamson 已提交
5104 5105 5106 5107 5108 5109

	/* Channel attributes */
	status = decode_chan_attrs(xdr, &session->fc_attrs);
	if (!status)
		status = decode_chan_attrs(xdr, &session->bc_attrs);
	return status;
B
Benny Halevy 已提交
5110 5111 5112
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
A
Andy Adamson 已提交
5113
}
A
Andy Adamson 已提交
5114 5115 5116 5117 5118

static int decode_destroy_session(struct xdr_stream *xdr, void *dummy)
{
	return decode_op_hdr(xdr, OP_DESTROY_SESSION);
}
5119 5120 5121 5122 5123

static int decode_reclaim_complete(struct xdr_stream *xdr, void *dummy)
{
	return decode_op_hdr(xdr, OP_RECLAIM_COMPLETE);
}
B
Benny Halevy 已提交
5124 5125
#endif /* CONFIG_NFS_V4_1 */

5126 5127 5128 5129 5130
static int decode_sequence(struct xdr_stream *xdr,
			   struct nfs4_sequence_res *res,
			   struct rpc_rqst *rqstp)
{
#if defined(CONFIG_NFS_V4_1)
A
Andy Adamson 已提交
5131 5132 5133 5134 5135
	struct nfs4_sessionid id;
	u32 dummy;
	int status;
	__be32 *p;

5136 5137 5138
	if (!res->sr_session)
		return 0;

A
Andy Adamson 已提交
5139
	status = decode_op_hdr(xdr, OP_SEQUENCE);
5140 5141 5142
	if (!status)
		status = decode_sessionid(xdr, &id);
	if (unlikely(status))
A
Andy Adamson 已提交
5143
		goto out_err;
5144

A
Andy Adamson 已提交
5145 5146 5147 5148
	/*
	 * If the server returns different values for sessionID, slotID or
	 * sequence number, the server is looney tunes.
	 */
5149
	status = -EREMOTEIO;
A
Andy Adamson 已提交
5150 5151 5152 5153 5154 5155

	if (memcmp(id.data, res->sr_session->sess_id.data,
		   NFS4_MAX_SESSIONID_LEN)) {
		dprintk("%s Invalid session id\n", __func__);
		goto out_err;
	}
5156

B
Benny Halevy 已提交
5157 5158 5159
	p = xdr_inline_decode(xdr, 20);
	if (unlikely(!p))
		goto out_overflow;
5160

A
Andy Adamson 已提交
5161
	/* seqid */
B
Benny Halevy 已提交
5162
	dummy = be32_to_cpup(p++);
5163
	if (dummy != res->sr_slot->seq_nr) {
A
Andy Adamson 已提交
5164 5165 5166 5167
		dprintk("%s Invalid sequence number\n", __func__);
		goto out_err;
	}
	/* slot id */
B
Benny Halevy 已提交
5168
	dummy = be32_to_cpup(p++);
5169
	if (dummy != res->sr_slot - res->sr_session->fc_slot_table.slots) {
A
Andy Adamson 已提交
5170 5171 5172 5173
		dprintk("%s Invalid slot id\n", __func__);
		goto out_err;
	}
	/* highest slot id - currently not processed */
B
Benny Halevy 已提交
5174
	dummy = be32_to_cpup(p++);
A
Andy Adamson 已提交
5175
	/* target highest slot id - currently not processed */
B
Benny Halevy 已提交
5176
	dummy = be32_to_cpup(p++);
5177 5178
	/* result flags */
	res->sr_status_flags = be32_to_cpup(p);
A
Andy Adamson 已提交
5179 5180 5181 5182
	status = 0;
out_err:
	res->sr_status = status;
	return status;
B
Benny Halevy 已提交
5183 5184 5185 5186
out_overflow:
	print_overflow_msg(__func__, xdr);
	status = -EIO;
	goto out_err;
A
Andy Adamson 已提交
5187
#else  /* CONFIG_NFS_V4_1 */
5188
	return 0;
A
Andy Adamson 已提交
5189
#endif /* CONFIG_NFS_V4_1 */
5190 5191
}

5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236
#if defined(CONFIG_NFS_V4_1)

static int decode_getdeviceinfo(struct xdr_stream *xdr,
				struct pnfs_device *pdev)
{
	__be32 *p;
	uint32_t len, type;
	int status;

	status = decode_op_hdr(xdr, OP_GETDEVICEINFO);
	if (status) {
		if (status == -ETOOSMALL) {
			p = xdr_inline_decode(xdr, 4);
			if (unlikely(!p))
				goto out_overflow;
			pdev->mincount = be32_to_cpup(p);
			dprintk("%s: Min count too small. mincnt = %u\n",
				__func__, pdev->mincount);
		}
		return status;
	}

	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
	type = be32_to_cpup(p++);
	if (type != pdev->layout_type) {
		dprintk("%s: layout mismatch req: %u pdev: %u\n",
			__func__, pdev->layout_type, type);
		return -EINVAL;
	}
	/*
	 * Get the length of the opaque device_addr4. xdr_read_pages places
	 * the opaque device_addr4 in the xdr_buf->pages (pnfs_device->pages)
	 * and places the remaining xdr data in xdr_buf->tail
	 */
	pdev->mincount = be32_to_cpup(p);
	xdr_read_pages(xdr, pdev->mincount); /* include space for the length */

	/* Parse notification bitmap, verifying that it is zero. */
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
	len = be32_to_cpup(p);
	if (len) {
5237
		uint32_t i;
5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261

		p = xdr_inline_decode(xdr, 4 * len);
		if (unlikely(!p))
			goto out_overflow;
		for (i = 0; i < len; i++, p++) {
			if (be32_to_cpup(p)) {
				dprintk("%s: notifications not supported\n",
					__func__);
				return -EIO;
			}
		}
	}
	return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}

static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req,
			    struct nfs4_layoutget_res *res)
{
	__be32 *p;
	int status;
	u32 layout_count;
5262 5263 5264
	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
	struct kvec *iov = rcvbuf->head;
	u32 hdrlen, recvd;
5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280

	status = decode_op_hdr(xdr, OP_LAYOUTGET);
	if (status)
		return status;
	p = xdr_inline_decode(xdr, 8 + NFS4_STATEID_SIZE);
	if (unlikely(!p))
		goto out_overflow;
	res->return_on_close = be32_to_cpup(p++);
	p = xdr_decode_opaque_fixed(p, res->stateid.data, NFS4_STATEID_SIZE);
	layout_count = be32_to_cpup(p);
	if (!layout_count) {
		dprintk("%s: server responded with empty layout array\n",
			__func__);
		return -EINVAL;
	}

5281
	p = xdr_inline_decode(xdr, 28);
5282 5283 5284 5285 5286 5287
	if (unlikely(!p))
		goto out_overflow;
	p = xdr_decode_hyper(p, &res->range.offset);
	p = xdr_decode_hyper(p, &res->range.length);
	res->range.iomode = be32_to_cpup(p++);
	res->type = be32_to_cpup(p++);
5288
	res->layoutp->len = be32_to_cpup(p);
5289 5290 5291 5292 5293 5294 5295

	dprintk("%s roff:%lu rlen:%lu riomode:%d, lo_type:0x%x, lo.len:%d\n",
		__func__,
		(unsigned long)res->range.offset,
		(unsigned long)res->range.length,
		res->range.iomode,
		res->type,
5296 5297 5298 5299 5300 5301 5302 5303 5304 5305
		res->layoutp->len);

	hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base;
	recvd = req->rq_rcv_buf.len - hdrlen;
	if (res->layoutp->len > recvd) {
		dprintk("NFS: server cheating in layoutget reply: "
				"layout len %u > recvd %u\n",
				res->layoutp->len, recvd);
		return -EINVAL;
	}
5306

5307
	xdr_read_pages(xdr, res->layoutp->len);
5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323

	if (layout_count > 1) {
		/* We only handle a length one array at the moment.  Any
		 * further entries are just ignored.  Note that this means
		 * the client may see a response that is less than the
		 * minimum it requested.
		 */
		dprintk("%s: server responded with %d layouts, dropping tail\n",
			__func__, layout_count);
	}

	return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}
A
Andy Adamson 已提交
5324

B
Benny Halevy 已提交
5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345
static int decode_layoutreturn(struct xdr_stream *xdr,
			       struct nfs4_layoutreturn_res *res)
{
	__be32 *p;
	int status;

	status = decode_op_hdr(xdr, OP_LAYOUTRETURN);
	if (status)
		return status;
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
	res->lrs_present = be32_to_cpup(p);
	if (res->lrs_present)
		status = decode_stateid(xdr, &res->stateid);
	return status;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}

A
Andy Adamson 已提交
5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373
static int decode_layoutcommit(struct xdr_stream *xdr,
			       struct rpc_rqst *req,
			       struct nfs4_layoutcommit_res *res)
{
	__be32 *p;
	__u32 sizechanged;
	int status;

	status = decode_op_hdr(xdr, OP_LAYOUTCOMMIT);
	if (status)
		return status;

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
	sizechanged = be32_to_cpup(p);

	if (sizechanged) {
		/* throw away new size */
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
	}
	return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}
5374 5375
#endif /* CONFIG_NFS_V4_1 */

5376 5377 5378 5379
/*
 * END OF "GENERIC" DECODE ROUTINES.
 */

L
Linus Torvalds 已提交
5380 5381 5382
/*
 * Decode OPEN_DOWNGRADE response
 */
5383 5384 5385
static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
				       struct xdr_stream *xdr,
				       struct nfs_closeres *res)
L
Linus Torvalds 已提交
5386
{
A
Andy Adamson 已提交
5387 5388 5389
	struct compound_hdr hdr;
	int status;

5390
	status = decode_compound_hdr(xdr, &hdr);
5391 5392
	if (status)
		goto out;
5393
	status = decode_sequence(xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
5394 5395
	if (status)
		goto out;
5396
	status = decode_putfh(xdr);
A
Andy Adamson 已提交
5397 5398
	if (status)
		goto out;
5399
	status = decode_open_downgrade(xdr, res);
5400 5401
	if (status != 0)
		goto out;
5402
	decode_getfattr(xdr, res->fattr, res->server,
5403
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5404
out:
A
Andy Adamson 已提交
5405
	return status;
L
Linus Torvalds 已提交
5406 5407 5408 5409 5410
}

/*
 * Decode ACCESS response
 */
5411 5412
static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			       struct nfs4_accessres *res)
L
Linus Torvalds 已提交
5413 5414 5415
{
	struct compound_hdr hdr;
	int status;
5416

5417
	status = decode_compound_hdr(xdr, &hdr);
5418 5419
	if (status)
		goto out;
5420
	status = decode_sequence(xdr, &res->seq_res, rqstp);
5421
	if (status)
L
Linus Torvalds 已提交
5422
		goto out;
5423
	status = decode_putfh(xdr);
5424 5425
	if (status != 0)
		goto out;
5426
	status = decode_access(xdr, res);
5427 5428
	if (status != 0)
		goto out;
5429
	decode_getfattr(xdr, res->fattr, res->server,
5430
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5431 5432 5433 5434 5435 5436 5437
out:
	return status;
}

/*
 * Decode LOOKUP response
 */
5438 5439
static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			       struct nfs4_lookup_res *res)
L
Linus Torvalds 已提交
5440 5441 5442
{
	struct compound_hdr hdr;
	int status;
5443

5444
	status = decode_compound_hdr(xdr, &hdr);
5445 5446
	if (status)
		goto out;
5447
	status = decode_sequence(xdr, &res->seq_res, rqstp);
5448
	if (status)
L
Linus Torvalds 已提交
5449
		goto out;
5450 5451
	status = decode_putfh(xdr);
	if (status)
L
Linus Torvalds 已提交
5452
		goto out;
5453 5454
	status = decode_lookup(xdr);
	if (status)
L
Linus Torvalds 已提交
5455
		goto out;
5456 5457
	status = decode_getfh(xdr, res->fh);
	if (status)
L
Linus Torvalds 已提交
5458
		goto out;
5459
	status = decode_getfattr(xdr, res->fattr, res->server
5460
			,!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5461 5462 5463 5464 5465 5466 5467
out:
	return status;
}

/*
 * Decode LOOKUP_ROOT response
 */
5468 5469 5470
static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
				    struct xdr_stream *xdr,
				    struct nfs4_lookup_res *res)
L
Linus Torvalds 已提交
5471 5472 5473
{
	struct compound_hdr hdr;
	int status;
5474

5475
	status = decode_compound_hdr(xdr, &hdr);
5476 5477
	if (status)
		goto out;
5478
	status = decode_sequence(xdr, &res->seq_res, rqstp);
5479
	if (status)
L
Linus Torvalds 已提交
5480
		goto out;
5481 5482
	status = decode_putrootfh(xdr);
	if (status)
L
Linus Torvalds 已提交
5483
		goto out;
5484 5485 5486
	status = decode_getfh(xdr, res->fh);
	if (status == 0)
		status = decode_getfattr(xdr, res->fattr, res->server,
5487
				!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5488 5489 5490 5491 5492 5493 5494
out:
	return status;
}

/*
 * Decode REMOVE response
 */
5495 5496
static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			       struct nfs_removeres *res)
L
Linus Torvalds 已提交
5497 5498 5499
{
	struct compound_hdr hdr;
	int status;
5500

5501
	status = decode_compound_hdr(xdr, &hdr);
5502 5503
	if (status)
		goto out;
5504
	status = decode_sequence(xdr, &res->seq_res, rqstp);
5505
	if (status)
L
Linus Torvalds 已提交
5506
		goto out;
5507 5508
	status = decode_putfh(xdr);
	if (status)
5509
		goto out;
5510 5511
	status = decode_remove(xdr, &res->cinfo);
	if (status)
5512
		goto out;
5513
	decode_getfattr(xdr, res->dir_attr, res->server,
5514
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5515 5516 5517 5518 5519 5520 5521
out:
	return status;
}

/*
 * Decode RENAME response
 */
5522 5523
static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			       struct nfs_renameres *res)
L
Linus Torvalds 已提交
5524 5525 5526
{
	struct compound_hdr hdr;
	int status;
5527

5528
	status = decode_compound_hdr(xdr, &hdr);
5529 5530
	if (status)
		goto out;
5531
	status = decode_sequence(xdr, &res->seq_res, rqstp);
5532
	if (status)
L
Linus Torvalds 已提交
5533
		goto out;
5534 5535
	status = decode_putfh(xdr);
	if (status)
L
Linus Torvalds 已提交
5536
		goto out;
5537 5538
	status = decode_savefh(xdr);
	if (status)
L
Linus Torvalds 已提交
5539
		goto out;
5540 5541
	status = decode_putfh(xdr);
	if (status)
L
Linus Torvalds 已提交
5542
		goto out;
5543 5544
	status = decode_rename(xdr, &res->old_cinfo, &res->new_cinfo);
	if (status)
5545 5546
		goto out;
	/* Current FH is target directory */
5547
	if (decode_getfattr(xdr, res->new_fattr, res->server,
5548
				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
5549
		goto out;
5550 5551
	status = decode_restorefh(xdr);
	if (status)
5552
		goto out;
5553
	decode_getfattr(xdr, res->old_fattr, res->server,
5554
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5555 5556 5557 5558 5559 5560 5561
out:
	return status;
}

/*
 * Decode LINK response
 */
5562 5563
static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			     struct nfs4_link_res *res)
L
Linus Torvalds 已提交
5564 5565 5566
{
	struct compound_hdr hdr;
	int status;
5567

5568
	status = decode_compound_hdr(xdr, &hdr);
5569 5570
	if (status)
		goto out;
5571
	status = decode_sequence(xdr, &res->seq_res, rqstp);
5572
	if (status)
L
Linus Torvalds 已提交
5573
		goto out;
5574 5575
	status = decode_putfh(xdr);
	if (status)
L
Linus Torvalds 已提交
5576
		goto out;
5577 5578
	status = decode_savefh(xdr);
	if (status)
L
Linus Torvalds 已提交
5579
		goto out;
5580 5581
	status = decode_putfh(xdr);
	if (status)
L
Linus Torvalds 已提交
5582
		goto out;
5583 5584
	status = decode_link(xdr, &res->cinfo);
	if (status)
5585 5586 5587 5588 5589
		goto out;
	/*
	 * Note order: OP_LINK leaves the directory as the current
	 *             filehandle.
	 */
5590
	if (decode_getfattr(xdr, res->dir_attr, res->server,
5591
				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
5592
		goto out;
5593 5594
	status = decode_restorefh(xdr);
	if (status)
5595
		goto out;
5596
	decode_getfattr(xdr, res->fattr, res->server,
5597
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5598 5599 5600 5601 5602 5603 5604
out:
	return status;
}

/*
 * Decode CREATE response
 */
5605 5606
static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			       struct nfs4_create_res *res)
L
Linus Torvalds 已提交
5607 5608 5609
{
	struct compound_hdr hdr;
	int status;
5610

5611
	status = decode_compound_hdr(xdr, &hdr);
5612 5613
	if (status)
		goto out;
5614
	status = decode_sequence(xdr, &res->seq_res, rqstp);
5615
	if (status)
L
Linus Torvalds 已提交
5616
		goto out;
5617 5618
	status = decode_putfh(xdr);
	if (status)
L
Linus Torvalds 已提交
5619
		goto out;
5620 5621
	status = decode_savefh(xdr);
	if (status)
5622
		goto out;
5623 5624
	status = decode_create(xdr, &res->dir_cinfo);
	if (status)
L
Linus Torvalds 已提交
5625
		goto out;
5626 5627
	status = decode_getfh(xdr, res->fh);
	if (status)
L
Linus Torvalds 已提交
5628
		goto out;
5629
	if (decode_getfattr(xdr, res->fattr, res->server,
5630
				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
5631
		goto out;
5632 5633
	status = decode_restorefh(xdr);
	if (status)
5634
		goto out;
5635
	decode_getfattr(xdr, res->dir_fattr, res->server,
5636
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5637 5638 5639 5640 5641 5642 5643
out:
	return status;
}

/*
 * Decode SYMLINK response
 */
5644 5645
static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
				struct nfs4_create_res *res)
L
Linus Torvalds 已提交
5646
{
5647
	return nfs4_xdr_dec_create(rqstp, xdr, res);
L
Linus Torvalds 已提交
5648 5649 5650 5651 5652
}

/*
 * Decode GETATTR response
 */
5653 5654
static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
				struct nfs4_getattr_res *res)
L
Linus Torvalds 已提交
5655 5656 5657
{
	struct compound_hdr hdr;
	int status;
5658

5659
	status = decode_compound_hdr(xdr, &hdr);
5660 5661
	if (status)
		goto out;
5662
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5663 5664
	if (status)
		goto out;
5665
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
5666 5667
	if (status)
		goto out;
5668
	status = decode_getfattr(xdr, res->fattr, res->server,
5669
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5670 5671 5672 5673
out:
	return status;
}

5674 5675 5676
/*
 * Encode an SETACL request
 */
5677 5678
static void nfs4_xdr_enc_setacl(struct rpc_rqst *req, struct xdr_stream *xdr,
				struct nfs_setaclargs *args)
5679
{
A
Andy Adamson 已提交
5680
	struct compound_hdr hdr = {
5681
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
A
Andy Adamson 已提交
5682 5683
	};

5684 5685 5686 5687
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_setacl(xdr, args, &hdr);
5688
	encode_nops(&hdr);
5689
}
A
Andy Adamson 已提交
5690

5691 5692 5693 5694
/*
 * Decode SETACL response
 */
static int
5695
nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
B
Benny Halevy 已提交
5696
		    struct nfs_setaclres *res)
5697 5698 5699 5700
{
	struct compound_hdr hdr;
	int status;

5701
	status = decode_compound_hdr(xdr, &hdr);
5702 5703
	if (status)
		goto out;
5704
	status = decode_sequence(xdr, &res->seq_res, rqstp);
5705 5706
	if (status)
		goto out;
5707
	status = decode_putfh(xdr);
5708 5709
	if (status)
		goto out;
5710
	status = decode_setattr(xdr);
5711 5712 5713
out:
	return status;
}
L
Linus Torvalds 已提交
5714

5715 5716 5717 5718
/*
 * Decode GETACL response
 */
static int
5719
nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
B
Benny Halevy 已提交
5720
		    struct nfs_getaclres *res)
5721 5722 5723 5724
{
	struct compound_hdr hdr;
	int status;

5725
	status = decode_compound_hdr(xdr, &hdr);
5726 5727
	if (status)
		goto out;
5728
	status = decode_sequence(xdr, &res->seq_res, rqstp);
5729 5730
	if (status)
		goto out;
5731
	status = decode_putfh(xdr);
5732 5733
	if (status)
		goto out;
5734
	status = decode_getacl(xdr, rqstp, &res->acl_len);
5735 5736 5737 5738 5739

out:
	return status;
}

L
Linus Torvalds 已提交
5740 5741 5742
/*
 * Decode CLOSE response
 */
5743 5744
static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			      struct nfs_closeres *res)
L
Linus Torvalds 已提交
5745
{
A
Andy Adamson 已提交
5746 5747 5748
	struct compound_hdr hdr;
	int status;

5749
	status = decode_compound_hdr(xdr, &hdr);
5750 5751
	if (status)
		goto out;
5752
	status = decode_sequence(xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
5753 5754
	if (status)
		goto out;
5755
	status = decode_putfh(xdr);
A
Andy Adamson 已提交
5756 5757
	if (status)
		goto out;
5758
	status = decode_close(xdr, res);
5759 5760 5761 5762 5763 5764 5765 5766
	if (status != 0)
		goto out;
	/*
	 * Note: Server may do delete on close for this file
	 * 	in which case the getattr call will fail with
	 * 	an ESTALE error. Shouldn't be a problem,
	 * 	though, since fattr->valid will remain unset.
	 */
5767
	decode_getfattr(xdr, res->fattr, res->server,
5768
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5769
out:
A
Andy Adamson 已提交
5770
	return status;
L
Linus Torvalds 已提交
5771 5772 5773 5774 5775
}

/*
 * Decode OPEN response
 */
5776 5777
static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			     struct nfs_openres *res)
L
Linus Torvalds 已提交
5778
{
A
Andy Adamson 已提交
5779 5780 5781
	struct compound_hdr hdr;
	int status;

5782
	status = decode_compound_hdr(xdr, &hdr);
5783 5784
	if (status)
		goto out;
5785
	status = decode_sequence(xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
5786 5787
	if (status)
		goto out;
5788
	status = decode_putfh(xdr);
A
Andy Adamson 已提交
5789 5790
	if (status)
		goto out;
5791
	status = decode_savefh(xdr);
A
Andy Adamson 已提交
5792 5793
	if (status)
		goto out;
5794
	status = decode_open(xdr, res);
5795 5796
	if (status)
		goto out;
5797
	if (decode_getfh(xdr, &res->fh) != 0)
L
Linus Torvalds 已提交
5798
		goto out;
5799
	if (decode_getfattr(xdr, res->f_attr, res->server,
5800
				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
5801
		goto out;
5802
	if (decode_restorefh(xdr) != 0)
5803
		goto out;
5804
	decode_getfattr(xdr, res->dir_attr, res->server,
5805
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5806
out:
A
Andy Adamson 已提交
5807
	return status;
L
Linus Torvalds 已提交
5808 5809 5810 5811 5812
}

/*
 * Decode OPEN_CONFIRM response
 */
5813 5814 5815
static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp,
				     struct xdr_stream *xdr,
				     struct nfs_open_confirmres *res)
L
Linus Torvalds 已提交
5816
{
A
Andy Adamson 已提交
5817 5818 5819
	struct compound_hdr hdr;
	int status;

5820
	status = decode_compound_hdr(xdr, &hdr);
A
Andy Adamson 已提交
5821 5822
	if (status)
		goto out;
5823
	status = decode_putfh(xdr);
A
Andy Adamson 已提交
5824 5825
	if (status)
		goto out;
5826
	status = decode_open_confirm(xdr, res);
L
Linus Torvalds 已提交
5827
out:
A
Andy Adamson 已提交
5828
	return status;
L
Linus Torvalds 已提交
5829 5830 5831 5832 5833
}

/*
 * Decode OPEN response
 */
5834 5835 5836
static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
				    struct xdr_stream *xdr,
				    struct nfs_openres *res)
L
Linus Torvalds 已提交
5837
{
A
Andy Adamson 已提交
5838 5839 5840
	struct compound_hdr hdr;
	int status;

5841
	status = decode_compound_hdr(xdr, &hdr);
5842 5843
	if (status)
		goto out;
5844
	status = decode_sequence(xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
5845 5846
	if (status)
		goto out;
5847
	status = decode_putfh(xdr);
A
Andy Adamson 已提交
5848 5849
	if (status)
		goto out;
5850
	status = decode_open(xdr, res);
A
Andy Adamson 已提交
5851 5852
	if (status)
		goto out;
5853
	decode_getfattr(xdr, res->f_attr, res->server,
5854
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5855
out:
A
Andy Adamson 已提交
5856
	return status;
L
Linus Torvalds 已提交
5857 5858 5859 5860 5861
}

/*
 * Decode SETATTR response
 */
5862 5863 5864
static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp,
				struct xdr_stream *xdr,
				struct nfs_setattrres *res)
L
Linus Torvalds 已提交
5865
{
A
Andy Adamson 已提交
5866 5867 5868
	struct compound_hdr hdr;
	int status;

5869
	status = decode_compound_hdr(xdr, &hdr);
5870 5871
	if (status)
		goto out;
5872
	status = decode_sequence(xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
5873 5874
	if (status)
		goto out;
5875
	status = decode_putfh(xdr);
A
Andy Adamson 已提交
5876 5877
	if (status)
		goto out;
5878
	status = decode_setattr(xdr);
A
Andy Adamson 已提交
5879 5880
	if (status)
		goto out;
5881
	decode_getfattr(xdr, res->fattr, res->server,
5882
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5883
out:
A
Andy Adamson 已提交
5884
	return status;
L
Linus Torvalds 已提交
5885 5886 5887 5888 5889
}

/*
 * Decode LOCK response
 */
5890 5891
static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			     struct nfs_lock_res *res)
L
Linus Torvalds 已提交
5892 5893 5894 5895
{
	struct compound_hdr hdr;
	int status;

5896
	status = decode_compound_hdr(xdr, &hdr);
5897 5898
	if (status)
		goto out;
5899
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5900 5901
	if (status)
		goto out;
5902
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
5903 5904
	if (status)
		goto out;
5905
	status = decode_lock(xdr, res);
L
Linus Torvalds 已提交
5906 5907 5908 5909 5910 5911 5912
out:
	return status;
}

/*
 * Decode LOCKT response
 */
5913 5914
static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			      struct nfs_lockt_res *res)
L
Linus Torvalds 已提交
5915 5916 5917 5918
{
	struct compound_hdr hdr;
	int status;

5919
	status = decode_compound_hdr(xdr, &hdr);
5920 5921
	if (status)
		goto out;
5922
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5923 5924
	if (status)
		goto out;
5925
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
5926 5927
	if (status)
		goto out;
5928
	status = decode_lockt(xdr, res);
L
Linus Torvalds 已提交
5929 5930 5931 5932 5933 5934 5935
out:
	return status;
}

/*
 * Decode LOCKU response
 */
5936 5937
static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			      struct nfs_locku_res *res)
L
Linus Torvalds 已提交
5938 5939 5940 5941
{
	struct compound_hdr hdr;
	int status;

5942
	status = decode_compound_hdr(xdr, &hdr);
5943 5944
	if (status)
		goto out;
5945
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5946 5947
	if (status)
		goto out;
5948
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
5949 5950
	if (status)
		goto out;
5951
	status = decode_locku(xdr, res);
L
Linus Torvalds 已提交
5952 5953 5954 5955
out:
	return status;
}

5956 5957
static int nfs4_xdr_dec_release_lockowner(struct rpc_rqst *rqstp,
					  struct xdr_stream *xdr, void *dummy)
5958 5959 5960 5961
{
	struct compound_hdr hdr;
	int status;

5962
	status = decode_compound_hdr(xdr, &hdr);
5963
	if (!status)
5964
		status = decode_release_lockowner(xdr);
5965 5966 5967
	return status;
}

L
Linus Torvalds 已提交
5968 5969 5970
/*
 * Decode READLINK response
 */
5971 5972
static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp,
				 struct xdr_stream *xdr,
B
Benny Halevy 已提交
5973
				 struct nfs4_readlink_res *res)
L
Linus Torvalds 已提交
5974 5975 5976 5977
{
	struct compound_hdr hdr;
	int status;

5978
	status = decode_compound_hdr(xdr, &hdr);
5979 5980
	if (status)
		goto out;
5981
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5982 5983
	if (status)
		goto out;
5984
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
5985 5986
	if (status)
		goto out;
5987
	status = decode_readlink(xdr, rqstp);
L
Linus Torvalds 已提交
5988 5989 5990 5991 5992 5993 5994
out:
	return status;
}

/*
 * Decode READDIR response
 */
5995 5996
static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
				struct nfs4_readdir_res *res)
L
Linus Torvalds 已提交
5997 5998 5999 6000
{
	struct compound_hdr hdr;
	int status;

6001
	status = decode_compound_hdr(xdr, &hdr);
6002 6003
	if (status)
		goto out;
6004
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
6005 6006
	if (status)
		goto out;
6007
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6008 6009
	if (status)
		goto out;
6010
	status = decode_readdir(xdr, rqstp, res);
L
Linus Torvalds 已提交
6011 6012 6013 6014 6015 6016 6017
out:
	return status;
}

/*
 * Decode Read response
 */
6018 6019
static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			     struct nfs_readres *res)
L
Linus Torvalds 已提交
6020 6021 6022 6023
{
	struct compound_hdr hdr;
	int status;

6024
	status = decode_compound_hdr(xdr, &hdr);
6025 6026
	if (status)
		goto out;
6027
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
6028 6029
	if (status)
		goto out;
6030
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6031 6032
	if (status)
		goto out;
6033
	status = decode_read(xdr, rqstp, res);
L
Linus Torvalds 已提交
6034 6035 6036 6037 6038 6039 6040 6041 6042
	if (!status)
		status = res->count;
out:
	return status;
}

/*
 * Decode WRITE response
 */
6043 6044
static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			      struct nfs_writeres *res)
L
Linus Torvalds 已提交
6045 6046 6047 6048
{
	struct compound_hdr hdr;
	int status;

6049
	status = decode_compound_hdr(xdr, &hdr);
6050 6051
	if (status)
		goto out;
6052
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
6053 6054
	if (status)
		goto out;
6055
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6056 6057
	if (status)
		goto out;
6058
	status = decode_write(xdr, res);
6059 6060
	if (status)
		goto out;
6061 6062 6063
	if (res->fattr)
		decode_getfattr(xdr, res->fattr, res->server,
				!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
6064 6065 6066 6067 6068 6069 6070 6071 6072
	if (!status)
		status = res->count;
out:
	return status;
}

/*
 * Decode COMMIT response
 */
6073 6074
static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			       struct nfs_writeres *res)
L
Linus Torvalds 已提交
6075 6076 6077 6078
{
	struct compound_hdr hdr;
	int status;

6079
	status = decode_compound_hdr(xdr, &hdr);
6080 6081
	if (status)
		goto out;
6082
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
6083 6084
	if (status)
		goto out;
6085
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6086 6087
	if (status)
		goto out;
6088
	status = decode_commit(xdr, res);
6089 6090
	if (status)
		goto out;
6091 6092 6093
	if (res->fattr)
		decode_getfattr(xdr, res->fattr, res->server,
				!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
6094 6095 6096 6097 6098
out:
	return status;
}

/*
6099
 * Decode FSINFO response
L
Linus Torvalds 已提交
6100
 */
6101
static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, struct xdr_stream *xdr,
B
Benny Halevy 已提交
6102
			       struct nfs4_fsinfo_res *res)
L
Linus Torvalds 已提交
6103 6104 6105 6106
{
	struct compound_hdr hdr;
	int status;

6107
	status = decode_compound_hdr(xdr, &hdr);
6108
	if (!status)
6109
		status = decode_sequence(xdr, &res->seq_res, req);
L
Linus Torvalds 已提交
6110
	if (!status)
6111
		status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6112
	if (!status)
6113
		status = decode_fsinfo(xdr, res->fsinfo);
L
Linus Torvalds 已提交
6114 6115 6116 6117
	return status;
}

/*
6118
 * Decode PATHCONF response
L
Linus Torvalds 已提交
6119
 */
6120
static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, struct xdr_stream *xdr,
B
Benny Halevy 已提交
6121
				 struct nfs4_pathconf_res *res)
L
Linus Torvalds 已提交
6122 6123 6124 6125
{
	struct compound_hdr hdr;
	int status;

6126
	status = decode_compound_hdr(xdr, &hdr);
6127
	if (!status)
6128
		status = decode_sequence(xdr, &res->seq_res, req);
L
Linus Torvalds 已提交
6129
	if (!status)
6130
		status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6131
	if (!status)
6132
		status = decode_pathconf(xdr, res->pathconf);
L
Linus Torvalds 已提交
6133 6134 6135 6136
	return status;
}

/*
6137
 * Decode STATFS response
L
Linus Torvalds 已提交
6138
 */
6139
static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, struct xdr_stream *xdr,
B
Benny Halevy 已提交
6140
			       struct nfs4_statfs_res *res)
L
Linus Torvalds 已提交
6141 6142 6143 6144
{
	struct compound_hdr hdr;
	int status;

6145
	status = decode_compound_hdr(xdr, &hdr);
6146
	if (!status)
6147
		status = decode_sequence(xdr, &res->seq_res, req);
L
Linus Torvalds 已提交
6148
	if (!status)
6149
		status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6150
	if (!status)
6151
		status = decode_statfs(xdr, res->fsstat);
L
Linus Torvalds 已提交
6152 6153 6154 6155
	return status;
}

/*
6156
 * Decode GETATTR_BITMAP response
L
Linus Torvalds 已提交
6157
 */
6158 6159 6160
static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req,
				    struct xdr_stream *xdr,
				    struct nfs4_server_caps_res *res)
L
Linus Torvalds 已提交
6161 6162 6163 6164
{
	struct compound_hdr hdr;
	int status;

6165
	status = decode_compound_hdr(xdr, &hdr);
6166 6167
	if (status)
		goto out;
6168
	status = decode_sequence(xdr, &res->seq_res, req);
6169
	if (status)
L
Linus Torvalds 已提交
6170
		goto out;
6171 6172
	status = decode_putfh(xdr);
	if (status)
L
Linus Torvalds 已提交
6173
		goto out;
6174
	status = decode_server_caps(xdr, res);
L
Linus Torvalds 已提交
6175 6176 6177 6178 6179 6180 6181
out:
	return status;
}

/*
 * Decode RENEW response
 */
6182 6183
static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			      void *__unused)
L
Linus Torvalds 已提交
6184 6185 6186 6187
{
	struct compound_hdr hdr;
	int status;

6188
	status = decode_compound_hdr(xdr, &hdr);
L
Linus Torvalds 已提交
6189
	if (!status)
6190
		status = decode_renew(xdr);
L
Linus Torvalds 已提交
6191 6192 6193 6194
	return status;
}

/*
6195
 * Decode SETCLIENTID response
L
Linus Torvalds 已提交
6196
 */
6197 6198 6199
static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req,
				    struct xdr_stream *xdr,
				    struct nfs4_setclientid_res *res)
L
Linus Torvalds 已提交
6200 6201 6202 6203
{
	struct compound_hdr hdr;
	int status;

6204
	status = decode_compound_hdr(xdr, &hdr);
L
Linus Torvalds 已提交
6205
	if (!status)
6206
		status = decode_setclientid(xdr, res);
L
Linus Torvalds 已提交
6207 6208 6209 6210
	return status;
}

/*
6211
 * Decode SETCLIENTID_CONFIRM response
L
Linus Torvalds 已提交
6212
 */
6213 6214 6215
static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
					    struct xdr_stream *xdr,
					    struct nfs_fsinfo *fsinfo)
L
Linus Torvalds 已提交
6216 6217 6218 6219
{
	struct compound_hdr hdr;
	int status;

6220
	status = decode_compound_hdr(xdr, &hdr);
L
Linus Torvalds 已提交
6221
	if (!status)
6222
		status = decode_setclientid_confirm(xdr);
L
Linus Torvalds 已提交
6223
	if (!status)
6224
		status = decode_putrootfh(xdr);
L
Linus Torvalds 已提交
6225
	if (!status)
6226
		status = decode_fsinfo(xdr, fsinfo);
L
Linus Torvalds 已提交
6227 6228 6229 6230
	return status;
}

/*
6231
 * Decode DELEGRETURN response
L
Linus Torvalds 已提交
6232
 */
6233 6234 6235
static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
				    struct xdr_stream *xdr,
				    struct nfs4_delegreturnres *res)
L
Linus Torvalds 已提交
6236 6237 6238 6239
{
	struct compound_hdr hdr;
	int status;

6240
	status = decode_compound_hdr(xdr, &hdr);
6241 6242
	if (status)
		goto out;
6243
	status = decode_sequence(xdr, &res->seq_res, rqstp);
6244
	if (status)
6245
		goto out;
6246
	status = decode_putfh(xdr);
6247 6248
	if (status != 0)
		goto out;
6249
	status = decode_delegreturn(xdr);
6250 6251
	if (status != 0)
		goto out;
6252
	decode_getfattr(xdr, res->fattr, res->server,
6253
			!RPC_IS_ASYNC(rqstp->rq_task));
6254
out:
L
Linus Torvalds 已提交
6255 6256 6257
	return status;
}

6258
/*
6259
 * Decode FS_LOCATIONS response
6260
 */
6261 6262
static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
				     struct xdr_stream *xdr,
B
Benny Halevy 已提交
6263
				     struct nfs4_fs_locations_res *res)
6264 6265 6266 6267
{
	struct compound_hdr hdr;
	int status;

6268
	status = decode_compound_hdr(xdr, &hdr);
6269 6270
	if (status)
		goto out;
6271
	status = decode_sequence(xdr, &res->seq_res, req);
6272
	if (status)
6273
		goto out;
6274 6275
	status = decode_putfh(xdr);
	if (status)
6276
		goto out;
6277 6278
	status = decode_lookup(xdr);
	if (status)
6279
		goto out;
6280 6281
	xdr_enter_page(xdr, PAGE_SIZE);
	status = decode_getfattr(xdr, &res->fs_locations->fattr,
6282 6283
				 res->fs_locations->server,
				 !RPC_IS_ASYNC(req->rq_task));
6284 6285 6286 6287
out:
	return status;
}

B
Bryan Schumaker 已提交
6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313
/*
 * Decode SECINFO response
 */
static int nfs4_xdr_dec_secinfo(struct rpc_rqst *rqstp,
				struct xdr_stream *xdr,
				struct nfs4_secinfo_res *res)
{
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(xdr, &res->seq_res, rqstp);
	if (status)
		goto out;
	status = decode_putfh(xdr);
	if (status)
		goto out;
	status = decode_secinfo(xdr, res);
	if (status)
		goto out;
out:
	return status;
}

B
Benny Halevy 已提交
6314 6315
#if defined(CONFIG_NFS_V4_1)
/*
6316
 * Decode EXCHANGE_ID response
B
Benny Halevy 已提交
6317
 */
6318 6319
static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp,
				    struct xdr_stream *xdr,
B
Benny Halevy 已提交
6320 6321 6322 6323 6324
				    void *res)
{
	struct compound_hdr hdr;
	int status;

6325
	status = decode_compound_hdr(xdr, &hdr);
B
Benny Halevy 已提交
6326
	if (!status)
6327
		status = decode_exchange_id(xdr, res);
B
Benny Halevy 已提交
6328 6329
	return status;
}
A
Andy Adamson 已提交
6330

A
Andy Adamson 已提交
6331
/*
6332
 * Decode CREATE_SESSION response
A
Andy Adamson 已提交
6333
 */
6334 6335
static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp,
				       struct xdr_stream *xdr,
A
Andy Adamson 已提交
6336 6337 6338 6339 6340
				       struct nfs41_create_session_res *res)
{
	struct compound_hdr hdr;
	int status;

6341
	status = decode_compound_hdr(xdr, &hdr);
A
Andy Adamson 已提交
6342
	if (!status)
6343
		status = decode_create_session(xdr, res);
A
Andy Adamson 已提交
6344 6345 6346
	return status;
}

A
Andy Adamson 已提交
6347
/*
6348
 * Decode DESTROY_SESSION response
A
Andy Adamson 已提交
6349
 */
6350 6351 6352
static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp,
					struct xdr_stream *xdr,
					void *res)
A
Andy Adamson 已提交
6353 6354 6355 6356
{
	struct compound_hdr hdr;
	int status;

6357
	status = decode_compound_hdr(xdr, &hdr);
A
Andy Adamson 已提交
6358
	if (!status)
6359
		status = decode_destroy_session(xdr, res);
A
Andy Adamson 已提交
6360 6361 6362
	return status;
}

A
Andy Adamson 已提交
6363
/*
6364
 * Decode SEQUENCE response
A
Andy Adamson 已提交
6365
 */
6366 6367
static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp,
				 struct xdr_stream *xdr,
A
Andy Adamson 已提交
6368 6369 6370 6371 6372
				 struct nfs4_sequence_res *res)
{
	struct compound_hdr hdr;
	int status;

6373
	status = decode_compound_hdr(xdr, &hdr);
A
Andy Adamson 已提交
6374
	if (!status)
6375
		status = decode_sequence(xdr, res, rqstp);
A
Andy Adamson 已提交
6376 6377 6378
	return status;
}

A
Andy Adamson 已提交
6379
/*
6380
 * Decode GET_LEASE_TIME response
A
Andy Adamson 已提交
6381
 */
6382 6383
static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp,
				       struct xdr_stream *xdr,
A
Andy Adamson 已提交
6384 6385 6386 6387 6388
				       struct nfs4_get_lease_time_res *res)
{
	struct compound_hdr hdr;
	int status;

6389
	status = decode_compound_hdr(xdr, &hdr);
A
Andy Adamson 已提交
6390
	if (!status)
6391
		status = decode_sequence(xdr, &res->lr_seq_res, rqstp);
A
Andy Adamson 已提交
6392
	if (!status)
6393
		status = decode_putrootfh(xdr);
A
Andy Adamson 已提交
6394
	if (!status)
6395
		status = decode_fsinfo(xdr, res->lr_fsinfo);
A
Andy Adamson 已提交
6396 6397
	return status;
}
6398 6399 6400 6401

/*
 * Decode RECLAIM_COMPLETE response
 */
6402 6403
static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp,
					 struct xdr_stream *xdr,
6404 6405 6406 6407 6408
					 struct nfs41_reclaim_complete_res *res)
{
	struct compound_hdr hdr;
	int status;

6409
	status = decode_compound_hdr(xdr, &hdr);
6410
	if (!status)
6411
		status = decode_sequence(xdr, &res->seq_res, rqstp);
6412
	if (!status)
6413
		status = decode_reclaim_complete(xdr, (void *)NULL);
6414 6415
	return status;
}
6416 6417 6418 6419

/*
 * Decode GETDEVINFO response
 */
6420 6421
static int nfs4_xdr_dec_getdeviceinfo(struct rpc_rqst *rqstp,
				      struct xdr_stream *xdr,
6422 6423 6424 6425 6426
				      struct nfs4_getdeviceinfo_res *res)
{
	struct compound_hdr hdr;
	int status;

6427
	status = decode_compound_hdr(xdr, &hdr);
6428 6429
	if (status != 0)
		goto out;
6430
	status = decode_sequence(xdr, &res->seq_res, rqstp);
6431 6432
	if (status != 0)
		goto out;
6433
	status = decode_getdeviceinfo(xdr, res->pdev);
6434 6435 6436 6437 6438 6439 6440
out:
	return status;
}

/*
 * Decode LAYOUTGET response
 */
6441 6442
static int nfs4_xdr_dec_layoutget(struct rpc_rqst *rqstp,
				  struct xdr_stream *xdr,
6443 6444 6445 6446 6447
				  struct nfs4_layoutget_res *res)
{
	struct compound_hdr hdr;
	int status;

6448
	status = decode_compound_hdr(xdr, &hdr);
6449 6450
	if (status)
		goto out;
6451
	status = decode_sequence(xdr, &res->seq_res, rqstp);
6452 6453
	if (status)
		goto out;
6454
	status = decode_putfh(xdr);
6455 6456
	if (status)
		goto out;
6457
	status = decode_layoutget(xdr, rqstp, res);
6458 6459 6460
out:
	return status;
}
A
Andy Adamson 已提交
6461

B
Benny Halevy 已提交
6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485
/*
 * Decode LAYOUTRETURN response
 */
static int nfs4_xdr_dec_layoutreturn(struct rpc_rqst *rqstp,
				     struct xdr_stream *xdr,
				     struct nfs4_layoutreturn_res *res)
{
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(xdr, &res->seq_res, rqstp);
	if (status)
		goto out;
	status = decode_putfh(xdr);
	if (status)
		goto out;
	status = decode_layoutreturn(xdr, res);
out:
	return status;
}

A
Andy Adamson 已提交
6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512
/*
 * Decode LAYOUTCOMMIT response
 */
static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
				     struct xdr_stream *xdr,
				     struct nfs4_layoutcommit_res *res)
{
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(xdr, &res->seq_res, rqstp);
	if (status)
		goto out;
	status = decode_putfh(xdr);
	if (status)
		goto out;
	status = decode_layoutcommit(xdr, rqstp, res);
	if (status)
		goto out;
	decode_getfattr(xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
out:
	return status;
}
6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536

/*
 * Decode SECINFO_NO_NAME response
 */
static int nfs4_xdr_dec_secinfo_no_name(struct rpc_rqst *rqstp,
					struct xdr_stream *xdr,
					struct nfs4_secinfo_res *res)
{
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(xdr, &res->seq_res, rqstp);
	if (status)
		goto out;
	status = decode_putrootfh(xdr);
	if (status)
		goto out;
	status = decode_secinfo(xdr, res);
out:
	return status;
}
B
Benny Halevy 已提交
6537 6538
#endif /* CONFIG_NFS_V4_1 */

6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554
/**
 * nfs4_decode_dirent - Decode a single NFSv4 directory entry stored in
 *                      the local page cache.
 * @xdr: XDR stream where entry resides
 * @entry: buffer to fill in with entry data
 * @plus: boolean indicating whether this should be a readdirplus entry
 *
 * Returns zero if successful, otherwise a negative errno value is
 * returned.
 *
 * This function is not invoked during READDIR reply decoding, but
 * rather whenever an application invokes the getdents(2) system call
 * on a directory already in our cache.
 */
int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
		       int plus)
L
Linus Torvalds 已提交
6555 6556 6557
{
	uint32_t bitmap[2] = {0};
	uint32_t len;
6558 6559 6560
	__be32 *p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
6561
	if (*p == xdr_zero) {
6562 6563 6564
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
6565
		if (*p == xdr_zero)
6566
			return -EAGAIN;
L
Linus Torvalds 已提交
6567
		entry->eof = 1;
6568
		return -EBADCOOKIE;
L
Linus Torvalds 已提交
6569 6570
	}

6571 6572 6573
	p = xdr_inline_decode(xdr, 12);
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
6574 6575
	entry->prev_cookie = entry->cookie;
	p = xdr_decode_hyper(p, &entry->cookie);
6576
	entry->len = be32_to_cpup(p);
6577

6578
	p = xdr_inline_decode(xdr, entry->len);
6579 6580
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
6581 6582 6583 6584 6585 6586 6587 6588
	entry->name = (const char *) p;

	/*
	 * In case the server doesn't return an inode number,
	 * we fake one here.  (We don't use inode number 0,
	 * since glibc seems to choke on it...)
	 */
	entry->ino = 1;
6589
	entry->fattr->valid = 0;
L
Linus Torvalds 已提交
6590

6591 6592 6593 6594 6595 6596
	if (decode_attr_bitmap(xdr, bitmap) < 0)
		goto out_overflow;

	if (decode_attr_length(xdr, &len, &p) < 0)
		goto out_overflow;

6597 6598
	if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
					entry->server, 1) < 0)
6599
		goto out_overflow;
6600 6601 6602
	if (entry->fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID)
		entry->ino = entry->fattr->mounted_on_fileid;
	else if (entry->fattr->valid & NFS_ATTR_FATTR_FILEID)
6603 6604
		entry->ino = entry->fattr->fileid;

6605 6606 6607 6608
	entry->d_type = DT_UNKNOWN;
	if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE)
		entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);

6609
	return 0;
6610 6611 6612

out_overflow:
	print_overflow_msg(__func__, xdr);
6613
	return -EAGAIN;
L
Linus Torvalds 已提交
6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624
}

/*
 * We need to translate between nfs status return values and
 * the local errno values which may not be the same.
 */
static struct {
	int stat;
	int errno;
} nfs_errtbl[] = {
	{ NFS4_OK,		0		},
6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646
	{ NFS4ERR_PERM,		-EPERM		},
	{ NFS4ERR_NOENT,	-ENOENT		},
	{ NFS4ERR_IO,		-errno_NFSERR_IO},
	{ NFS4ERR_NXIO,		-ENXIO		},
	{ NFS4ERR_ACCESS,	-EACCES		},
	{ NFS4ERR_EXIST,	-EEXIST		},
	{ NFS4ERR_XDEV,		-EXDEV		},
	{ NFS4ERR_NOTDIR,	-ENOTDIR	},
	{ NFS4ERR_ISDIR,	-EISDIR		},
	{ NFS4ERR_INVAL,	-EINVAL		},
	{ NFS4ERR_FBIG,		-EFBIG		},
	{ NFS4ERR_NOSPC,	-ENOSPC		},
	{ NFS4ERR_ROFS,		-EROFS		},
	{ NFS4ERR_MLINK,	-EMLINK		},
	{ NFS4ERR_NAMETOOLONG,	-ENAMETOOLONG	},
	{ NFS4ERR_NOTEMPTY,	-ENOTEMPTY	},
	{ NFS4ERR_DQUOT,	-EDQUOT		},
	{ NFS4ERR_STALE,	-ESTALE		},
	{ NFS4ERR_BADHANDLE,	-EBADHANDLE	},
	{ NFS4ERR_BAD_COOKIE,	-EBADCOOKIE	},
	{ NFS4ERR_NOTSUPP,	-ENOTSUPP	},
	{ NFS4ERR_TOOSMALL,	-ETOOSMALL	},
6647
	{ NFS4ERR_SERVERFAULT,	-EREMOTEIO	},
6648 6649 6650 6651 6652 6653
	{ NFS4ERR_BADTYPE,	-EBADTYPE	},
	{ NFS4ERR_LOCKED,	-EAGAIN		},
	{ NFS4ERR_SYMLINK,	-ELOOP		},
	{ NFS4ERR_OP_ILLEGAL,	-EOPNOTSUPP	},
	{ NFS4ERR_DEADLOCK,	-EDEADLK	},
	{ -1,			-EIO		}
L
Linus Torvalds 已提交
6654 6655 6656 6657 6658 6659 6660
};

/*
 * Convert an NFS error code to a local one.
 * This one is used jointly by NFSv2 and NFSv3.
 */
static int
6661
nfs4_stat_to_errno(int stat)
L
Linus Torvalds 已提交
6662 6663 6664 6665 6666 6667 6668 6669
{
	int i;
	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
		if (nfs_errtbl[i].stat == stat)
			return nfs_errtbl[i].errno;
	}
	if (stat <= 10000 || stat > 10100) {
		/* The server is looney tunes. */
6670
		return -EREMOTEIO;
L
Linus Torvalds 已提交
6671 6672 6673 6674 6675 6676
	}
	/* If we cannot translate the error, the recovery routines should
	 * handle it.
	 * Note: remaining NFSv4 error codes have values > 10000, so should
	 * not conflict with native Linux error codes.
	 */
6677
	return -stat;
L
Linus Torvalds 已提交
6678 6679 6680 6681 6682
}

#define PROC(proc, argtype, restype)				\
[NFSPROC4_CLNT_##proc] = {					\
	.p_proc   = NFSPROC4_COMPOUND,				\
6683
	.p_encode = (kxdreproc_t)nfs4_xdr_##argtype,		\
6684
	.p_decode = (kxdrdproc_t)nfs4_xdr_##restype,		\
6685 6686
	.p_arglen = NFS4_##argtype##_sz,			\
	.p_replen = NFS4_##restype##_sz,			\
6687 6688
	.p_statidx = NFSPROC4_CLNT_##proc,			\
	.p_name   = #proc,					\
A
Andy Adamson 已提交
6689
}
L
Linus Torvalds 已提交
6690 6691

struct rpc_procinfo	nfs4_procedures[] = {
6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726
	PROC(READ,		enc_read,		dec_read),
	PROC(WRITE,		enc_write,		dec_write),
	PROC(COMMIT,		enc_commit,		dec_commit),
	PROC(OPEN,		enc_open,		dec_open),
	PROC(OPEN_CONFIRM,	enc_open_confirm,	dec_open_confirm),
	PROC(OPEN_NOATTR,	enc_open_noattr,	dec_open_noattr),
	PROC(OPEN_DOWNGRADE,	enc_open_downgrade,	dec_open_downgrade),
	PROC(CLOSE,		enc_close,		dec_close),
	PROC(SETATTR,		enc_setattr,		dec_setattr),
	PROC(FSINFO,		enc_fsinfo,		dec_fsinfo),
	PROC(RENEW,		enc_renew,		dec_renew),
	PROC(SETCLIENTID,	enc_setclientid,	dec_setclientid),
	PROC(SETCLIENTID_CONFIRM, enc_setclientid_confirm, dec_setclientid_confirm),
	PROC(LOCK,		enc_lock,		dec_lock),
	PROC(LOCKT,		enc_lockt,		dec_lockt),
	PROC(LOCKU,		enc_locku,		dec_locku),
	PROC(ACCESS,		enc_access,		dec_access),
	PROC(GETATTR,		enc_getattr,		dec_getattr),
	PROC(LOOKUP,		enc_lookup,		dec_lookup),
	PROC(LOOKUP_ROOT,	enc_lookup_root,	dec_lookup_root),
	PROC(REMOVE,		enc_remove,		dec_remove),
	PROC(RENAME,		enc_rename,		dec_rename),
	PROC(LINK,		enc_link,		dec_link),
	PROC(SYMLINK,		enc_symlink,		dec_symlink),
	PROC(CREATE,		enc_create,		dec_create),
	PROC(PATHCONF,		enc_pathconf,		dec_pathconf),
	PROC(STATFS,		enc_statfs,		dec_statfs),
	PROC(READLINK,		enc_readlink,		dec_readlink),
	PROC(READDIR,		enc_readdir,		dec_readdir),
	PROC(SERVER_CAPS,	enc_server_caps,	dec_server_caps),
	PROC(DELEGRETURN,	enc_delegreturn,	dec_delegreturn),
	PROC(GETACL,		enc_getacl,		dec_getacl),
	PROC(SETACL,		enc_setacl,		dec_setacl),
	PROC(FS_LOCATIONS,	enc_fs_locations,	dec_fs_locations),
	PROC(RELEASE_LOCKOWNER,	enc_release_lockowner,	dec_release_lockowner),
B
Bryan Schumaker 已提交
6727
	PROC(SECINFO,		enc_secinfo,		dec_secinfo),
B
Benny Halevy 已提交
6728
#if defined(CONFIG_NFS_V4_1)
6729 6730 6731 6732 6733 6734 6735 6736
	PROC(EXCHANGE_ID,	enc_exchange_id,	dec_exchange_id),
	PROC(CREATE_SESSION,	enc_create_session,	dec_create_session),
	PROC(DESTROY_SESSION,	enc_destroy_session,	dec_destroy_session),
	PROC(SEQUENCE,		enc_sequence,		dec_sequence),
	PROC(GET_LEASE_TIME,	enc_get_lease_time,	dec_get_lease_time),
	PROC(RECLAIM_COMPLETE,	enc_reclaim_complete,	dec_reclaim_complete),
	PROC(GETDEVICEINFO,	enc_getdeviceinfo,	dec_getdeviceinfo),
	PROC(LAYOUTGET,		enc_layoutget,		dec_layoutget),
A
Andy Adamson 已提交
6737
	PROC(LAYOUTCOMMIT,	enc_layoutcommit,	dec_layoutcommit),
B
Benny Halevy 已提交
6738
	PROC(LAYOUTRETURN,	enc_layoutreturn,	dec_layoutreturn),
6739
	PROC(SECINFO_NO_NAME,	enc_secinfo_no_name,	dec_secinfo_no_name),
B
Benny Halevy 已提交
6740
#endif /* CONFIG_NFS_V4_1 */
L
Linus Torvalds 已提交
6741 6742 6743 6744
};

struct rpc_version		nfs_version4 = {
	.number			= 4,
6745
	.nrprocs		= ARRAY_SIZE(nfs4_procedures),
L
Linus Torvalds 已提交
6746 6747 6748 6749 6750 6751 6752 6753
	.procs			= nfs4_procedures
};

/*
 * Local variables:
 *  c-basic-offset: 8
 * End:
 */