nfs4xdr.c 197.8 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
 *  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>
47 48
#include <linux/module.h>
#include <linux/utsname.h>
L
Linus Torvalds 已提交
49
#include <linux/sunrpc/clnt.h>
50
#include <linux/sunrpc/msg_prot.h>
B
Bryan Schumaker 已提交
51
#include <linux/sunrpc/gss_api.h>
L
Linus Torvalds 已提交
52 53 54
#include <linux/nfs.h>
#include <linux/nfs4.h>
#include <linux/nfs_fs.h>
55
#include <linux/fs_struct.h>
56

57
#include "nfs4_fs.h"
58
#include "internal.h"
59
#include "nfs4idmap.h"
60
#include "nfs4session.h"
61
#include "pnfs.h"
62
#include "netns.h"
L
Linus Torvalds 已提交
63 64 65 66 67 68

#define NFSDBG_FACILITY		NFSDBG_XDR

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

69
static int nfs4_stat_to_errno(int);
L
Linus Torvalds 已提交
70 71 72 73 74 75 76 77

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

78
/* lock,open owner id:
79
 * we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT  >> 2)
L
Linus Torvalds 已提交
80
 */
81
#define open_owner_id_maxsz	(1 + 2 + 1 + 1 + 2)
82
#define lock_owner_id_maxsz	(1 + 1 + 4)
T
Trond Myklebust 已提交
83
#define decode_lockowner_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
L
Linus Torvalds 已提交
84 85 86 87
#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 已提交
88 89 90 91
#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 已提交
92 93 94 95 96 97 98 99
#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))
100
#define nfs4_fattr_bitmap_maxsz 4
101
#define encode_getattr_maxsz    (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
L
Linus Torvalds 已提交
102 103
#define nfs4_name_maxsz		(1 + ((3 + NFS4_MAXNAMLEN) >> 2))
#define nfs4_path_maxsz		(1 + ((3 + NFS4_MAXPATHLEN) >> 2))
104 105
#define nfs4_owner_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
#define nfs4_group_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
106 107 108 109 110 111
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
/* PI(4 bytes) + LFS(4 bytes) + 1(for null terminator?) + MAXLABELLEN */
#define	nfs4_label_maxsz	(4 + 4 + 1 + XDR_QUADLEN(NFS4_MAXLABELLEN))
#else
#define	nfs4_label_maxsz	0
#endif
112 113
/* We support only one layout type per file system */
#define decode_mdsthreshold_maxsz (1 + 1 + nfs4_fattr_bitmap_maxsz + 1 + 8)
114 115
/* 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 + \
116
				3 + 3 + 3 + nfs4_owner_maxsz + \
117 118
				nfs4_group_maxsz + nfs4_label_maxsz + \
				 decode_mdsthreshold_maxsz))
119 120 121
#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 已提交
122 123 124 125
#define encode_attrs_maxsz	(nfs4_fattr_bitmap_maxsz + \
				 1 + 2 + 1 + \
				nfs4_owner_maxsz + \
				nfs4_group_maxsz + \
126
				nfs4_label_maxsz + \
T
Trond Myklebust 已提交
127
				4 + 4)
L
Linus Torvalds 已提交
128 129
#define encode_savefh_maxsz     (op_encode_hdr_maxsz)
#define decode_savefh_maxsz     (op_decode_hdr_maxsz)
130 131
#define encode_restorefh_maxsz  (op_encode_hdr_maxsz)
#define decode_restorefh_maxsz  (op_decode_hdr_maxsz)
F
Fred Isaman 已提交
132
#define encode_fsinfo_maxsz	(encode_getattr_maxsz)
133 134 135 136 137
/* The 5 accounts for the PNFS attributes, and assumes that at most three
 * layout types will be returned.
 */
#define decode_fsinfo_maxsz	(op_decode_hdr_maxsz + \
				 nfs4_fattr_bitmap_maxsz + 4 + 8 + 5)
L
Linus Torvalds 已提交
138 139 140 141
#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 + \
142
				XDR_QUADLEN(NFS4_VERIFIER_SIZE) + \
143 144
				/* client name */ \
				1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
145
				1 /* sc_prog */ + \
146 147
				1 + XDR_QUADLEN(RPCBIND_MAXNETIDLEN) + \
				1 + XDR_QUADLEN(RPCBIND_MAXUADDRLEN) + \
148
				1) /* sc_cb_ident */
L
Linus Torvalds 已提交
149 150
#define decode_setclientid_maxsz \
				(op_decode_hdr_maxsz + \
151 152 153 154
				2 /* clientid */ + \
				XDR_QUADLEN(NFS4_VERIFIER_SIZE) + \
				1 + XDR_QUADLEN(RPCBIND_MAXNETIDLEN) + \
				1 + XDR_QUADLEN(RPCBIND_MAXUADDRLEN))
L
Linus Torvalds 已提交
155 156 157 158 159
#define encode_setclientid_confirm_maxsz \
				(op_encode_hdr_maxsz + \
				3 + (NFS4_VERIFIER_SIZE >> 2))
#define decode_setclientid_confirm_maxsz \
				(op_decode_hdr_maxsz)
160 161
#define encode_lookup_maxsz	(op_encode_hdr_maxsz + nfs4_name_maxsz)
#define decode_lookup_maxsz	(op_decode_hdr_maxsz)
162 163
#define encode_share_access_maxsz \
				(2)
164
#define encode_createmode_maxsz	(1 + encode_attrs_maxsz + encode_verifier_maxsz)
165 166 167 168 169 170 171 172
#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 已提交
173
#define decode_delegation_maxsz	(1 + decode_stateid_maxsz + 1 + \
174 175 176
				decode_ace_maxsz)
#define decode_change_info_maxsz	(5)
#define decode_open_maxsz	(op_decode_hdr_maxsz + \
T
Trond Myklebust 已提交
177
				decode_stateid_maxsz + \
178 179 180
				decode_change_info_maxsz + 1 + \
				nfs4_fattr_bitmap_maxsz + \
				decode_delegation_maxsz)
T
Trond Myklebust 已提交
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
#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 + \
207 208
				 2 + encode_verifier_maxsz + 5 + \
				nfs4_label_maxsz)
T
Trond Myklebust 已提交
209
#define decode_readdir_maxsz	(op_decode_hdr_maxsz + \
210
				 decode_verifier_maxsz)
T
Trond Myklebust 已提交
211 212 213 214 215 216 217 218 219
#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 已提交
220 221
#define encode_remove_maxsz	(op_encode_hdr_maxsz + \
				nfs4_name_maxsz)
222 223
#define decode_remove_maxsz	(op_decode_hdr_maxsz + \
				 decode_change_info_maxsz)
L
Linus Torvalds 已提交
224 225
#define encode_rename_maxsz	(op_encode_hdr_maxsz + \
				2 * nfs4_name_maxsz)
226 227 228
#define decode_rename_maxsz	(op_decode_hdr_maxsz + \
				 decode_change_info_maxsz + \
				 decode_change_info_maxsz)
L
Linus Torvalds 已提交
229 230
#define encode_link_maxsz	(op_encode_hdr_maxsz + \
				nfs4_name_maxsz)
231
#define decode_link_maxsz	(op_decode_hdr_maxsz + decode_change_info_maxsz)
232
#define encode_lockowner_maxsz	(7)
T
Trond Myklebust 已提交
233 234
#define encode_lock_maxsz	(op_encode_hdr_maxsz + \
				 7 + \
235 236
				 1 + encode_stateid_maxsz + 1 + \
				 encode_lockowner_maxsz)
T
Trond Myklebust 已提交
237 238 239 240
#define decode_lock_denied_maxsz \
				(8 + decode_lockowner_maxsz)
#define decode_lock_maxsz	(op_decode_hdr_maxsz + \
				 decode_lock_denied_maxsz)
241 242
#define encode_lockt_maxsz	(op_encode_hdr_maxsz + 5 + \
				encode_lockowner_maxsz)
T
Trond Myklebust 已提交
243 244 245 246 247 248 249
#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)
250 251 252 253 254
#define encode_release_lockowner_maxsz \
				(op_encode_hdr_maxsz + \
				 encode_lockowner_maxsz)
#define decode_release_lockowner_maxsz \
				(op_decode_hdr_maxsz)
T
Trond Myklebust 已提交
255 256
#define encode_access_maxsz	(op_encode_hdr_maxsz + 1)
#define decode_access_maxsz	(op_decode_hdr_maxsz + 2)
L
Linus Torvalds 已提交
257 258
#define encode_symlink_maxsz	(op_encode_hdr_maxsz + \
				1 + nfs4_name_maxsz + \
259
				1 + \
260
				nfs4_fattr_maxsz)
L
Linus Torvalds 已提交
261 262
#define decode_symlink_maxsz	(op_decode_hdr_maxsz + 8)
#define encode_create_maxsz	(op_encode_hdr_maxsz + \
T
Trond Myklebust 已提交
263 264
				1 + 2 + nfs4_name_maxsz + \
				encode_attrs_maxsz)
265 266 267
#define decode_create_maxsz	(op_decode_hdr_maxsz + \
				decode_change_info_maxsz + \
				nfs4_fattr_bitmap_maxsz)
T
Trond Myklebust 已提交
268 269
#define encode_statfs_maxsz	(encode_getattr_maxsz)
#define decode_statfs_maxsz	(decode_getattr_maxsz)
L
Linus Torvalds 已提交
270 271
#define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4)
#define decode_delegreturn_maxsz (op_decode_hdr_maxsz)
T
Trond Myklebust 已提交
272 273 274 275 276 277
#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)
278 279 280 281
#define encode_fs_locations_maxsz \
				(encode_getattr_maxsz)
#define decode_fs_locations_maxsz \
				(0)
B
Bryan Schumaker 已提交
282
#define encode_secinfo_maxsz	(op_encode_hdr_maxsz + nfs4_name_maxsz)
B
Bryan Schumaker 已提交
283
#define decode_secinfo_maxsz	(op_decode_hdr_maxsz + 1 + ((NFS_MAX_SECFLAVORS * (16 + GSS_OID_MAX_LEN)) / 4))
284 285

#if defined(CONFIG_NFS_V4_1)
A
Andy Adamson 已提交
286
#define NFS4_MAX_MACHINE_NAME_LEN (64)
287 288
#define IMPL_NAME_LIMIT (sizeof(utsname()->sysname) + sizeof(utsname()->release) + \
			 sizeof(utsname()->version) + sizeof(utsname()->machine) + 8)
A
Andy Adamson 已提交
289

B
Benny Halevy 已提交
290 291 292
#define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \
				encode_verifier_maxsz + \
				1 /* co_ownerid.len */ + \
293 294
				/* eia_clientowner */ \
				1 + XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
B
Benny Halevy 已提交
295 296
				1 /* flags */ + \
				1 /* spa_how */ + \
297 298 299
				/* max is SP4_MACH_CRED (for now) */ + \
				1 + NFS4_OP_MAP_NUM_WORDS + \
				1 + NFS4_OP_MAP_NUM_WORDS + \
300 301 302 303
				1 /* implementation id array of size 1 */ + \
				1 /* nii_domain */ + \
				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
				1 /* nii_name */ + \
304
				XDR_QUADLEN(IMPL_NAME_LIMIT) + \
305
				3 /* nii_date */)
B
Benny Halevy 已提交
306 307 308 309 310
#define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \
				2 /* eir_clientid */ + \
				1 /* eir_sequenceid */ + \
				1 /* eir_flags */ + \
				1 /* spr_how */ + \
311 312 313
				  /* max is SP4_MACH_CRED (for now) */ + \
				1 + NFS4_OP_MAP_NUM_WORDS + \
				1 + NFS4_OP_MAP_NUM_WORDS + \
B
Benny Halevy 已提交
314 315 316 317 318 319
				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 */ + \
320 321 322 323 324
				1 /* nii_domain */ + \
				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
				1 /* nii_name */ + \
				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
				3 /* nii_date */)
A
Andy Adamson 已提交
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
#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)
350 351 352 353 354 355 356 357 358 359
#define encode_bind_conn_to_session_maxsz  (op_encode_hdr_maxsz + \
				     /* bctsa_sessid */ \
				     XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
				     1 /* bctsa_dir */ + \
				     1 /* bctsa_use_conn_in_rdma_mode */)
#define decode_bind_conn_to_session_maxsz  (op_decode_hdr_maxsz +	\
				     /* bctsr_sessid */ \
				     XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
				     1 /* bctsr_dir */ + \
				     1 /* bctsr_use_conn_in_rdma_mode */)
A
Andy Adamson 已提交
360 361
#define encode_destroy_session_maxsz    (op_encode_hdr_maxsz + 4)
#define decode_destroy_session_maxsz    (op_decode_hdr_maxsz)
T
Trond Myklebust 已提交
362 363
#define encode_destroy_clientid_maxsz   (op_encode_hdr_maxsz + 2)
#define decode_destroy_clientid_maxsz   (op_decode_hdr_maxsz)
A
Andy Adamson 已提交
364 365 366 367
#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)
368 369
#define encode_reclaim_complete_maxsz	(op_encode_hdr_maxsz + 4)
#define decode_reclaim_complete_maxsz	(op_decode_hdr_maxsz + 4)
370 371 372 373 374 375 376
#define encode_getdeviceinfo_maxsz (op_encode_hdr_maxsz + \
				XDR_QUADLEN(NFS4_DEVICEID4_SIZE) + \
				1 /* layout type */ + \
				1 /* maxcount */ + \
				1 /* bitmap size */ + \
				1 /* notification bitmap length */ + \
				1 /* notification bitmap, word 0 */)
377 378 379 380 381
#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 */ + \
382
				1 /* notification bitmap, word 0 */)
383 384 385 386 387
#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 已提交
388 389 390 391 392 393 394 395 396
#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 */ + \
397 398 399 400
				1 /* layoutupdate4 opaqueue len */)
				  /* the actual content of layoutupdate4 should
				     be allocated by drivers and spliced in
				     using xdr_write_pages */
A
Andy Adamson 已提交
401
#define decode_layoutcommit_maxsz (op_decode_hdr_maxsz + 3)
B
Benny Halevy 已提交
402 403
#define encode_layoutreturn_maxsz (8 + op_encode_hdr_maxsz + \
				encode_stateid_maxsz + \
404 405
				1 + \
				XDR_QUADLEN(NFS4_OPAQUE_LIMIT))
B
Benny Halevy 已提交
406 407
#define decode_layoutreturn_maxsz (op_decode_hdr_maxsz + \
				1 + decode_stateid_maxsz)
408 409
#define encode_secinfo_no_name_maxsz (op_encode_hdr_maxsz + 1)
#define decode_secinfo_no_name_maxsz decode_secinfo_maxsz
B
Bryan Schumaker 已提交
410 411 412
#define encode_test_stateid_maxsz	(op_encode_hdr_maxsz + 2 + \
					 XDR_QUADLEN(NFS4_STATEID_SIZE))
#define decode_test_stateid_maxsz	(op_decode_hdr_maxsz + 2 + 1)
B
Bryan Schumaker 已提交
413 414
#define encode_free_stateid_maxsz	(op_encode_hdr_maxsz + 1 + \
					 XDR_QUADLEN(NFS4_STATEID_SIZE))
A
Andy Adamson 已提交
415
#define decode_free_stateid_maxsz	(op_decode_hdr_maxsz)
416 417 418
#else /* CONFIG_NFS_V4_1 */
#define encode_sequence_maxsz	0
#define decode_sequence_maxsz	0
419 420
#define encode_layoutreturn_maxsz 0
#define decode_layoutreturn_maxsz 0
421 422
#endif /* CONFIG_NFS_V4_1 */

L
Linus Torvalds 已提交
423 424 425
#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 + \
426
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
427
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
428
				encode_read_maxsz)
L
Linus Torvalds 已提交
429
#define NFS4_dec_read_sz	(compound_decode_hdr_maxsz + \
430
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
431
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
432
				decode_read_maxsz)
L
Linus Torvalds 已提交
433
#define NFS4_enc_readlink_sz	(compound_encode_hdr_maxsz + \
434
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
435
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
436
				encode_readlink_maxsz)
L
Linus Torvalds 已提交
437
#define NFS4_dec_readlink_sz	(compound_decode_hdr_maxsz + \
438
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
439
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
440
				decode_readlink_maxsz)
L
Linus Torvalds 已提交
441
#define NFS4_enc_readdir_sz	(compound_encode_hdr_maxsz + \
442
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
443
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
444
				encode_readdir_maxsz)
L
Linus Torvalds 已提交
445
#define NFS4_dec_readdir_sz	(compound_decode_hdr_maxsz + \
446
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
447
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
448
				decode_readdir_maxsz)
L
Linus Torvalds 已提交
449
#define NFS4_enc_write_sz	(compound_encode_hdr_maxsz + \
450
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
451
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
452
				encode_write_maxsz + \
453
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
454
#define NFS4_dec_write_sz	(compound_decode_hdr_maxsz + \
455
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
456
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
457
				decode_write_maxsz + \
458
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
459
#define NFS4_enc_commit_sz	(compound_encode_hdr_maxsz + \
460
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
461
				encode_putfh_maxsz + \
462
				encode_commit_maxsz)
L
Linus Torvalds 已提交
463
#define NFS4_dec_commit_sz	(compound_decode_hdr_maxsz + \
464
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
465
				decode_putfh_maxsz + \
466
				decode_commit_maxsz)
L
Linus Torvalds 已提交
467
#define NFS4_enc_open_sz        (compound_encode_hdr_maxsz + \
468
				encode_sequence_maxsz + \
469 470
				encode_putfh_maxsz + \
				encode_open_maxsz + \
471
				encode_access_maxsz + \
472 473
				encode_getfh_maxsz + \
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
474
#define NFS4_dec_open_sz        (compound_decode_hdr_maxsz + \
475
				decode_sequence_maxsz + \
476 477
				decode_putfh_maxsz + \
				decode_open_maxsz + \
478
				decode_access_maxsz + \
479 480
				decode_getfh_maxsz + \
				decode_getattr_maxsz)
T
Trond Myklebust 已提交
481 482 483 484 485 486 487 488
#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 已提交
489
#define NFS4_enc_open_noattr_sz	(compound_encode_hdr_maxsz + \
490
					encode_sequence_maxsz + \
L
Linus Torvalds 已提交
491
					encode_putfh_maxsz + \
492
					encode_open_maxsz + \
493
					encode_access_maxsz + \
494
					encode_getattr_maxsz)
L
Linus Torvalds 已提交
495
#define NFS4_dec_open_noattr_sz	(compound_decode_hdr_maxsz + \
496
					decode_sequence_maxsz + \
L
Linus Torvalds 已提交
497
					decode_putfh_maxsz + \
498
					decode_open_maxsz + \
499
					decode_access_maxsz + \
500
					decode_getattr_maxsz)
L
Linus Torvalds 已提交
501 502
#define NFS4_enc_open_downgrade_sz \
				(compound_encode_hdr_maxsz + \
503
				 encode_sequence_maxsz + \
T
Trond Myklebust 已提交
504
				 encode_putfh_maxsz + \
505
				 encode_layoutreturn_maxsz + \
506
				 encode_open_downgrade_maxsz)
L
Linus Torvalds 已提交
507 508
#define NFS4_dec_open_downgrade_sz \
				(compound_decode_hdr_maxsz + \
509
				 decode_sequence_maxsz + \
T
Trond Myklebust 已提交
510
				 decode_putfh_maxsz + \
511
				 decode_layoutreturn_maxsz + \
512
				 decode_open_downgrade_maxsz)
T
Trond Myklebust 已提交
513
#define NFS4_enc_close_sz	(compound_encode_hdr_maxsz + \
514
				 encode_sequence_maxsz + \
T
Trond Myklebust 已提交
515
				 encode_putfh_maxsz + \
516
				 encode_layoutreturn_maxsz + \
T
Trond Myklebust 已提交
517 518 519
				 encode_close_maxsz + \
				 encode_getattr_maxsz)
#define NFS4_dec_close_sz	(compound_decode_hdr_maxsz + \
520
				 decode_sequence_maxsz + \
T
Trond Myklebust 已提交
521
				 decode_putfh_maxsz + \
522
				 decode_layoutreturn_maxsz + \
T
Trond Myklebust 已提交
523 524 525
				 decode_close_maxsz + \
				 decode_getattr_maxsz)
#define NFS4_enc_setattr_sz	(compound_encode_hdr_maxsz + \
526
				 encode_sequence_maxsz + \
T
Trond Myklebust 已提交
527 528 529 530
				 encode_putfh_maxsz + \
				 encode_setattr_maxsz + \
				 encode_getattr_maxsz)
#define NFS4_dec_setattr_sz	(compound_decode_hdr_maxsz + \
531
				 decode_sequence_maxsz + \
T
Trond Myklebust 已提交
532 533 534
				 decode_putfh_maxsz + \
				 decode_setattr_maxsz + \
				 decode_getattr_maxsz)
L
Linus Torvalds 已提交
535
#define NFS4_enc_fsinfo_sz	(compound_encode_hdr_maxsz + \
536
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
537 538 539
				encode_putfh_maxsz + \
				encode_fsinfo_maxsz)
#define NFS4_dec_fsinfo_sz	(compound_decode_hdr_maxsz + \
540
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
541 542 543 544 545 546 547 548 549 550 551 552
				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 + \
553
				encode_setclientid_confirm_maxsz)
L
Linus Torvalds 已提交
554 555
#define NFS4_dec_setclientid_confirm_sz \
				(compound_decode_hdr_maxsz + \
556
				decode_setclientid_confirm_maxsz)
L
Linus Torvalds 已提交
557
#define NFS4_enc_lock_sz        (compound_encode_hdr_maxsz + \
558
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
559
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
560
				encode_lock_maxsz)
L
Linus Torvalds 已提交
561
#define NFS4_dec_lock_sz        (compound_decode_hdr_maxsz + \
562
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
563
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
564
				decode_lock_maxsz)
L
Linus Torvalds 已提交
565
#define NFS4_enc_lockt_sz       (compound_encode_hdr_maxsz + \
566
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
567
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
568 569
				encode_lockt_maxsz)
#define NFS4_dec_lockt_sz       (compound_decode_hdr_maxsz + \
570
				 decode_sequence_maxsz + \
T
Trond Myklebust 已提交
571 572
				 decode_putfh_maxsz + \
				 decode_lockt_maxsz)
L
Linus Torvalds 已提交
573
#define NFS4_enc_locku_sz       (compound_encode_hdr_maxsz + \
574
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
575
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
576
				encode_locku_maxsz)
L
Linus Torvalds 已提交
577
#define NFS4_dec_locku_sz       (compound_decode_hdr_maxsz + \
578
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
579
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
580
				decode_locku_maxsz)
581 582 583 584 585 586
#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 已提交
587
#define NFS4_enc_access_sz	(compound_encode_hdr_maxsz + \
588
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
589
				encode_putfh_maxsz + \
590 591
				encode_access_maxsz + \
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
592
#define NFS4_dec_access_sz	(compound_decode_hdr_maxsz + \
593
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
594
				decode_putfh_maxsz + \
595 596
				decode_access_maxsz + \
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
597
#define NFS4_enc_getattr_sz	(compound_encode_hdr_maxsz + \
598
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
599
				encode_putfh_maxsz + \
600 601
				encode_getattr_maxsz + \
				encode_renew_maxsz)
L
Linus Torvalds 已提交
602
#define NFS4_dec_getattr_sz	(compound_decode_hdr_maxsz + \
603
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
604
				decode_putfh_maxsz + \
605 606
				decode_getattr_maxsz + \
				decode_renew_maxsz)
L
Linus Torvalds 已提交
607
#define NFS4_enc_lookup_sz	(compound_encode_hdr_maxsz + \
608
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
609 610 611 612 613
				encode_putfh_maxsz + \
				encode_lookup_maxsz + \
				encode_getattr_maxsz + \
				encode_getfh_maxsz)
#define NFS4_dec_lookup_sz	(compound_decode_hdr_maxsz + \
614
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
615
				decode_putfh_maxsz + \
616
				decode_lookup_maxsz + \
L
Linus Torvalds 已提交
617 618 619
				decode_getattr_maxsz + \
				decode_getfh_maxsz)
#define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \
620
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
621 622 623 624
				encode_putrootfh_maxsz + \
				encode_getattr_maxsz + \
				encode_getfh_maxsz)
#define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \
625
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
626 627 628 629
				decode_putrootfh_maxsz + \
				decode_getattr_maxsz + \
				decode_getfh_maxsz)
#define NFS4_enc_remove_sz	(compound_encode_hdr_maxsz + \
630
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
631
				encode_putfh_maxsz + \
632
				encode_remove_maxsz)
L
Linus Torvalds 已提交
633
#define NFS4_dec_remove_sz	(compound_decode_hdr_maxsz + \
634
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
635
				decode_putfh_maxsz + \
636
				decode_remove_maxsz)
L
Linus Torvalds 已提交
637
#define NFS4_enc_rename_sz	(compound_encode_hdr_maxsz + \
638
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
639 640 641
				encode_putfh_maxsz + \
				encode_savefh_maxsz + \
				encode_putfh_maxsz + \
642
				encode_rename_maxsz)
L
Linus Torvalds 已提交
643
#define NFS4_dec_rename_sz	(compound_decode_hdr_maxsz + \
644
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
645 646 647
				decode_putfh_maxsz + \
				decode_savefh_maxsz + \
				decode_putfh_maxsz + \
648
				decode_rename_maxsz)
L
Linus Torvalds 已提交
649
#define NFS4_enc_link_sz	(compound_encode_hdr_maxsz + \
650
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
651 652 653
				encode_putfh_maxsz + \
				encode_savefh_maxsz + \
				encode_putfh_maxsz + \
654 655
				encode_link_maxsz + \
				encode_restorefh_maxsz + \
656
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
657
#define NFS4_dec_link_sz	(compound_decode_hdr_maxsz + \
658
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
659 660 661
				decode_putfh_maxsz + \
				decode_savefh_maxsz + \
				decode_putfh_maxsz + \
662 663 664
				decode_link_maxsz + \
				decode_restorefh_maxsz + \
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
665
#define NFS4_enc_symlink_sz	(compound_encode_hdr_maxsz + \
666
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
667 668 669 670 671
				encode_putfh_maxsz + \
				encode_symlink_maxsz + \
				encode_getattr_maxsz + \
				encode_getfh_maxsz)
#define NFS4_dec_symlink_sz	(compound_decode_hdr_maxsz + \
672
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
673 674 675 676 677
				decode_putfh_maxsz + \
				decode_symlink_maxsz + \
				decode_getattr_maxsz + \
				decode_getfh_maxsz)
#define NFS4_enc_create_sz	(compound_encode_hdr_maxsz + \
678
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
679 680
				encode_putfh_maxsz + \
				encode_create_maxsz + \
681 682
				encode_getfh_maxsz + \
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
683
#define NFS4_dec_create_sz	(compound_decode_hdr_maxsz + \
684
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
685 686
				decode_putfh_maxsz + \
				decode_create_maxsz + \
687 688
				decode_getfh_maxsz + \
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
689
#define NFS4_enc_pathconf_sz	(compound_encode_hdr_maxsz + \
690
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
691 692 693
				encode_putfh_maxsz + \
				encode_getattr_maxsz)
#define NFS4_dec_pathconf_sz	(compound_decode_hdr_maxsz + \
694
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
695 696 697
				decode_putfh_maxsz + \
				decode_getattr_maxsz)
#define NFS4_enc_statfs_sz	(compound_encode_hdr_maxsz + \
698
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
699
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
700
				encode_statfs_maxsz)
L
Linus Torvalds 已提交
701
#define NFS4_dec_statfs_sz	(compound_decode_hdr_maxsz + \
702
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
703
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
704
				decode_statfs_maxsz)
L
Linus Torvalds 已提交
705
#define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \
706
				encode_sequence_maxsz + \
707
				encode_putfh_maxsz + \
L
Linus Torvalds 已提交
708 709
				encode_getattr_maxsz)
#define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \
710
				decode_sequence_maxsz + \
711
				decode_putfh_maxsz + \
L
Linus Torvalds 已提交
712 713
				decode_getattr_maxsz)
#define NFS4_enc_delegreturn_sz	(compound_encode_hdr_maxsz + \
714
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
715
				encode_putfh_maxsz + \
716
				encode_layoutreturn_maxsz + \
717 718
				encode_delegreturn_maxsz + \
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
719
#define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
720
				decode_sequence_maxsz + \
721
				decode_putfh_maxsz + \
722
				decode_layoutreturn_maxsz + \
723 724
				decode_delegreturn_maxsz + \
				decode_getattr_maxsz)
725
#define NFS4_enc_getacl_sz	(compound_encode_hdr_maxsz + \
726
				encode_sequence_maxsz + \
727
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
728
				encode_getacl_maxsz)
729
#define NFS4_dec_getacl_sz	(compound_decode_hdr_maxsz + \
730
				decode_sequence_maxsz + \
731
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
732
				decode_getacl_maxsz)
733
#define NFS4_enc_setacl_sz	(compound_encode_hdr_maxsz + \
734
				encode_sequence_maxsz + \
735
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
736
				encode_setacl_maxsz)
737
#define NFS4_dec_setacl_sz	(compound_decode_hdr_maxsz + \
738
				decode_sequence_maxsz + \
739
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
740
				decode_setacl_maxsz)
741 742
#define NFS4_enc_fs_locations_sz \
				(compound_encode_hdr_maxsz + \
743
				 encode_sequence_maxsz + \
744
				 encode_putfh_maxsz + \
745
				 encode_lookup_maxsz + \
746 747
				 encode_fs_locations_maxsz + \
				 encode_renew_maxsz)
748 749
#define NFS4_dec_fs_locations_sz \
				(compound_decode_hdr_maxsz + \
750
				 decode_sequence_maxsz + \
751
				 decode_putfh_maxsz + \
752
				 decode_lookup_maxsz + \
753 754
				 decode_fs_locations_maxsz + \
				 decode_renew_maxsz)
B
Bryan Schumaker 已提交
755 756 757 758 759 760 761 762
#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)
763 764 765 766 767 768 769 770 771 772 773 774
#define NFS4_enc_fsid_present_sz \
				(compound_encode_hdr_maxsz + \
				 encode_sequence_maxsz + \
				 encode_putfh_maxsz + \
				 encode_getfh_maxsz + \
				 encode_renew_maxsz)
#define NFS4_dec_fsid_present_sz \
				(compound_decode_hdr_maxsz + \
				 decode_sequence_maxsz + \
				 decode_putfh_maxsz + \
				 decode_getfh_maxsz + \
				 decode_renew_maxsz)
B
Benny Halevy 已提交
775
#if defined(CONFIG_NFS_V4_1)
776 777 778 779 780 781
#define NFS4_enc_bind_conn_to_session_sz \
				(compound_encode_hdr_maxsz + \
				 encode_bind_conn_to_session_maxsz)
#define NFS4_dec_bind_conn_to_session_sz \
				(compound_decode_hdr_maxsz + \
				 decode_bind_conn_to_session_maxsz)
B
Benny Halevy 已提交
782 783 784 785 786 787
#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 已提交
788 789 790 791 792 793
#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 已提交
794 795 796 797
#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)
T
Trond Myklebust 已提交
798 799 800 801
#define NFS4_enc_destroy_clientid_sz	(compound_encode_hdr_maxsz + \
					 encode_destroy_clientid_maxsz)
#define NFS4_dec_destroy_clientid_sz	(compound_decode_hdr_maxsz + \
					 decode_destroy_clientid_maxsz)
A
Andy Adamson 已提交
802 803 804 805 806 807
#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 已提交
808 809 810 811 812 813 814 815
#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)
816 817 818 819 820 821
#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)
822 823 824 825 826 827 828 829 830 831 832 833 834 835
#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 已提交
836 837 838 839 840 841 842 843 844 845
#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 已提交
846 847 848 849 850 851 852 853
#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)
854 855 856 857 858 859 860 861
#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)
B
Bryan Schumaker 已提交
862 863 864 865 866 867
#define NFS4_enc_test_stateid_sz	(compound_encode_hdr_maxsz + \
					 encode_sequence_maxsz + \
					 encode_test_stateid_maxsz)
#define NFS4_dec_test_stateid_sz	(compound_decode_hdr_maxsz + \
					 decode_sequence_maxsz + \
					 decode_test_stateid_maxsz)
B
Bryan Schumaker 已提交
868 869 870 871 872 873
#define NFS4_enc_free_stateid_sz	(compound_encode_hdr_maxsz + \
					 encode_sequence_maxsz + \
					 encode_free_stateid_maxsz)
#define NFS4_dec_free_stateid_sz	(compound_decode_hdr_maxsz + \
					 decode_sequence_maxsz + \
					 decode_free_stateid_maxsz)
874 875 876 877 878 879 880 881 882 883 884 885 886

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);
887 888 889 890 891 892

const u32 nfs41_maxgetdevinfo_overhead = ((RPC_MAX_REPHEADER_WITH_AUTH +
					   compound_decode_hdr_maxsz +
					   decode_sequence_maxsz) *
					  XDR_UNIT);
EXPORT_SYMBOL_GPL(nfs41_maxgetdevinfo_overhead);
B
Benny Halevy 已提交
893
#endif /* CONFIG_NFS_V4_1 */
L
Linus Torvalds 已提交
894

895 896 897 898 899 900 901 902 903 904 905
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 已提交
906 907 908 909 910
};

struct compound_hdr {
	int32_t		status;
	uint32_t	nops;
911
	__be32 *	nops_p;
L
Linus Torvalds 已提交
912 913
	uint32_t	taglen;
	char *		tag;
914
	uint32_t	replen;		/* expected reply words */
915
	u32		minorversion;
L
Linus Torvalds 已提交
916 917
};

918 919 920 921 922 923
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 已提交
924

925 926 927 928 929 930 931 932
static void encode_opaque_fixed(struct xdr_stream *xdr, const void *buf, size_t len)
{
	__be32 *p;

	p = xdr_reserve_space(xdr, len);
	xdr_encode_opaque_fixed(p, buf, len);
}

L
Linus Torvalds 已提交
933 934
static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
{
A
Al Viro 已提交
935
	__be32 *p;
L
Linus Torvalds 已提交
936

937
	p = reserve_space(xdr, 4 + len);
L
Linus Torvalds 已提交
938 939 940
	xdr_encode_opaque(p, str, len);
}

941 942 943 944 945 946 947 948
static void encode_uint32(struct xdr_stream *xdr, u32 n)
{
	__be32 *p;

	p = reserve_space(xdr, 4);
	*p = cpu_to_be32(n);
}

949 950 951 952 953 954 955 956
static void encode_uint64(struct xdr_stream *xdr, u64 n)
{
	__be32 *p;

	p = reserve_space(xdr, 8);
	xdr_encode_hyper(p, n);
}

957 958 959
static void encode_nfs4_seqid(struct xdr_stream *xdr,
		const struct nfs_seqid *seqid)
{
960 961 962 963
	if (seqid != NULL)
		encode_uint32(xdr, seqid->sequence->counter);
	else
		encode_uint32(xdr, 0);
964 965
}

966 967 968
static void encode_compound_hdr(struct xdr_stream *xdr,
				struct rpc_rqst *req,
				struct compound_hdr *hdr)
L
Linus Torvalds 已提交
969
{
A
Al Viro 已提交
970
	__be32 *p;
971
	struct rpc_auth *auth = req->rq_cred->cr_auth;
972 973 974 975 976

	/* 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 已提交
977

978
	WARN_ON_ONCE(hdr->taglen > NFS4_MAXTAGLEN);
979 980
	encode_string(xdr, hdr->taglen, hdr->tag);
	p = reserve_space(xdr, 8);
B
Benny Halevy 已提交
981
	*p++ = cpu_to_be32(hdr->minorversion);
982
	hdr->nops_p = p;
983
	*p = cpu_to_be32(hdr->nops);
984 985
}

T
Trond Myklebust 已提交
986 987 988 989 990 991 992 993 994
static void encode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 op,
		uint32_t replen,
		struct compound_hdr *hdr)
{
	encode_uint32(xdr, op);
	hdr->nops++;
	hdr->replen += replen;
}

995 996
static void encode_nops(struct compound_hdr *hdr)
{
997
	WARN_ON_ONCE(hdr->nops > NFS4_MAX_OPS);
998
	*hdr->nops_p = htonl(hdr->nops);
L
Linus Torvalds 已提交
999 1000
}

1001 1002
static void encode_nfs4_stateid(struct xdr_stream *xdr, const nfs4_stateid *stateid)
{
1003
	encode_opaque_fixed(xdr, stateid, NFS4_STATEID_SIZE);
1004 1005
}

L
Linus Torvalds 已提交
1006 1007
static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
{
1008
	encode_opaque_fixed(xdr, verf->data, NFS4_VERIFIER_SIZE);
L
Linus Torvalds 已提交
1009 1010
}

1011 1012
static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
				const struct nfs4_label *label,
1013
				const struct nfs_server *server,
1014
				bool excl_check, const umode_t *umask)
L
Linus Torvalds 已提交
1015 1016 1017 1018 1019
{
	char owner_name[IDMAP_NAMESZ];
	char owner_group[IDMAP_NAMESZ];
	int owner_namelen = 0;
	int owner_grouplen = 0;
A
Al Viro 已提交
1020
	__be32 *p;
1021 1022 1023 1024
	unsigned i;
	uint32_t len = 0;
	uint32_t bmval_len;
	uint32_t bmval[3] = { 0 };
L
Linus Torvalds 已提交
1025 1026 1027 1028

	/*
	 * We reserve enough space to write the entire attribute buffer at once.
	 */
1029 1030
	if (iap->ia_valid & ATTR_SIZE) {
		bmval[0] |= FATTR4_WORD0_SIZE;
L
Linus Torvalds 已提交
1031
		len += 8;
1032
	}
1033 1034
	if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
		umask = NULL;
1035
	if (iap->ia_valid & ATTR_MODE) {
1036 1037 1038 1039 1040 1041 1042
		if (umask) {
			bmval[2] |= FATTR4_WORD2_MODE_UMASK;
			len += 8;
		} else {
			bmval[1] |= FATTR4_WORD1_MODE;
			len += 4;
		}
1043
	}
L
Linus Torvalds 已提交
1044
	if (iap->ia_valid & ATTR_UID) {
1045
		owner_namelen = nfs_map_uid_to_name(server, iap->ia_uid, owner_name, IDMAP_NAMESZ);
L
Linus Torvalds 已提交
1046
		if (owner_namelen < 0) {
1047
			dprintk("nfs: couldn't resolve uid %d to string\n",
1048
					from_kuid(&init_user_ns, iap->ia_uid));
L
Linus Torvalds 已提交
1049 1050 1051 1052 1053
			/* XXX */
			strcpy(owner_name, "nobody");
			owner_namelen = sizeof("nobody") - 1;
			/* goto out; */
		}
1054
		bmval[1] |= FATTR4_WORD1_OWNER;
L
Linus Torvalds 已提交
1055 1056 1057
		len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
	}
	if (iap->ia_valid & ATTR_GID) {
1058
		owner_grouplen = nfs_map_gid_to_group(server, iap->ia_gid, owner_group, IDMAP_NAMESZ);
L
Linus Torvalds 已提交
1059
		if (owner_grouplen < 0) {
1060
			dprintk("nfs: couldn't resolve gid %d to string\n",
1061
					from_kgid(&init_user_ns, iap->ia_gid));
L
Linus Torvalds 已提交
1062 1063 1064 1065
			strcpy(owner_group, "nobody");
			owner_grouplen = sizeof("nobody") - 1;
			/* goto out; */
		}
1066
		bmval[1] |= FATTR4_WORD1_OWNER_GROUP;
L
Linus Torvalds 已提交
1067 1068
		len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
	}
1069 1070
	if (iap->ia_valid & ATTR_ATIME_SET) {
		bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
L
Linus Torvalds 已提交
1071
		len += 16;
1072 1073
	} else if (iap->ia_valid & ATTR_ATIME) {
		bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
L
Linus Torvalds 已提交
1074
		len += 4;
1075 1076 1077
	}
	if (iap->ia_valid & ATTR_MTIME_SET) {
		bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
L
Linus Torvalds 已提交
1078
		len += 16;
1079 1080
	} else if (iap->ia_valid & ATTR_MTIME) {
		bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
L
Linus Torvalds 已提交
1081
		len += 4;
1082
	}
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093

	if (excl_check) {
		const u32 *excl_bmval = server->exclcreat_bitmask;
		bmval[0] &= excl_bmval[0];
		bmval[1] &= excl_bmval[1];
		bmval[2] &= excl_bmval[2];

		if (!(excl_bmval[2] & FATTR4_WORD2_SECURITY_LABEL))
			label = NULL;
	}

1094 1095
	if (label) {
		len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2);
1096
		bmval[2] |= FATTR4_WORD2_SECURITY_LABEL;
1097 1098
	}

1099 1100 1101 1102 1103 1104 1105 1106
	if (bmval[2] != 0)
		bmval_len = 3;
	else if (bmval[1] != 0)
		bmval_len = 2;
	else
		bmval_len = 1;

	p = reserve_space(xdr, 4 + (bmval_len << 2) + 4 + len);
L
Linus Torvalds 已提交
1107

1108
	*p++ = cpu_to_be32(bmval_len);
1109 1110 1111
	for (i = 0; i < bmval_len; i++)
		*p++ = cpu_to_be32(bmval[i]);
	*p++ = cpu_to_be32(len);
L
Linus Torvalds 已提交
1112

1113
	if (bmval[0] & FATTR4_WORD0_SIZE)
B
Benny Halevy 已提交
1114
		p = xdr_encode_hyper(p, iap->ia_size);
1115
	if (bmval[1] & FATTR4_WORD1_MODE)
B
Benny Halevy 已提交
1116
		*p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO);
1117
	if (bmval[1] & FATTR4_WORD1_OWNER)
1118
		p = xdr_encode_opaque(p, owner_name, owner_namelen);
1119
	if (bmval[1] & FATTR4_WORD1_OWNER_GROUP)
1120
		p = xdr_encode_opaque(p, owner_group, owner_grouplen);
1121 1122 1123 1124 1125 1126 1127
	if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
		if (iap->ia_valid & ATTR_ATIME_SET) {
			*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
			p = xdr_encode_hyper(p, (s64)iap->ia_atime.tv_sec);
			*p++ = cpu_to_be32(iap->ia_atime.tv_nsec);
		} else
			*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
L
Linus Torvalds 已提交
1128
	}
1129 1130 1131 1132 1133 1134 1135
	if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
		if (iap->ia_valid & ATTR_MTIME_SET) {
			*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
			p = xdr_encode_hyper(p, (s64)iap->ia_mtime.tv_sec);
			*p++ = cpu_to_be32(iap->ia_mtime.tv_nsec);
		} else
			*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
L
Linus Torvalds 已提交
1136
	}
1137
	if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) {
1138 1139 1140 1141 1142
		*p++ = cpu_to_be32(label->lfs);
		*p++ = cpu_to_be32(label->pi);
		*p++ = cpu_to_be32(label->len);
		p = xdr_encode_opaque_fixed(p, label->label, label->len);
	}
1143 1144 1145 1146
	if (bmval[2] & FATTR4_WORD2_MODE_UMASK) {
		*p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO);
		*p++ = cpu_to_be32(*umask);
	}
1147

L
Linus Torvalds 已提交
1148 1149 1150
/* out: */
}

1151
static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1152
{
T
Trond Myklebust 已提交
1153 1154
	encode_op_hdr(xdr, OP_ACCESS, decode_access_maxsz, hdr);
	encode_uint32(xdr, access);
L
Linus Torvalds 已提交
1155 1156
}

1157
static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1158
{
T
Trond Myklebust 已提交
1159
	encode_op_hdr(xdr, OP_CLOSE, decode_close_maxsz, hdr);
1160
	encode_nfs4_seqid(xdr, arg->seqid);
1161
	encode_nfs4_stateid(xdr, &arg->stateid);
L
Linus Torvalds 已提交
1162 1163
}

1164
static void encode_commit(struct xdr_stream *xdr, const struct nfs_commitargs *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1165
{
A
Al Viro 已提交
1166
	__be32 *p;
1167

T
Trond Myklebust 已提交
1168 1169
	encode_op_hdr(xdr, OP_COMMIT, decode_commit_maxsz, hdr);
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
1170
	p = xdr_encode_hyper(p, args->offset);
1171
	*p = cpu_to_be32(args->count);
L
Linus Torvalds 已提交
1172 1173
}

1174
static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1175
{
A
Al Viro 已提交
1176
	__be32 *p;
1177

T
Trond Myklebust 已提交
1178 1179
	encode_op_hdr(xdr, OP_CREATE, decode_create_maxsz, hdr);
	encode_uint32(xdr, create->ftype);
L
Linus Torvalds 已提交
1180 1181 1182

	switch (create->ftype) {
	case NF4LNK:
1183
		p = reserve_space(xdr, 4);
1184
		*p = cpu_to_be32(create->u.symlink.len);
1185 1186 1187
		xdr_write_pages(xdr, create->u.symlink.pages, 0,
				create->u.symlink.len);
		xdr->buf->flags |= XDRBUF_WRITE;
L
Linus Torvalds 已提交
1188 1189 1190
		break;

	case NF4BLK: case NF4CHR:
1191
		p = reserve_space(xdr, 8);
B
Benny Halevy 已提交
1192
		*p++ = cpu_to_be32(create->u.device.specdata1);
1193
		*p = cpu_to_be32(create->u.device.specdata2);
L
Linus Torvalds 已提交
1194 1195 1196 1197 1198 1199
		break;

	default:
		break;
	}

1200
	encode_string(xdr, create->name->len, create->name->name);
1201 1202
	encode_attrs(xdr, create->attrs, create->label, create->server, false,
		     &create->umask);
L
Linus Torvalds 已提交
1203 1204
}

1205
static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1206
{
A
Andy Adamson 已提交
1207
	__be32 *p;
L
Linus Torvalds 已提交
1208

T
Trond Myklebust 已提交
1209 1210
	encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr);
	p = reserve_space(xdr, 8);
B
Benny Halevy 已提交
1211
	*p++ = cpu_to_be32(1);
1212
	*p = cpu_to_be32(bitmap);
L
Linus Torvalds 已提交
1213 1214
}

1215
static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1216
{
A
Andy Adamson 已提交
1217
	__be32 *p;
L
Linus Torvalds 已提交
1218

T
Trond Myklebust 已提交
1219 1220
	encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr);
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
1221 1222
	*p++ = cpu_to_be32(2);
	*p++ = cpu_to_be32(bm0);
1223
	*p = cpu_to_be32(bm1);
L
Linus Torvalds 已提交
1224 1225
}

1226 1227 1228 1229 1230 1231 1232
static void
encode_getattr_three(struct xdr_stream *xdr,
		     uint32_t bm0, uint32_t bm1, uint32_t bm2,
		     struct compound_hdr *hdr)
{
	__be32 *p;

T
Trond Myklebust 已提交
1233
	encode_op_hdr(xdr, OP_GETATTR, decode_getattr_maxsz, hdr);
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251
	if (bm2) {
		p = reserve_space(xdr, 16);
		*p++ = cpu_to_be32(3);
		*p++ = cpu_to_be32(bm0);
		*p++ = cpu_to_be32(bm1);
		*p = cpu_to_be32(bm2);
	} else if (bm1) {
		p = reserve_space(xdr, 12);
		*p++ = cpu_to_be32(2);
		*p++ = cpu_to_be32(bm0);
		*p = cpu_to_be32(bm1);
	} else {
		p = reserve_space(xdr, 8);
		*p++ = cpu_to_be32(1);
		*p = cpu_to_be32(bm0);
	}
}

1252
static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1253
{
1254 1255 1256 1257
	encode_getattr_three(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
			   bitmask[1] & nfs4_fattr_bitmap[1],
			   bitmask[2] & nfs4_fattr_bitmap[2],
			   hdr);
L
Linus Torvalds 已提交
1258 1259
}

1260
static void encode_getfattr_open(struct xdr_stream *xdr, const u32 *bitmask,
1261
				 const u32 *open_bitmap,
1262 1263 1264
				 struct compound_hdr *hdr)
{
	encode_getattr_three(xdr,
1265 1266 1267
			     bitmask[0] & open_bitmap[0],
			     bitmask[1] & open_bitmap[1],
			     bitmask[2] & open_bitmap[2],
1268 1269 1270
			     hdr);
}

1271
static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1272
{
1273 1274 1275 1276 1277
	encode_getattr_three(xdr,
			     bitmask[0] & nfs4_fsinfo_bitmap[0],
			     bitmask[1] & nfs4_fsinfo_bitmap[1],
			     bitmask[2] & nfs4_fsinfo_bitmap[2],
			     hdr);
L
Linus Torvalds 已提交
1278 1279
}

1280
static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
1281
{
1282 1283
	encode_getattr_two(xdr, bitmask[0] & nfs4_fs_locations_bitmap[0],
			   bitmask[1] & nfs4_fs_locations_bitmap[1], hdr);
1284 1285
}

1286
static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1287
{
T
Trond Myklebust 已提交
1288
	encode_op_hdr(xdr, OP_GETFH, decode_getfh_maxsz, hdr);
L
Linus Torvalds 已提交
1289 1290
}

1291
static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1292
{
T
Trond Myklebust 已提交
1293
	encode_op_hdr(xdr, OP_LINK, decode_link_maxsz, hdr);
1294
	encode_string(xdr, name->len, name->name);
L
Linus Torvalds 已提交
1295 1296
}

T
Trond Myklebust 已提交
1297 1298
static inline int nfs4_lock_type(struct file_lock *fl, int block)
{
1299
	if (fl->fl_type == F_RDLCK)
T
Trond Myklebust 已提交
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310
		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;
}

1311 1312 1313 1314
static void encode_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner)
{
	__be32 *p;

1315
	p = reserve_space(xdr, 32);
1316
	p = xdr_encode_hyper(p, lowner->clientid);
1317
	*p++ = cpu_to_be32(20);
1318
	p = xdr_encode_opaque_fixed(p, "lock id:", 8);
1319
	*p++ = cpu_to_be32(lowner->s_dev);
1320 1321 1322
	xdr_encode_hyper(p, lowner->id);
}

L
Linus Torvalds 已提交
1323 1324 1325 1326
/*
 * opcode,type,reclaim,offset,length,new_lock_owner = 32
 * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
 */
1327
static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1328
{
A
Al Viro 已提交
1329
	__be32 *p;
L
Linus Torvalds 已提交
1330

T
Trond Myklebust 已提交
1331 1332
	encode_op_hdr(xdr, OP_LOCK, decode_lock_maxsz, hdr);
	p = reserve_space(xdr, 28);
B
Benny Halevy 已提交
1333 1334
	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, args->block));
	*p++ = cpu_to_be32(args->reclaim);
B
Benny Halevy 已提交
1335 1336
	p = xdr_encode_hyper(p, args->fl->fl_start);
	p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
1337
	*p = cpu_to_be32(args->new_lock_owner);
T
Trond Myklebust 已提交
1338
	if (args->new_lock_owner){
1339
		encode_nfs4_seqid(xdr, args->open_seqid);
1340
		encode_nfs4_stateid(xdr, &args->open_stateid);
1341
		encode_nfs4_seqid(xdr, args->lock_seqid);
1342
		encode_lockowner(xdr, &args->lock_owner);
L
Linus Torvalds 已提交
1343 1344
	}
	else {
1345
		encode_nfs4_stateid(xdr, &args->lock_stateid);
1346
		encode_nfs4_seqid(xdr, args->lock_seqid);
L
Linus Torvalds 已提交
1347 1348 1349
	}
}

1350
static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1351
{
A
Al Viro 已提交
1352
	__be32 *p;
L
Linus Torvalds 已提交
1353

T
Trond Myklebust 已提交
1354 1355
	encode_op_hdr(xdr, OP_LOCKT, decode_lockt_maxsz, hdr);
	p = reserve_space(xdr, 20);
B
Benny Halevy 已提交
1356
	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
B
Benny Halevy 已提交
1357 1358
	p = xdr_encode_hyper(p, args->fl->fl_start);
	p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
1359
	encode_lockowner(xdr, &args->lock_owner);
L
Linus Torvalds 已提交
1360 1361
}

1362
static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1363
{
A
Al Viro 已提交
1364
	__be32 *p;
L
Linus Torvalds 已提交
1365

T
Trond Myklebust 已提交
1366 1367
	encode_op_hdr(xdr, OP_LOCKU, decode_locku_maxsz, hdr);
	encode_uint32(xdr, nfs4_lock_type(args->fl, 0));
1368
	encode_nfs4_seqid(xdr, args->seqid);
1369
	encode_nfs4_stateid(xdr, &args->stateid);
1370
	p = reserve_space(xdr, 16);
B
Benny Halevy 已提交
1371
	p = xdr_encode_hyper(p, args->fl->fl_start);
1372
	xdr_encode_hyper(p, nfs4_lock_length(args->fl));
L
Linus Torvalds 已提交
1373 1374
}

1375 1376
static void encode_release_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner, struct compound_hdr *hdr)
{
T
Trond Myklebust 已提交
1377
	encode_op_hdr(xdr, OP_RELEASE_LOCKOWNER, decode_release_lockowner_maxsz, hdr);
1378 1379 1380
	encode_lockowner(xdr, lowner);
}

1381
static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1382
{
T
Trond Myklebust 已提交
1383
	encode_op_hdr(xdr, OP_LOOKUP, decode_lookup_maxsz, hdr);
1384
	encode_string(xdr, name->len, name->name);
L
Linus Torvalds 已提交
1385 1386
}

1387
static void encode_share_access(struct xdr_stream *xdr, u32 share_access)
L
Linus Torvalds 已提交
1388
{
A
Al Viro 已提交
1389
	__be32 *p;
L
Linus Torvalds 已提交
1390

1391
	p = reserve_space(xdr, 8);
1392
	*p++ = cpu_to_be32(share_access);
1393
	*p = cpu_to_be32(0);		/* for linux, share_deny = 0 always */
L
Linus Torvalds 已提交
1394 1395 1396 1397
}

static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg)
{
A
Al Viro 已提交
1398
	__be32 *p;
L
Linus Torvalds 已提交
1399 1400 1401 1402
 /*
 * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
 * owner 4 = 32
 */
1403
	encode_nfs4_seqid(xdr, arg->seqid);
1404
	encode_share_access(xdr, arg->share_access);
1405
	p = reserve_space(xdr, 36);
B
Benny Halevy 已提交
1406
	p = xdr_encode_hyper(p, arg->clientid);
1407
	*p++ = cpu_to_be32(24);
B
Benny Halevy 已提交
1408
	p = xdr_encode_opaque_fixed(p, "open id:", 8);
1409
	*p++ = cpu_to_be32(arg->server->s_dev);
1410 1411
	*p++ = cpu_to_be32(arg->id.uniquifier);
	xdr_encode_hyper(p, arg->id.create_time);
L
Linus Torvalds 已提交
1412 1413 1414 1415
}

static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
{
A
Al Viro 已提交
1416
	__be32 *p;
L
Linus Torvalds 已提交
1417

1418
	p = reserve_space(xdr, 4);
1419 1420
	switch(arg->createmode) {
	case NFS4_CREATE_UNCHECKED:
1421
		*p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
1422 1423
		encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, false,
			     &arg->umask);
A
Andy Adamson 已提交
1424
		break;
1425 1426
	case NFS4_CREATE_GUARDED:
		*p = cpu_to_be32(NFS4_CREATE_GUARDED);
1427 1428
		encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, false,
			     &arg->umask);
1429 1430 1431 1432 1433 1434 1435 1436
		break;
	case NFS4_CREATE_EXCLUSIVE:
		*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
		encode_nfs4_verifier(xdr, &arg->u.verifier);
		break;
	case NFS4_CREATE_EXCLUSIVE4_1:
		*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
		encode_nfs4_verifier(xdr, &arg->u.verifier);
1437 1438
		encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, true,
			     &arg->umask);
L
Linus Torvalds 已提交
1439 1440 1441 1442 1443
	}
}

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

1446
	p = reserve_space(xdr, 4);
L
Linus Torvalds 已提交
1447
	switch (arg->open_flags & O_CREAT) {
A
Andy Adamson 已提交
1448
	case 0:
1449
		*p = cpu_to_be32(NFS4_OPEN_NOCREATE);
A
Andy Adamson 已提交
1450 1451
		break;
	default:
1452
		*p = cpu_to_be32(NFS4_OPEN_CREATE);
A
Andy Adamson 已提交
1453
		encode_createmode(xdr, arg);
L
Linus Torvalds 已提交
1454 1455 1456
	}
}

1457
static inline void encode_delegation_type(struct xdr_stream *xdr, fmode_t delegation_type)
L
Linus Torvalds 已提交
1458
{
A
Al Viro 已提交
1459
	__be32 *p;
L
Linus Torvalds 已提交
1460

1461
	p = reserve_space(xdr, 4);
L
Linus Torvalds 已提交
1462
	switch (delegation_type) {
A
Andy Adamson 已提交
1463
	case 0:
1464
		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_NONE);
A
Andy Adamson 已提交
1465 1466
		break;
	case FMODE_READ:
1467
		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_READ);
A
Andy Adamson 已提交
1468 1469
		break;
	case FMODE_WRITE|FMODE_READ:
1470
		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_WRITE);
A
Andy Adamson 已提交
1471 1472 1473
		break;
	default:
		BUG();
L
Linus Torvalds 已提交
1474 1475 1476 1477 1478
	}
}

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

1481
	p = reserve_space(xdr, 4);
1482
	*p = cpu_to_be32(NFS4_OPEN_CLAIM_NULL);
L
Linus Torvalds 已提交
1483 1484 1485
	encode_string(xdr, name->len, name->name);
}

1486
static inline void encode_claim_previous(struct xdr_stream *xdr, fmode_t type)
L
Linus Torvalds 已提交
1487
{
A
Al Viro 已提交
1488
	__be32 *p;
L
Linus Torvalds 已提交
1489

1490
	p = reserve_space(xdr, 4);
1491
	*p = cpu_to_be32(NFS4_OPEN_CLAIM_PREVIOUS);
L
Linus Torvalds 已提交
1492 1493 1494 1495 1496
	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 已提交
1497
	__be32 *p;
L
Linus Torvalds 已提交
1498

1499 1500 1501
	p = reserve_space(xdr, 4);
	*p = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
	encode_nfs4_stateid(xdr, stateid);
L
Linus Torvalds 已提交
1502 1503 1504
	encode_string(xdr, name->len, name->name);
}

1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521
static inline void encode_claim_fh(struct xdr_stream *xdr)
{
	__be32 *p;

	p = reserve_space(xdr, 4);
	*p = cpu_to_be32(NFS4_OPEN_CLAIM_FH);
}

static inline void encode_claim_delegate_cur_fh(struct xdr_stream *xdr, const nfs4_stateid *stateid)
{
	__be32 *p;

	p = reserve_space(xdr, 4);
	*p = cpu_to_be32(NFS4_OPEN_CLAIM_DELEG_CUR_FH);
	encode_nfs4_stateid(xdr, stateid);
}

1522
static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1523
{
T
Trond Myklebust 已提交
1524
	encode_op_hdr(xdr, OP_OPEN, decode_open_maxsz, hdr);
L
Linus Torvalds 已提交
1525 1526 1527
	encode_openhdr(xdr, arg);
	encode_opentype(xdr, arg);
	switch (arg->claim) {
A
Andy Adamson 已提交
1528 1529 1530 1531 1532 1533 1534 1535 1536
	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;
1537 1538 1539 1540 1541 1542
	case NFS4_OPEN_CLAIM_FH:
		encode_claim_fh(xdr);
		break;
	case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
		encode_claim_delegate_cur_fh(xdr, &arg->u.delegation);
		break;
A
Andy Adamson 已提交
1543 1544
	default:
		BUG();
L
Linus Torvalds 已提交
1545 1546 1547
	}
}

1548
static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1549
{
T
Trond Myklebust 已提交
1550
	encode_op_hdr(xdr, OP_OPEN_CONFIRM, decode_open_confirm_maxsz, hdr);
1551
	encode_nfs4_stateid(xdr, arg->stateid);
1552
	encode_nfs4_seqid(xdr, arg->seqid);
L
Linus Torvalds 已提交
1553 1554
}

1555
static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1556
{
T
Trond Myklebust 已提交
1557
	encode_op_hdr(xdr, OP_OPEN_DOWNGRADE, decode_open_downgrade_maxsz, hdr);
1558
	encode_nfs4_stateid(xdr, &arg->stateid);
1559
	encode_nfs4_seqid(xdr, arg->seqid);
1560
	encode_share_access(xdr, arg->share_access);
L
Linus Torvalds 已提交
1561 1562
}

1563
static void
1564
encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1565
{
T
Trond Myklebust 已提交
1566
	encode_op_hdr(xdr, OP_PUTFH, decode_putfh_maxsz, hdr);
1567
	encode_string(xdr, fh->size, fh->data);
L
Linus Torvalds 已提交
1568 1569
}

1570
static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1571
{
T
Trond Myklebust 已提交
1572
	encode_op_hdr(xdr, OP_PUTROOTFH, decode_putrootfh_maxsz, hdr);
L
Linus Torvalds 已提交
1573 1574
}

1575 1576
static void encode_read(struct xdr_stream *xdr, const struct nfs_pgio_args *args,
			struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1577
{
A
Al Viro 已提交
1578
	__be32 *p;
L
Linus Torvalds 已提交
1579

T
Trond Myklebust 已提交
1580
	encode_op_hdr(xdr, OP_READ, decode_read_maxsz, hdr);
1581
	encode_nfs4_stateid(xdr, &args->stateid);
L
Linus Torvalds 已提交
1582

1583
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
1584
	p = xdr_encode_hyper(p, args->offset);
1585
	*p = cpu_to_be32(args->count);
L
Linus Torvalds 已提交
1586 1587
}

1588
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 已提交
1589
{
1590
	uint32_t attrs[3] = {
1591 1592 1593
		FATTR4_WORD0_RDATTR_ERROR,
		FATTR4_WORD1_MOUNTED_ON_FILEID,
	};
1594
	uint32_t dircount = readdir->count >> 1;
1595
	__be32 *p, verf[2];
1596 1597
	uint32_t attrlen = 0;
	unsigned int i;
L
Linus Torvalds 已提交
1598

B
Bryan Schumaker 已提交
1599 1600
	if (readdir->plus) {
		attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
1601
			FATTR4_WORD0_FSID|FATTR4_WORD0_FILEHANDLE|FATTR4_WORD0_FILEID;
B
Bryan Schumaker 已提交
1602 1603 1604 1605
		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;
1606
		attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
1607
		dircount >>= 1;
B
Bryan Schumaker 已提交
1608
	}
1609 1610 1611
	/* Use mounted_on_fileid only if the server supports it */
	if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))
		attrs[0] |= FATTR4_WORD0_FILEID;
1612 1613 1614 1615 1616
	for (i = 0; i < ARRAY_SIZE(attrs); i++) {
		attrs[i] &= readdir->bitmask[i];
		if (attrs[i] != 0)
			attrlen = i+1;
	}
B
Bryan Schumaker 已提交
1617

T
Trond Myklebust 已提交
1618
	encode_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr);
1619
	encode_uint64(xdr, readdir->cookie);
1620
	encode_nfs4_verifier(xdr, &readdir->verifier);
1621
	p = reserve_space(xdr, 12 + (attrlen << 2));
1622
	*p++ = cpu_to_be32(dircount);
B
Benny Halevy 已提交
1623
	*p++ = cpu_to_be32(readdir->count);
1624 1625 1626
	*p++ = cpu_to_be32(attrlen);
	for (i = 0; i < attrlen; i++)
		*p++ = cpu_to_be32(attrs[i]);
1627
	memcpy(verf, readdir->verifier.data, sizeof(verf));
1628 1629

	dprintk("%s: cookie = %llu, verifier = %08x:%08x, bitmap = %08x:%08x:%08x\n",
1630
			__func__,
1631
			(unsigned long long)readdir->cookie,
1632
			verf[0], verf[1],
1633
			attrs[0] & readdir->bitmask[0],
1634 1635
			attrs[1] & readdir->bitmask[1],
			attrs[2] & readdir->bitmask[2]);
L
Linus Torvalds 已提交
1636 1637
}

1638
static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1639
{
T
Trond Myklebust 已提交
1640
	encode_op_hdr(xdr, OP_READLINK, decode_readlink_maxsz, hdr);
L
Linus Torvalds 已提交
1641 1642
}

1643
static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1644
{
T
Trond Myklebust 已提交
1645
	encode_op_hdr(xdr, OP_REMOVE, decode_remove_maxsz, hdr);
1646
	encode_string(xdr, name->len, name->name);
L
Linus Torvalds 已提交
1647 1648
}

1649
static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1650
{
T
Trond Myklebust 已提交
1651
	encode_op_hdr(xdr, OP_RENAME, decode_rename_maxsz, hdr);
1652 1653
	encode_string(xdr, oldname->len, oldname->name);
	encode_string(xdr, newname->len, newname->name);
L
Linus Torvalds 已提交
1654 1655
}

1656 1657
static void encode_renew(struct xdr_stream *xdr, clientid4 clid,
			 struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1658
{
T
Trond Myklebust 已提交
1659
	encode_op_hdr(xdr, OP_RENEW, decode_renew_maxsz, hdr);
1660
	encode_uint64(xdr, clid);
L
Linus Torvalds 已提交
1661 1662
}

1663
static void
1664
encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
1665
{
T
Trond Myklebust 已提交
1666
	encode_op_hdr(xdr, OP_RESTOREFH, decode_restorefh_maxsz, hdr);
1667 1668
}

1669
static void
1670
encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compound_hdr *hdr)
1671
{
A
Al Viro 已提交
1672
	__be32 *p;
1673

T
Trond Myklebust 已提交
1674
	encode_op_hdr(xdr, OP_SETATTR, decode_setacl_maxsz, hdr);
1675
	encode_nfs4_stateid(xdr, &zero_stateid);
1676
	p = reserve_space(xdr, 2*4);
B
Benny Halevy 已提交
1677
	*p++ = cpu_to_be32(1);
1678
	*p = cpu_to_be32(FATTR4_WORD0_ACL);
1679
	p = reserve_space(xdr, 4);
1680
	*p = cpu_to_be32(arg->acl_len);
1681
	xdr_write_pages(xdr, arg->acl_pages, 0, arg->acl_len);
1682 1683
}

1684
static void
1685
encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1686
{
T
Trond Myklebust 已提交
1687
	encode_op_hdr(xdr, OP_SAVEFH, decode_savefh_maxsz, hdr);
L
Linus Torvalds 已提交
1688 1689
}

1690
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 已提交
1691
{
T
Trond Myklebust 已提交
1692
	encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr);
1693
	encode_nfs4_stateid(xdr, &arg->stateid);
1694
	encode_attrs(xdr, arg->iap, arg->label, server, false, NULL);
L
Linus Torvalds 已提交
1695 1696
}

1697
static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1698
{
A
Al Viro 已提交
1699
	__be32 *p;
L
Linus Torvalds 已提交
1700

1701
	encode_op_hdr(xdr, OP_SETCLIENTID, decode_setclientid_maxsz, hdr);
1702
	encode_nfs4_verifier(xdr, setclientid->sc_verifier);
L
Linus Torvalds 已提交
1703

1704 1705
	encode_string(xdr, strlen(setclientid->sc_clnt->cl_owner_id),
			setclientid->sc_clnt->cl_owner_id);
1706
	p = reserve_space(xdr, 4);
1707
	*p = cpu_to_be32(setclientid->sc_prog);
L
Linus Torvalds 已提交
1708 1709
	encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid);
	encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
1710
	p = reserve_space(xdr, 4);
1711
	*p = cpu_to_be32(setclientid->sc_clnt->cl_cb_ident);
L
Linus Torvalds 已提交
1712 1713
}

1714
static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_setclientid_res *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1715
{
T
Trond Myklebust 已提交
1716 1717
	encode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM,
			decode_setclientid_confirm_maxsz, hdr);
1718
	encode_uint64(xdr, arg->clientid);
1719
	encode_nfs4_verifier(xdr, &arg->confirm);
L
Linus Torvalds 已提交
1720 1721
}

1722 1723
static void encode_write(struct xdr_stream *xdr, const struct nfs_pgio_args *args,
			 struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1724
{
A
Al Viro 已提交
1725
	__be32 *p;
L
Linus Torvalds 已提交
1726

T
Trond Myklebust 已提交
1727
	encode_op_hdr(xdr, OP_WRITE, decode_write_maxsz, hdr);
1728
	encode_nfs4_stateid(xdr, &args->stateid);
L
Linus Torvalds 已提交
1729

1730
	p = reserve_space(xdr, 16);
B
Benny Halevy 已提交
1731
	p = xdr_encode_hyper(p, args->offset);
B
Benny Halevy 已提交
1732
	*p++ = cpu_to_be32(args->stable);
1733
	*p = cpu_to_be32(args->count);
L
Linus Torvalds 已提交
1734 1735 1736 1737

	xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
}

1738
static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1739
{
T
Trond Myklebust 已提交
1740
	encode_op_hdr(xdr, OP_DELEGRETURN, decode_delegreturn_maxsz, hdr);
1741
	encode_nfs4_stateid(xdr, stateid);
L
Linus Torvalds 已提交
1742
}
1743

B
Bryan Schumaker 已提交
1744 1745
static void encode_secinfo(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
{
T
Trond Myklebust 已提交
1746
	encode_op_hdr(xdr, OP_SECINFO, decode_secinfo_maxsz, hdr);
1747
	encode_string(xdr, name->len, name->name);
B
Bryan Schumaker 已提交
1748 1749
}

B
Benny Halevy 已提交
1750
#if defined(CONFIG_NFS_V4_1)
1751
/* NFSv4.1 operations */
1752
static void encode_bind_conn_to_session(struct xdr_stream *xdr,
1753
				   struct nfs41_bind_conn_to_session_args *args,
1754 1755 1756 1757 1758 1759
				   struct compound_hdr *hdr)
{
	__be32 *p;

	encode_op_hdr(xdr, OP_BIND_CONN_TO_SESSION,
		decode_bind_conn_to_session_maxsz, hdr);
1760
	encode_opaque_fixed(xdr, args->sessionid.data, NFS4_MAX_SESSIONID_LEN);
1761
	p = xdr_reserve_space(xdr, 8);
1762 1763
	*p++ = cpu_to_be32(args->dir);
	*p = (args->use_conn_in_rdma_mode) ? cpu_to_be32(1) : cpu_to_be32(0);
1764 1765
}

1766 1767 1768 1769 1770 1771 1772 1773
static void encode_op_map(struct xdr_stream *xdr, struct nfs4_op_map *op_map)
{
	unsigned int i;
	encode_uint32(xdr, NFS4_OP_MAP_NUM_WORDS);
	for (i = 0; i < NFS4_OP_MAP_NUM_WORDS; i++)
		encode_uint32(xdr, op_map->u.words[i]);
}

B
Benny Halevy 已提交
1774 1775 1776 1777 1778
static void encode_exchange_id(struct xdr_stream *xdr,
			       struct nfs41_exchange_id_args *args,
			       struct compound_hdr *hdr)
{
	__be32 *p;
1779
	char impl_name[IMPL_NAME_LIMIT];
1780
	int len = 0;
B
Benny Halevy 已提交
1781

1782
	encode_op_hdr(xdr, OP_EXCHANGE_ID, decode_exchange_id_maxsz, hdr);
1783
	encode_nfs4_verifier(xdr, args->verifier);
B
Benny Halevy 已提交
1784

1785 1786
	encode_string(xdr, strlen(args->client->cl_owner_id),
			args->client->cl_owner_id);
B
Benny Halevy 已提交
1787

1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801
	encode_uint32(xdr, args->flags);
	encode_uint32(xdr, args->state_protect.how);

	switch (args->state_protect.how) {
	case SP4_NONE:
		break;
	case SP4_MACH_CRED:
		encode_op_map(xdr, &args->state_protect.enforce);
		encode_op_map(xdr, &args->state_protect.allow);
		break;
	default:
		WARN_ON_ONCE(1);
		break;
	}
1802 1803 1804 1805

	if (send_implementation_id &&
	    sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) > 1 &&
	    sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN)
1806
		<= sizeof(impl_name) + 1)
1807 1808 1809 1810 1811
		len = snprintf(impl_name, sizeof(impl_name), "%s %s %s %s",
			       utsname()->sysname, utsname()->release,
			       utsname()->version, utsname()->machine);

	if (len > 0) {
1812
		encode_uint32(xdr, 1);	/* implementation id array length=1 */
1813 1814 1815 1816 1817 1818 1819 1820 1821 1822

		encode_string(xdr,
			sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) - 1,
			CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN);
		encode_string(xdr, len, impl_name);
		/* just send zeros for nii_date - the date is in nii_name */
		p = reserve_space(xdr, 12);
		p = xdr_encode_hyper(p, 0);
		*p = cpu_to_be32(0);
	} else
1823
		encode_uint32(xdr, 0);	/* implementation id array length=0 */
B
Benny Halevy 已提交
1824
}
A
Andy Adamson 已提交
1825 1826 1827 1828 1829 1830 1831

static void encode_create_session(struct xdr_stream *xdr,
				  struct nfs41_create_session_args *args,
				  struct compound_hdr *hdr)
{
	__be32 *p;
	struct nfs_client *clp = args->client;
1832
	struct rpc_clnt *clnt = clp->cl_rpcclient;
1833
	struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
1834 1835 1836 1837 1838 1839 1840 1841
	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 已提交
1842

T
Trond Myklebust 已提交
1843
	encode_op_hdr(xdr, OP_CREATE_SESSION, decode_create_session_maxsz, hdr);
1844
	p = reserve_space(xdr, 16 + 2*28 + 20 + clnt->cl_nodelen + 12);
1845 1846
	p = xdr_encode_hyper(p, args->clientid);
	*p++ = cpu_to_be32(args->seqid);			/*Sequence id */
B
Benny Halevy 已提交
1847
	*p++ = cpu_to_be32(args->flags);			/*flags */
A
Andy Adamson 已提交
1848 1849

	/* Fore Channel */
1850
	*p++ = cpu_to_be32(0);				/* header padding size */
B
Benny Halevy 已提交
1851 1852
	*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 */
1853
	*p++ = cpu_to_be32(max_resp_sz_cached);		/* Max resp sz cached */
B
Benny Halevy 已提交
1854 1855 1856
	*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 已提交
1857 1858

	/* Back Channel */
1859
	*p++ = cpu_to_be32(0);				/* header padding size */
B
Benny Halevy 已提交
1860 1861 1862 1863 1864 1865
	*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 已提交
1866

B
Benny Halevy 已提交
1867 1868 1869
	*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 已提交
1870 1871

	/* authsys_parms rfc1831 */
1872
	*p++ = cpu_to_be32(ktime_to_ns(nn->boot_time));	/* stamp */
1873
	p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen);
B
Benny Halevy 已提交
1874 1875
	*p++ = cpu_to_be32(0);				/* UID */
	*p++ = cpu_to_be32(0);				/* GID */
1876
	*p = cpu_to_be32(0);				/* No more gids */
A
Andy Adamson 已提交
1877
}
A
Andy Adamson 已提交
1878 1879 1880 1881 1882

static void encode_destroy_session(struct xdr_stream *xdr,
				   struct nfs4_session *session,
				   struct compound_hdr *hdr)
{
T
Trond Myklebust 已提交
1883 1884
	encode_op_hdr(xdr, OP_DESTROY_SESSION, decode_destroy_session_maxsz, hdr);
	encode_opaque_fixed(xdr, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
A
Andy Adamson 已提交
1885
}
1886

T
Trond Myklebust 已提交
1887 1888 1889 1890 1891 1892 1893 1894
static void encode_destroy_clientid(struct xdr_stream *xdr,
				   uint64_t clientid,
				   struct compound_hdr *hdr)
{
	encode_op_hdr(xdr, OP_DESTROY_CLIENTID, decode_destroy_clientid_maxsz, hdr);
	encode_uint64(xdr, clientid);
}

1895 1896 1897 1898
static void encode_reclaim_complete(struct xdr_stream *xdr,
				    struct nfs41_reclaim_complete_args *args,
				    struct compound_hdr *hdr)
{
T
Trond Myklebust 已提交
1899 1900
	encode_op_hdr(xdr, OP_RECLAIM_COMPLETE, decode_reclaim_complete_maxsz, hdr);
	encode_uint32(xdr, args->one_fs);
1901
}
B
Benny Halevy 已提交
1902 1903
#endif /* CONFIG_NFS_V4_1 */

1904 1905 1906 1907 1908
static void encode_sequence(struct xdr_stream *xdr,
			    const struct nfs4_sequence_args *args,
			    struct compound_hdr *hdr)
{
#if defined(CONFIG_NFS_V4_1)
1909
	struct nfs4_session *session;
A
Andy Adamson 已提交
1910
	struct nfs4_slot_table *tp;
1911
	struct nfs4_slot *slot = args->sa_slot;
A
Andy Adamson 已提交
1912
	__be32 *p;
1913

1914 1915
	tp = slot->table;
	session = tp->session;
C
Chuck Lever 已提交
1916 1917
	if (!session)
		return;
A
Andy Adamson 已提交
1918

T
Trond Myklebust 已提交
1919
	encode_op_hdr(xdr, OP_SEQUENCE, decode_sequence_maxsz, hdr);
A
Andy Adamson 已提交
1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930

	/*
	 * 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],
1931
		slot->seq_nr, slot->slot_nr,
A
Andy Adamson 已提交
1932
		tp->highest_used_slotid, args->sa_cache_this);
T
Trond Myklebust 已提交
1933
	p = reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 16);
B
Benny Halevy 已提交
1934
	p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
B
Benny Halevy 已提交
1935
	*p++ = cpu_to_be32(slot->seq_nr);
1936
	*p++ = cpu_to_be32(slot->slot_nr);
B
Benny Halevy 已提交
1937
	*p++ = cpu_to_be32(tp->highest_used_slotid);
1938
	*p = cpu_to_be32(args->sa_cache_this);
1939 1940 1941
#endif /* CONFIG_NFS_V4_1 */
}

1942 1943 1944 1945 1946 1947 1948 1949
#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;

T
Trond Myklebust 已提交
1950
	encode_op_hdr(xdr, OP_GETDEVICEINFO, decode_getdeviceinfo_maxsz, hdr);
1951
	p = reserve_space(xdr, NFS4_DEVICEID4_SIZE + 4 + 4);
1952 1953 1954
	p = xdr_encode_opaque_fixed(p, args->pdev->dev_id.data,
				    NFS4_DEVICEID4_SIZE);
	*p++ = cpu_to_be32(args->pdev->layout_type);
1955
	*p++ = cpu_to_be32(args->pdev->maxcount);	/* gdia_maxcount */
1956 1957 1958

	p = reserve_space(xdr, 4 + 4);
	*p++ = cpu_to_be32(1);			/* bitmap length */
1959
	*p++ = cpu_to_be32(args->notify_types);
1960 1961 1962 1963 1964 1965 1966 1967 1968
}

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

T
Trond Myklebust 已提交
1969 1970
	encode_op_hdr(xdr, OP_LAYOUTGET, decode_layoutget_maxsz, hdr);
	p = reserve_space(xdr, 36);
1971 1972 1973 1974 1975 1976
	*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);
1977
	encode_nfs4_stateid(xdr, &args->stateid);
T
Trond Myklebust 已提交
1978
	encode_uint32(xdr, args->maxcount);
1979 1980 1981 1982 1983 1984 1985 1986 1987

	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);
}
A
Andy Adamson 已提交
1988 1989 1990

static int
encode_layoutcommit(struct xdr_stream *xdr,
B
Benny Halevy 已提交
1991
		    struct inode *inode,
1992
		    struct nfs4_layoutcommit_args *args,
A
Andy Adamson 已提交
1993 1994 1995 1996 1997 1998 1999
		    struct compound_hdr *hdr)
{
	__be32 *p;

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

T
Trond Myklebust 已提交
2000 2001
	encode_op_hdr(xdr, OP_LAYOUTCOMMIT, decode_layoutcommit_maxsz, hdr);
	p = reserve_space(xdr, 20);
A
Andy Adamson 已提交
2002 2003
	/* Only whole file layouts */
	p = xdr_encode_hyper(p, 0); /* offset */
P
Peng Tao 已提交
2004
	p = xdr_encode_hyper(p, args->lastbytewritten + 1);	/* length */
2005 2006
	*p = cpu_to_be32(0); /* reclaim */
	encode_nfs4_stateid(xdr, &args->stateid);
2007 2008 2009 2010 2011 2012 2013 2014
	if (args->lastbytewritten != U64_MAX) {
		p = reserve_space(xdr, 20);
		*p++ = cpu_to_be32(1); /* newoffset = TRUE */
		p = xdr_encode_hyper(p, args->lastbytewritten);
	} else {
		p = reserve_space(xdr, 12);
		*p++ = cpu_to_be32(0); /* newoffset = FALSE */
	}
A
Andy Adamson 已提交
2015 2016
	*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 已提交
2017

2018
	if (NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit) {
B
Benny Halevy 已提交
2019 2020
		NFS_SERVER(inode)->pnfs_curr_ld->encode_layoutcommit(
			NFS_I(inode)->layout, xdr, args);
2021 2022 2023 2024 2025 2026 2027
	} else {
		encode_uint32(xdr, args->layoutupdate_len);
		if (args->layoutupdate_pages) {
			xdr_write_pages(xdr, args->layoutupdate_pages, 0,
					args->layoutupdate_len);
		}
	}
A
Andy Adamson 已提交
2028 2029 2030

	return 0;
}
B
Benny Halevy 已提交
2031 2032 2033 2034 2035 2036

static void
encode_layoutreturn(struct xdr_stream *xdr,
		    const struct nfs4_layoutreturn_args *args,
		    struct compound_hdr *hdr)
{
2037
	const struct pnfs_layoutdriver_type *lr_ops = NFS_SERVER(args->inode)->pnfs_curr_ld;
B
Benny Halevy 已提交
2038 2039
	__be32 *p;

T
Trond Myklebust 已提交
2040 2041
	encode_op_hdr(xdr, OP_LAYOUTRETURN, decode_layoutreturn_maxsz, hdr);
	p = reserve_space(xdr, 16);
B
Benny Halevy 已提交
2042 2043
	*p++ = cpu_to_be32(0);		/* reclaim. always 0 for now */
	*p++ = cpu_to_be32(args->layout_type);
P
Peng Tao 已提交
2044
	*p++ = cpu_to_be32(args->range.iomode);
B
Benny Halevy 已提交
2045
	*p = cpu_to_be32(RETURN_FILE);
2046
	p = reserve_space(xdr, 16);
P
Peng Tao 已提交
2047 2048
	p = xdr_encode_hyper(p, args->range.offset);
	p = xdr_encode_hyper(p, args->range.length);
B
Benny Halevy 已提交
2049
	spin_lock(&args->inode->i_lock);
2050
	encode_nfs4_stateid(xdr, &args->stateid);
B
Benny Halevy 已提交
2051
	spin_unlock(&args->inode->i_lock);
2052 2053 2054
	if (args->ld_private->ops && args->ld_private->ops->encode)
		args->ld_private->ops->encode(xdr, args, args->ld_private);
	else if (lr_ops->encode_layoutreturn)
2055 2056
		lr_ops->encode_layoutreturn(xdr, args);
	else
T
Trond Myklebust 已提交
2057
		encode_uint32(xdr, 0);
B
Benny Halevy 已提交
2058
}
2059 2060 2061 2062 2063 2064

static int
encode_secinfo_no_name(struct xdr_stream *xdr,
		       const struct nfs41_secinfo_no_name_args *args,
		       struct compound_hdr *hdr)
{
T
Trond Myklebust 已提交
2065 2066
	encode_op_hdr(xdr, OP_SECINFO_NO_NAME, decode_secinfo_no_name_maxsz, hdr);
	encode_uint32(xdr, args->style);
2067 2068
	return 0;
}
B
Bryan Schumaker 已提交
2069 2070 2071 2072 2073

static void encode_test_stateid(struct xdr_stream *xdr,
				struct nfs41_test_stateid_args *args,
				struct compound_hdr *hdr)
{
T
Trond Myklebust 已提交
2074 2075
	encode_op_hdr(xdr, OP_TEST_STATEID, decode_test_stateid_maxsz, hdr);
	encode_uint32(xdr, 1);
2076
	encode_nfs4_stateid(xdr, args->stateid);
B
Bryan Schumaker 已提交
2077
}
B
Bryan Schumaker 已提交
2078 2079 2080 2081 2082

static void encode_free_stateid(struct xdr_stream *xdr,
				struct nfs41_free_stateid_args *args,
				struct compound_hdr *hdr)
{
T
Trond Myklebust 已提交
2083
	encode_op_hdr(xdr, OP_FREE_STATEID, decode_free_stateid_maxsz, hdr);
2084
	encode_nfs4_stateid(xdr, &args->stateid);
B
Bryan Schumaker 已提交
2085
}
2086 2087 2088 2089 2090 2091 2092
#else
static inline void
encode_layoutreturn(struct xdr_stream *xdr,
		    const struct nfs4_layoutreturn_args *args,
		    struct compound_hdr *hdr)
{
}
2093 2094
#endif /* CONFIG_NFS_V4_1 */

L
Linus Torvalds 已提交
2095 2096 2097 2098
/*
 * END OF "GENERIC" ENCODE ROUTINES.
 */

2099 2100 2101
static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args)
{
#if defined(CONFIG_NFS_V4_1)
C
Chuck Lever 已提交
2102 2103 2104
	struct nfs4_session *session = args->sa_slot->table->session;
	if (session)
		return session->clp->cl_mvops->minor_version;
2105 2106 2107 2108
#endif /* CONFIG_NFS_V4_1 */
	return 0;
}

L
Linus Torvalds 已提交
2109 2110 2111
/*
 * Encode an ACCESS request
 */
2112 2113
static void nfs4_xdr_enc_access(struct rpc_rqst *req, struct xdr_stream *xdr,
				const struct nfs4_accessargs *args)
L
Linus Torvalds 已提交
2114 2115
{
	struct compound_hdr hdr = {
2116
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2117 2118
	};

2119 2120 2121 2122 2123
	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);
2124
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2125 2126 2127 2128 2129
}

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

2137 2138 2139 2140 2141 2142
	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);
2143
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2144 2145 2146 2147 2148
}

/*
 * Encode LOOKUP_ROOT request
 */
2149 2150 2151
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 已提交
2152 2153
{
	struct compound_hdr hdr = {
2154
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2155 2156
	};

2157 2158 2159 2160 2161
	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);
2162
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2163 2164 2165 2166 2167
}

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

2175 2176 2177 2178
	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);
2179
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2180 2181 2182 2183 2184
}

/*
 * Encode RENAME request
 */
2185 2186
static void nfs4_xdr_enc_rename(struct rpc_rqst *req, struct xdr_stream *xdr,
				const struct nfs_renameargs *args)
L
Linus Torvalds 已提交
2187 2188
{
	struct compound_hdr hdr = {
2189
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2190 2191
	};

2192 2193 2194 2195 2196 2197
	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);
2198
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2199 2200 2201 2202 2203
}

/*
 * Encode LINK request
 */
2204 2205
static void nfs4_xdr_enc_link(struct rpc_rqst *req, struct xdr_stream *xdr,
			     const struct nfs4_link_arg *args)
L
Linus Torvalds 已提交
2206 2207
{
	struct compound_hdr hdr = {
2208
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2209 2210
	};

2211 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_savefh(xdr, &hdr);
	encode_putfh(xdr, args->dir_fh, &hdr);
	encode_link(xdr, args->name, &hdr);
	encode_restorefh(xdr, &hdr);
	encode_getfattr(xdr, args->bitmask, &hdr);
2219
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2220 2221 2222 2223 2224
}

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

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

/*
 * Encode SYMLINK request
 */
2244 2245
static void nfs4_xdr_enc_symlink(struct rpc_rqst *req, struct xdr_stream *xdr,
				 const struct nfs4_create_arg *args)
L
Linus Torvalds 已提交
2246
{
2247
	nfs4_xdr_enc_create(req, xdr, args);
L
Linus Torvalds 已提交
2248 2249 2250 2251 2252
}

/*
 * Encode GETATTR request
 */
2253 2254
static void nfs4_xdr_enc_getattr(struct rpc_rqst *req, struct xdr_stream *xdr,
				 const struct nfs4_getattr_arg *args)
L
Linus Torvalds 已提交
2255 2256
{
	struct compound_hdr hdr = {
2257
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2258 2259
	};

2260 2261 2262 2263
	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);
2264
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2265 2266 2267 2268 2269
}

/*
 * Encode a CLOSE request
 */
2270 2271
static void nfs4_xdr_enc_close(struct rpc_rqst *req, struct xdr_stream *xdr,
			       struct nfs_closeargs *args)
L
Linus Torvalds 已提交
2272
{
A
Andy Adamson 已提交
2273
	struct compound_hdr hdr = {
2274
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
A
Andy Adamson 已提交
2275 2276
	};

2277 2278 2279
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
2280 2281
	if (args->lr_args)
		encode_layoutreturn(xdr, args->lr_args, &hdr);
2282
	encode_close(xdr, args, &hdr);
2283 2284
	if (args->bitmask != NULL)
		encode_getfattr(xdr, args->bitmask, &hdr);
2285
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2286 2287 2288 2289 2290
}

/*
 * Encode an OPEN request
 */
2291 2292
static void nfs4_xdr_enc_open(struct rpc_rqst *req, struct xdr_stream *xdr,
			      struct nfs_openargs *args)
L
Linus Torvalds 已提交
2293 2294
{
	struct compound_hdr hdr = {
2295
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2296 2297
	};

2298 2299 2300 2301 2302
	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_getfh(xdr, &hdr);
2303 2304
	if (args->access)
		encode_access(xdr, args->access, &hdr);
2305
	encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr);
2306
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2307 2308 2309 2310 2311
}

/*
 * Encode an OPEN_CONFIRM request
 */
2312 2313 2314
static void nfs4_xdr_enc_open_confirm(struct rpc_rqst *req,
				      struct xdr_stream *xdr,
				      struct nfs_open_confirmargs *args)
L
Linus Torvalds 已提交
2315 2316
{
	struct compound_hdr hdr = {
2317
		.nops   = 0,
L
Linus Torvalds 已提交
2318 2319
	};

2320 2321 2322
	encode_compound_hdr(xdr, req, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_open_confirm(xdr, args, &hdr);
2323
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2324 2325 2326 2327 2328
}

/*
 * Encode an OPEN request with no attributes.
 */
2329 2330 2331
static void nfs4_xdr_enc_open_noattr(struct rpc_rqst *req,
				     struct xdr_stream *xdr,
				     struct nfs_openargs *args)
L
Linus Torvalds 已提交
2332 2333
{
	struct compound_hdr hdr = {
2334
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2335 2336
	};

2337 2338 2339 2340
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_open(xdr, args, &hdr);
2341 2342
	if (args->access)
		encode_access(xdr, args->access, &hdr);
2343
	encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr);
2344
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2345 2346 2347 2348 2349
}

/*
 * Encode an OPEN_DOWNGRADE request
 */
2350 2351 2352
static void nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req,
					struct xdr_stream *xdr,
					struct nfs_closeargs *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
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
2361 2362
	if (args->lr_args)
		encode_layoutreturn(xdr, args->lr_args, &hdr);
2363
	encode_open_downgrade(xdr, args, &hdr);
2364
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2365 2366 2367 2368 2369
}

/*
 * Encode a LOCK request
 */
2370 2371
static void nfs4_xdr_enc_lock(struct rpc_rqst *req, struct xdr_stream *xdr,
			      struct nfs_lock_args *args)
L
Linus Torvalds 已提交
2372 2373
{
	struct compound_hdr hdr = {
2374
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2375 2376
	};

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

/*
 * Encode a LOCKT request
 */
2387 2388
static void nfs4_xdr_enc_lockt(struct rpc_rqst *req, struct xdr_stream *xdr,
			       struct nfs_lockt_args *args)
L
Linus Torvalds 已提交
2389 2390
{
	struct compound_hdr hdr = {
2391
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2392 2393
	};

2394 2395 2396 2397
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_lockt(xdr, args, &hdr);
2398
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2399 2400 2401 2402 2403
}

/*
 * Encode a LOCKU request
 */
2404 2405
static void nfs4_xdr_enc_locku(struct rpc_rqst *req, struct xdr_stream *xdr,
			       struct nfs_locku_args *args)
L
Linus Torvalds 已提交
2406 2407
{
	struct compound_hdr hdr = {
2408
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2409 2410
	};

2411 2412 2413 2414
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_locku(xdr, args, &hdr);
2415
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2416 2417
}

2418 2419 2420
static void nfs4_xdr_enc_release_lockowner(struct rpc_rqst *req,
					   struct xdr_stream *xdr,
					struct nfs_release_lockowner_args *args)
2421 2422 2423 2424 2425
{
	struct compound_hdr hdr = {
		.minorversion = 0,
	};

2426 2427
	encode_compound_hdr(xdr, req, &hdr);
	encode_release_lockowner(xdr, &args->lock_owner, &hdr);
2428 2429 2430
	encode_nops(&hdr);
}

L
Linus Torvalds 已提交
2431 2432 2433
/*
 * Encode a READLINK request
 */
2434 2435
static void nfs4_xdr_enc_readlink(struct rpc_rqst *req, struct xdr_stream *xdr,
				  const struct nfs4_readlink *args)
L
Linus Torvalds 已提交
2436 2437
{
	struct compound_hdr hdr = {
2438
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2439 2440
	};

2441 2442 2443 2444
	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);
2445

2446
	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
2447
			args->pgbase, args->pglen);
2448
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2449 2450 2451 2452 2453
}

/*
 * Encode a READDIR request
 */
2454 2455
static void nfs4_xdr_enc_readdir(struct rpc_rqst *req, struct xdr_stream *xdr,
				 const struct nfs4_readdir_arg *args)
L
Linus Torvalds 已提交
2456 2457
{
	struct compound_hdr hdr = {
2458
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2459 2460
	};

2461 2462 2463 2464
	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);
2465

2466
	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
2467 2468
			 args->pgbase, args->count);
	dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
2469
			__func__, hdr.replen << 2, args->pages,
2470
			args->pgbase, args->count);
2471
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2472 2473 2474 2475 2476
}

/*
 * Encode a READ request
 */
2477
static void nfs4_xdr_enc_read(struct rpc_rqst *req, struct xdr_stream *xdr,
2478
			      struct nfs_pgio_args *args)
L
Linus Torvalds 已提交
2479 2480
{
	struct compound_hdr hdr = {
2481
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2482 2483
	};

2484 2485 2486 2487
	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 已提交
2488

2489
	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2,
L
Linus Torvalds 已提交
2490
			 args->pages, args->pgbase, args->count);
2491
	req->rq_rcv_buf.flags |= XDRBUF_READ;
2492
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2493 2494 2495 2496 2497
}

/*
 * Encode an SETATTR request
 */
2498 2499
static void nfs4_xdr_enc_setattr(struct rpc_rqst *req, struct xdr_stream *xdr,
				 struct nfs_setattrargs *args)
L
Linus Torvalds 已提交
2500
{
A
Andy Adamson 已提交
2501
	struct compound_hdr hdr = {
2502
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
A
Andy Adamson 已提交
2503 2504
	};

2505 2506 2507 2508 2509
	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);
2510
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2511 2512
}

2513 2514 2515
/*
 * Encode a GETACL request
 */
2516 2517
static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
				struct nfs_getaclargs *args)
2518 2519
{
	struct compound_hdr hdr = {
2520
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
2521
	};
2522
	uint32_t replen;
2523

2524 2525 2526
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
2527
	replen = hdr.replen + op_decode_hdr_maxsz + 1;
2528
	encode_getattr_two(xdr, FATTR4_WORD0_ACL, 0, &hdr);
2529

2530
	xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
2531
		args->acl_pages, 0, args->acl_len);
2532

2533
	encode_nops(&hdr);
2534 2535
}

L
Linus Torvalds 已提交
2536 2537 2538
/*
 * Encode a WRITE request
 */
2539
static void nfs4_xdr_enc_write(struct rpc_rqst *req, struct xdr_stream *xdr,
2540
			       struct nfs_pgio_args *args)
L
Linus Torvalds 已提交
2541 2542
{
	struct compound_hdr hdr = {
2543
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2544 2545
	};

2546 2547 2548 2549
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_write(xdr, args, &hdr);
2550
	req->rq_snd_buf.flags |= XDRBUF_WRITE;
2551 2552
	if (args->bitmask)
		encode_getfattr(xdr, args->bitmask, &hdr);
2553
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2554 2555 2556 2557 2558
}

/*
 *  a COMMIT request
 */
2559
static void nfs4_xdr_enc_commit(struct rpc_rqst *req, struct xdr_stream *xdr,
2560
				struct nfs_commitargs *args)
L
Linus Torvalds 已提交
2561 2562
{
	struct compound_hdr hdr = {
2563
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2564 2565
	};

2566 2567 2568 2569
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_commit(xdr, args, &hdr);
2570
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2571 2572 2573 2574 2575
}

/*
 * FSINFO request
 */
2576 2577
static void nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, struct xdr_stream *xdr,
				struct nfs4_fsinfo_arg *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
	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);
2587
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2588 2589 2590 2591 2592
}

/*
 * a PATHCONF request
 */
2593 2594
static void nfs4_xdr_enc_pathconf(struct rpc_rqst *req, struct xdr_stream *xdr,
				  const struct nfs4_pathconf_arg *args)
L
Linus Torvalds 已提交
2595 2596
{
	struct compound_hdr hdr = {
2597
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2598 2599
	};

2600 2601 2602 2603
	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],
2604
			   &hdr);
2605
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2606 2607 2608 2609 2610
}

/*
 * a STATFS request
 */
2611 2612
static void nfs4_xdr_enc_statfs(struct rpc_rqst *req, struct xdr_stream *xdr,
				const struct nfs4_statfs_arg *args)
L
Linus Torvalds 已提交
2613 2614
{
	struct compound_hdr hdr = {
2615
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2616 2617
	};

2618 2619 2620 2621
	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],
2622
			   args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr);
2623
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2624 2625 2626 2627 2628
}

/*
 * GETATTR_BITMAP request
 */
2629 2630 2631
static void nfs4_xdr_enc_server_caps(struct rpc_rqst *req,
				     struct xdr_stream *xdr,
				     struct nfs4_server_caps_arg *args)
L
Linus Torvalds 已提交
2632
{
2633
	const u32 *bitmask = args->bitmask;
L
Linus Torvalds 已提交
2634
	struct compound_hdr hdr = {
2635
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2636 2637
	};

2638 2639 2640
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fhandle, &hdr);
2641
	encode_getattr_three(xdr, bitmask[0], bitmask[1], bitmask[2], &hdr);
2642
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2643 2644 2645 2646 2647
}

/*
 * a RENEW request
 */
2648 2649
static void nfs4_xdr_enc_renew(struct rpc_rqst *req, struct xdr_stream *xdr,
			       struct nfs_client *clp)
L
Linus Torvalds 已提交
2650 2651
{
	struct compound_hdr hdr = {
2652
		.nops	= 0,
L
Linus Torvalds 已提交
2653 2654
	};

2655
	encode_compound_hdr(xdr, req, &hdr);
2656
	encode_renew(xdr, clp->cl_clientid, &hdr);
2657
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2658 2659 2660 2661 2662
}

/*
 * a SETCLIENTID request
 */
2663 2664 2665
static void nfs4_xdr_enc_setclientid(struct rpc_rqst *req,
				     struct xdr_stream *xdr,
				     struct nfs4_setclientid *sc)
L
Linus Torvalds 已提交
2666 2667
{
	struct compound_hdr hdr = {
2668
		.nops	= 0,
L
Linus Torvalds 已提交
2669 2670
	};

2671 2672
	encode_compound_hdr(xdr, req, &hdr);
	encode_setclientid(xdr, sc, &hdr);
2673
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2674 2675 2676 2677 2678
}

/*
 * a SETCLIENTID_CONFIRM request
 */
2679 2680 2681
static void nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req,
					     struct xdr_stream *xdr,
					     struct nfs4_setclientid_res *arg)
L
Linus Torvalds 已提交
2682 2683
{
	struct compound_hdr hdr = {
2684
		.nops	= 0,
L
Linus Torvalds 已提交
2685 2686
	};

2687 2688
	encode_compound_hdr(xdr, req, &hdr);
	encode_setclientid_confirm(xdr, arg, &hdr);
2689
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2690 2691 2692 2693 2694
}

/*
 * DELEGRETURN request
 */
2695 2696 2697
static void nfs4_xdr_enc_delegreturn(struct rpc_rqst *req,
				     struct xdr_stream *xdr,
				     const struct nfs4_delegreturnargs *args)
L
Linus Torvalds 已提交
2698 2699
{
	struct compound_hdr hdr = {
2700
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2701 2702
	};

2703 2704 2705
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fhandle, &hdr);
2706 2707
	if (args->lr_args)
		encode_layoutreturn(xdr, args->lr_args, &hdr);
2708
	encode_getfattr(xdr, args->bitmask, &hdr);
2709
	encode_delegreturn(xdr, args->stateid, &hdr);
2710
	encode_nops(&hdr);
L
Linus Torvalds 已提交
2711 2712
}

2713 2714 2715
/*
 * Encode FS_LOCATIONS request
 */
2716 2717 2718
static void nfs4_xdr_enc_fs_locations(struct rpc_rqst *req,
				      struct xdr_stream *xdr,
				      struct nfs4_fs_locations_arg *args)
2719 2720
{
	struct compound_hdr hdr = {
2721
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
2722
	};
2723
	uint32_t replen;
2724

2725 2726
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738
	if (args->migration) {
		encode_putfh(xdr, args->fh, &hdr);
		replen = hdr.replen;
		encode_fs_locations(xdr, args->bitmask, &hdr);
		if (args->renew)
			encode_renew(xdr, args->clientid, &hdr);
	} else {
		encode_putfh(xdr, args->dir_fh, &hdr);
		encode_lookup(xdr, args->name, &hdr);
		replen = hdr.replen;
		encode_fs_locations(xdr, args->bitmask, &hdr);
	}
2739

2740
	/* Set up reply kvec to capture returned fs_locations array. */
2741
	xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page,
2742
			0, PAGE_SIZE);
2743
	encode_nops(&hdr);
2744 2745
}

B
Bryan Schumaker 已提交
2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763
/*
 * 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);
}

2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783
/*
 * Encode FSID_PRESENT request
 */
static void nfs4_xdr_enc_fsid_present(struct rpc_rqst *req,
				      struct xdr_stream *xdr,
				      struct nfs4_fsid_present_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->fh, &hdr);
	encode_getfh(xdr, &hdr);
	if (args->renew)
		encode_renew(xdr, args->clientid, &hdr);
	encode_nops(&hdr);
}

B
Benny Halevy 已提交
2784
#if defined(CONFIG_NFS_V4_1)
2785 2786 2787 2788 2789
/*
 * BIND_CONN_TO_SESSION request
 */
static void nfs4_xdr_enc_bind_conn_to_session(struct rpc_rqst *req,
				struct xdr_stream *xdr,
2790
				struct nfs41_bind_conn_to_session_args *args)
2791 2792
{
	struct compound_hdr hdr = {
2793
		.minorversion = args->client->cl_mvops->minor_version,
2794 2795 2796
	};

	encode_compound_hdr(xdr, req, &hdr);
2797
	encode_bind_conn_to_session(xdr, args, &hdr);
2798 2799 2800
	encode_nops(&hdr);
}

B
Benny Halevy 已提交
2801 2802 2803
/*
 * EXCHANGE_ID request
 */
2804 2805 2806
static void nfs4_xdr_enc_exchange_id(struct rpc_rqst *req,
				     struct xdr_stream *xdr,
				     struct nfs41_exchange_id_args *args)
B
Benny Halevy 已提交
2807 2808
{
	struct compound_hdr hdr = {
2809
		.minorversion = args->client->cl_mvops->minor_version,
B
Benny Halevy 已提交
2810 2811
	};

2812 2813
	encode_compound_hdr(xdr, req, &hdr);
	encode_exchange_id(xdr, args, &hdr);
B
Benny Halevy 已提交
2814 2815
	encode_nops(&hdr);
}
A
Andy Adamson 已提交
2816

A
Andy Adamson 已提交
2817 2818 2819
/*
 * a CREATE_SESSION request
 */
2820 2821 2822
static void nfs4_xdr_enc_create_session(struct rpc_rqst *req,
					struct xdr_stream *xdr,
					struct nfs41_create_session_args *args)
A
Andy Adamson 已提交
2823 2824
{
	struct compound_hdr hdr = {
2825
		.minorversion = args->client->cl_mvops->minor_version,
A
Andy Adamson 已提交
2826 2827
	};

2828 2829
	encode_compound_hdr(xdr, req, &hdr);
	encode_create_session(xdr, args, &hdr);
A
Andy Adamson 已提交
2830 2831 2832
	encode_nops(&hdr);
}

A
Andy Adamson 已提交
2833 2834 2835
/*
 * a DESTROY_SESSION request
 */
2836 2837 2838
static void nfs4_xdr_enc_destroy_session(struct rpc_rqst *req,
					 struct xdr_stream *xdr,
					 struct nfs4_session *session)
A
Andy Adamson 已提交
2839 2840
{
	struct compound_hdr hdr = {
2841
		.minorversion = session->clp->cl_mvops->minor_version,
A
Andy Adamson 已提交
2842 2843
	};

2844 2845
	encode_compound_hdr(xdr, req, &hdr);
	encode_destroy_session(xdr, session, &hdr);
A
Andy Adamson 已提交
2846 2847 2848
	encode_nops(&hdr);
}

T
Trond Myklebust 已提交
2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864
/*
 * a DESTROY_CLIENTID request
 */
static void nfs4_xdr_enc_destroy_clientid(struct rpc_rqst *req,
					 struct xdr_stream *xdr,
					 struct nfs_client *clp)
{
	struct compound_hdr hdr = {
		.minorversion = clp->cl_mvops->minor_version,
	};

	encode_compound_hdr(xdr, req, &hdr);
	encode_destroy_clientid(xdr, clp->cl_clientid, &hdr);
	encode_nops(&hdr);
}

A
Andy Adamson 已提交
2865 2866 2867
/*
 * a SEQUENCE request
 */
2868 2869
static void nfs4_xdr_enc_sequence(struct rpc_rqst *req, struct xdr_stream *xdr,
				  struct nfs4_sequence_args *args)
A
Andy Adamson 已提交
2870 2871 2872 2873 2874
{
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(args),
	};

2875 2876
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, args, &hdr);
A
Andy Adamson 已提交
2877 2878 2879
	encode_nops(&hdr);
}

A
Andy Adamson 已提交
2880 2881 2882
/*
 * a GET_LEASE_TIME request
 */
2883 2884 2885
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 已提交
2886 2887 2888 2889
{
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->la_seq_args),
	};
2890
	const u32 lease_bitmap[3] = { FATTR4_WORD0_LEASE_TIME };
A
Andy Adamson 已提交
2891

2892 2893 2894 2895
	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 已提交
2896 2897
	encode_nops(&hdr);
}
2898 2899 2900 2901

/*
 * a RECLAIM_COMPLETE request
 */
2902 2903 2904
static void nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req,
					  struct xdr_stream *xdr,
				struct nfs41_reclaim_complete_args *args)
2905 2906 2907 2908 2909
{
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args)
	};

2910 2911 2912
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_reclaim_complete(xdr, args, &hdr);
2913 2914 2915
	encode_nops(&hdr);
}

2916 2917 2918
/*
 * Encode GETDEVICEINFO request
 */
2919 2920 2921
static void nfs4_xdr_enc_getdeviceinfo(struct rpc_rqst *req,
				       struct xdr_stream *xdr,
				       struct nfs4_getdeviceinfo_args *args)
2922 2923 2924 2925 2926
{
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

2927 2928 2929
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_getdeviceinfo(xdr, args, &hdr);
2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942

	/* 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
 */
2943 2944 2945
static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req,
				   struct xdr_stream *xdr,
				   struct nfs4_layoutget_args *args)
2946 2947 2948 2949 2950
{
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
	};

2951 2952 2953 2954
	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);
2955 2956 2957 2958

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

2959 2960
	encode_nops(&hdr);
}
A
Andy Adamson 已提交
2961 2962 2963 2964

/*
 *  Encode LAYOUTCOMMIT request
 */
B
Benny Halevy 已提交
2965 2966 2967
static void nfs4_xdr_enc_layoutcommit(struct rpc_rqst *req,
				      struct xdr_stream *xdr,
				      struct nfs4_layoutcommit_args *args)
A
Andy Adamson 已提交
2968
{
B
Benny Halevy 已提交
2969 2970
	struct nfs4_layoutcommit_data *data =
		container_of(args, struct nfs4_layoutcommit_data, args);
A
Andy Adamson 已提交
2971 2972 2973 2974 2975 2976 2977
	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 已提交
2978
	encode_layoutcommit(xdr, data->args.inode, args, &hdr);
A
Andy Adamson 已提交
2979
	encode_getfattr(xdr, args->bitmask, &hdr);
2980
	encode_nops(&hdr);
B
Benny Halevy 已提交
2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998
}

/*
 * 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);
2999
}
3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018

/*
 * 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
Bryan Schumaker 已提交
3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035

/*
 *  Encode TEST_STATEID request
 */
static void nfs4_xdr_enc_test_stateid(struct rpc_rqst *req,
				      struct xdr_stream *xdr,
				      struct nfs41_test_stateid_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_test_stateid(xdr, args, &hdr);
	encode_nops(&hdr);
}
B
Bryan Schumaker 已提交
3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052

/*
 *  Encode FREE_STATEID request
 */
static void nfs4_xdr_enc_free_stateid(struct rpc_rqst *req,
				     struct xdr_stream *xdr,
				     struct nfs41_free_stateid_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_free_stateid(xdr, args, &hdr);
	encode_nops(&hdr);
}
B
Benny Halevy 已提交
3053 3054
#endif /* CONFIG_NFS_V4_1 */

3055 3056 3057 3058 3059 3060
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 已提交
3061

3062
static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
L
Linus Torvalds 已提交
3063
{
A
Al Viro 已提交
3064
	__be32 *p;
L
Linus Torvalds 已提交
3065

B
Benny Halevy 已提交
3066 3067 3068
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
3069
	*len = be32_to_cpup(p);
B
Benny Halevy 已提交
3070 3071 3072
	p = xdr_inline_decode(xdr, *len);
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
3073 3074
	*string = (char *)p;
	return 0;
B
Benny Halevy 已提交
3075 3076 3077
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3078 3079 3080 3081
}

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

B
Benny Halevy 已提交
3084 3085 3086
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3087
	hdr->status = be32_to_cpup(p++);
3088
	hdr->taglen = be32_to_cpup(p);
3089

B
Benny Halevy 已提交
3090 3091 3092
	p = xdr_inline_decode(xdr, hdr->taglen + 4);
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
3093 3094
	hdr->tag = (char *)p;
	p += XDR_QUADLEN(hdr->taglen);
3095
	hdr->nops = be32_to_cpup(p);
3096 3097
	if (unlikely(hdr->nops < 1))
		return nfs4_stat_to_errno(hdr->status);
L
Linus Torvalds 已提交
3098
	return 0;
B
Benny Halevy 已提交
3099 3100 3101
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3102 3103
}

3104 3105
static bool __decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected,
		int *nfs_retval)
L
Linus Torvalds 已提交
3106
{
A
Al Viro 已提交
3107
	__be32 *p;
L
Linus Torvalds 已提交
3108 3109 3110
	uint32_t opnum;
	int32_t nfserr;

B
Benny Halevy 已提交
3111 3112 3113
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3114
	opnum = be32_to_cpup(p++);
3115 3116
	if (unlikely(opnum != expected))
		goto out_bad_operation;
3117
	nfserr = be32_to_cpup(p);
3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128
	if (nfserr == NFS_OK)
		*nfs_retval = 0;
	else
		*nfs_retval = nfs4_stat_to_errno(nfserr);
	return true;
out_bad_operation:
	dprintk("nfs: Server returned operation"
		" %d but we issued a request for %d\n",
			opnum, expected);
	*nfs_retval = -EREMOTEIO;
	return false;
B
Benny Halevy 已提交
3129 3130
out_overflow:
	print_overflow_msg(__func__, xdr);
3131 3132 3133 3134 3135 3136 3137 3138 3139 3140
	*nfs_retval = -EIO;
	return false;
}

static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
{
	int retval;

	__decode_op_hdr(xdr, expected, &retval);
	return retval;
L
Linus Torvalds 已提交
3141 3142 3143
}

/* Dummy routine */
3144
static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp)
L
Linus Torvalds 已提交
3145
{
A
Al Viro 已提交
3146
	__be32 *p;
3147
	unsigned int strlen;
L
Linus Torvalds 已提交
3148 3149
	char *str;

B
Benny Halevy 已提交
3150 3151 3152 3153 3154
	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 已提交
3155 3156 3157 3158
}

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

B
Benny Halevy 已提交
3162 3163 3164
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
3165
	bmlen = be32_to_cpup(p);
L
Linus Torvalds 已提交
3166

3167
	bitmap[0] = bitmap[1] = bitmap[2] = 0;
B
Benny Halevy 已提交
3168 3169 3170
	p = xdr_inline_decode(xdr, (bmlen << 2));
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
3171
	if (bmlen > 0) {
B
Benny Halevy 已提交
3172
		bitmap[0] = be32_to_cpup(p++);
3173 3174 3175 3176 3177
		if (bmlen > 1) {
			bitmap[1] = be32_to_cpup(p++);
			if (bmlen > 2)
				bitmap[2] = be32_to_cpup(p);
		}
L
Linus Torvalds 已提交
3178 3179
	}
	return 0;
B
Benny Halevy 已提交
3180 3181 3182
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3183 3184
}

3185
static int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, unsigned int *savep)
L
Linus Torvalds 已提交
3186
{
A
Al Viro 已提交
3187
	__be32 *p;
L
Linus Torvalds 已提交
3188

B
Benny Halevy 已提交
3189 3190 3191
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
3192
	*attrlen = be32_to_cpup(p);
3193
	*savep = xdr_stream_pos(xdr);
L
Linus Torvalds 已提交
3194
	return 0;
B
Benny Halevy 已提交
3195 3196 3197
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3198 3199 3200 3201 3202
}

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 已提交
3203 3204 3205 3206
		int ret;
		ret = decode_attr_bitmap(xdr, bitmask);
		if (unlikely(ret < 0))
			return ret;
L
Linus Torvalds 已提交
3207 3208
		bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS;
	} else
3209 3210 3211
		bitmask[0] = bitmask[1] = bitmask[2] = 0;
	dprintk("%s: bitmask=%08x:%08x:%08x\n", __func__,
		bitmask[0], bitmask[1], bitmask[2]);
L
Linus Torvalds 已提交
3212 3213 3214 3215 3216
	return 0;
}

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

	*type = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_TYPE)) {
B
Benny Halevy 已提交
3224 3225 3226
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3227
		*type = be32_to_cpup(p);
L
Linus Torvalds 已提交
3228
		if (*type < NF4REG || *type > NF4NAMEDATTR) {
3229
			dprintk("%s: bad type %d\n", __func__, *type);
L
Linus Torvalds 已提交
3230 3231 3232
			return -EIO;
		}
		bitmap[0] &= ~FATTR4_WORD0_TYPE;
3233
		ret = NFS_ATTR_FATTR_TYPE;
L
Linus Torvalds 已提交
3234
	}
3235
	dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type]);
3236
	return ret;
B
Benny Halevy 已提交
3237 3238 3239
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3240 3241
}

3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263
static int decode_attr_fh_expire_type(struct xdr_stream *xdr,
				      uint32_t *bitmap, uint32_t *type)
{
	__be32 *p;

	*type = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_FH_EXPIRE_TYPE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_FH_EXPIRE_TYPE)) {
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
		*type = be32_to_cpup(p);
		bitmap[0] &= ~FATTR4_WORD0_FH_EXPIRE_TYPE;
	}
	dprintk("%s: expire type=0x%x\n", __func__, *type);
	return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}

L
Linus Torvalds 已提交
3264 3265
static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
{
A
Al Viro 已提交
3266
	__be32 *p;
3267
	int ret = 0;
L
Linus Torvalds 已提交
3268 3269 3270 3271 3272

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

static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
{
A
Al Viro 已提交
3290
	__be32 *p;
3291
	int ret = 0;
L
Linus Torvalds 已提交
3292 3293 3294 3295 3296

	*size = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) {
B
Benny Halevy 已提交
3297 3298 3299
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3300
		xdr_decode_hyper(p, size);
L
Linus Torvalds 已提交
3301
		bitmap[0] &= ~FATTR4_WORD0_SIZE;
3302
		ret = NFS_ATTR_FATTR_SIZE;
L
Linus Torvalds 已提交
3303
	}
3304
	dprintk("%s: file size=%Lu\n", __func__, (unsigned long long)*size);
3305
	return ret;
B
Benny Halevy 已提交
3306 3307 3308
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3309 3310 3311 3312
}

static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
3313
	__be32 *p;
L
Linus Torvalds 已提交
3314 3315 3316 3317 3318

	*res = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) {
B
Benny Halevy 已提交
3319 3320 3321
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3322
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
3323 3324
		bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT;
	}
3325
	dprintk("%s: link support=%s\n", __func__, *res == 0 ? "false" : "true");
L
Linus Torvalds 已提交
3326
	return 0;
B
Benny Halevy 已提交
3327 3328 3329
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3330 3331 3332 3333
}

static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
3334
	__be32 *p;
L
Linus Torvalds 已提交
3335 3336 3337 3338 3339

	*res = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) {
B
Benny Halevy 已提交
3340 3341 3342
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3343
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
3344 3345
		bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT;
	}
3346
	dprintk("%s: symlink support=%s\n", __func__, *res == 0 ? "false" : "true");
L
Linus Torvalds 已提交
3347
	return 0;
B
Benny Halevy 已提交
3348 3349 3350
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3351 3352
}

3353
static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
L
Linus Torvalds 已提交
3354
{
A
Al Viro 已提交
3355
	__be32 *p;
3356
	int ret = 0;
L
Linus Torvalds 已提交
3357 3358 3359 3360 3361 3362

	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 已提交
3363 3364 3365
		p = xdr_inline_decode(xdr, 16);
		if (unlikely(!p))
			goto out_overflow;
B
Benny Halevy 已提交
3366
		p = xdr_decode_hyper(p, &fsid->major);
3367
		xdr_decode_hyper(p, &fsid->minor);
L
Linus Torvalds 已提交
3368
		bitmap[0] &= ~FATTR4_WORD0_FSID;
3369
		ret = NFS_ATTR_FATTR_FSID;
L
Linus Torvalds 已提交
3370
	}
3371
	dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __func__,
L
Linus Torvalds 已提交
3372 3373
			(unsigned long long)fsid->major,
			(unsigned long long)fsid->minor);
3374
	return ret;
B
Benny Halevy 已提交
3375 3376 3377
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3378 3379 3380 3381
}

static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
3382
	__be32 *p;
L
Linus Torvalds 已提交
3383 3384 3385 3386 3387

	*res = 60;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) {
B
Benny Halevy 已提交
3388 3389 3390
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3391
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
3392 3393
		bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME;
	}
3394
	dprintk("%s: file size=%u\n", __func__, (unsigned int)*res);
L
Linus Torvalds 已提交
3395
	return 0;
B
Benny Halevy 已提交
3396 3397 3398
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3399 3400
}

3401
static int decode_attr_error(struct xdr_stream *xdr, uint32_t *bitmap, int32_t *res)
3402 3403 3404 3405 3406 3407 3408 3409 3410 3411
{
	__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;
3412
		*res = -be32_to_cpup(p);
3413 3414 3415 3416 3417 3418 3419
	}
	return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}

3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435
static int decode_attr_exclcreat_supported(struct xdr_stream *xdr,
				 uint32_t *bitmap, uint32_t *bitmask)
{
	if (likely(bitmap[2] & FATTR4_WORD2_SUPPATTR_EXCLCREAT)) {
		int ret;
		ret = decode_attr_bitmap(xdr, bitmask);
		if (unlikely(ret < 0))
			return ret;
		bitmap[2] &= ~FATTR4_WORD2_SUPPATTR_EXCLCREAT;
	} else
		bitmask[0] = bitmask[1] = bitmask[2] = 0;
	dprintk("%s: bitmask=%08x:%08x:%08x\n", __func__,
		bitmask[0], bitmask[1], bitmask[2]);
	return 0;
}

3436 3437 3438 3439 3440
static int decode_attr_filehandle(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fh *fh)
{
	__be32 *p;
	int len;

3441 3442
	if (fh != NULL)
		memset(fh, 0, sizeof(*fh));
3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455

	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;
3456 3457 3458 3459
		if (fh != NULL) {
			memcpy(fh->data, p, len);
			fh->size = len;
		}
3460 3461 3462 3463 3464 3465 3466 3467
		bitmap[0] &= ~FATTR4_WORD0_FILEHANDLE;
	}
	return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}

L
Linus Torvalds 已提交
3468 3469
static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
3470
	__be32 *p;
L
Linus Torvalds 已提交
3471

3472
	*res = 0;
L
Linus Torvalds 已提交
3473 3474 3475
	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) {
B
Benny Halevy 已提交
3476 3477 3478
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3479
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
3480 3481
		bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT;
	}
3482
	dprintk("%s: ACLs supported=%u\n", __func__, (unsigned int)*res);
L
Linus Torvalds 已提交
3483
	return 0;
B
Benny Halevy 已提交
3484 3485 3486
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3487 3488 3489 3490
}

static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
{
A
Al Viro 已提交
3491
	__be32 *p;
3492
	int ret = 0;
L
Linus Torvalds 已提交
3493 3494 3495 3496 3497

	*fileid = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) {
B
Benny Halevy 已提交
3498 3499 3500
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3501
		xdr_decode_hyper(p, fileid);
L
Linus Torvalds 已提交
3502
		bitmap[0] &= ~FATTR4_WORD0_FILEID;
3503
		ret = NFS_ATTR_FATTR_FILEID;
L
Linus Torvalds 已提交
3504
	}
3505
	dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
3506
	return ret;
B
Benny Halevy 已提交
3507 3508 3509
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3510 3511
}

3512 3513
static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
{
A
Al Viro 已提交
3514
	__be32 *p;
3515
	int ret = 0;
3516 3517 3518 3519 3520

	*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 已提交
3521 3522 3523
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3524
		xdr_decode_hyper(p, fileid);
3525
		bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
3526
		ret = NFS_ATTR_FATTR_MOUNTED_ON_FILEID;
3527
	}
3528
	dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
3529
	return ret;
B
Benny Halevy 已提交
3530 3531 3532
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
3533 3534
}

L
Linus Torvalds 已提交
3535 3536
static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3537
	__be32 *p;
L
Linus Torvalds 已提交
3538 3539 3540 3541 3542 3543
	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 已提交
3544 3545 3546
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3547
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3548 3549
		bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL;
	}
3550
	dprintk("%s: files avail=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3551
	return status;
B
Benny Halevy 已提交
3552 3553 3554
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3555 3556 3557 3558
}

static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3559
	__be32 *p;
L
Linus Torvalds 已提交
3560 3561 3562 3563 3564 3565
	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 已提交
3566 3567 3568
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3569
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3570 3571
		bitmap[0] &= ~FATTR4_WORD0_FILES_FREE;
	}
3572
	dprintk("%s: files free=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3573
	return status;
B
Benny Halevy 已提交
3574 3575 3576
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3577 3578 3579 3580
}

static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3581
	__be32 *p;
L
Linus Torvalds 已提交
3582 3583 3584 3585 3586 3587
	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 已提交
3588 3589 3590
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3591
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3592 3593
		bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL;
	}
3594
	dprintk("%s: files total=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3595
	return status;
B
Benny Halevy 已提交
3596 3597 3598
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3599 3600
}

3601 3602
static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
{
3603
	u32 n;
A
Al Viro 已提交
3604
	__be32 *p;
3605 3606
	int status = 0;

B
Benny Halevy 已提交
3607 3608 3609
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
3610
	n = be32_to_cpup(p);
3611 3612
	if (n == 0)
		goto root_path;
3613
	dprintk("pathname4: ");
3614 3615 3616 3617 3618
	if (n > NFS4_PATHNAME_MAXCOMPONENTS) {
		dprintk("cannot parse %d components in path\n", n);
		goto out_eio;
	}
	for (path->ncomponents = 0; path->ncomponents < n; path->ncomponents++) {
3619 3620 3621 3622
		struct nfs4_string *component = &path->components[path->ncomponents];
		status = decode_opaque_inline(xdr, &component->len, &component->data);
		if (unlikely(status != 0))
			goto out_eio;
3623
		ifdebug (XDR)
3624 3625 3626
			pr_cont("%s%.*s ",
				(path->ncomponents != n ? "/ " : ""),
				component->len, component->data);
3627 3628 3629
	}
out:
	return status;
3630 3631 3632 3633 3634
root_path:
/* a root pathname is sent as a zero component4 */
	path->ncomponents = 1;
	path->components[0].len=0;
	path->components[0].data=NULL;
3635
	dprintk("pathname4: /\n");
3636
	goto out;
3637 3638 3639 3640
out_eio:
	dprintk(" status %d", status);
	status = -EIO;
	goto out;
B
Benny Halevy 已提交
3641 3642 3643
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
3644 3645 3646
}

static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res)
3647 3648
{
	int n;
A
Al Viro 已提交
3649
	__be32 *p;
3650 3651 3652 3653 3654 3655 3656
	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;
3657
	bitmap[0] &= ~FATTR4_WORD0_FS_LOCATIONS;
3658 3659 3660 3661
	status = -EIO;
	/* Ignore borken servers that return unrequested attrs */
	if (unlikely(res == NULL))
		goto out;
3662
	dprintk("%s: fsroot:\n", __func__);
3663
	status = decode_pathname(xdr, &res->fs_path);
3664 3665
	if (unlikely(status != 0))
		goto out;
B
Benny Halevy 已提交
3666 3667 3668
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
3669
	n = be32_to_cpup(p);
3670 3671
	if (n <= 0)
		goto out_eio;
3672
	for (res->nlocations = 0; res->nlocations < n; res->nlocations++) {
3673
		u32 m;
3674
		struct nfs4_fs_location *loc;
3675

3676 3677 3678
		if (res->nlocations == NFS4_FS_LOCATIONS_MAXENTRIES)
			break;
		loc = &res->locations[res->nlocations];
B
Benny Halevy 已提交
3679 3680 3681
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3682
		m = be32_to_cpup(p);
3683

3684
		dprintk("%s: servers:\n", __func__);
3685 3686 3687 3688
		for (loc->nservers = 0; loc->nservers < m; loc->nservers++) {
			struct nfs4_string *server;

			if (loc->nservers == NFS4_FS_LOCATION_MAXSERVERS) {
3689 3690 3691
				unsigned int i;
				dprintk("%s: using first %u of %u servers "
					"returned for location %u\n",
3692
						__func__,
3693 3694
						NFS4_FS_LOCATION_MAXSERVERS,
						m, res->nlocations);
3695
				for (i = loc->nservers; i < m; i++) {
T
Trond Myklebust 已提交
3696
					unsigned int len;
3697 3698 3699 3700 3701
					char *data;
					status = decode_opaque_inline(xdr, &len, &data);
					if (unlikely(status != 0))
						goto out_eio;
				}
3702
				break;
3703
			}
3704 3705 3706 3707 3708
			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);
3709 3710
		}
		status = decode_pathname(xdr, &loc->rootpath);
3711 3712 3713
		if (unlikely(status != 0))
			goto out_eio;
	}
3714
	if (res->nlocations != 0)
3715
		status = NFS_ATTR_FATTR_V4_LOCATIONS;
3716
out:
3717
	dprintk("%s: fs_locations done, error = %d\n", __func__, status);
3718
	return status;
B
Benny Halevy 已提交
3719 3720
out_overflow:
	print_overflow_msg(__func__, xdr);
3721 3722 3723 3724 3725
out_eio:
	status = -EIO;
	goto out;
}

L
Linus Torvalds 已提交
3726 3727
static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3728
	__be32 *p;
L
Linus Torvalds 已提交
3729 3730 3731 3732 3733 3734
	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 已提交
3735 3736 3737
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3738
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3739 3740
		bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE;
	}
3741
	dprintk("%s: maxfilesize=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3742
	return status;
B
Benny Halevy 已提交
3743 3744 3745
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3746 3747 3748 3749
}

static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink)
{
A
Al Viro 已提交
3750
	__be32 *p;
L
Linus Torvalds 已提交
3751 3752 3753 3754 3755 3756
	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 已提交
3757 3758 3759
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3760
		*maxlink = be32_to_cpup(p);
L
Linus Torvalds 已提交
3761 3762
		bitmap[0] &= ~FATTR4_WORD0_MAXLINK;
	}
3763
	dprintk("%s: maxlink=%u\n", __func__, *maxlink);
L
Linus Torvalds 已提交
3764
	return status;
B
Benny Halevy 已提交
3765 3766 3767
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3768 3769 3770 3771
}

static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname)
{
A
Al Viro 已提交
3772
	__be32 *p;
L
Linus Torvalds 已提交
3773 3774 3775 3776 3777 3778
	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 已提交
3779 3780 3781
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3782
		*maxname = be32_to_cpup(p);
L
Linus Torvalds 已提交
3783 3784
		bitmap[0] &= ~FATTR4_WORD0_MAXNAME;
	}
3785
	dprintk("%s: maxname=%u\n", __func__, *maxname);
L
Linus Torvalds 已提交
3786
	return status;
B
Benny Halevy 已提交
3787 3788 3789
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3790 3791 3792 3793
}

static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
3794
	__be32 *p;
L
Linus Torvalds 已提交
3795 3796 3797 3798 3799 3800 3801
	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 已提交
3802 3803 3804
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3805
		xdr_decode_hyper(p, &maxread);
L
Linus Torvalds 已提交
3806 3807 3808 3809 3810
		if (maxread > 0x7FFFFFFF)
			maxread = 0x7FFFFFFF;
		*res = (uint32_t)maxread;
		bitmap[0] &= ~FATTR4_WORD0_MAXREAD;
	}
3811
	dprintk("%s: maxread=%lu\n", __func__, (unsigned long)*res);
L
Linus Torvalds 已提交
3812
	return status;
B
Benny Halevy 已提交
3813 3814 3815
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3816 3817 3818 3819
}

static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
3820
	__be32 *p;
L
Linus Torvalds 已提交
3821 3822 3823 3824 3825 3826 3827
	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 已提交
3828 3829 3830
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3831
		xdr_decode_hyper(p, &maxwrite);
L
Linus Torvalds 已提交
3832 3833 3834 3835 3836
		if (maxwrite > 0x7FFFFFFF)
			maxwrite = 0x7FFFFFFF;
		*res = (uint32_t)maxwrite;
		bitmap[0] &= ~FATTR4_WORD0_MAXWRITE;
	}
3837
	dprintk("%s: maxwrite=%lu\n", __func__, (unsigned long)*res);
L
Linus Torvalds 已提交
3838
	return status;
B
Benny Halevy 已提交
3839 3840 3841
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3842 3843
}

3844
static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *mode)
L
Linus Torvalds 已提交
3845
{
3846
	uint32_t tmp;
A
Al Viro 已提交
3847
	__be32 *p;
3848
	int ret = 0;
L
Linus Torvalds 已提交
3849 3850 3851 3852 3853

	*mode = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_MODE)) {
B
Benny Halevy 已提交
3854 3855 3856
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3857
		tmp = be32_to_cpup(p);
3858
		*mode = tmp & ~S_IFMT;
L
Linus Torvalds 已提交
3859
		bitmap[1] &= ~FATTR4_WORD1_MODE;
3860
		ret = NFS_ATTR_FATTR_MODE;
L
Linus Torvalds 已提交
3861
	}
3862
	dprintk("%s: file mode=0%o\n", __func__, (unsigned int)*mode);
3863
	return ret;
B
Benny Halevy 已提交
3864 3865 3866
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3867 3868 3869 3870
}

static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
{
A
Al Viro 已提交
3871
	__be32 *p;
3872
	int ret = 0;
L
Linus Torvalds 已提交
3873 3874 3875 3876 3877

	*nlink = 1;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) {
B
Benny Halevy 已提交
3878 3879 3880
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3881
		*nlink = be32_to_cpup(p);
L
Linus Torvalds 已提交
3882
		bitmap[1] &= ~FATTR4_WORD1_NUMLINKS;
3883
		ret = NFS_ATTR_FATTR_NLINK;
L
Linus Torvalds 已提交
3884
	}
3885
	dprintk("%s: nlink=%u\n", __func__, (unsigned int)*nlink);
3886
	return ret;
B
Benny Halevy 已提交
3887 3888 3889
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3890 3891
}

3892
static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap,
3893
		const struct nfs_server *server, kuid_t *uid,
3894
		struct nfs4_string *owner_name)
L
Linus Torvalds 已提交
3895
{
A
Al Viro 已提交
3896 3897
	uint32_t len;
	__be32 *p;
3898
	int ret = 0;
L
Linus Torvalds 已提交
3899

3900
	*uid = make_kuid(&init_user_ns, -2);
L
Linus Torvalds 已提交
3901 3902 3903
	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) {
B
Benny Halevy 已提交
3904 3905 3906
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3907
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
3908 3909 3910
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
3911 3912 3913 3914 3915 3916
		if (owner_name != NULL) {
			owner_name->data = kmemdup(p, len, GFP_NOWAIT);
			if (owner_name->data != NULL) {
				owner_name->len = len;
				ret = NFS_ATTR_FATTR_OWNER_NAME;
			}
3917
		} else if (len < XDR_MAX_NETOBJ) {
3918
			if (nfs_map_name_to_uid(server, (char *)p, len, uid) == 0)
3919 3920
				ret = NFS_ATTR_FATTR_OWNER;
			else
L
Linus Torvalds 已提交
3921
				dprintk("%s: nfs_map_name_to_uid failed!\n",
3922
						__func__);
L
Linus Torvalds 已提交
3923
		} else
3924
			dprintk("%s: name too long (%u)!\n",
3925
					__func__, len);
L
Linus Torvalds 已提交
3926 3927
		bitmap[1] &= ~FATTR4_WORD1_OWNER;
	}
3928
	dprintk("%s: uid=%d\n", __func__, (int)from_kuid(&init_user_ns, *uid));
3929
	return ret;
B
Benny Halevy 已提交
3930 3931 3932
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3933 3934
}

3935
static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap,
3936
		const struct nfs_server *server, kgid_t *gid,
3937
		struct nfs4_string *group_name)
L
Linus Torvalds 已提交
3938
{
A
Al Viro 已提交
3939 3940
	uint32_t len;
	__be32 *p;
3941
	int ret = 0;
L
Linus Torvalds 已提交
3942

3943
	*gid = make_kgid(&init_user_ns, -2);
L
Linus Torvalds 已提交
3944 3945 3946
	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) {
B
Benny Halevy 已提交
3947 3948 3949
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3950
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
3951 3952 3953
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
3954 3955 3956 3957 3958 3959
		if (group_name != NULL) {
			group_name->data = kmemdup(p, len, GFP_NOWAIT);
			if (group_name->data != NULL) {
				group_name->len = len;
				ret = NFS_ATTR_FATTR_GROUP_NAME;
			}
3960
		} else if (len < XDR_MAX_NETOBJ) {
3961
			if (nfs_map_group_to_gid(server, (char *)p, len, gid) == 0)
3962 3963
				ret = NFS_ATTR_FATTR_GROUP;
			else
L
Linus Torvalds 已提交
3964
				dprintk("%s: nfs_map_group_to_gid failed!\n",
3965
						__func__);
L
Linus Torvalds 已提交
3966
		} else
3967
			dprintk("%s: name too long (%u)!\n",
3968
					__func__, len);
L
Linus Torvalds 已提交
3969 3970
		bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
	}
3971
	dprintk("%s: gid=%d\n", __func__, (int)from_kgid(&init_user_ns, *gid));
3972
	return ret;
B
Benny Halevy 已提交
3973 3974 3975
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3976 3977 3978 3979
}

static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
{
A
Al Viro 已提交
3980 3981
	uint32_t major = 0, minor = 0;
	__be32 *p;
3982
	int ret = 0;
L
Linus Torvalds 已提交
3983 3984 3985 3986 3987 3988 3989

	*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 已提交
3990 3991 3992
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
B
Benny Halevy 已提交
3993
		major = be32_to_cpup(p++);
3994
		minor = be32_to_cpup(p);
L
Linus Torvalds 已提交
3995 3996 3997 3998
		tmp = MKDEV(major, minor);
		if (MAJOR(tmp) == major && MINOR(tmp) == minor)
			*rdev = tmp;
		bitmap[1] &= ~ FATTR4_WORD1_RAWDEV;
3999
		ret = NFS_ATTR_FATTR_RDEV;
L
Linus Torvalds 已提交
4000
	}
4001
	dprintk("%s: rdev=(0x%x:0x%x)\n", __func__, major, minor);
4002
	return ret;
B
Benny Halevy 已提交
4003 4004 4005
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4006 4007 4008 4009
}

static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
4010
	__be32 *p;
L
Linus Torvalds 已提交
4011 4012 4013 4014 4015 4016
	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 已提交
4017 4018 4019
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
4020
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
4021 4022
		bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL;
	}
4023
	dprintk("%s: space avail=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
4024
	return status;
B
Benny Halevy 已提交
4025 4026 4027
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4028 4029 4030 4031
}

static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
4032
	__be32 *p;
L
Linus Torvalds 已提交
4033 4034 4035 4036 4037 4038
	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 已提交
4039 4040 4041
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
4042
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
4043 4044
		bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE;
	}
4045
	dprintk("%s: space free=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
4046
	return status;
B
Benny Halevy 已提交
4047 4048 4049
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4050 4051 4052 4053
}

static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
4054
	__be32 *p;
L
Linus Torvalds 已提交
4055 4056 4057 4058 4059 4060
	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 已提交
4061 4062 4063
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
4064
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
4065 4066
		bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL;
	}
4067
	dprintk("%s: space total=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
4068
	return status;
B
Benny Halevy 已提交
4069 4070 4071
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4072 4073 4074 4075
}

static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
{
A
Al Viro 已提交
4076
	__be32 *p;
4077
	int ret = 0;
L
Linus Torvalds 已提交
4078 4079 4080 4081 4082

	*used = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) {
B
Benny Halevy 已提交
4083 4084 4085
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
4086
		xdr_decode_hyper(p, used);
L
Linus Torvalds 已提交
4087
		bitmap[1] &= ~FATTR4_WORD1_SPACE_USED;
4088
		ret = NFS_ATTR_FATTR_SPACE_USED;
L
Linus Torvalds 已提交
4089
	}
4090
	dprintk("%s: space used=%Lu\n", __func__,
L
Linus Torvalds 已提交
4091
			(unsigned long long)*used);
4092
	return ret;
B
Benny Halevy 已提交
4093 4094 4095
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4096 4097 4098 4099
}

static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
{
A
Al Viro 已提交
4100
	__be32 *p;
L
Linus Torvalds 已提交
4101 4102 4103
	uint64_t sec;
	uint32_t nsec;

B
Benny Halevy 已提交
4104 4105 4106
	p = xdr_inline_decode(xdr, 12);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4107
	p = xdr_decode_hyper(p, &sec);
4108
	nsec = be32_to_cpup(p);
L
Linus Torvalds 已提交
4109 4110 4111
	time->tv_sec = (time_t)sec;
	time->tv_nsec = (long)nsec;
	return 0;
B
Benny Halevy 已提交
4112 4113 4114
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126
}

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);
4127 4128
		if (status == 0)
			status = NFS_ATTR_FATTR_ATIME;
L
Linus Torvalds 已提交
4129 4130
		bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS;
	}
4131
	dprintk("%s: atime=%ld\n", __func__, (long)time->tv_sec);
L
Linus Torvalds 已提交
4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144
	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);
4145 4146
		if (status == 0)
			status = NFS_ATTR_FATTR_CTIME;
L
Linus Torvalds 已提交
4147 4148
		bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
	}
4149
	dprintk("%s: ctime=%ld\n", __func__, (long)time->tv_sec);
L
Linus Torvalds 已提交
4150 4151 4152
	return status;
}

4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170
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;
}

4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220
static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap,
					struct nfs4_label *label)
{
	uint32_t pi = 0;
	uint32_t lfs = 0;
	__u32 len;
	__be32 *p;
	int status = 0;

	if (unlikely(bitmap[2] & (FATTR4_WORD2_SECURITY_LABEL - 1U)))
		return -EIO;
	if (likely(bitmap[2] & FATTR4_WORD2_SECURITY_LABEL)) {
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
		lfs = be32_to_cpup(p++);
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
		pi = be32_to_cpup(p++);
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
		len = be32_to_cpup(p++);
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
		if (len < NFS4_MAXLABELLEN) {
			if (label) {
				memcpy(label->label, p, len);
				label->len = len;
				label->pi = pi;
				label->lfs = lfs;
				status = NFS_ATTR_FATTR_V4_SECURITY_LABEL;
			}
			bitmap[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
		} else
			printk(KERN_WARNING "%s: label too long (%u)!\n",
					__func__, len);
	}
	if (label && label->label)
		dprintk("%s: label=%s, len=%d, PI=%d, LFS=%d\n", __func__,
			(char *)label->label, label->len, label->pi, label->lfs);
	return status;

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

L
Linus Torvalds 已提交
4221 4222 4223 4224 4225 4226 4227 4228 4229 4230
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);
4231 4232
		if (status == 0)
			status = NFS_ATTR_FATTR_MTIME;
L
Linus Torvalds 已提交
4233 4234
		bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
	}
4235
	dprintk("%s: mtime=%ld\n", __func__, (long)time->tv_sec);
L
Linus Torvalds 已提交
4236 4237 4238
	return status;
}

4239
static int verify_attr_len(struct xdr_stream *xdr, unsigned int savep, uint32_t attrlen)
L
Linus Torvalds 已提交
4240 4241
{
	unsigned int attrwords = XDR_QUADLEN(attrlen);
4242
	unsigned int nwords = (xdr_stream_pos(xdr) - savep) >> 2;
L
Linus Torvalds 已提交
4243 4244

	if (unlikely(attrwords != nwords)) {
4245 4246
		dprintk("%s: server returned incorrect attribute length: "
			"%u %c %u\n",
4247
				__func__,
L
Linus Torvalds 已提交
4248 4249 4250 4251 4252 4253 4254 4255 4256 4257
				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 已提交
4258
	__be32 *p;
L
Linus Torvalds 已提交
4259

B
Benny Halevy 已提交
4260 4261 4262
	p = xdr_inline_decode(xdr, 20);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4263
	cinfo->atomic = be32_to_cpup(p++);
B
Benny Halevy 已提交
4264
	p = xdr_decode_hyper(p, &cinfo->before);
4265
	xdr_decode_hyper(p, &cinfo->after);
L
Linus Torvalds 已提交
4266
	return 0;
B
Benny Halevy 已提交
4267 4268 4269
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4270 4271
}

4272
static int decode_access(struct xdr_stream *xdr, u32 *supported, u32 *access)
L
Linus Torvalds 已提交
4273
{
A
Al Viro 已提交
4274
	__be32 *p;
L
Linus Torvalds 已提交
4275 4276 4277 4278 4279 4280
	uint32_t supp, acc;
	int status;

	status = decode_op_hdr(xdr, OP_ACCESS);
	if (status)
		return status;
B
Benny Halevy 已提交
4281 4282 4283
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4284
	supp = be32_to_cpup(p++);
4285
	acc = be32_to_cpup(p);
4286 4287
	*supported = supp;
	*access = acc;
L
Linus Torvalds 已提交
4288
	return 0;
B
Benny Halevy 已提交
4289 4290 4291
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4292 4293
}

4294
static int decode_opaque_fixed(struct xdr_stream *xdr, void *buf, size_t len)
L
Linus Torvalds 已提交
4295
{
A
Al Viro 已提交
4296
	__be32 *p;
4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308

	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)
{
4309
	return decode_opaque_fixed(xdr, stateid, NFS4_STATEID_SIZE);
4310 4311
}

4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329
static int decode_open_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
{
	stateid->type = NFS4_OPEN_STATEID_TYPE;
	return decode_stateid(xdr, stateid);
}

static int decode_lock_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
{
	stateid->type = NFS4_LOCK_STATEID_TYPE;
	return decode_stateid(xdr, stateid);
}

static int decode_delegation_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
{
	stateid->type = NFS4_DELEGATION_STATEID_TYPE;
	return decode_stateid(xdr, stateid);
}

4330 4331
static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
{
L
Linus Torvalds 已提交
4332 4333 4334
	int status;

	status = decode_op_hdr(xdr, OP_CLOSE);
4335 4336
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
4337
	if (!status)
4338
		status = decode_open_stateid(xdr, &res->stateid);
4339
	return status;
L
Linus Torvalds 已提交
4340 4341
}

4342 4343
static int decode_verifier(struct xdr_stream *xdr, void *verifier)
{
4344
	return decode_opaque_fixed(xdr, verifier, NFS4_VERIFIER_SIZE);
L
Linus Torvalds 已提交
4345 4346
}

4347 4348 4349 4350 4351
static int decode_write_verifier(struct xdr_stream *xdr, struct nfs_write_verifier *verifier)
{
	return decode_opaque_fixed(xdr, verifier->data, NFS4_VERIFIER_SIZE);
}

4352
static int decode_commit(struct xdr_stream *xdr, struct nfs_commitres *res)
L
Linus Torvalds 已提交
4353 4354 4355 4356
{
	int status;

	status = decode_op_hdr(xdr, OP_COMMIT);
4357
	if (!status)
4358
		status = decode_write_verifier(xdr, &res->verf->verifier);
4359
	return status;
L
Linus Torvalds 已提交
4360 4361 4362 4363
}

static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
A
Al Viro 已提交
4364
	__be32 *p;
L
Linus Torvalds 已提交
4365 4366 4367 4368 4369 4370 4371 4372
	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 已提交
4373 4374 4375
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4376
	bmlen = be32_to_cpup(p);
B
Benny Halevy 已提交
4377 4378 4379 4380 4381 4382
	p = xdr_inline_decode(xdr, bmlen << 2);
	if (likely(p))
		return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4383 4384 4385 4386
}

static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
{
4387
	unsigned int savep;
4388
	uint32_t attrlen, bitmap[3] = {0};
L
Linus Torvalds 已提交
4389 4390 4391 4392 4393 4394 4395 4396 4397 4398
	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;
4399 4400 4401
	if ((status = decode_attr_fh_expire_type(xdr, bitmap,
						 &res->fh_expire_type)) != 0)
		goto xdr_error;
L
Linus Torvalds 已提交
4402 4403 4404 4405 4406 4407
	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;
4408 4409 4410
	if ((status = decode_attr_exclcreat_supported(xdr, bitmap,
				res->exclcreat_bitmask)) != 0)
		goto xdr_error;
L
Linus Torvalds 已提交
4411 4412
	status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
4413
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
4414 4415
	return status;
}
4416

L
Linus Torvalds 已提交
4417 4418
static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
{
4419
	unsigned int savep;
4420
	uint32_t attrlen, bitmap[3] = {0};
L
Linus Torvalds 已提交
4421
	int status;
4422

L
Linus Torvalds 已提交
4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435
	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;
4436 4437 4438 4439 4440

	status = -EIO;
	if (unlikely(bitmap[0]))
		goto xdr_error;

L
Linus Torvalds 已提交
4441 4442 4443 4444 4445 4446 4447 4448 4449
	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:
4450
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
4451 4452 4453 4454 4455
	return status;
}

static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
{
4456
	unsigned int savep;
4457
	uint32_t attrlen, bitmap[3] = {0};
L
Linus Torvalds 已提交
4458
	int status;
4459

L
Linus Torvalds 已提交
4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473
	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:
4474
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
4475 4476 4477
	return status;
}

4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500
static int decode_threshold_hint(struct xdr_stream *xdr,
				  uint32_t *bitmap,
				  uint64_t *res,
				  uint32_t hint_bit)
{
	__be32 *p;

	*res = 0;
	if (likely(bitmap[0] & hint_bit)) {
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
		xdr_decode_hyper(p, res);
	}
	return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}

static int decode_first_threshold_item4(struct xdr_stream *xdr,
					struct nfs4_threshold *res)
{
4501 4502
	__be32 *p;
	unsigned int savep;
4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562
	uint32_t bitmap[3] = {0,}, attrlen;
	int status;

	/* layout type */
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p)) {
		print_overflow_msg(__func__, xdr);
		return -EIO;
	}
	res->l_type = be32_to_cpup(p);

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

	/* thi_hintlist length */
	status = decode_attr_length(xdr, &attrlen, &savep);
	if (status < 0)
		goto xdr_error;
	/* thi_hintlist */
	status = decode_threshold_hint(xdr, bitmap, &res->rd_sz, THRESHOLD_RD);
	if (status < 0)
		goto xdr_error;
	status = decode_threshold_hint(xdr, bitmap, &res->wr_sz, THRESHOLD_WR);
	if (status < 0)
		goto xdr_error;
	status = decode_threshold_hint(xdr, bitmap, &res->rd_io_sz,
				       THRESHOLD_RD_IO);
	if (status < 0)
		goto xdr_error;
	status = decode_threshold_hint(xdr, bitmap, &res->wr_io_sz,
				       THRESHOLD_WR_IO);
	if (status < 0)
		goto xdr_error;

	status = verify_attr_len(xdr, savep, attrlen);
	res->bm = bitmap[0];

	dprintk("%s bm=0x%x rd_sz=%llu wr_sz=%llu rd_io=%llu wr_io=%llu\n",
		 __func__, res->bm, res->rd_sz, res->wr_sz, res->rd_io_sz,
		res->wr_io_sz);
xdr_error:
	dprintk("%s ret=%d!\n", __func__, status);
	return status;
}

/*
 * Thresholds on pNFS direct I/O vrs MDS I/O
 */
static int decode_attr_mdsthreshold(struct xdr_stream *xdr,
				    uint32_t *bitmap,
				    struct nfs4_threshold *res)
{
	__be32 *p;
	int status = 0;
	uint32_t num;

	if (unlikely(bitmap[2] & (FATTR4_WORD2_MDSTHRESHOLD - 1U)))
		return -EIO;
4563
	if (bitmap[2] & FATTR4_WORD2_MDSTHRESHOLD) {
4564 4565 4566
		/* Did the server return an unrequested attribute? */
		if (unlikely(res == NULL))
			return -EREMOTEIO;
4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
		num = be32_to_cpup(p);
		if (num == 0)
			return 0;
		if (num > 1)
			printk(KERN_INFO "%s: Warning: Multiple pNFS layout "
				"drivers per filesystem not supported\n",
				__func__);

		status = decode_first_threshold_item4(xdr, res);
4579
		bitmap[2] &= ~FATTR4_WORD2_MDSTHRESHOLD;
4580 4581 4582 4583 4584 4585 4586
	}
	return status;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}

4587 4588
static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
		struct nfs_fattr *fattr, struct nfs_fh *fh,
4589
		struct nfs4_fs_locations *fs_loc, struct nfs4_label *label,
4590
		const struct nfs_server *server)
L
Linus Torvalds 已提交
4591
{
4592 4593
	int status;
	umode_t fmode = 0;
4594
	uint32_t type;
4595
	int32_t err;
L
Linus Torvalds 已提交
4596

4597 4598
	status = decode_attr_type(xdr, bitmap, &type);
	if (status < 0)
L
Linus Torvalds 已提交
4599
		goto xdr_error;
4600 4601 4602 4603 4604
	fattr->mode = 0;
	if (status != 0) {
		fattr->mode |= nfs_type2fmt[type];
		fattr->valid |= status;
	}
L
Linus Torvalds 已提交
4605

4606 4607
	status = decode_attr_change(xdr, bitmap, &fattr->change_attr);
	if (status < 0)
L
Linus Torvalds 已提交
4608
		goto xdr_error;
4609
	fattr->valid |= status;
4610 4611 4612

	status = decode_attr_size(xdr, bitmap, &fattr->size);
	if (status < 0)
L
Linus Torvalds 已提交
4613
		goto xdr_error;
4614
	fattr->valid |= status;
4615 4616 4617

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

4621 4622
	err = 0;
	status = decode_attr_error(xdr, bitmap, &err);
4623 4624 4625 4626 4627 4628 4629
	if (status < 0)
		goto xdr_error;

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

4630 4631
	status = decode_attr_fileid(xdr, bitmap, &fattr->fileid);
	if (status < 0)
L
Linus Torvalds 已提交
4632
		goto xdr_error;
4633
	fattr->valid |= status;
4634

4635
	status = decode_attr_fs_locations(xdr, bitmap, fs_loc);
4636
	if (status < 0)
4637
		goto xdr_error;
4638
	fattr->valid |= status;
4639

4640 4641 4642 4643
	status = -EIO;
	if (unlikely(bitmap[0]))
		goto xdr_error;

4644 4645
	status = decode_attr_mode(xdr, bitmap, &fmode);
	if (status < 0)
L
Linus Torvalds 已提交
4646
		goto xdr_error;
4647 4648 4649 4650
	if (status != 0) {
		fattr->mode |= fmode;
		fattr->valid |= status;
	}
4651 4652 4653

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

4657
	status = decode_attr_owner(xdr, bitmap, server, &fattr->uid, fattr->owner_name);
4658
	if (status < 0)
L
Linus Torvalds 已提交
4659
		goto xdr_error;
4660
	fattr->valid |= status;
4661

4662
	status = decode_attr_group(xdr, bitmap, server, &fattr->gid, fattr->group_name);
4663
	if (status < 0)
L
Linus Torvalds 已提交
4664
		goto xdr_error;
4665
	fattr->valid |= status;
4666 4667 4668

	status = decode_attr_rdev(xdr, bitmap, &fattr->rdev);
	if (status < 0)
L
Linus Torvalds 已提交
4669
		goto xdr_error;
4670
	fattr->valid |= status;
4671 4672 4673

	status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used);
	if (status < 0)
L
Linus Torvalds 已提交
4674
		goto xdr_error;
4675
	fattr->valid |= status;
4676 4677 4678

	status = decode_attr_time_access(xdr, bitmap, &fattr->atime);
	if (status < 0)
L
Linus Torvalds 已提交
4679
		goto xdr_error;
4680
	fattr->valid |= status;
4681 4682 4683

	status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
	if (status < 0)
L
Linus Torvalds 已提交
4684
		goto xdr_error;
4685
	fattr->valid |= status;
4686 4687 4688

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

4692
	status = decode_attr_mounted_on_fileid(xdr, bitmap, &fattr->mounted_on_fileid);
4693
	if (status < 0)
4694
		goto xdr_error;
4695
	fattr->valid |= status;
4696

4697 4698 4699 4700
	status = -EIO;
	if (unlikely(bitmap[1]))
		goto xdr_error;

4701 4702 4703 4704
	status = decode_attr_mdsthreshold(xdr, bitmap, fattr->mdsthreshold);
	if (status < 0)
		goto xdr_error;

4705 4706 4707 4708 4709 4710 4711
	if (label) {
		status = decode_attr_security_label(xdr, bitmap, label);
		if (status < 0)
			goto xdr_error;
		fattr->valid |= status;
	}

4712 4713 4714 4715 4716 4717
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,
4718
		struct nfs_fh *fh, struct nfs4_fs_locations *fs_loc,
4719
		struct nfs4_label *label, const struct nfs_server *server)
4720
{
4721
	unsigned int savep;
4722
	uint32_t attrlen,
4723
		 bitmap[3] = {0};
4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737
	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;

4738 4739
	status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, fs_loc,
					label, server);
4740 4741 4742
	if (status < 0)
		goto xdr_error;

4743
	status = verify_attr_len(xdr, savep, attrlen);
L
Linus Torvalds 已提交
4744
xdr_error:
4745
	dprintk("%s: xdr returned %d\n", __func__, -status);
L
Linus Torvalds 已提交
4746 4747 4748
	return status;
}

4749 4750 4751 4752 4753 4754
static int decode_getfattr_label(struct xdr_stream *xdr, struct nfs_fattr *fattr,
		struct nfs4_label *label, const struct nfs_server *server)
{
	return decode_getfattr_generic(xdr, fattr, NULL, NULL, label, server);
}

4755
static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
4756
		const struct nfs_server *server)
4757
{
4758
	return decode_getfattr_generic(xdr, fattr, NULL, NULL, NULL, server);
4759
}
L
Linus Torvalds 已提交
4760

4761
/*
4762
 * Decode potentially multiple layout types.
4763
 */
4764
static int decode_pnfs_layout_types(struct xdr_stream *xdr,
4765
				    struct nfs_fsinfo *fsinfo)
4766
{
4767
	__be32 *p;
4768
	uint32_t i;
4769 4770 4771 4772

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4773
	fsinfo->nlayouttypes = be32_to_cpup(p);
4774 4775

	/* pNFS is not supported by the underlying file system */
4776
	if (fsinfo->nlayouttypes == 0)
4777 4778 4779
		return 0;

	/* Decode and set first layout type, move xdr->p past unused types */
4780
	p = xdr_inline_decode(xdr, fsinfo->nlayouttypes * 4);
4781 4782
	if (unlikely(!p))
		goto out_overflow;
4783 4784 4785 4786 4787 4788 4789 4790 4791 4792

	/* If we get too many, then just cap it at the max */
	if (fsinfo->nlayouttypes > NFS_MAX_LAYOUT_TYPES) {
		printk(KERN_INFO "NFS: %s: Warning: Too many (%u) pNFS layout types\n",
			__func__, fsinfo->nlayouttypes);
		fsinfo->nlayouttypes = NFS_MAX_LAYOUT_TYPES;
	}

	for(i = 0; i < fsinfo->nlayouttypes; ++i)
		fsinfo->layouttype[i] = be32_to_cpup(p++);
4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803
	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,
4804
				struct nfs_fsinfo *fsinfo)
4805 4806 4807 4808 4809 4810 4811
{
	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) {
4812
		status = decode_pnfs_layout_types(xdr, fsinfo);
4813
		bitmap[1] &= ~FATTR4_WORD1_FS_LAYOUT_TYPES;
4814
	}
4815 4816 4817
	return status;
}

4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839
/*
 * The prefered block size for layout directed io
 */
static int decode_attr_layout_blksize(struct xdr_stream *xdr, uint32_t *bitmap,
				      uint32_t *res)
{
	__be32 *p;

	dprintk("%s: bitmap is %x\n", __func__, bitmap[2]);
	*res = 0;
	if (bitmap[2] & FATTR4_WORD2_LAYOUT_BLKSIZE) {
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p)) {
			print_overflow_msg(__func__, xdr);
			return -EIO;
		}
		*res = be32_to_cpup(p);
		bitmap[2] &= ~FATTR4_WORD2_LAYOUT_BLKSIZE;
	}
	return 0;
}

4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861
/*
 * The granularity of a CLONE operation.
 */
static int decode_attr_clone_blksize(struct xdr_stream *xdr, uint32_t *bitmap,
				     uint32_t *res)
{
	__be32 *p;

	dprintk("%s: bitmap is %x\n", __func__, bitmap[2]);
	*res = 0;
	if (bitmap[2] & FATTR4_WORD2_CLONE_BLKSIZE) {
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p)) {
			print_overflow_msg(__func__, xdr);
			return -EIO;
		}
		*res = be32_to_cpup(p);
		bitmap[2] &= ~FATTR4_WORD2_CLONE_BLKSIZE;
	}
	return 0;
}

L
Linus Torvalds 已提交
4862 4863
static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
{
4864
	unsigned int savep;
4865
	uint32_t attrlen, bitmap[3];
L
Linus Torvalds 已提交
4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886
	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;
4887 4888 4889 4890 4891

	status = -EIO;
	if (unlikely(bitmap[0]))
		goto xdr_error;

4892
	status = decode_attr_time_delta(xdr, bitmap, &fsinfo->time_delta);
4893 4894
	if (status != 0)
		goto xdr_error;
4895
	status = decode_attr_pnfstype(xdr, bitmap, fsinfo);
4896 4897
	if (status != 0)
		goto xdr_error;
4898 4899 4900 4901 4902

	status = -EIO;
	if (unlikely(bitmap[1]))
		goto xdr_error;

4903
	status = decode_attr_layout_blksize(xdr, bitmap, &fsinfo->blksize);
4904 4905 4906
	if (status)
		goto xdr_error;
	status = decode_attr_clone_blksize(xdr, bitmap, &fsinfo->clone_blksize);
4907 4908
	if (status)
		goto xdr_error;
L
Linus Torvalds 已提交
4909 4910 4911

	status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
4912
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
4913 4914 4915 4916 4917
	return status;
}

static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
{
A
Al Viro 已提交
4918
	__be32 *p;
L
Linus Torvalds 已提交
4919 4920 4921
	uint32_t len;
	int status;

4922 4923 4924
	/* Zero handle first to allow comparisons */
	memset(fh, 0, sizeof(*fh));

L
Linus Torvalds 已提交
4925 4926 4927 4928
	status = decode_op_hdr(xdr, OP_GETFH);
	if (status)
		return status;

B
Benny Halevy 已提交
4929 4930 4931
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4932
	len = be32_to_cpup(p);
L
Linus Torvalds 已提交
4933 4934 4935
	if (len > NFS4_FHSIZE)
		return -EIO;
	fh->size = len;
B
Benny Halevy 已提交
4936 4937 4938
	p = xdr_inline_decode(xdr, len);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4939
	memcpy(fh->data, p, len);
L
Linus Torvalds 已提交
4940
	return 0;
B
Benny Halevy 已提交
4941 4942 4943
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4944 4945 4946 4947 4948
}

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

L
Linus Torvalds 已提交
4950 4951 4952 4953 4954 4955 4956 4957 4958
	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 已提交
4959
static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
L
Linus Torvalds 已提交
4960
{
T
Trond Myklebust 已提交
4961
	uint64_t offset, length, clientid;
A
Al Viro 已提交
4962
	__be32 *p;
T
Trond Myklebust 已提交
4963
	uint32_t namelen, type;
L
Linus Torvalds 已提交
4964

4965
	p = xdr_inline_decode(xdr, 32); /* read 32 bytes */
B
Benny Halevy 已提交
4966 4967
	if (unlikely(!p))
		goto out_overflow;
4968
	p = xdr_decode_hyper(p, &offset); /* read 2 8-byte long words */
B
Benny Halevy 已提交
4969
	p = xdr_decode_hyper(p, &length);
4970 4971
	type = be32_to_cpup(p++); /* 4 byte read */
	if (fl != NULL) { /* manipulate file lock */
T
Trond Myklebust 已提交
4972 4973 4974 4975 4976 4977 4978 4979 4980
		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;
	}
4981 4982 4983
	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 已提交
4984 4985 4986 4987 4988
	if (likely(p))
		return -NFS4ERR_DENIED;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4989 4990
}

T
Trond Myklebust 已提交
4991
static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
L
Linus Torvalds 已提交
4992 4993 4994 4995
{
	int status;

	status = decode_op_hdr(xdr, OP_LOCK);
4996 4997
	if (status == -EIO)
		goto out;
L
Linus Torvalds 已提交
4998
	if (status == 0) {
4999
		status = decode_lock_stateid(xdr, &res->stateid);
5000 5001
		if (unlikely(status))
			goto out;
L
Linus Torvalds 已提交
5002
	} else if (status == -NFS4ERR_DENIED)
5003 5004 5005 5006 5007
		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 已提交
5008 5009 5010
	return status;
}

T
Trond Myklebust 已提交
5011
static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res)
L
Linus Torvalds 已提交
5012 5013 5014 5015
{
	int status;
	status = decode_op_hdr(xdr, OP_LOCKT);
	if (status == -NFS4ERR_DENIED)
T
Trond Myklebust 已提交
5016
		return decode_lock_denied(xdr, res->denied);
L
Linus Torvalds 已提交
5017 5018 5019
	return status;
}

T
Trond Myklebust 已提交
5020
static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
L
Linus Torvalds 已提交
5021 5022 5023 5024
{
	int status;

	status = decode_op_hdr(xdr, OP_LOCKU);
5025 5026
	if (status != -EIO)
		nfs_increment_lock_seqid(status, res->seqid);
5027
	if (status == 0)
5028
		status = decode_lock_stateid(xdr, &res->stateid);
L
Linus Torvalds 已提交
5029 5030 5031
	return status;
}

5032 5033 5034 5035 5036
static int decode_release_lockowner(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_RELEASE_LOCKOWNER);
}

L
Linus Torvalds 已提交
5037 5038 5039 5040 5041 5042
static int decode_lookup(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_LOOKUP);
}

/* This is too sick! */
5043 5044
static int decode_space_limit(struct xdr_stream *xdr,
		unsigned long *pagemod_limit)
L
Linus Torvalds 已提交
5045
{
A
Andy Adamson 已提交
5046
	__be32 *p;
L
Linus Torvalds 已提交
5047
	uint32_t limit_type, nblocks, blocksize;
5048
	u64 maxsize = 0;
L
Linus Torvalds 已提交
5049

B
Benny Halevy 已提交
5050 5051 5052
	p = xdr_inline_decode(xdr, 12);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
5053
	limit_type = be32_to_cpup(p++);
L
Linus Torvalds 已提交
5054
	switch (limit_type) {
5055 5056
	case NFS4_LIMIT_SIZE:
		xdr_decode_hyper(p, &maxsize);
A
Andy Adamson 已提交
5057
		break;
5058
	case NFS4_LIMIT_BLOCKS:
B
Benny Halevy 已提交
5059
		nblocks = be32_to_cpup(p++);
5060
		blocksize = be32_to_cpup(p);
5061
		maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
L
Linus Torvalds 已提交
5062
	}
5063
	maxsize >>= PAGE_SHIFT;
5064
	*pagemod_limit = min_t(u64, maxsize, ULONG_MAX);
L
Linus Torvalds 已提交
5065
	return 0;
B
Benny Halevy 已提交
5066 5067 5068
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
5069 5070
}

5071 5072 5073
static int decode_rw_delegation(struct xdr_stream *xdr,
		uint32_t delegation_type,
		struct nfs_openres *res)
L
Linus Torvalds 已提交
5074
{
A
Andy Adamson 已提交
5075
	__be32 *p;
5076
	int status;
L
Linus Torvalds 已提交
5077

5078
	status = decode_delegation_stateid(xdr, &res->delegation);
5079 5080
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
5081 5082 5083
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
5084
	res->do_recall = be32_to_cpup(p);
A
Andy Adamson 已提交
5085

L
Linus Torvalds 已提交
5086
	switch (delegation_type) {
A
Andy Adamson 已提交
5087 5088 5089 5090 5091
	case NFS4_OPEN_DELEGATE_READ:
		res->delegation_type = FMODE_READ;
		break;
	case NFS4_OPEN_DELEGATE_WRITE:
		res->delegation_type = FMODE_WRITE|FMODE_READ;
5092
		if (decode_space_limit(xdr, &res->pagemod_limit) < 0)
L
Linus Torvalds 已提交
5093 5094
				return -EIO;
	}
5095
	return decode_ace(xdr, NULL, res->server->nfs_client);
B
Benny Halevy 已提交
5096 5097 5098
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
5099 5100
}

5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146
static int decode_no_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
{
	__be32 *p;
	uint32_t why_no_delegation;

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
	why_no_delegation = be32_to_cpup(p);
	switch (why_no_delegation) {
		case WND4_CONTENTION:
		case WND4_RESOURCE:
			xdr_inline_decode(xdr, 4);
			/* Ignore for now */
	}
	return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}

static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
{
	__be32 *p;
	uint32_t delegation_type;

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
	delegation_type = be32_to_cpup(p);
	res->delegation_type = 0;
	switch (delegation_type) {
	case NFS4_OPEN_DELEGATE_NONE:
		return 0;
	case NFS4_OPEN_DELEGATE_READ:
	case NFS4_OPEN_DELEGATE_WRITE:
		return decode_rw_delegation(xdr, delegation_type, res);
	case NFS4_OPEN_DELEGATE_NONE_EXT:
		return decode_no_delegation(xdr, res);
	}
	return -EIO;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}

L
Linus Torvalds 已提交
5147 5148
static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
{
A
Andy Adamson 已提交
5149
	__be32 *p;
5150
	uint32_t savewords, bmlen, i;
A
Andy Adamson 已提交
5151
	int status;
L
Linus Torvalds 已提交
5152

5153 5154 5155 5156 5157
	if (!__decode_op_hdr(xdr, OP_OPEN, &status))
		return status;
	nfs_increment_open_seqid(status, res->seqid);
	if (status)
		return status;
5158
	status = decode_open_stateid(xdr, &res->stateid);
5159
	if (unlikely(status))
A
Andy Adamson 已提交
5160
		return status;
L
Linus Torvalds 已提交
5161

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

B
Benny Halevy 已提交
5164 5165 5166
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
5167
	res->rflags = be32_to_cpup(p++);
5168
	bmlen = be32_to_cpup(p);
A
Andy Adamson 已提交
5169 5170
	if (bmlen > 10)
		goto xdr_error;
L
Linus Torvalds 已提交
5171

B
Benny Halevy 已提交
5172 5173 5174
	p = xdr_inline_decode(xdr, bmlen << 2);
	if (unlikely(!p))
		goto out_overflow;
5175 5176
	savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE);
	for (i = 0; i < savewords; ++i)
B
Benny Halevy 已提交
5177
		res->attrset[i] = be32_to_cpup(p++);
5178 5179 5180
	for (; i < NFS4_BITMAP_SIZE; i++)
		res->attrset[i] = 0;

L
Linus Torvalds 已提交
5181 5182
	return decode_delegation(xdr, res);
xdr_error:
5183
	dprintk("%s: Bitmap too large! Length = %u\n", __func__, bmlen);
L
Linus Torvalds 已提交
5184
	return -EIO;
B
Benny Halevy 已提交
5185 5186 5187
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
5188 5189 5190 5191 5192 5193
}

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

A
Andy Adamson 已提交
5194
	status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
5195 5196
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
5197
	if (!status)
5198
		status = decode_open_stateid(xdr, &res->stateid);
5199
	return status;
L
Linus Torvalds 已提交
5200 5201 5202 5203 5204 5205 5206
}

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

	status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE);
5207 5208
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
5209
	if (!status)
5210
		status = decode_open_stateid(xdr, &res->stateid);
5211
	return status;
L
Linus Torvalds 已提交
5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223
}

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);
}

5224 5225
static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req,
		       struct nfs_pgio_res *res)
L
Linus Torvalds 已提交
5226
{
A
Al Viro 已提交
5227
	__be32 *p;
5228
	uint32_t count, eof, recvd;
L
Linus Torvalds 已提交
5229 5230 5231 5232 5233
	int status;

	status = decode_op_hdr(xdr, OP_READ);
	if (status)
		return status;
B
Benny Halevy 已提交
5234 5235 5236
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
5237
	eof = be32_to_cpup(p++);
5238
	count = be32_to_cpup(p);
5239
	recvd = xdr_read_pages(xdr, count);
L
Linus Torvalds 已提交
5240
	if (count > recvd) {
5241
		dprintk("NFS: server cheating in read reply: "
L
Linus Torvalds 已提交
5242 5243 5244 5245 5246 5247 5248
				"count %u > recvd %u\n", count, recvd);
		count = recvd;
		eof = 0;
	}
	res->eof = eof;
	res->count = count;
	return 0;
B
Benny Halevy 已提交
5249 5250 5251
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
5252 5253 5254 5255
}

static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
{
5256
	int		status;
5257
	__be32		verf[2];
L
Linus Torvalds 已提交
5258 5259

	status = decode_op_hdr(xdr, OP_READDIR);
5260 5261 5262
	if (!status)
		status = decode_verifier(xdr, readdir->verifier.data);
	if (unlikely(status))
L
Linus Torvalds 已提交
5263
		return status;
5264
	memcpy(verf, readdir->verifier.data, sizeof(verf));
5265
	dprintk("%s: verifier = %08x:%08x\n",
5266
			__func__, verf[0], verf[1]);
5267
	return xdr_read_pages(xdr, xdr->buf->page_len);
L
Linus Torvalds 已提交
5268 5269 5270 5271 5272
}

static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
{
	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
5273
	u32 len, recvd;
A
Al Viro 已提交
5274
	__be32 *p;
L
Linus Torvalds 已提交
5275 5276 5277 5278 5279 5280 5281
	int status;

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

	/* Convert length of symlink */
B
Benny Halevy 已提交
5282 5283 5284
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
5285
	len = be32_to_cpup(p);
L
Linus Torvalds 已提交
5286
	if (len >= rcvbuf->page_len || len <= 0) {
5287
		dprintk("nfs: server returned giant symlink!\n");
L
Linus Torvalds 已提交
5288 5289
		return -ENAMETOOLONG;
	}
5290
	recvd = xdr_read_pages(xdr, len);
L
Linus Torvalds 已提交
5291
	if (recvd < len) {
5292
		dprintk("NFS: server cheating in readlink reply: "
L
Linus Torvalds 已提交
5293 5294 5295 5296 5297 5298 5299 5300 5301 5302
				"count %u > recvd %u\n", len, recvd);
		return -EIO;
	}
	/*
	 * 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).
	 */
5303
	xdr_terminate_string(rcvbuf, len);
L
Linus Torvalds 已提交
5304
	return 0;
B
Benny Halevy 已提交
5305 5306 5307
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341
}

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);
}

5342 5343 5344 5345 5346 5347
static int
decode_restorefh(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_RESTOREFH);
}

5348
static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
5349
			 struct nfs_getaclres *res)
5350
{
5351
	unsigned int savep;
5352
	uint32_t attrlen,
5353
		 bitmap[3] = {0};
5354
	int status;
5355
	unsigned int pg_offset;
5356

5357
	res->acl_len = 0;
5358 5359
	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
		goto out;
5360

5361 5362
	xdr_enter_page(xdr, xdr->buf->page_len);

5363 5364
	/* Calculate the offset of the page data */
	pg_offset = xdr->buf->head[0].iov_len;
5365

5366 5367 5368 5369 5370 5371 5372 5373 5374
	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)) {

5375 5376 5377
		/* The bitmap (xdr len + bitmaps) and the attr xdr len words
		 * are stored with the acl data to handle the problem of
		 * variable length bitmaps.*/
5378
		res->acl_data_offset = xdr_stream_pos(xdr) - pg_offset;
5379
		res->acl_len = attrlen;
5380 5381 5382 5383 5384

		/* Check for receive buffer overflow */
		if (res->acl_len > (xdr->nwords << 2) ||
		    res->acl_len + res->acl_data_offset > xdr->buf->page_len) {
			res->acl_flags |= NFS4_ACL_TRUNC;
5385
			dprintk("NFS: acl reply: attrlen %u > page_len %u\n",
5386
					attrlen, xdr->nwords << 2);
5387
		}
J
J. Bruce Fields 已提交
5388 5389
	} else
		status = -EOPNOTSUPP;
5390 5391 5392 5393 5394

out:
	return status;
}

L
Linus Torvalds 已提交
5395 5396 5397 5398 5399 5400
static int
decode_savefh(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_SAVEFH);
}

5401
static int decode_setattr(struct xdr_stream *xdr)
L
Linus Torvalds 已提交
5402
{
A
Al Viro 已提交
5403
	__be32 *p;
L
Linus Torvalds 已提交
5404 5405 5406 5407 5408 5409
	uint32_t bmlen;
	int status;

	status = decode_op_hdr(xdr, OP_SETATTR);
	if (status)
		return status;
B
Benny Halevy 已提交
5410 5411 5412
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
5413
	bmlen = be32_to_cpup(p);
B
Benny Halevy 已提交
5414 5415 5416 5417 5418 5419
	p = xdr_inline_decode(xdr, bmlen << 2);
	if (likely(p))
		return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
5420 5421
}

5422
static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid_res *res)
L
Linus Torvalds 已提交
5423
{
A
Al Viro 已提交
5424
	__be32 *p;
L
Linus Torvalds 已提交
5425 5426 5427
	uint32_t opnum;
	int32_t nfserr;

B
Benny Halevy 已提交
5428 5429 5430
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
5431
	opnum = be32_to_cpup(p++);
L
Linus Torvalds 已提交
5432
	if (opnum != OP_SETCLIENTID) {
5433
		dprintk("nfs: decode_setclientid: Server returned operation"
5434
			" %d\n", opnum);
L
Linus Torvalds 已提交
5435 5436
		return -EIO;
	}
5437
	nfserr = be32_to_cpup(p);
L
Linus Torvalds 已提交
5438
	if (nfserr == NFS_OK) {
B
Benny Halevy 已提交
5439 5440 5441
		p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE);
		if (unlikely(!p))
			goto out_overflow;
5442 5443
		p = xdr_decode_hyper(p, &res->clientid);
		memcpy(res->confirm.data, p, NFS4_VERIFIER_SIZE);
L
Linus Torvalds 已提交
5444 5445 5446 5447
	} else if (nfserr == NFSERR_CLID_INUSE) {
		uint32_t len;

		/* skip netid string */
B
Benny Halevy 已提交
5448 5449 5450
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
5451
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
5452 5453 5454
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
L
Linus Torvalds 已提交
5455 5456

		/* skip uaddr string */
B
Benny Halevy 已提交
5457 5458 5459
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
5460
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
5461 5462 5463
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
L
Linus Torvalds 已提交
5464 5465
		return -NFSERR_CLID_INUSE;
	} else
5466
		return nfs4_stat_to_errno(nfserr);
L
Linus Torvalds 已提交
5467 5468

	return 0;
B
Benny Halevy 已提交
5469 5470 5471
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
5472 5473 5474 5475 5476 5477 5478
}

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

5479
static int decode_write(struct xdr_stream *xdr, struct nfs_pgio_res *res)
L
Linus Torvalds 已提交
5480
{
A
Al Viro 已提交
5481
	__be32 *p;
L
Linus Torvalds 已提交
5482 5483 5484 5485 5486 5487
	int status;

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

5488
	p = xdr_inline_decode(xdr, 8);
B
Benny Halevy 已提交
5489 5490
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
5491 5492
	res->count = be32_to_cpup(p++);
	res->verf->committed = be32_to_cpup(p++);
5493
	return decode_write_verifier(xdr, &res->verf->verifier);
B
Benny Halevy 已提交
5494 5495 5496
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
5497 5498 5499 5500 5501 5502 5503
}

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

5504 5505
static int decode_secinfo_gss(struct xdr_stream *xdr,
			      struct nfs4_secinfo4 *flavor)
B
Bryan Schumaker 已提交
5506
{
5507
	u32 oid_len;
B
Bryan Schumaker 已提交
5508 5509 5510 5511 5512
	__be32 *p;

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
5513 5514
	oid_len = be32_to_cpup(p);
	if (oid_len > GSS_OID_MAX_LEN)
B
Bryan Schumaker 已提交
5515 5516
		goto out_err;

5517
	p = xdr_inline_decode(xdr, oid_len);
B
Bryan Schumaker 已提交
5518 5519
	if (unlikely(!p))
		goto out_overflow;
5520 5521
	memcpy(flavor->flavor_info.oid.data, p, oid_len);
	flavor->flavor_info.oid.len = oid_len;
B
Bryan Schumaker 已提交
5522 5523 5524 5525

	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
5526 5527
	flavor->flavor_info.qop = be32_to_cpup(p++);
	flavor->flavor_info.service = be32_to_cpup(p);
B
Bryan Schumaker 已提交
5528 5529 5530 5531 5532 5533 5534 5535 5536 5537

	return 0;

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

B
Bryan Schumaker 已提交
5538
static int decode_secinfo_common(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
B
Bryan Schumaker 已提交
5539
{
5540 5541
	struct nfs4_secinfo4 *sec_flavor;
	unsigned int i, num_flavors;
B
Bryan Schumaker 已提交
5542 5543 5544 5545 5546 5547 5548
	int status;
	__be32 *p;

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

5549 5550 5551 5552
	res->flavors->num_flavors = 0;
	num_flavors = be32_to_cpup(p);

	for (i = 0; i < num_flavors; i++) {
B
Bryan Schumaker 已提交
5553
		sec_flavor = &res->flavors->flavors[i];
5554
		if ((char *)&sec_flavor[1] - (char *)res->flavors > PAGE_SIZE)
B
Bryan Schumaker 已提交
5555 5556 5557 5558 5559 5560 5561 5562
			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) {
5563 5564 5565
			status = decode_secinfo_gss(xdr, sec_flavor);
			if (status)
				goto out;
B
Bryan Schumaker 已提交
5566
		}
5567
		res->flavors->num_flavors++;
B
Bryan Schumaker 已提交
5568 5569
	}

B
Bryan Schumaker 已提交
5570
	status = 0;
5571 5572
out:
	return status;
B
Bryan Schumaker 已提交
5573 5574 5575 5576 5577
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}

B
Bryan Schumaker 已提交
5578 5579 5580 5581 5582 5583 5584 5585
static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
{
	int status = decode_op_hdr(xdr, OP_SECINFO);
	if (status)
		return status;
	return decode_secinfo_common(xdr, res);
}

B
Benny Halevy 已提交
5586
#if defined(CONFIG_NFS_V4_1)
B
Bryan Schumaker 已提交
5587 5588 5589 5590 5591 5592 5593 5594
static int decode_secinfo_no_name(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
{
	int status = decode_op_hdr(xdr, OP_SECINFO_NO_NAME);
	if (status)
		return status;
	return decode_secinfo_common(xdr, res);
}

5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611
static int decode_op_map(struct xdr_stream *xdr, struct nfs4_op_map *op_map)
{
	__be32 *p;
	uint32_t bitmap_words;
	unsigned int i;

	p = xdr_inline_decode(xdr, 4);
	bitmap_words = be32_to_cpup(p++);
	if (bitmap_words > NFS4_OP_MAP_NUM_WORDS)
		return -EIO;
	p = xdr_inline_decode(xdr, 4 * bitmap_words);
	for (i = 0; i < bitmap_words; i++)
		op_map->u.words[i] = be32_to_cpup(p++);

	return 0;
}

B
Benny Halevy 已提交
5612 5613 5614 5615 5616
static int decode_exchange_id(struct xdr_stream *xdr,
			      struct nfs41_exchange_id_res *res)
{
	__be32 *p;
	uint32_t dummy;
5617
	char *dummy_str;
B
Benny Halevy 已提交
5618
	int status;
5619
	uint32_t impl_id_count;
B
Benny Halevy 已提交
5620 5621 5622 5623 5624

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

B
Benny Halevy 已提交
5625 5626 5627
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
5628
	xdr_decode_hyper(p, &res->clientid);
B
Benny Halevy 已提交
5629 5630 5631
	p = xdr_inline_decode(xdr, 12);
	if (unlikely(!p))
		goto out_overflow;
5632 5633
	res->seqid = be32_to_cpup(p++);
	res->flags = be32_to_cpup(p++);
B
Benny Halevy 已提交
5634

5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648
	res->state_protect.how = be32_to_cpup(p);
	switch (res->state_protect.how) {
	case SP4_NONE:
		break;
	case SP4_MACH_CRED:
		status = decode_op_map(xdr, &res->state_protect.enforce);
		if (status)
			return status;
		status = decode_op_map(xdr, &res->state_protect.allow);
		if (status)
			return status;
		break;
	default:
		WARN_ON_ONCE(1);
B
Benny Halevy 已提交
5649
		return -EIO;
5650
	}
B
Benny Halevy 已提交
5651

5652
	/* server_owner4.so_minor_id */
B
Benny Halevy 已提交
5653 5654 5655
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
5656
	p = xdr_decode_hyper(p, &res->server_owner->minor_id);
B
Benny Halevy 已提交
5657

5658
	/* server_owner4.so_major_id */
5659 5660 5661
	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
	if (unlikely(status))
		return status;
5662 5663 5664 5665
	if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
		return -EIO;
	memcpy(res->server_owner->major_id, dummy_str, dummy);
	res->server_owner->major_id_sz = dummy;
B
Benny Halevy 已提交
5666

5667
	/* server_scope4 */
5668 5669 5670
	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
	if (unlikely(status))
		return status;
5671 5672 5673 5674 5675
	if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
		return -EIO;
	memcpy(res->server_scope->server_scope, dummy_str, dummy);
	res->server_scope->server_scope_sz = dummy;

5676 5677 5678 5679 5680
	/* Implementation Id */
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
	impl_id_count = be32_to_cpup(p++);
B
Benny Halevy 已提交
5681

5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707
	if (impl_id_count) {
		/* nii_domain */
		status = decode_opaque_inline(xdr, &dummy, &dummy_str);
		if (unlikely(status))
			return status;
		if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
			return -EIO;
		memcpy(res->impl_id->domain, dummy_str, dummy);

		/* nii_name */
		status = decode_opaque_inline(xdr, &dummy, &dummy_str);
		if (unlikely(status))
			return status;
		if (unlikely(dummy > NFS4_OPAQUE_LIMIT))
			return -EIO;
		memcpy(res->impl_id->name, dummy_str, dummy);

		/* nii_date */
		p = xdr_inline_decode(xdr, 12);
		if (unlikely(!p))
			goto out_overflow;
		p = xdr_decode_hyper(p, &res->impl_id->date.seconds);
		res->impl_id->date.nseconds = be32_to_cpup(p);

		/* if there's more than one entry, ignore the rest */
	}
B
Benny Halevy 已提交
5708
	return 0;
B
Benny Halevy 已提交
5709 5710 5711
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
B
Benny Halevy 已提交
5712
}
A
Andy Adamson 已提交
5713 5714 5715 5716 5717

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

B
Benny Halevy 已提交
5720 5721 5722
	p = xdr_inline_decode(xdr, 28);
	if (unlikely(!p))
		goto out_overflow;
5723 5724 5725
	val = be32_to_cpup(p++);	/* headerpadsz */
	if (val)
		return -EINVAL;		/* no support for header padding yet */
B
Benny Halevy 已提交
5726 5727 5728 5729 5730
	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++);
5731
	nr_attrs = be32_to_cpup(p);
A
Andy Adamson 已提交
5732
	if (unlikely(nr_attrs > 1)) {
5733 5734
		printk(KERN_WARNING "NFS: %s: Invalid rdma channel attrs "
			"count %u\n", __func__, nr_attrs);
A
Andy Adamson 已提交
5735 5736
		return -EINVAL;
	}
B
Benny Halevy 已提交
5737 5738 5739 5740 5741
	if (nr_attrs == 1) {
		p = xdr_inline_decode(xdr, 4); /* skip rdma_attrs */
		if (unlikely(!p))
			goto out_overflow;
	}
A
Andy Adamson 已提交
5742
	return 0;
B
Benny Halevy 已提交
5743 5744 5745
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
A
Andy Adamson 已提交
5746 5747
}

5748 5749 5750
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 已提交
5751 5752
}

5753 5754 5755 5756 5757 5758 5759 5760
static int decode_bind_conn_to_session(struct xdr_stream *xdr,
				struct nfs41_bind_conn_to_session_res *res)
{
	__be32 *p;
	int status;

	status = decode_op_hdr(xdr, OP_BIND_CONN_TO_SESSION);
	if (!status)
5761
		status = decode_sessionid(xdr, &res->sessionid);
5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783
	if (unlikely(status))
		return status;

	/* dir flags, rdma mode bool */
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;

	res->dir = be32_to_cpup(p++);
	if (res->dir == 0 || res->dir > NFS4_CDFS4_BOTH)
		return -EIO;
	if (be32_to_cpup(p) == 0)
		res->use_conn_in_rdma_mode = false;
	else
		res->use_conn_in_rdma_mode = true;

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

A
Andy Adamson 已提交
5784 5785 5786 5787 5788 5789 5790
static int decode_create_session(struct xdr_stream *xdr,
				 struct nfs41_create_session_res *res)
{
	__be32 *p;
	int status;

	status = decode_op_hdr(xdr, OP_CREATE_SESSION);
5791
	if (!status)
5792
		status = decode_sessionid(xdr, &res->sessionid);
5793
	if (unlikely(status))
A
Andy Adamson 已提交
5794 5795 5796
		return status;

	/* seqid, flags */
B
Benny Halevy 已提交
5797 5798 5799
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
5800 5801
	res->seqid = be32_to_cpup(p++);
	res->flags = be32_to_cpup(p);
A
Andy Adamson 已提交
5802 5803

	/* Channel attributes */
5804
	status = decode_chan_attrs(xdr, &res->fc_attrs);
A
Andy Adamson 已提交
5805
	if (!status)
5806
		status = decode_chan_attrs(xdr, &res->bc_attrs);
A
Andy Adamson 已提交
5807
	return status;
B
Benny Halevy 已提交
5808 5809 5810
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
A
Andy Adamson 已提交
5811
}
A
Andy Adamson 已提交
5812 5813 5814 5815 5816

static int decode_destroy_session(struct xdr_stream *xdr, void *dummy)
{
	return decode_op_hdr(xdr, OP_DESTROY_SESSION);
}
5817

T
Trond Myklebust 已提交
5818 5819 5820 5821 5822
static int decode_destroy_clientid(struct xdr_stream *xdr, void *dummy)
{
	return decode_op_hdr(xdr, OP_DESTROY_CLIENTID);
}

5823 5824 5825 5826
static int decode_reclaim_complete(struct xdr_stream *xdr, void *dummy)
{
	return decode_op_hdr(xdr, OP_RECLAIM_COMPLETE);
}
B
Benny Halevy 已提交
5827 5828
#endif /* CONFIG_NFS_V4_1 */

5829 5830 5831 5832 5833
static int decode_sequence(struct xdr_stream *xdr,
			   struct nfs4_sequence_res *res,
			   struct rpc_rqst *rqstp)
{
#if defined(CONFIG_NFS_V4_1)
5834
	struct nfs4_session *session;
A
Andy Adamson 已提交
5835 5836 5837 5838 5839
	struct nfs4_sessionid id;
	u32 dummy;
	int status;
	__be32 *p;

5840
	if (res->sr_slot == NULL)
5841
		return 0;
C
Chuck Lever 已提交
5842 5843
	if (!res->sr_slot->table->session)
		return 0;
5844

A
Andy Adamson 已提交
5845
	status = decode_op_hdr(xdr, OP_SEQUENCE);
5846 5847 5848
	if (!status)
		status = decode_sessionid(xdr, &id);
	if (unlikely(status))
A
Andy Adamson 已提交
5849
		goto out_err;
5850

A
Andy Adamson 已提交
5851 5852 5853 5854
	/*
	 * If the server returns different values for sessionID, slotID or
	 * sequence number, the server is looney tunes.
	 */
5855
	status = -EREMOTEIO;
5856
	session = res->sr_slot->table->session;
A
Andy Adamson 已提交
5857

5858
	if (memcmp(id.data, session->sess_id.data,
A
Andy Adamson 已提交
5859 5860 5861 5862
		   NFS4_MAX_SESSIONID_LEN)) {
		dprintk("%s Invalid session id\n", __func__);
		goto out_err;
	}
5863

B
Benny Halevy 已提交
5864 5865 5866
	p = xdr_inline_decode(xdr, 20);
	if (unlikely(!p))
		goto out_overflow;
5867

A
Andy Adamson 已提交
5868
	/* seqid */
B
Benny Halevy 已提交
5869
	dummy = be32_to_cpup(p++);
5870
	if (dummy != res->sr_slot->seq_nr) {
A
Andy Adamson 已提交
5871 5872 5873 5874
		dprintk("%s Invalid sequence number\n", __func__);
		goto out_err;
	}
	/* slot id */
B
Benny Halevy 已提交
5875
	dummy = be32_to_cpup(p++);
5876
	if (dummy != res->sr_slot->slot_nr) {
A
Andy Adamson 已提交
5877 5878 5879
		dprintk("%s Invalid slot id\n", __func__);
		goto out_err;
	}
5880 5881
	/* highest slot id */
	res->sr_highest_slotid = be32_to_cpup(p++);
5882 5883
	/* target highest slot id */
	res->sr_target_highest_slotid = be32_to_cpup(p++);
5884 5885
	/* result flags */
	res->sr_status_flags = be32_to_cpup(p);
A
Andy Adamson 已提交
5886 5887 5888 5889
	status = 0;
out_err:
	res->sr_status = status;
	return status;
B
Benny Halevy 已提交
5890 5891 5892 5893
out_overflow:
	print_overflow_msg(__func__, xdr);
	status = -EIO;
	goto out_err;
A
Andy Adamson 已提交
5894
#else  /* CONFIG_NFS_V4_1 */
5895
	return 0;
A
Andy Adamson 已提交
5896
#endif /* CONFIG_NFS_V4_1 */
5897 5898
}

5899
#if defined(CONFIG_NFS_V4_1)
5900 5901 5902 5903 5904 5905
static int decode_layout_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
{
	stateid->type = NFS4_LAYOUT_STATEID_TYPE;
	return decode_stateid(xdr, stateid);
}

5906
static int decode_getdeviceinfo(struct xdr_stream *xdr,
5907
				struct nfs4_getdeviceinfo_res *res)
5908
{
5909
	struct pnfs_device *pdev = res->pdev;
5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941
	__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);
5942 5943
	if (xdr_read_pages(xdr, pdev->mincount) != pdev->mincount)
		goto out_overflow;
5944 5945 5946 5947 5948 5949 5950

	/* 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) {
5951
		uint32_t i;
5952 5953 5954 5955

		p = xdr_inline_decode(xdr, 4 * len);
		if (unlikely(!p))
			goto out_overflow;
5956

5957
		res->notification = be32_to_cpup(p++);
5958 5959 5960
		for (i = 1; i < len; i++) {
			if (be32_to_cpup(p++)) {
				dprintk("%s: unsupported notification\n",
5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977
					__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;
5978
	u32 recvd;
5979 5980 5981 5982

	status = decode_op_hdr(xdr, OP_LAYOUTGET);
	if (status)
		return status;
5983 5984 5985 5986
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
	res->return_on_close = be32_to_cpup(p);
5987
	decode_layout_stateid(xdr, &res->stateid);
5988
	p = xdr_inline_decode(xdr, 4);
5989 5990 5991 5992 5993 5994 5995 5996 5997
	if (unlikely(!p))
		goto out_overflow;
	layout_count = be32_to_cpup(p);
	if (!layout_count) {
		dprintk("%s: server responded with empty layout array\n",
			__func__);
		return -EINVAL;
	}

5998
	p = xdr_inline_decode(xdr, 28);
5999 6000 6001 6002 6003 6004
	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++);
6005
	res->layoutp->len = be32_to_cpup(p);
6006 6007 6008 6009 6010 6011 6012

	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,
6013 6014
		res->layoutp->len);

6015
	recvd = xdr_read_pages(xdr, res->layoutp->len);
6016 6017 6018 6019 6020 6021
	if (res->layoutp->len > recvd) {
		dprintk("NFS: server cheating in layoutget reply: "
				"layout len %u > recvd %u\n",
				res->layoutp->len, recvd);
		return -EINVAL;
	}
6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037

	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 已提交
6038

B
Benny Halevy 已提交
6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052
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)
6053
		status = decode_layout_stateid(xdr, &res->stateid);
B
Benny Halevy 已提交
6054 6055 6056 6057 6058 6059
	return status;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
}

A
Andy Adamson 已提交
6060 6061 6062 6063 6064 6065 6066 6067 6068
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);
A
Andy Adamson 已提交
6069
	res->status = status;
A
Andy Adamson 已提交
6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088
	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;
}
B
Bryan Schumaker 已提交
6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111

static int decode_test_stateid(struct xdr_stream *xdr,
			       struct nfs41_test_stateid_res *res)
{
	__be32 *p;
	int status;
	int num_res;

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

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
	num_res = be32_to_cpup(p++);
	if (num_res != 1)
		goto out;

	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
	res->status = be32_to_cpup(p++);
6112 6113

	return status;
B
Bryan Schumaker 已提交
6114 6115 6116 6117 6118
out_overflow:
	print_overflow_msg(__func__, xdr);
out:
	return -EIO;
}
B
Bryan Schumaker 已提交
6119 6120 6121 6122

static int decode_free_stateid(struct xdr_stream *xdr,
			       struct nfs41_free_stateid_res *res)
{
A
Andy Adamson 已提交
6123
	res->status = decode_op_hdr(xdr, OP_FREE_STATEID);
B
Bryan Schumaker 已提交
6124 6125
	return res->status;
}
6126 6127 6128 6129 6130 6131 6132
#else
static inline
int decode_layoutreturn(struct xdr_stream *xdr,
			       struct nfs4_layoutreturn_res *res)
{
	return 0;
}
6133 6134
#endif /* CONFIG_NFS_V4_1 */

6135 6136 6137 6138
/*
 * END OF "GENERIC" DECODE ROUTINES.
 */

L
Linus Torvalds 已提交
6139 6140 6141
/*
 * Decode OPEN_DOWNGRADE response
 */
6142 6143 6144
static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp,
				       struct xdr_stream *xdr,
				       struct nfs_closeres *res)
L
Linus Torvalds 已提交
6145
{
A
Andy Adamson 已提交
6146 6147 6148
	struct compound_hdr hdr;
	int status;

6149
	status = decode_compound_hdr(xdr, &hdr);
6150 6151
	if (status)
		goto out;
6152
	status = decode_sequence(xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
6153 6154
	if (status)
		goto out;
6155
	status = decode_putfh(xdr);
A
Andy Adamson 已提交
6156 6157
	if (status)
		goto out;
6158 6159 6160 6161 6162 6163
	if (res->lr_res) {
		status = decode_layoutreturn(xdr, res->lr_res);
		res->lr_ret = status;
		if (status)
			goto out;
	}
6164
	status = decode_open_downgrade(xdr, res);
L
Linus Torvalds 已提交
6165
out:
A
Andy Adamson 已提交
6166
	return status;
L
Linus Torvalds 已提交
6167 6168 6169 6170 6171
}

/*
 * Decode ACCESS response
 */
6172 6173
static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			       struct nfs4_accessres *res)
L
Linus Torvalds 已提交
6174 6175 6176
{
	struct compound_hdr hdr;
	int status;
6177

6178
	status = decode_compound_hdr(xdr, &hdr);
6179 6180
	if (status)
		goto out;
6181
	status = decode_sequence(xdr, &res->seq_res, rqstp);
6182
	if (status)
L
Linus Torvalds 已提交
6183
		goto out;
6184
	status = decode_putfh(xdr);
6185 6186
	if (status != 0)
		goto out;
6187
	status = decode_access(xdr, &res->supported, &res->access);
6188 6189
	if (status != 0)
		goto out;
6190
	decode_getfattr(xdr, res->fattr, res->server);
L
Linus Torvalds 已提交
6191 6192 6193 6194 6195 6196 6197
out:
	return status;
}

/*
 * Decode LOOKUP response
 */
6198 6199
static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			       struct nfs4_lookup_res *res)
L
Linus Torvalds 已提交
6200 6201 6202
{
	struct compound_hdr hdr;
	int status;
6203

6204
	status = decode_compound_hdr(xdr, &hdr);
6205 6206
	if (status)
		goto out;
6207
	status = decode_sequence(xdr, &res->seq_res, rqstp);
6208
	if (status)
L
Linus Torvalds 已提交
6209
		goto out;
6210 6211
	status = decode_putfh(xdr);
	if (status)
L
Linus Torvalds 已提交
6212
		goto out;
6213 6214
	status = decode_lookup(xdr);
	if (status)
L
Linus Torvalds 已提交
6215
		goto out;
6216 6217
	status = decode_getfh(xdr, res->fh);
	if (status)
L
Linus Torvalds 已提交
6218
		goto out;
6219
	status = decode_getfattr_label(xdr, res->fattr, res->label, res->server);
L
Linus Torvalds 已提交
6220 6221 6222 6223 6224 6225 6226
out:
	return status;
}

/*
 * Decode LOOKUP_ROOT response
 */
6227 6228 6229
static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp,
				    struct xdr_stream *xdr,
				    struct nfs4_lookup_res *res)
L
Linus Torvalds 已提交
6230 6231 6232
{
	struct compound_hdr hdr;
	int status;
6233

6234
	status = decode_compound_hdr(xdr, &hdr);
6235 6236
	if (status)
		goto out;
6237
	status = decode_sequence(xdr, &res->seq_res, rqstp);
6238
	if (status)
L
Linus Torvalds 已提交
6239
		goto out;
6240 6241
	status = decode_putrootfh(xdr);
	if (status)
L
Linus Torvalds 已提交
6242
		goto out;
6243 6244
	status = decode_getfh(xdr, res->fh);
	if (status == 0)
6245 6246
		status = decode_getfattr_label(xdr, res->fattr,
						res->label, res->server);
L
Linus Torvalds 已提交
6247 6248 6249 6250 6251 6252 6253
out:
	return status;
}

/*
 * Decode REMOVE response
 */
6254 6255
static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			       struct nfs_removeres *res)
L
Linus Torvalds 已提交
6256 6257 6258
{
	struct compound_hdr hdr;
	int status;
6259

6260
	status = decode_compound_hdr(xdr, &hdr);
6261 6262
	if (status)
		goto out;
6263
	status = decode_sequence(xdr, &res->seq_res, rqstp);
6264
	if (status)
L
Linus Torvalds 已提交
6265
		goto out;
6266 6267
	status = decode_putfh(xdr);
	if (status)
6268
		goto out;
6269
	status = decode_remove(xdr, &res->cinfo);
L
Linus Torvalds 已提交
6270 6271 6272 6273 6274 6275 6276
out:
	return status;
}

/*
 * Decode RENAME response
 */
6277 6278
static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			       struct nfs_renameres *res)
L
Linus Torvalds 已提交
6279 6280 6281
{
	struct compound_hdr hdr;
	int status;
6282

6283
	status = decode_compound_hdr(xdr, &hdr);
6284 6285
	if (status)
		goto out;
6286
	status = decode_sequence(xdr, &res->seq_res, rqstp);
6287
	if (status)
L
Linus Torvalds 已提交
6288
		goto out;
6289 6290
	status = decode_putfh(xdr);
	if (status)
L
Linus Torvalds 已提交
6291
		goto out;
6292 6293
	status = decode_savefh(xdr);
	if (status)
L
Linus Torvalds 已提交
6294
		goto out;
6295 6296
	status = decode_putfh(xdr);
	if (status)
L
Linus Torvalds 已提交
6297
		goto out;
6298
	status = decode_rename(xdr, &res->old_cinfo, &res->new_cinfo);
L
Linus Torvalds 已提交
6299 6300 6301 6302 6303 6304 6305
out:
	return status;
}

/*
 * Decode LINK response
 */
6306 6307
static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			     struct nfs4_link_res *res)
L
Linus Torvalds 已提交
6308 6309 6310
{
	struct compound_hdr hdr;
	int status;
6311

6312
	status = decode_compound_hdr(xdr, &hdr);
6313 6314
	if (status)
		goto out;
6315
	status = decode_sequence(xdr, &res->seq_res, rqstp);
6316
	if (status)
L
Linus Torvalds 已提交
6317
		goto out;
6318 6319
	status = decode_putfh(xdr);
	if (status)
L
Linus Torvalds 已提交
6320
		goto out;
6321 6322
	status = decode_savefh(xdr);
	if (status)
L
Linus Torvalds 已提交
6323
		goto out;
6324 6325
	status = decode_putfh(xdr);
	if (status)
L
Linus Torvalds 已提交
6326
		goto out;
6327 6328
	status = decode_link(xdr, &res->cinfo);
	if (status)
6329 6330 6331 6332 6333
		goto out;
	/*
	 * Note order: OP_LINK leaves the directory as the current
	 *             filehandle.
	 */
6334 6335
	status = decode_restorefh(xdr);
	if (status)
6336
		goto out;
6337
	decode_getfattr_label(xdr, res->fattr, res->label, res->server);
L
Linus Torvalds 已提交
6338 6339 6340 6341 6342 6343 6344
out:
	return status;
}

/*
 * Decode CREATE response
 */
6345 6346
static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			       struct nfs4_create_res *res)
L
Linus Torvalds 已提交
6347 6348 6349
{
	struct compound_hdr hdr;
	int status;
6350

6351
	status = decode_compound_hdr(xdr, &hdr);
6352 6353
	if (status)
		goto out;
6354
	status = decode_sequence(xdr, &res->seq_res, rqstp);
6355
	if (status)
L
Linus Torvalds 已提交
6356
		goto out;
6357 6358
	status = decode_putfh(xdr);
	if (status)
6359
		goto out;
6360 6361
	status = decode_create(xdr, &res->dir_cinfo);
	if (status)
L
Linus Torvalds 已提交
6362
		goto out;
6363 6364
	status = decode_getfh(xdr, res->fh);
	if (status)
L
Linus Torvalds 已提交
6365
		goto out;
6366
	decode_getfattr_label(xdr, res->fattr, res->label, res->server);
L
Linus Torvalds 已提交
6367 6368 6369 6370 6371 6372 6373
out:
	return status;
}

/*
 * Decode SYMLINK response
 */
6374 6375
static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
				struct nfs4_create_res *res)
L
Linus Torvalds 已提交
6376
{
6377
	return nfs4_xdr_dec_create(rqstp, xdr, res);
L
Linus Torvalds 已提交
6378 6379 6380 6381 6382
}

/*
 * Decode GETATTR response
 */
6383 6384
static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
				struct nfs4_getattr_res *res)
L
Linus Torvalds 已提交
6385 6386 6387
{
	struct compound_hdr hdr;
	int status;
6388

6389
	status = decode_compound_hdr(xdr, &hdr);
6390 6391
	if (status)
		goto out;
6392
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
6393 6394
	if (status)
		goto out;
6395
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6396 6397
	if (status)
		goto out;
6398
	status = decode_getfattr_label(xdr, res->fattr, res->label, res->server);
L
Linus Torvalds 已提交
6399 6400 6401 6402
out:
	return status;
}

6403 6404 6405
/*
 * Encode an SETACL request
 */
6406 6407
static void nfs4_xdr_enc_setacl(struct rpc_rqst *req, struct xdr_stream *xdr,
				struct nfs_setaclargs *args)
6408
{
A
Andy Adamson 已提交
6409
	struct compound_hdr hdr = {
6410
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
A
Andy Adamson 已提交
6411 6412
	};

6413 6414 6415 6416
	encode_compound_hdr(xdr, req, &hdr);
	encode_sequence(xdr, &args->seq_args, &hdr);
	encode_putfh(xdr, args->fh, &hdr);
	encode_setacl(xdr, args, &hdr);
6417
	encode_nops(&hdr);
6418
}
A
Andy Adamson 已提交
6419

6420 6421 6422 6423
/*
 * Decode SETACL response
 */
static int
6424
nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
B
Benny Halevy 已提交
6425
		    struct nfs_setaclres *res)
6426 6427 6428 6429
{
	struct compound_hdr hdr;
	int status;

6430
	status = decode_compound_hdr(xdr, &hdr);
6431 6432
	if (status)
		goto out;
6433
	status = decode_sequence(xdr, &res->seq_res, rqstp);
6434 6435
	if (status)
		goto out;
6436
	status = decode_putfh(xdr);
6437 6438
	if (status)
		goto out;
6439
	status = decode_setattr(xdr);
6440 6441 6442
out:
	return status;
}
L
Linus Torvalds 已提交
6443

6444 6445 6446 6447
/*
 * Decode GETACL response
 */
static int
6448
nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
B
Benny Halevy 已提交
6449
		    struct nfs_getaclres *res)
6450 6451 6452 6453
{
	struct compound_hdr hdr;
	int status;

6454 6455 6456 6457
	if (res->acl_scratch != NULL) {
		void *p = page_address(res->acl_scratch);
		xdr_set_scratch_buffer(xdr, p, PAGE_SIZE);
	}
6458
	status = decode_compound_hdr(xdr, &hdr);
6459 6460
	if (status)
		goto out;
6461
	status = decode_sequence(xdr, &res->seq_res, rqstp);
6462 6463
	if (status)
		goto out;
6464
	status = decode_putfh(xdr);
6465 6466
	if (status)
		goto out;
6467
	status = decode_getacl(xdr, rqstp, res);
6468 6469 6470 6471 6472

out:
	return status;
}

L
Linus Torvalds 已提交
6473 6474 6475
/*
 * Decode CLOSE response
 */
6476 6477
static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			      struct nfs_closeres *res)
L
Linus Torvalds 已提交
6478
{
A
Andy Adamson 已提交
6479 6480 6481
	struct compound_hdr hdr;
	int status;

6482
	status = decode_compound_hdr(xdr, &hdr);
6483 6484
	if (status)
		goto out;
6485
	status = decode_sequence(xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
6486 6487
	if (status)
		goto out;
6488
	status = decode_putfh(xdr);
A
Andy Adamson 已提交
6489 6490
	if (status)
		goto out;
6491 6492 6493 6494 6495 6496
	if (res->lr_res) {
		status = decode_layoutreturn(xdr, res->lr_res);
		res->lr_ret = status;
		if (status)
			goto out;
	}
6497
	status = decode_close(xdr, res);
6498 6499 6500 6501 6502 6503 6504 6505
	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.
	 */
6506
	decode_getfattr(xdr, res->fattr, res->server);
L
Linus Torvalds 已提交
6507
out:
A
Andy Adamson 已提交
6508
	return status;
L
Linus Torvalds 已提交
6509 6510 6511 6512 6513
}

/*
 * Decode OPEN response
 */
6514 6515
static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			     struct nfs_openres *res)
L
Linus Torvalds 已提交
6516
{
A
Andy Adamson 已提交
6517 6518 6519
	struct compound_hdr hdr;
	int status;

6520
	status = decode_compound_hdr(xdr, &hdr);
6521 6522
	if (status)
		goto out;
6523
	status = decode_sequence(xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
6524 6525
	if (status)
		goto out;
6526
	status = decode_putfh(xdr);
A
Andy Adamson 已提交
6527 6528
	if (status)
		goto out;
6529
	status = decode_open(xdr, res);
6530 6531
	if (status)
		goto out;
6532 6533
	status = decode_getfh(xdr, &res->fh);
	if (status)
L
Linus Torvalds 已提交
6534
		goto out;
6535 6536
	if (res->access_request)
		decode_access(xdr, &res->access_supported, &res->access_result);
6537
	decode_getfattr_label(xdr, res->f_attr, res->f_label, res->server);
L
Linus Torvalds 已提交
6538
out:
A
Andy Adamson 已提交
6539
	return status;
L
Linus Torvalds 已提交
6540 6541 6542 6543 6544
}

/*
 * Decode OPEN_CONFIRM response
 */
6545 6546 6547
static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp,
				     struct xdr_stream *xdr,
				     struct nfs_open_confirmres *res)
L
Linus Torvalds 已提交
6548
{
A
Andy Adamson 已提交
6549 6550 6551
	struct compound_hdr hdr;
	int status;

6552
	status = decode_compound_hdr(xdr, &hdr);
A
Andy Adamson 已提交
6553 6554
	if (status)
		goto out;
6555
	status = decode_putfh(xdr);
A
Andy Adamson 已提交
6556 6557
	if (status)
		goto out;
6558
	status = decode_open_confirm(xdr, res);
L
Linus Torvalds 已提交
6559
out:
A
Andy Adamson 已提交
6560
	return status;
L
Linus Torvalds 已提交
6561 6562 6563 6564 6565
}

/*
 * Decode OPEN response
 */
6566 6567 6568
static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
				    struct xdr_stream *xdr,
				    struct nfs_openres *res)
L
Linus Torvalds 已提交
6569
{
A
Andy Adamson 已提交
6570 6571 6572
	struct compound_hdr hdr;
	int status;

6573
	status = decode_compound_hdr(xdr, &hdr);
6574 6575
	if (status)
		goto out;
6576
	status = decode_sequence(xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
6577 6578
	if (status)
		goto out;
6579
	status = decode_putfh(xdr);
A
Andy Adamson 已提交
6580 6581
	if (status)
		goto out;
6582
	status = decode_open(xdr, res);
A
Andy Adamson 已提交
6583 6584
	if (status)
		goto out;
6585 6586
	if (res->access_request)
		decode_access(xdr, &res->access_supported, &res->access_result);
6587
	decode_getfattr(xdr, res->f_attr, res->server);
L
Linus Torvalds 已提交
6588
out:
A
Andy Adamson 已提交
6589
	return status;
L
Linus Torvalds 已提交
6590 6591 6592 6593 6594
}

/*
 * Decode SETATTR response
 */
6595 6596 6597
static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp,
				struct xdr_stream *xdr,
				struct nfs_setattrres *res)
L
Linus Torvalds 已提交
6598
{
A
Andy Adamson 已提交
6599 6600 6601
	struct compound_hdr hdr;
	int status;

6602
	status = decode_compound_hdr(xdr, &hdr);
6603 6604
	if (status)
		goto out;
6605
	status = decode_sequence(xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
6606 6607
	if (status)
		goto out;
6608
	status = decode_putfh(xdr);
A
Andy Adamson 已提交
6609 6610
	if (status)
		goto out;
6611
	status = decode_setattr(xdr);
A
Andy Adamson 已提交
6612 6613
	if (status)
		goto out;
6614
	decode_getfattr_label(xdr, res->fattr, res->label, res->server);
L
Linus Torvalds 已提交
6615
out:
A
Andy Adamson 已提交
6616
	return status;
L
Linus Torvalds 已提交
6617 6618 6619 6620 6621
}

/*
 * Decode LOCK response
 */
6622 6623
static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			     struct nfs_lock_res *res)
L
Linus Torvalds 已提交
6624 6625 6626 6627
{
	struct compound_hdr hdr;
	int status;

6628
	status = decode_compound_hdr(xdr, &hdr);
6629 6630
	if (status)
		goto out;
6631
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
6632 6633
	if (status)
		goto out;
6634
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6635 6636
	if (status)
		goto out;
6637
	status = decode_lock(xdr, res);
L
Linus Torvalds 已提交
6638 6639 6640 6641 6642 6643 6644
out:
	return status;
}

/*
 * Decode LOCKT response
 */
6645 6646
static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			      struct nfs_lockt_res *res)
L
Linus Torvalds 已提交
6647 6648 6649 6650
{
	struct compound_hdr hdr;
	int status;

6651
	status = decode_compound_hdr(xdr, &hdr);
6652 6653
	if (status)
		goto out;
6654
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
6655 6656
	if (status)
		goto out;
6657
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6658 6659
	if (status)
		goto out;
6660
	status = decode_lockt(xdr, res);
L
Linus Torvalds 已提交
6661 6662 6663 6664 6665 6666 6667
out:
	return status;
}

/*
 * Decode LOCKU response
 */
6668 6669
static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			      struct nfs_locku_res *res)
L
Linus Torvalds 已提交
6670 6671 6672 6673
{
	struct compound_hdr hdr;
	int status;

6674
	status = decode_compound_hdr(xdr, &hdr);
6675 6676
	if (status)
		goto out;
6677
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
6678 6679
	if (status)
		goto out;
6680
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6681 6682
	if (status)
		goto out;
6683
	status = decode_locku(xdr, res);
L
Linus Torvalds 已提交
6684 6685 6686 6687
out:
	return status;
}

6688 6689
static int nfs4_xdr_dec_release_lockowner(struct rpc_rqst *rqstp,
					  struct xdr_stream *xdr, void *dummy)
6690 6691 6692 6693
{
	struct compound_hdr hdr;
	int status;

6694
	status = decode_compound_hdr(xdr, &hdr);
6695
	if (!status)
6696
		status = decode_release_lockowner(xdr);
6697 6698 6699
	return status;
}

L
Linus Torvalds 已提交
6700 6701 6702
/*
 * Decode READLINK response
 */
6703 6704
static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp,
				 struct xdr_stream *xdr,
B
Benny Halevy 已提交
6705
				 struct nfs4_readlink_res *res)
L
Linus Torvalds 已提交
6706 6707 6708 6709
{
	struct compound_hdr hdr;
	int status;

6710
	status = decode_compound_hdr(xdr, &hdr);
6711 6712
	if (status)
		goto out;
6713
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
6714 6715
	if (status)
		goto out;
6716
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6717 6718
	if (status)
		goto out;
6719
	status = decode_readlink(xdr, rqstp);
L
Linus Torvalds 已提交
6720 6721 6722 6723 6724 6725 6726
out:
	return status;
}

/*
 * Decode READDIR response
 */
6727 6728
static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
				struct nfs4_readdir_res *res)
L
Linus Torvalds 已提交
6729 6730 6731 6732
{
	struct compound_hdr hdr;
	int status;

6733
	status = decode_compound_hdr(xdr, &hdr);
6734 6735
	if (status)
		goto out;
6736
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
6737 6738
	if (status)
		goto out;
6739
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6740 6741
	if (status)
		goto out;
6742
	status = decode_readdir(xdr, rqstp, res);
L
Linus Torvalds 已提交
6743 6744 6745 6746 6747 6748 6749
out:
	return status;
}

/*
 * Decode Read response
 */
6750
static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
6751
			     struct nfs_pgio_res *res)
L
Linus Torvalds 已提交
6752 6753 6754 6755
{
	struct compound_hdr hdr;
	int status;

6756
	status = decode_compound_hdr(xdr, &hdr);
6757
	res->op_status = hdr.status;
6758 6759
	if (status)
		goto out;
6760
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
6761 6762
	if (status)
		goto out;
6763
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6764 6765
	if (status)
		goto out;
6766
	status = decode_read(xdr, rqstp, res);
L
Linus Torvalds 已提交
6767 6768 6769 6770 6771 6772 6773 6774 6775
	if (!status)
		status = res->count;
out:
	return status;
}

/*
 * Decode WRITE response
 */
6776
static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
6777
			      struct nfs_pgio_res *res)
L
Linus Torvalds 已提交
6778 6779 6780 6781
{
	struct compound_hdr hdr;
	int status;

6782
	status = decode_compound_hdr(xdr, &hdr);
6783
	res->op_status = hdr.status;
6784 6785
	if (status)
		goto out;
6786
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
6787 6788
	if (status)
		goto out;
6789
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6790 6791
	if (status)
		goto out;
6792
	status = decode_write(xdr, res);
6793 6794
	if (status)
		goto out;
6795
	if (res->fattr)
6796
		decode_getfattr(xdr, res->fattr, res->server);
L
Linus Torvalds 已提交
6797 6798 6799 6800 6801 6802 6803 6804 6805
	if (!status)
		status = res->count;
out:
	return status;
}

/*
 * Decode COMMIT response
 */
6806
static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
6807
			       struct nfs_commitres *res)
L
Linus Torvalds 已提交
6808 6809 6810 6811
{
	struct compound_hdr hdr;
	int status;

6812
	status = decode_compound_hdr(xdr, &hdr);
6813
	res->op_status = hdr.status;
6814 6815
	if (status)
		goto out;
6816
	status = decode_sequence(xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
6817 6818
	if (status)
		goto out;
6819
	status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6820 6821
	if (status)
		goto out;
6822
	status = decode_commit(xdr, res);
L
Linus Torvalds 已提交
6823 6824 6825 6826 6827
out:
	return status;
}

/*
6828
 * Decode FSINFO response
L
Linus Torvalds 已提交
6829
 */
6830
static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, struct xdr_stream *xdr,
B
Benny Halevy 已提交
6831
			       struct nfs4_fsinfo_res *res)
L
Linus Torvalds 已提交
6832 6833 6834 6835
{
	struct compound_hdr hdr;
	int status;

6836
	status = decode_compound_hdr(xdr, &hdr);
6837
	if (!status)
6838
		status = decode_sequence(xdr, &res->seq_res, req);
L
Linus Torvalds 已提交
6839
	if (!status)
6840
		status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6841
	if (!status)
6842
		status = decode_fsinfo(xdr, res->fsinfo);
L
Linus Torvalds 已提交
6843 6844 6845 6846
	return status;
}

/*
6847
 * Decode PATHCONF response
L
Linus Torvalds 已提交
6848
 */
6849
static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, struct xdr_stream *xdr,
B
Benny Halevy 已提交
6850
				 struct nfs4_pathconf_res *res)
L
Linus Torvalds 已提交
6851 6852 6853 6854
{
	struct compound_hdr hdr;
	int status;

6855
	status = decode_compound_hdr(xdr, &hdr);
6856
	if (!status)
6857
		status = decode_sequence(xdr, &res->seq_res, req);
L
Linus Torvalds 已提交
6858
	if (!status)
6859
		status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6860
	if (!status)
6861
		status = decode_pathconf(xdr, res->pathconf);
L
Linus Torvalds 已提交
6862 6863 6864 6865
	return status;
}

/*
6866
 * Decode STATFS response
L
Linus Torvalds 已提交
6867
 */
6868
static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, struct xdr_stream *xdr,
B
Benny Halevy 已提交
6869
			       struct nfs4_statfs_res *res)
L
Linus Torvalds 已提交
6870 6871 6872 6873
{
	struct compound_hdr hdr;
	int status;

6874
	status = decode_compound_hdr(xdr, &hdr);
6875
	if (!status)
6876
		status = decode_sequence(xdr, &res->seq_res, req);
L
Linus Torvalds 已提交
6877
	if (!status)
6878
		status = decode_putfh(xdr);
L
Linus Torvalds 已提交
6879
	if (!status)
6880
		status = decode_statfs(xdr, res->fsstat);
L
Linus Torvalds 已提交
6881 6882 6883 6884
	return status;
}

/*
6885
 * Decode GETATTR_BITMAP response
L
Linus Torvalds 已提交
6886
 */
6887 6888 6889
static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req,
				    struct xdr_stream *xdr,
				    struct nfs4_server_caps_res *res)
L
Linus Torvalds 已提交
6890 6891 6892 6893
{
	struct compound_hdr hdr;
	int status;

6894
	status = decode_compound_hdr(xdr, &hdr);
6895 6896
	if (status)
		goto out;
6897
	status = decode_sequence(xdr, &res->seq_res, req);
6898
	if (status)
L
Linus Torvalds 已提交
6899
		goto out;
6900 6901
	status = decode_putfh(xdr);
	if (status)
L
Linus Torvalds 已提交
6902
		goto out;
6903
	status = decode_server_caps(xdr, res);
L
Linus Torvalds 已提交
6904 6905 6906 6907 6908 6909 6910
out:
	return status;
}

/*
 * Decode RENEW response
 */
6911 6912
static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
			      void *__unused)
L
Linus Torvalds 已提交
6913 6914 6915 6916
{
	struct compound_hdr hdr;
	int status;

6917
	status = decode_compound_hdr(xdr, &hdr);
L
Linus Torvalds 已提交
6918
	if (!status)
6919
		status = decode_renew(xdr);
L
Linus Torvalds 已提交
6920 6921 6922 6923
	return status;
}

/*
6924
 * Decode SETCLIENTID response
L
Linus Torvalds 已提交
6925
 */
6926 6927 6928
static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req,
				    struct xdr_stream *xdr,
				    struct nfs4_setclientid_res *res)
L
Linus Torvalds 已提交
6929 6930 6931 6932
{
	struct compound_hdr hdr;
	int status;

6933
	status = decode_compound_hdr(xdr, &hdr);
L
Linus Torvalds 已提交
6934
	if (!status)
6935
		status = decode_setclientid(xdr, res);
L
Linus Torvalds 已提交
6936 6937 6938 6939
	return status;
}

/*
6940
 * Decode SETCLIENTID_CONFIRM response
L
Linus Torvalds 已提交
6941
 */
6942
static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req,
6943
					    struct xdr_stream *xdr)
L
Linus Torvalds 已提交
6944 6945 6946 6947
{
	struct compound_hdr hdr;
	int status;

6948
	status = decode_compound_hdr(xdr, &hdr);
L
Linus Torvalds 已提交
6949
	if (!status)
6950
		status = decode_setclientid_confirm(xdr);
L
Linus Torvalds 已提交
6951 6952 6953 6954
	return status;
}

/*
6955
 * Decode DELEGRETURN response
L
Linus Torvalds 已提交
6956
 */
6957 6958 6959
static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp,
				    struct xdr_stream *xdr,
				    struct nfs4_delegreturnres *res)
L
Linus Torvalds 已提交
6960 6961 6962 6963
{
	struct compound_hdr hdr;
	int status;

6964
	status = decode_compound_hdr(xdr, &hdr);
6965 6966
	if (status)
		goto out;
6967
	status = decode_sequence(xdr, &res->seq_res, rqstp);
6968
	if (status)
6969
		goto out;
6970
	status = decode_putfh(xdr);
6971 6972
	if (status != 0)
		goto out;
6973 6974 6975 6976 6977 6978
	if (res->lr_res) {
		status = decode_layoutreturn(xdr, res->lr_res);
		res->lr_ret = status;
		if (status)
			goto out;
	}
6979
	status = decode_getfattr(xdr, res->fattr, res->server);
6980 6981
	if (status != 0)
		goto out;
6982
	status = decode_delegreturn(xdr);
6983
out:
L
Linus Torvalds 已提交
6984 6985 6986
	return status;
}

6987
/*
6988
 * Decode FS_LOCATIONS response
6989
 */
6990 6991
static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
				     struct xdr_stream *xdr,
B
Benny Halevy 已提交
6992
				     struct nfs4_fs_locations_res *res)
6993 6994 6995 6996
{
	struct compound_hdr hdr;
	int status;

6997
	status = decode_compound_hdr(xdr, &hdr);
6998 6999
	if (status)
		goto out;
7000
	status = decode_sequence(xdr, &res->seq_res, req);
7001
	if (status)
7002
		goto out;
7003 7004
	status = decode_putfh(xdr);
	if (status)
7005
		goto out;
7006 7007 7008 7009
	if (res->migration) {
		xdr_enter_page(xdr, PAGE_SIZE);
		status = decode_getfattr_generic(xdr,
					&res->fs_locations->fattr,
7010
					 NULL, res->fs_locations,
7011
					 NULL, res->fs_locations->server);
7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025
		if (status)
			goto out;
		if (res->renew)
			status = decode_renew(xdr);
	} else {
		status = decode_lookup(xdr);
		if (status)
			goto out;
		xdr_enter_page(xdr, PAGE_SIZE);
		status = decode_getfattr_generic(xdr,
					&res->fs_locations->fattr,
					 NULL, res->fs_locations,
					 NULL, res->fs_locations->server);
	}
7026 7027 7028 7029
out:
	return status;
}

B
Bryan Schumaker 已提交
7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053
/*
 * 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);
out:
	return status;
}

7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081
/*
 * Decode FSID_PRESENT response
 */
static int nfs4_xdr_dec_fsid_present(struct rpc_rqst *rqstp,
				     struct xdr_stream *xdr,
				     struct nfs4_fsid_present_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_getfh(xdr, res->fh);
	if (status)
		goto out;
	if (res->renew)
		status = decode_renew(xdr);
out:
	return status;
}

B
Benny Halevy 已提交
7082
#if defined(CONFIG_NFS_V4_1)
7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098
/*
 * Decode BIND_CONN_TO_SESSION response
 */
static int nfs4_xdr_dec_bind_conn_to_session(struct rpc_rqst *rqstp,
					struct xdr_stream *xdr,
					void *res)
{
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (!status)
		status = decode_bind_conn_to_session(xdr, res);
	return status;
}

B
Benny Halevy 已提交
7099
/*
7100
 * Decode EXCHANGE_ID response
B
Benny Halevy 已提交
7101
 */
7102 7103
static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp,
				    struct xdr_stream *xdr,
B
Benny Halevy 已提交
7104 7105 7106 7107 7108
				    void *res)
{
	struct compound_hdr hdr;
	int status;

7109
	status = decode_compound_hdr(xdr, &hdr);
B
Benny Halevy 已提交
7110
	if (!status)
7111
		status = decode_exchange_id(xdr, res);
B
Benny Halevy 已提交
7112 7113
	return status;
}
A
Andy Adamson 已提交
7114

A
Andy Adamson 已提交
7115
/*
7116
 * Decode CREATE_SESSION response
A
Andy Adamson 已提交
7117
 */
7118 7119
static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp,
				       struct xdr_stream *xdr,
A
Andy Adamson 已提交
7120 7121 7122 7123 7124
				       struct nfs41_create_session_res *res)
{
	struct compound_hdr hdr;
	int status;

7125
	status = decode_compound_hdr(xdr, &hdr);
A
Andy Adamson 已提交
7126
	if (!status)
7127
		status = decode_create_session(xdr, res);
A
Andy Adamson 已提交
7128 7129 7130
	return status;
}

A
Andy Adamson 已提交
7131
/*
7132
 * Decode DESTROY_SESSION response
A
Andy Adamson 已提交
7133
 */
7134 7135 7136
static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp,
					struct xdr_stream *xdr,
					void *res)
A
Andy Adamson 已提交
7137 7138 7139 7140
{
	struct compound_hdr hdr;
	int status;

7141
	status = decode_compound_hdr(xdr, &hdr);
A
Andy Adamson 已提交
7142
	if (!status)
7143
		status = decode_destroy_session(xdr, res);
A
Andy Adamson 已提交
7144 7145 7146
	return status;
}

T
Trond Myklebust 已提交
7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162
/*
 * Decode DESTROY_CLIENTID response
 */
static int nfs4_xdr_dec_destroy_clientid(struct rpc_rqst *rqstp,
					struct xdr_stream *xdr,
					void *res)
{
	struct compound_hdr hdr;
	int status;

	status = decode_compound_hdr(xdr, &hdr);
	if (!status)
		status = decode_destroy_clientid(xdr, res);
	return status;
}

A
Andy Adamson 已提交
7163
/*
7164
 * Decode SEQUENCE response
A
Andy Adamson 已提交
7165
 */
7166 7167
static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp,
				 struct xdr_stream *xdr,
A
Andy Adamson 已提交
7168 7169 7170 7171 7172
				 struct nfs4_sequence_res *res)
{
	struct compound_hdr hdr;
	int status;

7173
	status = decode_compound_hdr(xdr, &hdr);
A
Andy Adamson 已提交
7174
	if (!status)
7175
		status = decode_sequence(xdr, res, rqstp);
A
Andy Adamson 已提交
7176 7177 7178
	return status;
}

A
Andy Adamson 已提交
7179
/*
7180
 * Decode GET_LEASE_TIME response
A
Andy Adamson 已提交
7181
 */
7182 7183
static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp,
				       struct xdr_stream *xdr,
A
Andy Adamson 已提交
7184 7185 7186 7187 7188
				       struct nfs4_get_lease_time_res *res)
{
	struct compound_hdr hdr;
	int status;

7189
	status = decode_compound_hdr(xdr, &hdr);
A
Andy Adamson 已提交
7190
	if (!status)
7191
		status = decode_sequence(xdr, &res->lr_seq_res, rqstp);
A
Andy Adamson 已提交
7192
	if (!status)
7193
		status = decode_putrootfh(xdr);
A
Andy Adamson 已提交
7194
	if (!status)
7195
		status = decode_fsinfo(xdr, res->lr_fsinfo);
A
Andy Adamson 已提交
7196 7197
	return status;
}
7198 7199 7200 7201

/*
 * Decode RECLAIM_COMPLETE response
 */
7202 7203
static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp,
					 struct xdr_stream *xdr,
7204 7205 7206 7207 7208
					 struct nfs41_reclaim_complete_res *res)
{
	struct compound_hdr hdr;
	int status;

7209
	status = decode_compound_hdr(xdr, &hdr);
7210
	if (!status)
7211
		status = decode_sequence(xdr, &res->seq_res, rqstp);
7212
	if (!status)
H
Himangi Saraogi 已提交
7213
		status = decode_reclaim_complete(xdr, NULL);
7214 7215
	return status;
}
7216 7217 7218 7219

/*
 * Decode GETDEVINFO response
 */
7220 7221
static int nfs4_xdr_dec_getdeviceinfo(struct rpc_rqst *rqstp,
				      struct xdr_stream *xdr,
7222 7223 7224 7225 7226
				      struct nfs4_getdeviceinfo_res *res)
{
	struct compound_hdr hdr;
	int status;

7227
	status = decode_compound_hdr(xdr, &hdr);
7228 7229
	if (status != 0)
		goto out;
7230
	status = decode_sequence(xdr, &res->seq_res, rqstp);
7231 7232
	if (status != 0)
		goto out;
7233
	status = decode_getdeviceinfo(xdr, res);
7234 7235 7236 7237 7238 7239 7240
out:
	return status;
}

/*
 * Decode LAYOUTGET response
 */
7241 7242
static int nfs4_xdr_dec_layoutget(struct rpc_rqst *rqstp,
				  struct xdr_stream *xdr,
7243 7244 7245 7246 7247
				  struct nfs4_layoutget_res *res)
{
	struct compound_hdr hdr;
	int status;

7248
	status = decode_compound_hdr(xdr, &hdr);
7249 7250
	if (status)
		goto out;
7251
	status = decode_sequence(xdr, &res->seq_res, rqstp);
7252 7253
	if (status)
		goto out;
7254
	status = decode_putfh(xdr);
7255 7256
	if (status)
		goto out;
7257
	status = decode_layoutget(xdr, rqstp, res);
7258 7259 7260
out:
	return status;
}
A
Andy Adamson 已提交
7261

B
Benny Halevy 已提交
7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285
/*
 * 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 已提交
7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307
/*
 * 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;
7308
	decode_getfattr(xdr, res->fattr, res->server);
A
Andy Adamson 已提交
7309 7310 7311
out:
	return status;
}
7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331

/*
 * 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;
B
Bryan Schumaker 已提交
7332
	status = decode_secinfo_no_name(xdr, res);
7333 7334 7335
out:
	return status;
}
B
Bryan Schumaker 已提交
7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356

/*
 * Decode TEST_STATEID response
 */
static int nfs4_xdr_dec_test_stateid(struct rpc_rqst *rqstp,
				     struct xdr_stream *xdr,
				     struct nfs41_test_stateid_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_test_stateid(xdr, res);
out:
	return status;
}
B
Bryan Schumaker 已提交
7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377

/*
 * Decode FREE_STATEID response
 */
static int nfs4_xdr_dec_free_stateid(struct rpc_rqst *rqstp,
				     struct xdr_stream *xdr,
				     struct nfs41_free_stateid_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_free_stateid(xdr, res);
out:
	return status;
}
B
Benny Halevy 已提交
7378 7379
#endif /* CONFIG_NFS_V4_1 */

7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395
/**
 * 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 已提交
7396
{
7397
	unsigned int savep;
7398
	uint32_t bitmap[3] = {0};
L
Linus Torvalds 已提交
7399
	uint32_t len;
7400 7401 7402
	__be32 *p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
7403
	if (*p == xdr_zero) {
7404 7405 7406
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
7407
		if (*p == xdr_zero)
7408
			return -EAGAIN;
L
Linus Torvalds 已提交
7409
		entry->eof = 1;
7410
		return -EBADCOOKIE;
L
Linus Torvalds 已提交
7411 7412
	}

7413 7414 7415
	p = xdr_inline_decode(xdr, 12);
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
7416 7417
	entry->prev_cookie = entry->cookie;
	p = xdr_decode_hyper(p, &entry->cookie);
7418
	entry->len = be32_to_cpup(p);
7419

7420
	p = xdr_inline_decode(xdr, entry->len);
7421 7422
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
7423 7424 7425 7426 7427 7428 7429 7430
	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;
7431
	entry->fattr->valid = 0;
L
Linus Torvalds 已提交
7432

7433 7434 7435
	if (decode_attr_bitmap(xdr, bitmap) < 0)
		goto out_overflow;

7436
	if (decode_attr_length(xdr, &len, &savep) < 0)
7437 7438
		goto out_overflow;

7439
	if (decode_getfattr_attrs(xdr, bitmap, entry->fattr, entry->fh,
7440
			NULL, entry->label, entry->server) < 0)
7441
		goto out_overflow;
7442 7443 7444
	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)
7445 7446
		entry->ino = entry->fattr->fileid;

7447 7448 7449 7450
	entry->d_type = DT_UNKNOWN;
	if (entry->fattr->valid & NFS_ATTR_FATTR_TYPE)
		entry->d_type = nfs_umode_to_dtype(entry->fattr->mode);

7451
	return 0;
7452 7453 7454

out_overflow:
	print_overflow_msg(__func__, xdr);
7455
	return -EAGAIN;
L
Linus Torvalds 已提交
7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466
}

/*
 * 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		},
7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488
	{ 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	},
7489
	{ NFS4ERR_SERVERFAULT,	-EREMOTEIO	},
7490 7491 7492 7493 7494 7495
	{ NFS4ERR_BADTYPE,	-EBADTYPE	},
	{ NFS4ERR_LOCKED,	-EAGAIN		},
	{ NFS4ERR_SYMLINK,	-ELOOP		},
	{ NFS4ERR_OP_ILLEGAL,	-EOPNOTSUPP	},
	{ NFS4ERR_DEADLOCK,	-EDEADLK	},
	{ -1,			-EIO		}
L
Linus Torvalds 已提交
7496 7497 7498 7499 7500 7501 7502
};

/*
 * Convert an NFS error code to a local one.
 * This one is used jointly by NFSv2 and NFSv3.
 */
static int
7503
nfs4_stat_to_errno(int stat)
L
Linus Torvalds 已提交
7504 7505 7506 7507 7508 7509 7510 7511
{
	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. */
7512
		return -EREMOTEIO;
L
Linus Torvalds 已提交
7513 7514 7515 7516 7517 7518
	}
	/* 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.
	 */
7519
	return -stat;
L
Linus Torvalds 已提交
7520 7521
}

A
Anna Schumaker 已提交
7522 7523 7524 7525
#ifdef CONFIG_NFS_V4_2
#include "nfs42xdr.c"
#endif /* CONFIG_NFS_V4_2 */

L
Linus Torvalds 已提交
7526 7527 7528
#define PROC(proc, argtype, restype)				\
[NFSPROC4_CLNT_##proc] = {					\
	.p_proc   = NFSPROC4_COMPOUND,				\
7529
	.p_encode = (kxdreproc_t)nfs4_xdr_##argtype,		\
7530
	.p_decode = (kxdrdproc_t)nfs4_xdr_##restype,		\
7531 7532
	.p_arglen = NFS4_##argtype##_sz,			\
	.p_replen = NFS4_##restype##_sz,			\
7533 7534
	.p_statidx = NFSPROC4_CLNT_##proc,			\
	.p_name   = #proc,					\
A
Andy Adamson 已提交
7535
}
L
Linus Torvalds 已提交
7536

7537 7538 7539 7540 7541
#define STUB(proc)		\
[NFSPROC4_CLNT_##proc] = {	\
	.p_name = #proc,	\
}

L
Linus Torvalds 已提交
7542
struct rpc_procinfo	nfs4_procedures[] = {
7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577
	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 已提交
7578
	PROC(SECINFO,		enc_secinfo,		dec_secinfo),
7579
	PROC(FSID_PRESENT,	enc_fsid_present,	dec_fsid_present),
B
Benny Halevy 已提交
7580
#if defined(CONFIG_NFS_V4_1)
7581 7582 7583 7584 7585 7586 7587 7588
	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 已提交
7589
	PROC(LAYOUTCOMMIT,	enc_layoutcommit,	dec_layoutcommit),
B
Benny Halevy 已提交
7590
	PROC(LAYOUTRETURN,	enc_layoutreturn,	dec_layoutreturn),
7591
	PROC(SECINFO_NO_NAME,	enc_secinfo_no_name,	dec_secinfo_no_name),
B
Bryan Schumaker 已提交
7592
	PROC(TEST_STATEID,	enc_test_stateid,	dec_test_stateid),
B
Bryan Schumaker 已提交
7593
	PROC(FREE_STATEID,	enc_free_stateid,	dec_free_stateid),
7594
	STUB(GETDEVICELIST),
7595 7596
	PROC(BIND_CONN_TO_SESSION,
			enc_bind_conn_to_session, dec_bind_conn_to_session),
T
Trond Myklebust 已提交
7597
	PROC(DESTROY_CLIENTID,	enc_destroy_clientid,	dec_destroy_clientid),
B
Benny Halevy 已提交
7598
#endif /* CONFIG_NFS_V4_1 */
A
Anna Schumaker 已提交
7599 7600
#ifdef CONFIG_NFS_V4_2
	PROC(SEEK,		enc_seek,		dec_seek),
A
Anna Schumaker 已提交
7601
	PROC(ALLOCATE,		enc_allocate,		dec_allocate),
A
Anna Schumaker 已提交
7602
	PROC(DEALLOCATE,	enc_deallocate,		dec_deallocate),
7603
	PROC(LAYOUTSTATS,	enc_layoutstats,	dec_layoutstats),
P
Peng Tao 已提交
7604
	PROC(CLONE,		enc_clone,		dec_clone),
A
Anna Schumaker 已提交
7605
	PROC(COPY,		enc_copy,		dec_copy),
A
Anna Schumaker 已提交
7606
#endif /* CONFIG_NFS_V4_2 */
L
Linus Torvalds 已提交
7607 7608
};

7609
const struct rpc_version nfs_version4 = {
L
Linus Torvalds 已提交
7610
	.number			= 4,
7611
	.nrprocs		= ARRAY_SIZE(nfs4_procedures),
L
Linus Torvalds 已提交
7612 7613 7614 7615 7616 7617 7618 7619
	.procs			= nfs4_procedures
};

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