nfs4xdr.c 154.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10
/*
 *  fs/nfs/nfs4xdr.c
 *
 *  Client-side XDR for NFSv4.
 *
 *  Copyright (c) 2002 The Regents of the University of Michigan.
 *  All rights reserved.
 *
 *  Kendrick Smith <kmsmith@umich.edu>
 *  Andy Adamson   <andros@umich.edu>
11
 *
L
Linus Torvalds 已提交
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the University nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <linux/param.h>
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/in.h>
#include <linux/pagemap.h>
#include <linux/proc_fs.h>
#include <linux/kdev_t.h>
#include <linux/sunrpc/clnt.h>
48
#include <linux/sunrpc/msg_prot.h>
L
Linus Torvalds 已提交
49 50 51 52
#include <linux/nfs.h>
#include <linux/nfs4.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_idmap.h>
53
#include "nfs4_fs.h"
54
#include "internal.h"
L
Linus Torvalds 已提交
55 56 57 58 59 60

#define NFSDBG_FACILITY		NFSDBG_XDR

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

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

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

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

#if defined(CONFIG_NFS_V4_1)
A
Andy Adamson 已提交
252 253
#define NFS4_MAX_MACHINE_NAME_LEN (64)

B
Benny Halevy 已提交
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
#define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \
				encode_verifier_maxsz + \
				1 /* co_ownerid.len */ + \
				XDR_QUADLEN(NFS4_EXCHANGE_ID_LEN) + \
				1 /* flags */ + \
				1 /* spa_how */ + \
				0 /* SP4_NONE (for now) */ + \
				1 /* zero implemetation id array */)
#define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \
				2 /* eir_clientid */ + \
				1 /* eir_sequenceid */ + \
				1 /* eir_flags */ + \
				1 /* spr_how */ + \
				0 /* SP4_NONE (for now) */ + \
				2 /* eir_server_owner.so_minor_id */ + \
				/* eir_server_owner.so_major_id<> */ \
				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \
				/* eir_server_scope<> */ \
				XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \
				1 /* eir_server_impl_id array length */ + \
				0 /* ignored eir_server_impl_id contents */)
A
Andy Adamson 已提交
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
#define encode_channel_attrs_maxsz  (6 + 1 /* ca_rdma_ird.len (0) */)
#define decode_channel_attrs_maxsz  (6 + \
				     1 /* ca_rdma_ird.len */ + \
				     1 /* ca_rdma_ird */)
#define encode_create_session_maxsz  (op_encode_hdr_maxsz + \
				     2 /* csa_clientid */ + \
				     1 /* csa_sequence */ + \
				     1 /* csa_flags */ + \
				     encode_channel_attrs_maxsz + \
				     encode_channel_attrs_maxsz + \
				     1 /* csa_cb_program */ + \
				     1 /* csa_sec_parms.len (1) */ + \
				     1 /* cb_secflavor (AUTH_SYS) */ + \
				     1 /* stamp */ + \
				     1 /* machinename.len */ + \
				     XDR_QUADLEN(NFS4_MAX_MACHINE_NAME_LEN) + \
				     1 /* uid */ + \
				     1 /* gid */ + \
				     1 /* gids.len (0) */)
#define decode_create_session_maxsz  (op_decode_hdr_maxsz +	\
				     XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
				     1 /* csr_sequence */ + \
				     1 /* csr_flags */ + \
				     decode_channel_attrs_maxsz + \
				     decode_channel_attrs_maxsz)
A
Andy Adamson 已提交
300 301
#define encode_destroy_session_maxsz    (op_encode_hdr_maxsz + 4)
#define decode_destroy_session_maxsz    (op_decode_hdr_maxsz)
A
Andy Adamson 已提交
302 303 304 305
#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)
306 307
#define encode_reclaim_complete_maxsz	(op_encode_hdr_maxsz + 4)
#define decode_reclaim_complete_maxsz	(op_decode_hdr_maxsz + 4)
308 309 310 311 312
#else /* CONFIG_NFS_V4_1 */
#define encode_sequence_maxsz	0
#define decode_sequence_maxsz	0
#endif /* CONFIG_NFS_V4_1 */

L
Linus Torvalds 已提交
313 314 315
#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 + \
316
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
317
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
318
				encode_read_maxsz)
L
Linus Torvalds 已提交
319
#define NFS4_dec_read_sz	(compound_decode_hdr_maxsz + \
320
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
321
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
322
				decode_read_maxsz)
L
Linus Torvalds 已提交
323
#define NFS4_enc_readlink_sz	(compound_encode_hdr_maxsz + \
324
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
325
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
326
				encode_readlink_maxsz)
L
Linus Torvalds 已提交
327
#define NFS4_dec_readlink_sz	(compound_decode_hdr_maxsz + \
328
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
329
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
330
				decode_readlink_maxsz)
L
Linus Torvalds 已提交
331
#define NFS4_enc_readdir_sz	(compound_encode_hdr_maxsz + \
332
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
333
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
334
				encode_readdir_maxsz)
L
Linus Torvalds 已提交
335
#define NFS4_dec_readdir_sz	(compound_decode_hdr_maxsz + \
336
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
337
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
338
				decode_readdir_maxsz)
L
Linus Torvalds 已提交
339
#define NFS4_enc_write_sz	(compound_encode_hdr_maxsz + \
340
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
341
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
342
				encode_write_maxsz + \
343
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
344
#define NFS4_dec_write_sz	(compound_decode_hdr_maxsz + \
345
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
346
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
347
				decode_write_maxsz + \
348
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
349
#define NFS4_enc_commit_sz	(compound_encode_hdr_maxsz + \
350
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
351
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
352
				encode_commit_maxsz + \
353
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
354
#define NFS4_dec_commit_sz	(compound_decode_hdr_maxsz + \
355
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
356
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
357
				decode_commit_maxsz + \
358
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
359
#define NFS4_enc_open_sz        (compound_encode_hdr_maxsz + \
360
				encode_sequence_maxsz + \
361 362 363 364 365 366 367
				encode_putfh_maxsz + \
				encode_savefh_maxsz + \
				encode_open_maxsz + \
				encode_getfh_maxsz + \
				encode_getattr_maxsz + \
				encode_restorefh_maxsz + \
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
368
#define NFS4_dec_open_sz        (compound_decode_hdr_maxsz + \
369
				decode_sequence_maxsz + \
370 371 372 373 374 375 376
				decode_putfh_maxsz + \
				decode_savefh_maxsz + \
				decode_open_maxsz + \
				decode_getfh_maxsz + \
				decode_getattr_maxsz + \
				decode_restorefh_maxsz + \
				decode_getattr_maxsz)
T
Trond Myklebust 已提交
377 378 379 380 381 382 383 384
#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 已提交
385
#define NFS4_enc_open_noattr_sz	(compound_encode_hdr_maxsz + \
386
					encode_sequence_maxsz + \
L
Linus Torvalds 已提交
387
					encode_putfh_maxsz + \
388 389
					encode_open_maxsz + \
					encode_getattr_maxsz)
L
Linus Torvalds 已提交
390
#define NFS4_dec_open_noattr_sz	(compound_decode_hdr_maxsz + \
391
					decode_sequence_maxsz + \
L
Linus Torvalds 已提交
392
					decode_putfh_maxsz + \
393 394
					decode_open_maxsz + \
					decode_getattr_maxsz)
L
Linus Torvalds 已提交
395 396
#define NFS4_enc_open_downgrade_sz \
				(compound_encode_hdr_maxsz + \
397
				 encode_sequence_maxsz + \
T
Trond Myklebust 已提交
398 399 400
				 encode_putfh_maxsz + \
				 encode_open_downgrade_maxsz + \
				 encode_getattr_maxsz)
L
Linus Torvalds 已提交
401 402
#define NFS4_dec_open_downgrade_sz \
				(compound_decode_hdr_maxsz + \
403
				 decode_sequence_maxsz + \
T
Trond Myklebust 已提交
404 405 406 407
				 decode_putfh_maxsz + \
				 decode_open_downgrade_maxsz + \
				 decode_getattr_maxsz)
#define NFS4_enc_close_sz	(compound_encode_hdr_maxsz + \
408
				 encode_sequence_maxsz + \
T
Trond Myklebust 已提交
409 410 411 412
				 encode_putfh_maxsz + \
				 encode_close_maxsz + \
				 encode_getattr_maxsz)
#define NFS4_dec_close_sz	(compound_decode_hdr_maxsz + \
413
				 decode_sequence_maxsz + \
T
Trond Myklebust 已提交
414 415 416 417
				 decode_putfh_maxsz + \
				 decode_close_maxsz + \
				 decode_getattr_maxsz)
#define NFS4_enc_setattr_sz	(compound_encode_hdr_maxsz + \
418
				 encode_sequence_maxsz + \
T
Trond Myklebust 已提交
419 420 421 422
				 encode_putfh_maxsz + \
				 encode_setattr_maxsz + \
				 encode_getattr_maxsz)
#define NFS4_dec_setattr_sz	(compound_decode_hdr_maxsz + \
423
				 decode_sequence_maxsz + \
T
Trond Myklebust 已提交
424 425 426
				 decode_putfh_maxsz + \
				 decode_setattr_maxsz + \
				 decode_getattr_maxsz)
L
Linus Torvalds 已提交
427
#define NFS4_enc_fsinfo_sz	(compound_encode_hdr_maxsz + \
428
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
429 430 431
				encode_putfh_maxsz + \
				encode_fsinfo_maxsz)
#define NFS4_dec_fsinfo_sz	(compound_decode_hdr_maxsz + \
432
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
				decode_putfh_maxsz + \
				decode_fsinfo_maxsz)
#define NFS4_enc_renew_sz	(compound_encode_hdr_maxsz + \
				encode_renew_maxsz)
#define NFS4_dec_renew_sz	(compound_decode_hdr_maxsz + \
				decode_renew_maxsz)
#define NFS4_enc_setclientid_sz	(compound_encode_hdr_maxsz + \
				encode_setclientid_maxsz)
#define NFS4_dec_setclientid_sz	(compound_decode_hdr_maxsz + \
				decode_setclientid_maxsz)
#define NFS4_enc_setclientid_confirm_sz \
				(compound_encode_hdr_maxsz + \
				encode_setclientid_confirm_maxsz + \
				encode_putrootfh_maxsz + \
				encode_fsinfo_maxsz)
#define NFS4_dec_setclientid_confirm_sz \
				(compound_decode_hdr_maxsz + \
				decode_setclientid_confirm_maxsz + \
				decode_putrootfh_maxsz + \
				decode_fsinfo_maxsz)
#define NFS4_enc_lock_sz        (compound_encode_hdr_maxsz + \
454
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
455
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
456
				encode_lock_maxsz)
L
Linus Torvalds 已提交
457
#define NFS4_dec_lock_sz        (compound_decode_hdr_maxsz + \
458
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
459
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
460
				decode_lock_maxsz)
L
Linus Torvalds 已提交
461
#define NFS4_enc_lockt_sz       (compound_encode_hdr_maxsz + \
462
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
463
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
464 465
				encode_lockt_maxsz)
#define NFS4_dec_lockt_sz       (compound_decode_hdr_maxsz + \
466
				 decode_sequence_maxsz + \
T
Trond Myklebust 已提交
467 468
				 decode_putfh_maxsz + \
				 decode_lockt_maxsz)
L
Linus Torvalds 已提交
469
#define NFS4_enc_locku_sz       (compound_encode_hdr_maxsz + \
470
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
471
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
472
				encode_locku_maxsz)
L
Linus Torvalds 已提交
473
#define NFS4_dec_locku_sz       (compound_decode_hdr_maxsz + \
474
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
475
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
476
				decode_locku_maxsz)
L
Linus Torvalds 已提交
477
#define NFS4_enc_access_sz	(compound_encode_hdr_maxsz + \
478
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
479
				encode_putfh_maxsz + \
480 481
				encode_access_maxsz + \
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
482
#define NFS4_dec_access_sz	(compound_decode_hdr_maxsz + \
483
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
484
				decode_putfh_maxsz + \
485 486
				decode_access_maxsz + \
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
487
#define NFS4_enc_getattr_sz	(compound_encode_hdr_maxsz + \
488
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
489 490 491
				encode_putfh_maxsz + \
				encode_getattr_maxsz)
#define NFS4_dec_getattr_sz	(compound_decode_hdr_maxsz + \
492
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
493 494 495
				decode_putfh_maxsz + \
				decode_getattr_maxsz)
#define NFS4_enc_lookup_sz	(compound_encode_hdr_maxsz + \
496
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
497 498 499 500 501
				encode_putfh_maxsz + \
				encode_lookup_maxsz + \
				encode_getattr_maxsz + \
				encode_getfh_maxsz)
#define NFS4_dec_lookup_sz	(compound_decode_hdr_maxsz + \
502
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
503
				decode_putfh_maxsz + \
504
				decode_lookup_maxsz + \
L
Linus Torvalds 已提交
505 506 507
				decode_getattr_maxsz + \
				decode_getfh_maxsz)
#define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \
508
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
509 510 511 512
				encode_putrootfh_maxsz + \
				encode_getattr_maxsz + \
				encode_getfh_maxsz)
#define NFS4_dec_lookup_root_sz (compound_decode_hdr_maxsz + \
513
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
514 515 516 517
				decode_putrootfh_maxsz + \
				decode_getattr_maxsz + \
				decode_getfh_maxsz)
#define NFS4_enc_remove_sz	(compound_encode_hdr_maxsz + \
518
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
519
				encode_putfh_maxsz + \
520 521
				encode_remove_maxsz + \
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
522
#define NFS4_dec_remove_sz	(compound_decode_hdr_maxsz + \
523
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
524
				decode_putfh_maxsz + \
525
				decode_remove_maxsz + \
526
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
527
#define NFS4_enc_rename_sz	(compound_encode_hdr_maxsz + \
528
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
529 530 531
				encode_putfh_maxsz + \
				encode_savefh_maxsz + \
				encode_putfh_maxsz + \
532 533 534 535
				encode_rename_maxsz + \
				encode_getattr_maxsz + \
				encode_restorefh_maxsz + \
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
536
#define NFS4_dec_rename_sz	(compound_decode_hdr_maxsz + \
537
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
538 539 540
				decode_putfh_maxsz + \
				decode_savefh_maxsz + \
				decode_putfh_maxsz + \
541 542 543 544
				decode_rename_maxsz + \
				decode_getattr_maxsz + \
				decode_restorefh_maxsz + \
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
545
#define NFS4_enc_link_sz	(compound_encode_hdr_maxsz + \
546
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
547 548 549
				encode_putfh_maxsz + \
				encode_savefh_maxsz + \
				encode_putfh_maxsz + \
550 551 552 553
				encode_link_maxsz + \
				decode_getattr_maxsz + \
				encode_restorefh_maxsz + \
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
554
#define NFS4_dec_link_sz	(compound_decode_hdr_maxsz + \
555
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
556 557 558
				decode_putfh_maxsz + \
				decode_savefh_maxsz + \
				decode_putfh_maxsz + \
559 560 561 562
				decode_link_maxsz + \
				decode_getattr_maxsz + \
				decode_restorefh_maxsz + \
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
563
#define NFS4_enc_symlink_sz	(compound_encode_hdr_maxsz + \
564
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
565 566 567 568 569
				encode_putfh_maxsz + \
				encode_symlink_maxsz + \
				encode_getattr_maxsz + \
				encode_getfh_maxsz)
#define NFS4_dec_symlink_sz	(compound_decode_hdr_maxsz + \
570
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
571 572 573 574 575
				decode_putfh_maxsz + \
				decode_symlink_maxsz + \
				decode_getattr_maxsz + \
				decode_getfh_maxsz)
#define NFS4_enc_create_sz	(compound_encode_hdr_maxsz + \
576
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
577
				encode_putfh_maxsz + \
578
				encode_savefh_maxsz + \
L
Linus Torvalds 已提交
579
				encode_create_maxsz + \
580
				encode_getfh_maxsz + \
L
Linus Torvalds 已提交
581
				encode_getattr_maxsz + \
582 583
				encode_restorefh_maxsz + \
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
584
#define NFS4_dec_create_sz	(compound_decode_hdr_maxsz + \
585
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
586
				decode_putfh_maxsz + \
587
				decode_savefh_maxsz + \
L
Linus Torvalds 已提交
588
				decode_create_maxsz + \
589
				decode_getfh_maxsz + \
L
Linus Torvalds 已提交
590
				decode_getattr_maxsz + \
591 592
				decode_restorefh_maxsz + \
				decode_getattr_maxsz)
L
Linus Torvalds 已提交
593
#define NFS4_enc_pathconf_sz	(compound_encode_hdr_maxsz + \
594
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
595 596 597
				encode_putfh_maxsz + \
				encode_getattr_maxsz)
#define NFS4_dec_pathconf_sz	(compound_decode_hdr_maxsz + \
598
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
599 600 601
				decode_putfh_maxsz + \
				decode_getattr_maxsz)
#define NFS4_enc_statfs_sz	(compound_encode_hdr_maxsz + \
602
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
603
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
604
				encode_statfs_maxsz)
L
Linus Torvalds 已提交
605
#define NFS4_dec_statfs_sz	(compound_decode_hdr_maxsz + \
606
				decode_sequence_maxsz + \
L
Linus Torvalds 已提交
607
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
608
				decode_statfs_maxsz)
L
Linus Torvalds 已提交
609
#define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \
610
				encode_sequence_maxsz + \
611
				encode_putfh_maxsz + \
L
Linus Torvalds 已提交
612 613
				encode_getattr_maxsz)
#define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \
614
				decode_sequence_maxsz + \
615
				decode_putfh_maxsz + \
L
Linus Torvalds 已提交
616 617
				decode_getattr_maxsz)
#define NFS4_enc_delegreturn_sz	(compound_encode_hdr_maxsz + \
618
				encode_sequence_maxsz + \
L
Linus Torvalds 已提交
619
				encode_putfh_maxsz + \
620 621
				encode_delegreturn_maxsz + \
				encode_getattr_maxsz)
L
Linus Torvalds 已提交
622
#define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
623
				decode_sequence_maxsz + \
624 625
				decode_delegreturn_maxsz + \
				decode_getattr_maxsz)
626
#define NFS4_enc_getacl_sz	(compound_encode_hdr_maxsz + \
627
				encode_sequence_maxsz + \
628
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
629
				encode_getacl_maxsz)
630
#define NFS4_dec_getacl_sz	(compound_decode_hdr_maxsz + \
631
				decode_sequence_maxsz + \
632
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
633
				decode_getacl_maxsz)
634
#define NFS4_enc_setacl_sz	(compound_encode_hdr_maxsz + \
635
				encode_sequence_maxsz + \
636
				encode_putfh_maxsz + \
T
Trond Myklebust 已提交
637
				encode_setacl_maxsz)
638
#define NFS4_dec_setacl_sz	(compound_decode_hdr_maxsz + \
639
				decode_sequence_maxsz + \
640
				decode_putfh_maxsz + \
T
Trond Myklebust 已提交
641
				decode_setacl_maxsz)
642 643
#define NFS4_enc_fs_locations_sz \
				(compound_encode_hdr_maxsz + \
644
				 encode_sequence_maxsz + \
645
				 encode_putfh_maxsz + \
646 647
				 encode_lookup_maxsz + \
				 encode_fs_locations_maxsz)
648 649
#define NFS4_dec_fs_locations_sz \
				(compound_decode_hdr_maxsz + \
650
				 decode_sequence_maxsz + \
651
				 decode_putfh_maxsz + \
652 653
				 decode_lookup_maxsz + \
				 decode_fs_locations_maxsz)
B
Benny Halevy 已提交
654 655 656 657 658 659 660
#if defined(CONFIG_NFS_V4_1)
#define NFS4_enc_exchange_id_sz \
				(compound_encode_hdr_maxsz + \
				 encode_exchange_id_maxsz)
#define NFS4_dec_exchange_id_sz \
				(compound_decode_hdr_maxsz + \
				 decode_exchange_id_maxsz)
A
Andy Adamson 已提交
661 662 663 664 665 666
#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 已提交
667 668 669 670
#define NFS4_enc_destroy_session_sz	(compound_encode_hdr_maxsz + \
					 encode_destroy_session_maxsz)
#define NFS4_dec_destroy_session_sz	(compound_decode_hdr_maxsz + \
					 decode_destroy_session_maxsz)
A
Andy Adamson 已提交
671 672 673 674 675 676
#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 已提交
677 678 679 680 681 682 683 684
#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)
685 686 687 688 689 690
#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)
691 692 693 694 695 696 697 698 699 700 701 702 703

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

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

706 707 708 709 710 711 712 713 714 715 716
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 已提交
717 718 719 720 721
};

struct compound_hdr {
	int32_t		status;
	uint32_t	nops;
722
	__be32 *	nops_p;
L
Linus Torvalds 已提交
723 724
	uint32_t	taglen;
	char *		tag;
725
	uint32_t	replen;		/* expected reply words */
726
	u32		minorversion;
L
Linus Torvalds 已提交
727 728
};

729 730 731 732 733 734
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 已提交
735 736 737

static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
{
A
Al Viro 已提交
738
	__be32 *p;
L
Linus Torvalds 已提交
739 740 741 742 743 744

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

745 746 747
static void encode_compound_hdr(struct xdr_stream *xdr,
				struct rpc_rqst *req,
				struct compound_hdr *hdr)
L
Linus Torvalds 已提交
748
{
A
Al Viro 已提交
749
	__be32 *p;
750 751 752 753 754 755
	struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;

	/* initialize running count of expected bytes in reply.
	 * NOTE: the replied tag SHOULD be the same is the one sent,
	 * but this is not required as a MUST for the server to do so. */
	hdr->replen = RPC_REPHDRSIZE + auth->au_rslack + 3 + hdr->taglen;
L
Linus Torvalds 已提交
756 757 758

	dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
	BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
759 760
	p = reserve_space(xdr, 4 + hdr->taglen + 8);
	p = xdr_encode_opaque(p, hdr->tag, hdr->taglen);
B
Benny Halevy 已提交
761
	*p++ = cpu_to_be32(hdr->minorversion);
762
	hdr->nops_p = p;
763
	*p = cpu_to_be32(hdr->nops);
764 765 766 767
}

static void encode_nops(struct compound_hdr *hdr)
{
A
Andy Adamson 已提交
768
	BUG_ON(hdr->nops > NFS4_MAX_OPS);
769
	*hdr->nops_p = htonl(hdr->nops);
L
Linus Torvalds 已提交
770 771 772 773
}

static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
{
A
Al Viro 已提交
774
	__be32 *p;
L
Linus Torvalds 已提交
775 776 777 778 779 780

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

781
static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
L
Linus Torvalds 已提交
782 783 784 785 786
{
	char owner_name[IDMAP_NAMESZ];
	char owner_group[IDMAP_NAMESZ];
	int owner_namelen = 0;
	int owner_grouplen = 0;
A
Al Viro 已提交
787 788
	__be32 *p;
	__be32 *q;
L
Linus Torvalds 已提交
789 790 791 792 793 794 795 796 797
	int len;
	uint32_t bmval0 = 0;
	uint32_t bmval1 = 0;

	/*
	 * We reserve enough space to write the entire attribute buffer at once.
	 * In the worst-case, this would be
	 *   12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
	 *          = 36 bytes, plus any contribution from variable-length fields
798
	 *            such as owner/group.
L
Linus Torvalds 已提交
799 800 801 802 803 804 805 806 807
	 */
	len = 16;

	/* Sigh */
	if (iap->ia_valid & ATTR_SIZE)
		len += 8;
	if (iap->ia_valid & ATTR_MODE)
		len += 4;
	if (iap->ia_valid & ATTR_UID) {
808
		owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
L
Linus Torvalds 已提交
809
		if (owner_namelen < 0) {
810 811
			dprintk("nfs: couldn't resolve uid %d to string\n",
					iap->ia_uid);
L
Linus Torvalds 已提交
812 813 814 815 816 817 818 819
			/* XXX */
			strcpy(owner_name, "nobody");
			owner_namelen = sizeof("nobody") - 1;
			/* goto out; */
		}
		len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
	}
	if (iap->ia_valid & ATTR_GID) {
820
		owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group);
L
Linus Torvalds 已提交
821
		if (owner_grouplen < 0) {
822 823
			dprintk("nfs: couldn't resolve gid %d to string\n",
					iap->ia_gid);
L
Linus Torvalds 已提交
824 825 826 827 828 829 830 831 832 833 834 835 836 837
			strcpy(owner_group, "nobody");
			owner_grouplen = sizeof("nobody") - 1;
			/* goto out; */
		}
		len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
	}
	if (iap->ia_valid & ATTR_ATIME_SET)
		len += 16;
	else if (iap->ia_valid & ATTR_ATIME)
		len += 4;
	if (iap->ia_valid & ATTR_MTIME_SET)
		len += 16;
	else if (iap->ia_valid & ATTR_MTIME)
		len += 4;
838
	p = reserve_space(xdr, len);
L
Linus Torvalds 已提交
839 840 841 842 843

	/*
	 * We write the bitmap length now, but leave the bitmap and the attribute
	 * buffer length to be backfilled at the end of this routine.
	 */
B
Benny Halevy 已提交
844
	*p++ = cpu_to_be32(2);
L
Linus Torvalds 已提交
845 846 847 848 849
	q = p;
	p += 3;

	if (iap->ia_valid & ATTR_SIZE) {
		bmval0 |= FATTR4_WORD0_SIZE;
B
Benny Halevy 已提交
850
		p = xdr_encode_hyper(p, iap->ia_size);
L
Linus Torvalds 已提交
851 852 853
	}
	if (iap->ia_valid & ATTR_MODE) {
		bmval1 |= FATTR4_WORD1_MODE;
B
Benny Halevy 已提交
854
		*p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO);
L
Linus Torvalds 已提交
855 856 857
	}
	if (iap->ia_valid & ATTR_UID) {
		bmval1 |= FATTR4_WORD1_OWNER;
858
		p = xdr_encode_opaque(p, owner_name, owner_namelen);
L
Linus Torvalds 已提交
859 860 861
	}
	if (iap->ia_valid & ATTR_GID) {
		bmval1 |= FATTR4_WORD1_OWNER_GROUP;
862
		p = xdr_encode_opaque(p, owner_group, owner_grouplen);
L
Linus Torvalds 已提交
863 864 865
	}
	if (iap->ia_valid & ATTR_ATIME_SET) {
		bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
B
Benny Halevy 已提交
866 867
		*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
		*p++ = cpu_to_be32(0);
868 869
		*p++ = cpu_to_be32(iap->ia_atime.tv_sec);
		*p++ = cpu_to_be32(iap->ia_atime.tv_nsec);
L
Linus Torvalds 已提交
870 871 872
	}
	else if (iap->ia_valid & ATTR_ATIME) {
		bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
B
Benny Halevy 已提交
873
		*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
L
Linus Torvalds 已提交
874 875 876
	}
	if (iap->ia_valid & ATTR_MTIME_SET) {
		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
B
Benny Halevy 已提交
877 878 879 880
		*p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
		*p++ = cpu_to_be32(0);
		*p++ = cpu_to_be32(iap->ia_mtime.tv_sec);
		*p++ = cpu_to_be32(iap->ia_mtime.tv_nsec);
L
Linus Torvalds 已提交
881 882 883
	}
	else if (iap->ia_valid & ATTR_MTIME) {
		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
B
Benny Halevy 已提交
884
		*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
L
Linus Torvalds 已提交
885
	}
886

L
Linus Torvalds 已提交
887 888 889 890
	/*
	 * Now we backfill the bitmap and the attribute buffer length.
	 */
	if (len != ((char *)p - (char *)q) + 4) {
891
		printk(KERN_ERR "nfs: Attr length error, %u != %Zu\n",
L
Linus Torvalds 已提交
892 893 894 895 896 897
				len, ((char *)p - (char *)q) + 4);
		BUG();
	}
	len = (char *)p - (char *)q - 12;
	*q++ = htonl(bmval0);
	*q++ = htonl(bmval1);
898
	*q = htonl(len);
L
Linus Torvalds 已提交
899 900 901 902

/* out: */
}

903
static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
904
{
A
Al Viro 已提交
905
	__be32 *p;
L
Linus Torvalds 已提交
906

907
	p = reserve_space(xdr, 8);
B
Benny Halevy 已提交
908
	*p++ = cpu_to_be32(OP_ACCESS);
909
	*p = cpu_to_be32(access);
910
	hdr->nops++;
911
	hdr->replen += decode_access_maxsz;
L
Linus Torvalds 已提交
912 913
}

914
static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
915
{
A
Al Viro 已提交
916
	__be32 *p;
L
Linus Torvalds 已提交
917

918
	p = reserve_space(xdr, 8+NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
919 920
	*p++ = cpu_to_be32(OP_CLOSE);
	*p++ = cpu_to_be32(arg->seqid->sequence->counter);
921
	xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
922
	hdr->nops++;
923
	hdr->replen += decode_close_maxsz;
L
Linus Torvalds 已提交
924 925
}

926
static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
927
{
A
Al Viro 已提交
928
	__be32 *p;
929

930
	p = reserve_space(xdr, 16);
B
Benny Halevy 已提交
931
	*p++ = cpu_to_be32(OP_COMMIT);
B
Benny Halevy 已提交
932
	p = xdr_encode_hyper(p, args->offset);
933
	*p = cpu_to_be32(args->count);
934
	hdr->nops++;
935
	hdr->replen += decode_commit_maxsz;
L
Linus Torvalds 已提交
936 937
}

938
static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
939
{
A
Al Viro 已提交
940
	__be32 *p;
941

942
	p = reserve_space(xdr, 8);
B
Benny Halevy 已提交
943
	*p++ = cpu_to_be32(OP_CREATE);
944
	*p = cpu_to_be32(create->ftype);
L
Linus Torvalds 已提交
945 946 947

	switch (create->ftype) {
	case NF4LNK:
948
		p = reserve_space(xdr, 4);
949
		*p = cpu_to_be32(create->u.symlink.len);
950
		xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len);
L
Linus Torvalds 已提交
951 952 953
		break;

	case NF4BLK: case NF4CHR:
954
		p = reserve_space(xdr, 8);
B
Benny Halevy 已提交
955
		*p++ = cpu_to_be32(create->u.device.specdata1);
956
		*p = cpu_to_be32(create->u.device.specdata2);
L
Linus Torvalds 已提交
957 958 959 960 961 962
		break;

	default:
		break;
	}

963
	encode_string(xdr, create->name->len, create->name->name);
964
	hdr->nops++;
965
	hdr->replen += decode_create_maxsz;
L
Linus Torvalds 已提交
966

967
	encode_attrs(xdr, create->attrs, create->server);
L
Linus Torvalds 已提交
968 969
}

970
static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
971
{
A
Andy Adamson 已提交
972
	__be32 *p;
L
Linus Torvalds 已提交
973

974
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
975 976
	*p++ = cpu_to_be32(OP_GETATTR);
	*p++ = cpu_to_be32(1);
977
	*p = cpu_to_be32(bitmap);
978
	hdr->nops++;
979
	hdr->replen += decode_getattr_maxsz;
L
Linus Torvalds 已提交
980 981
}

982
static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
983
{
A
Andy Adamson 已提交
984
	__be32 *p;
L
Linus Torvalds 已提交
985

986
	p = reserve_space(xdr, 16);
B
Benny Halevy 已提交
987 988 989
	*p++ = cpu_to_be32(OP_GETATTR);
	*p++ = cpu_to_be32(2);
	*p++ = cpu_to_be32(bm0);
990
	*p = cpu_to_be32(bm1);
991
	hdr->nops++;
992
	hdr->replen += decode_getattr_maxsz;
L
Linus Torvalds 已提交
993 994
}

995
static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
996
{
997 998
	encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
			   bitmask[1] & nfs4_fattr_bitmap[1], hdr);
L
Linus Torvalds 已提交
999 1000
}

1001
static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1002
{
1003 1004
	encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
			   bitmask[1] & nfs4_fsinfo_bitmap[1], hdr);
L
Linus Torvalds 已提交
1005 1006
}

1007
static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
1008
{
1009 1010
	encode_getattr_two(xdr, bitmask[0] & nfs4_fs_locations_bitmap[0],
			   bitmask[1] & nfs4_fs_locations_bitmap[1], hdr);
1011 1012
}

1013
static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1014
{
A
Al Viro 已提交
1015
	__be32 *p;
L
Linus Torvalds 已提交
1016

1017
	p = reserve_space(xdr, 4);
1018
	*p = cpu_to_be32(OP_GETFH);
1019
	hdr->nops++;
1020
	hdr->replen += decode_getfh_maxsz;
L
Linus Torvalds 已提交
1021 1022
}

1023
static void encode_link(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1024
{
A
Al Viro 已提交
1025
	__be32 *p;
L
Linus Torvalds 已提交
1026

1027
	p = reserve_space(xdr, 8 + name->len);
B
Benny Halevy 已提交
1028
	*p++ = cpu_to_be32(OP_LINK);
1029
	xdr_encode_opaque(p, name->name, name->len);
1030
	hdr->nops++;
1031
	hdr->replen += decode_link_maxsz;
L
Linus Torvalds 已提交
1032 1033
}

T
Trond Myklebust 已提交
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
static inline int nfs4_lock_type(struct file_lock *fl, int block)
{
	if ((fl->fl_type & (F_RDLCK|F_WRLCK|F_UNLCK)) == F_RDLCK)
		return block ? NFS4_READW_LT : NFS4_READ_LT;
	return block ? NFS4_WRITEW_LT : NFS4_WRITE_LT;
}

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

1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
static void encode_lockowner(struct xdr_stream *xdr, const struct nfs_lowner *lowner)
{
	__be32 *p;

	p = reserve_space(xdr, 28);
	p = xdr_encode_hyper(p, lowner->clientid);
	*p++ = cpu_to_be32(16);
	p = xdr_encode_opaque_fixed(p, "lock id:", 8);
	xdr_encode_hyper(p, lowner->id);
}

L
Linus Torvalds 已提交
1059 1060 1061 1062
/*
 * opcode,type,reclaim,offset,length,new_lock_owner = 32
 * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
 */
1063
static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1064
{
A
Al Viro 已提交
1065
	__be32 *p;
L
Linus Torvalds 已提交
1066

1067
	p = reserve_space(xdr, 32);
B
Benny Halevy 已提交
1068 1069 1070
	*p++ = cpu_to_be32(OP_LOCK);
	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, args->block));
	*p++ = cpu_to_be32(args->reclaim);
B
Benny Halevy 已提交
1071 1072
	p = xdr_encode_hyper(p, args->fl->fl_start);
	p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
1073
	*p = cpu_to_be32(args->new_lock_owner);
T
Trond Myklebust 已提交
1074
	if (args->new_lock_owner){
1075
		p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
B
Benny Halevy 已提交
1076
		*p++ = cpu_to_be32(args->open_seqid->sequence->counter);
B
Benny Halevy 已提交
1077
		p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1078
		*p++ = cpu_to_be32(args->lock_seqid->sequence->counter);
1079
		encode_lockowner(xdr, &args->lock_owner);
L
Linus Torvalds 已提交
1080 1081
	}
	else {
1082
		p = reserve_space(xdr, NFS4_STATEID_SIZE+4);
B
Benny Halevy 已提交
1083
		p = xdr_encode_opaque_fixed(p, args->lock_stateid->data, NFS4_STATEID_SIZE);
1084
		*p = cpu_to_be32(args->lock_seqid->sequence->counter);
L
Linus Torvalds 已提交
1085
	}
1086
	hdr->nops++;
1087
	hdr->replen += decode_lock_maxsz;
L
Linus Torvalds 已提交
1088 1089
}

1090
static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1091
{
A
Al Viro 已提交
1092
	__be32 *p;
L
Linus Torvalds 已提交
1093

1094
	p = reserve_space(xdr, 24);
B
Benny Halevy 已提交
1095 1096
	*p++ = cpu_to_be32(OP_LOCKT);
	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
B
Benny Halevy 已提交
1097 1098
	p = xdr_encode_hyper(p, args->fl->fl_start);
	p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
1099
	encode_lockowner(xdr, &args->lock_owner);
1100
	hdr->nops++;
1101
	hdr->replen += decode_lockt_maxsz;
L
Linus Torvalds 已提交
1102 1103
}

1104
static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1105
{
A
Al Viro 已提交
1106
	__be32 *p;
L
Linus Torvalds 已提交
1107

1108
	p = reserve_space(xdr, 12+NFS4_STATEID_SIZE+16);
B
Benny Halevy 已提交
1109 1110 1111
	*p++ = cpu_to_be32(OP_LOCKU);
	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
	*p++ = cpu_to_be32(args->seqid->sequence->counter);
B
Benny Halevy 已提交
1112
	p = xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1113
	p = xdr_encode_hyper(p, args->fl->fl_start);
1114
	xdr_encode_hyper(p, nfs4_lock_length(args->fl));
1115
	hdr->nops++;
1116
	hdr->replen += decode_locku_maxsz;
L
Linus Torvalds 已提交
1117 1118
}

1119
static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1120 1121
{
	int len = name->len;
A
Al Viro 已提交
1122
	__be32 *p;
L
Linus Torvalds 已提交
1123

1124
	p = reserve_space(xdr, 8 + len);
B
Benny Halevy 已提交
1125
	*p++ = cpu_to_be32(OP_LOOKUP);
1126
	xdr_encode_opaque(p, name->name, len);
1127
	hdr->nops++;
1128
	hdr->replen += decode_lookup_maxsz;
L
Linus Torvalds 已提交
1129 1130
}

1131
static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode)
L
Linus Torvalds 已提交
1132
{
A
Al Viro 已提交
1133
	__be32 *p;
L
Linus Torvalds 已提交
1134

1135
	p = reserve_space(xdr, 8);
1136
	switch (fmode & (FMODE_READ|FMODE_WRITE)) {
A
Andy Adamson 已提交
1137
	case FMODE_READ:
B
Benny Halevy 已提交
1138
		*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_READ);
A
Andy Adamson 已提交
1139 1140
		break;
	case FMODE_WRITE:
B
Benny Halevy 已提交
1141
		*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_WRITE);
A
Andy Adamson 已提交
1142 1143
		break;
	case FMODE_READ|FMODE_WRITE:
B
Benny Halevy 已提交
1144
		*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_BOTH);
A
Andy Adamson 已提交
1145 1146
		break;
	default:
B
Benny Halevy 已提交
1147
		*p++ = cpu_to_be32(0);
L
Linus Torvalds 已提交
1148
	}
1149
	*p = cpu_to_be32(0);		/* for linux, share_deny = 0 always */
L
Linus Torvalds 已提交
1150 1151 1152 1153
}

static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg)
{
A
Al Viro 已提交
1154
	__be32 *p;
L
Linus Torvalds 已提交
1155 1156 1157 1158
 /*
 * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
 * owner 4 = 32
 */
1159
	p = reserve_space(xdr, 8);
B
Benny Halevy 已提交
1160
	*p++ = cpu_to_be32(OP_OPEN);
1161
	*p = cpu_to_be32(arg->seqid->sequence->counter);
1162
	encode_share_access(xdr, arg->fmode);
1163
	p = reserve_space(xdr, 28);
B
Benny Halevy 已提交
1164
	p = xdr_encode_hyper(p, arg->clientid);
B
Benny Halevy 已提交
1165
	*p++ = cpu_to_be32(16);
B
Benny Halevy 已提交
1166
	p = xdr_encode_opaque_fixed(p, "open id:", 8);
1167
	xdr_encode_hyper(p, arg->id);
L
Linus Torvalds 已提交
1168 1169 1170 1171
}

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

1175
	p = reserve_space(xdr, 4);
L
Linus Torvalds 已提交
1176
	switch(arg->open_flags & O_EXCL) {
A
Andy Adamson 已提交
1177
	case 0:
1178
		*p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
A
Andy Adamson 已提交
1179 1180 1181
		encode_attrs(xdr, arg->u.attrs, arg->server);
		break;
	default:
1182
		clp = arg->server->nfs_client;
1183
		if (clp->cl_mvops->minor_version > 0) {
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
			if (nfs4_has_persistent_session(clp)) {
				*p = cpu_to_be32(NFS4_CREATE_GUARDED);
				encode_attrs(xdr, arg->u.attrs, arg->server);
			} else {
				struct iattr dummy;

				*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1);
				encode_nfs4_verifier(xdr, &arg->u.verifier);
				dummy.ia_valid = 0;
				encode_attrs(xdr, &dummy, arg->server);
			}
		} else {
			*p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE);
			encode_nfs4_verifier(xdr, &arg->u.verifier);
		}
L
Linus Torvalds 已提交
1199 1200 1201 1202 1203
	}
}

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

1206
	p = reserve_space(xdr, 4);
L
Linus Torvalds 已提交
1207
	switch (arg->open_flags & O_CREAT) {
A
Andy Adamson 已提交
1208
	case 0:
1209
		*p = cpu_to_be32(NFS4_OPEN_NOCREATE);
A
Andy Adamson 已提交
1210 1211 1212
		break;
	default:
		BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL);
1213
		*p = cpu_to_be32(NFS4_OPEN_CREATE);
A
Andy Adamson 已提交
1214
		encode_createmode(xdr, arg);
L
Linus Torvalds 已提交
1215 1216 1217
	}
}

1218
static inline void encode_delegation_type(struct xdr_stream *xdr, fmode_t delegation_type)
L
Linus Torvalds 已提交
1219
{
A
Al Viro 已提交
1220
	__be32 *p;
L
Linus Torvalds 已提交
1221

1222
	p = reserve_space(xdr, 4);
L
Linus Torvalds 已提交
1223
	switch (delegation_type) {
A
Andy Adamson 已提交
1224
	case 0:
1225
		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_NONE);
A
Andy Adamson 已提交
1226 1227
		break;
	case FMODE_READ:
1228
		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_READ);
A
Andy Adamson 已提交
1229 1230
		break;
	case FMODE_WRITE|FMODE_READ:
1231
		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_WRITE);
A
Andy Adamson 已提交
1232 1233 1234
		break;
	default:
		BUG();
L
Linus Torvalds 已提交
1235 1236 1237 1238 1239
	}
}

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

1242
	p = reserve_space(xdr, 4);
1243
	*p = cpu_to_be32(NFS4_OPEN_CLAIM_NULL);
L
Linus Torvalds 已提交
1244 1245 1246
	encode_string(xdr, name->len, name->name);
}

1247
static inline void encode_claim_previous(struct xdr_stream *xdr, fmode_t type)
L
Linus Torvalds 已提交
1248
{
A
Al Viro 已提交
1249
	__be32 *p;
L
Linus Torvalds 已提交
1250

1251
	p = reserve_space(xdr, 4);
1252
	*p = cpu_to_be32(NFS4_OPEN_CLAIM_PREVIOUS);
L
Linus Torvalds 已提交
1253 1254 1255 1256 1257
	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 已提交
1258
	__be32 *p;
L
Linus Torvalds 已提交
1259

1260
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1261
	*p++ = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
1262
	xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1263 1264 1265
	encode_string(xdr, name->len, name->name);
}

1266
static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1267 1268 1269 1270
{
	encode_openhdr(xdr, arg);
	encode_opentype(xdr, arg);
	switch (arg->claim) {
A
Andy Adamson 已提交
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281
	case NFS4_OPEN_CLAIM_NULL:
		encode_claim_null(xdr, arg->name);
		break;
	case NFS4_OPEN_CLAIM_PREVIOUS:
		encode_claim_previous(xdr, arg->u.delegation_type);
		break;
	case NFS4_OPEN_CLAIM_DELEGATE_CUR:
		encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation);
		break;
	default:
		BUG();
L
Linus Torvalds 已提交
1282
	}
1283
	hdr->nops++;
1284
	hdr->replen += decode_open_maxsz;
L
Linus Torvalds 已提交
1285 1286
}

1287
static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1288
{
A
Al Viro 已提交
1289
	__be32 *p;
L
Linus Torvalds 已提交
1290

1291
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
B
Benny Halevy 已提交
1292
	*p++ = cpu_to_be32(OP_OPEN_CONFIRM);
B
Benny Halevy 已提交
1293
	p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
1294
	*p = cpu_to_be32(arg->seqid->sequence->counter);
1295
	hdr->nops++;
1296
	hdr->replen += decode_open_confirm_maxsz;
L
Linus Torvalds 已提交
1297 1298
}

1299
static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1300
{
A
Al Viro 已提交
1301
	__be32 *p;
L
Linus Torvalds 已提交
1302

1303
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
B
Benny Halevy 已提交
1304
	*p++ = cpu_to_be32(OP_OPEN_DOWNGRADE);
B
Benny Halevy 已提交
1305
	p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
1306
	*p = cpu_to_be32(arg->seqid->sequence->counter);
1307
	encode_share_access(xdr, arg->fmode);
1308
	hdr->nops++;
1309
	hdr->replen += decode_open_downgrade_maxsz;
L
Linus Torvalds 已提交
1310 1311
}

1312
static void
1313
encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1314 1315
{
	int len = fh->size;
A
Al Viro 已提交
1316
	__be32 *p;
L
Linus Torvalds 已提交
1317

1318
	p = reserve_space(xdr, 8 + len);
B
Benny Halevy 已提交
1319
	*p++ = cpu_to_be32(OP_PUTFH);
1320
	xdr_encode_opaque(p, fh->data, len);
1321
	hdr->nops++;
1322
	hdr->replen += decode_putfh_maxsz;
L
Linus Torvalds 已提交
1323 1324
}

1325
static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1326
{
A
Andy Adamson 已提交
1327
	__be32 *p;
1328

1329
	p = reserve_space(xdr, 4);
1330
	*p = cpu_to_be32(OP_PUTROOTFH);
1331
	hdr->nops++;
1332
	hdr->replen += decode_putrootfh_maxsz;
L
Linus Torvalds 已提交
1333 1334
}

1335
static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx, const struct nfs_lock_context *l_ctx)
L
Linus Torvalds 已提交
1336 1337
{
	nfs4_stateid stateid;
A
Al Viro 已提交
1338
	__be32 *p;
L
Linus Torvalds 已提交
1339

1340
	p = reserve_space(xdr, NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1341
	if (ctx->state != NULL) {
1342
		nfs4_copy_stateid(&stateid, ctx->state, l_ctx->lockowner);
1343
		xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1344
	} else
1345
		xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1346 1347
}

1348
static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1349
{
A
Al Viro 已提交
1350
	__be32 *p;
L
Linus Torvalds 已提交
1351

1352
	p = reserve_space(xdr, 4);
1353
	*p = cpu_to_be32(OP_READ);
L
Linus Torvalds 已提交
1354

1355
	encode_stateid(xdr, args->context, args->lock_context);
L
Linus Torvalds 已提交
1356

1357
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
1358
	p = xdr_encode_hyper(p, args->offset);
1359
	*p = cpu_to_be32(args->count);
1360
	hdr->nops++;
1361
	hdr->replen += decode_read_maxsz;
L
Linus Torvalds 已提交
1362 1363
}

1364
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 已提交
1365
{
1366 1367 1368 1369
	uint32_t attrs[2] = {
		FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID,
		FATTR4_WORD1_MOUNTED_ON_FILEID,
	};
A
Al Viro 已提交
1370
	__be32 *p;
L
Linus Torvalds 已提交
1371

1372
	p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
B
Benny Halevy 已提交
1373
	*p++ = cpu_to_be32(OP_READDIR);
B
Benny Halevy 已提交
1374
	p = xdr_encode_hyper(p, readdir->cookie);
B
Benny Halevy 已提交
1375
	p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE);
B
Benny Halevy 已提交
1376 1377 1378
	*p++ = cpu_to_be32(readdir->count >> 1);  /* We're not doing readdirplus */
	*p++ = cpu_to_be32(readdir->count);
	*p++ = cpu_to_be32(2);
1379 1380 1381 1382 1383
	/* Switch to mounted_on_fileid if the server supports it */
	if (readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
		attrs[0] &= ~FATTR4_WORD0_FILEID;
	else
		attrs[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
B
Benny Halevy 已提交
1384
	*p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]);
1385
	*p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
1386
	hdr->nops++;
1387
	hdr->replen += decode_readdir_maxsz;
1388 1389
	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
			__func__,
1390 1391 1392 1393 1394
			(unsigned long long)readdir->cookie,
			((u32 *)readdir->verifier.data)[0],
			((u32 *)readdir->verifier.data)[1],
			attrs[0] & readdir->bitmask[0],
			attrs[1] & readdir->bitmask[1]);
L
Linus Torvalds 已提交
1395 1396
}

1397
static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1398
{
A
Al Viro 已提交
1399
	__be32 *p;
L
Linus Torvalds 已提交
1400

1401
	p = reserve_space(xdr, 4);
1402
	*p = cpu_to_be32(OP_READLINK);
1403
	hdr->nops++;
1404
	hdr->replen += decode_readlink_maxsz;
L
Linus Torvalds 已提交
1405 1406
}

1407
static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1408
{
A
Al Viro 已提交
1409
	__be32 *p;
L
Linus Torvalds 已提交
1410

1411
	p = reserve_space(xdr, 8 + name->len);
B
Benny Halevy 已提交
1412
	*p++ = cpu_to_be32(OP_REMOVE);
1413
	xdr_encode_opaque(p, name->name, name->len);
1414
	hdr->nops++;
1415
	hdr->replen += decode_remove_maxsz;
L
Linus Torvalds 已提交
1416 1417
}

1418
static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1419
{
A
Al Viro 已提交
1420
	__be32 *p;
L
Linus Torvalds 已提交
1421

1422 1423 1424 1425
	p = reserve_space(xdr, 4);
	*p = cpu_to_be32(OP_RENAME);
	encode_string(xdr, oldname->len, oldname->name);
	encode_string(xdr, newname->len, newname->name);
1426
	hdr->nops++;
1427
	hdr->replen += decode_rename_maxsz;
L
Linus Torvalds 已提交
1428 1429
}

1430
static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1431
{
A
Al Viro 已提交
1432
	__be32 *p;
L
Linus Torvalds 已提交
1433

1434
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
1435
	*p++ = cpu_to_be32(OP_RENEW);
1436
	xdr_encode_hyper(p, client_stateid->cl_clientid);
1437
	hdr->nops++;
1438
	hdr->replen += decode_renew_maxsz;
L
Linus Torvalds 已提交
1439 1440
}

1441
static void
1442
encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
1443
{
A
Al Viro 已提交
1444
	__be32 *p;
1445

1446
	p = reserve_space(xdr, 4);
1447
	*p = cpu_to_be32(OP_RESTOREFH);
1448
	hdr->nops++;
1449
	hdr->replen += decode_restorefh_maxsz;
1450 1451
}

1452
static int
1453
encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compound_hdr *hdr)
1454
{
A
Al Viro 已提交
1455
	__be32 *p;
1456

1457
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1458
	*p++ = cpu_to_be32(OP_SETATTR);
1459
	xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
1460
	p = reserve_space(xdr, 2*4);
B
Benny Halevy 已提交
1461
	*p++ = cpu_to_be32(1);
1462
	*p = cpu_to_be32(FATTR4_WORD0_ACL);
1463 1464
	if (arg->acl_len % 4)
		return -EINVAL;
1465
	p = reserve_space(xdr, 4);
1466
	*p = cpu_to_be32(arg->acl_len);
1467
	xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
1468
	hdr->nops++;
1469
	hdr->replen += decode_setacl_maxsz;
1470 1471 1472
	return 0;
}

1473
static void
1474
encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1475
{
A
Al Viro 已提交
1476
	__be32 *p;
L
Linus Torvalds 已提交
1477

1478
	p = reserve_space(xdr, 4);
1479
	*p = cpu_to_be32(OP_SAVEFH);
1480
	hdr->nops++;
1481
	hdr->replen += decode_savefh_maxsz;
L
Linus Torvalds 已提交
1482 1483
}

1484
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 已提交
1485
{
A
Al Viro 已提交
1486
	__be32 *p;
1487

1488
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1489
	*p++ = cpu_to_be32(OP_SETATTR);
1490
	xdr_encode_opaque_fixed(p, arg->stateid.data, NFS4_STATEID_SIZE);
1491
	hdr->nops++;
1492
	hdr->replen += decode_setattr_maxsz;
1493
	encode_attrs(xdr, arg->iap, server);
L
Linus Torvalds 已提交
1494 1495
}

1496
static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1497
{
A
Al Viro 已提交
1498
	__be32 *p;
L
Linus Torvalds 已提交
1499

1500
	p = reserve_space(xdr, 4 + NFS4_VERIFIER_SIZE);
B
Benny Halevy 已提交
1501
	*p++ = cpu_to_be32(OP_SETCLIENTID);
1502
	xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE);
L
Linus Torvalds 已提交
1503 1504

	encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
1505
	p = reserve_space(xdr, 4);
1506
	*p = cpu_to_be32(setclientid->sc_prog);
L
Linus Torvalds 已提交
1507 1508
	encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid);
	encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
1509
	p = reserve_space(xdr, 4);
1510
	*p = cpu_to_be32(setclientid->sc_cb_ident);
1511
	hdr->nops++;
1512
	hdr->replen += decode_setclientid_maxsz;
L
Linus Torvalds 已提交
1513 1514
}

1515
static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs4_setclientid_res *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1516
{
A
Andy Adamson 已提交
1517
	__be32 *p;
L
Linus Torvalds 已提交
1518

1519
	p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE);
B
Benny Halevy 已提交
1520
	*p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM);
1521 1522
	p = xdr_encode_hyper(p, arg->clientid);
	xdr_encode_opaque_fixed(p, arg->confirm.data, NFS4_VERIFIER_SIZE);
1523
	hdr->nops++;
1524
	hdr->replen += decode_setclientid_confirm_maxsz;
L
Linus Torvalds 已提交
1525 1526
}

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

1531
	p = reserve_space(xdr, 4);
1532
	*p = cpu_to_be32(OP_WRITE);
L
Linus Torvalds 已提交
1533

1534
	encode_stateid(xdr, args->context, args->lock_context);
L
Linus Torvalds 已提交
1535

1536
	p = reserve_space(xdr, 16);
B
Benny Halevy 已提交
1537
	p = xdr_encode_hyper(p, args->offset);
B
Benny Halevy 已提交
1538
	*p++ = cpu_to_be32(args->stable);
1539
	*p = cpu_to_be32(args->count);
L
Linus Torvalds 已提交
1540 1541

	xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
1542
	hdr->nops++;
1543
	hdr->replen += decode_write_maxsz;
L
Linus Torvalds 已提交
1544 1545
}

1546
static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1547
{
A
Al Viro 已提交
1548
	__be32 *p;
L
Linus Torvalds 已提交
1549

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

B
Benny Halevy 已提交
1552
	*p++ = cpu_to_be32(OP_DELEGRETURN);
1553
	xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
1554
	hdr->nops++;
1555
	hdr->replen += decode_delegreturn_maxsz;
L
Linus Torvalds 已提交
1556
}
1557

B
Benny Halevy 已提交
1558
#if defined(CONFIG_NFS_V4_1)
1559
/* NFSv4.1 operations */
B
Benny Halevy 已提交
1560 1561 1562 1563 1564 1565
static void encode_exchange_id(struct xdr_stream *xdr,
			       struct nfs41_exchange_id_args *args,
			       struct compound_hdr *hdr)
{
	__be32 *p;

1566
	p = reserve_space(xdr, 4 + sizeof(args->verifier->data));
B
Benny Halevy 已提交
1567
	*p++ = cpu_to_be32(OP_EXCHANGE_ID);
1568
	xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data));
B
Benny Halevy 已提交
1569 1570 1571

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

1572
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
1573 1574
	*p++ = cpu_to_be32(args->flags);
	*p++ = cpu_to_be32(0);	/* zero length state_protect4_a */
1575
	*p = cpu_to_be32(0);	/* zero length implementation id array */
B
Benny Halevy 已提交
1576 1577 1578
	hdr->nops++;
	hdr->replen += decode_exchange_id_maxsz;
}
A
Andy Adamson 已提交
1579 1580 1581 1582 1583 1584 1585 1586 1587

static void encode_create_session(struct xdr_stream *xdr,
				  struct nfs41_create_session_args *args,
				  struct compound_hdr *hdr)
{
	__be32 *p;
	char machine_name[NFS4_MAX_MACHINE_NAME_LEN];
	uint32_t len;
	struct nfs_client *clp = args->client;
1588 1589 1590 1591 1592 1593 1594 1595
	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 已提交
1596

1597 1598
	len = scnprintf(machine_name, sizeof(machine_name), "%s",
			clp->cl_ipaddr);
A
Andy Adamson 已提交
1599

1600
	p = reserve_space(xdr, 20 + 2*28 + 20 + len + 12);
1601
	*p++ = cpu_to_be32(OP_CREATE_SESSION);
B
Benny Halevy 已提交
1602
	p = xdr_encode_hyper(p, clp->cl_ex_clid);
B
Benny Halevy 已提交
1603 1604
	*p++ = cpu_to_be32(clp->cl_seqid);			/*Sequence id */
	*p++ = cpu_to_be32(args->flags);			/*flags */
A
Andy Adamson 已提交
1605 1606

	/* Fore Channel */
B
Benny Halevy 已提交
1607 1608 1609
	*p++ = cpu_to_be32(args->fc_attrs.headerpadsz);	/* header padding size */
	*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 */
1610
	*p++ = cpu_to_be32(max_resp_sz_cached);		/* Max resp sz cached */
B
Benny Halevy 已提交
1611 1612 1613
	*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 已提交
1614 1615

	/* Back Channel */
B
Benny Halevy 已提交
1616 1617 1618 1619 1620 1621 1622
	*p++ = cpu_to_be32(args->fc_attrs.headerpadsz);	/* header padding size */
	*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 已提交
1623

B
Benny Halevy 已提交
1624 1625 1626
	*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 已提交
1627 1628

	/* authsys_parms rfc1831 */
B
Benny Halevy 已提交
1629
	*p++ = cpu_to_be32((u32)clp->cl_boot_time.tv_nsec);	/* stamp */
1630
	p = xdr_encode_opaque(p, machine_name, len);
B
Benny Halevy 已提交
1631 1632
	*p++ = cpu_to_be32(0);				/* UID */
	*p++ = cpu_to_be32(0);				/* GID */
1633
	*p = cpu_to_be32(0);				/* No more gids */
A
Andy Adamson 已提交
1634 1635 1636
	hdr->nops++;
	hdr->replen += decode_create_session_maxsz;
}
A
Andy Adamson 已提交
1637 1638 1639 1640 1641 1642

static void encode_destroy_session(struct xdr_stream *xdr,
				   struct nfs4_session *session,
				   struct compound_hdr *hdr)
{
	__be32 *p;
1643
	p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN);
B
Benny Halevy 已提交
1644
	*p++ = cpu_to_be32(OP_DESTROY_SESSION);
1645
	xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
A
Andy Adamson 已提交
1646 1647 1648
	hdr->nops++;
	hdr->replen += decode_destroy_session_maxsz;
}
1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661

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

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

1664 1665 1666 1667 1668 1669
static void encode_sequence(struct xdr_stream *xdr,
			    const struct nfs4_sequence_args *args,
			    struct compound_hdr *hdr)
{
#if defined(CONFIG_NFS_V4_1)
	struct nfs4_session *session = args->sa_session;
A
Andy Adamson 已提交
1670 1671 1672
	struct nfs4_slot_table *tp;
	struct nfs4_slot *slot;
	__be32 *p;
1673 1674 1675 1676

	if (!session)
		return;

A
Andy Adamson 已提交
1677 1678 1679 1680 1681
	tp = &session->fc_slot_table;

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

1682
	p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN + 16);
B
Benny Halevy 已提交
1683
	*p++ = cpu_to_be32(OP_SEQUENCE);
A
Andy Adamson 已提交
1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696

	/*
	 * Sessionid + seqid + slotid + max slotid + cache_this
	 */
	dprintk("%s: sessionid=%u:%u:%u:%u seqid=%d slotid=%d "
		"max_slotid=%d cache_this=%d\n",
		__func__,
		((u32 *)session->sess_id.data)[0],
		((u32 *)session->sess_id.data)[1],
		((u32 *)session->sess_id.data)[2],
		((u32 *)session->sess_id.data)[3],
		slot->seq_nr, args->sa_slotid,
		tp->highest_used_slotid, args->sa_cache_this);
B
Benny Halevy 已提交
1697
	p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
B
Benny Halevy 已提交
1698 1699 1700
	*p++ = cpu_to_be32(slot->seq_nr);
	*p++ = cpu_to_be32(args->sa_slotid);
	*p++ = cpu_to_be32(tp->highest_used_slotid);
1701
	*p = cpu_to_be32(args->sa_cache_this);
1702 1703 1704 1705 1706
	hdr->nops++;
	hdr->replen += decode_sequence_maxsz;
#endif /* CONFIG_NFS_V4_1 */
}

L
Linus Torvalds 已提交
1707 1708 1709 1710
/*
 * END OF "GENERIC" ENCODE ROUTINES.
 */

1711 1712 1713 1714
static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args)
{
#if defined(CONFIG_NFS_V4_1)
	if (args->sa_session)
1715
		return args->sa_session->clp->cl_mvops->minor_version;
1716 1717 1718 1719
#endif /* CONFIG_NFS_V4_1 */
	return 0;
}

L
Linus Torvalds 已提交
1720 1721 1722
/*
 * Encode an ACCESS request
 */
A
Al Viro 已提交
1723
static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs4_accessargs *args)
L
Linus Torvalds 已提交
1724 1725 1726
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1727
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1728 1729 1730
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1731
	encode_compound_hdr(&xdr, req, &hdr);
1732
	encode_sequence(&xdr, &args->seq_args, &hdr);
1733 1734 1735
	encode_putfh(&xdr, args->fh, &hdr);
	encode_access(&xdr, args->access, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1736
	encode_nops(&hdr);
1737
	return 0;
L
Linus Torvalds 已提交
1738 1739 1740 1741 1742
}

/*
 * Encode LOOKUP request
 */
A
Al Viro 已提交
1743
static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_arg *args)
L
Linus Torvalds 已提交
1744 1745 1746
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1747
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1748 1749 1750
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1751
	encode_compound_hdr(&xdr, req, &hdr);
1752
	encode_sequence(&xdr, &args->seq_args, &hdr);
1753 1754 1755 1756
	encode_putfh(&xdr, args->dir_fh, &hdr);
	encode_lookup(&xdr, args->name, &hdr);
	encode_getfh(&xdr, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1757
	encode_nops(&hdr);
1758
	return 0;
L
Linus Torvalds 已提交
1759 1760 1761 1762 1763
}

/*
 * Encode LOOKUP_ROOT request
 */
A
Al Viro 已提交
1764
static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_root_arg *args)
L
Linus Torvalds 已提交
1765 1766 1767
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1768
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1769 1770 1771
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1772
	encode_compound_hdr(&xdr, req, &hdr);
1773
	encode_sequence(&xdr, &args->seq_args, &hdr);
1774 1775 1776
	encode_putrootfh(&xdr, &hdr);
	encode_getfh(&xdr, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1777
	encode_nops(&hdr);
1778
	return 0;
L
Linus Torvalds 已提交
1779 1780 1781 1782 1783
}

/*
 * Encode REMOVE request
 */
1784
static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
L
Linus Torvalds 已提交
1785 1786 1787
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1788
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1789 1790 1791
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1792
	encode_compound_hdr(&xdr, req, &hdr);
1793
	encode_sequence(&xdr, &args->seq_args, &hdr);
1794 1795 1796
	encode_putfh(&xdr, args->fh, &hdr);
	encode_remove(&xdr, &args->name, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1797
	encode_nops(&hdr);
1798
	return 0;
L
Linus Torvalds 已提交
1799 1800 1801 1802 1803
}

/*
 * Encode RENAME request
 */
A
Al Viro 已提交
1804
static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs4_rename_arg *args)
L
Linus Torvalds 已提交
1805 1806 1807
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1808
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1809 1810 1811
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1812
	encode_compound_hdr(&xdr, req, &hdr);
1813
	encode_sequence(&xdr, &args->seq_args, &hdr);
1814 1815 1816 1817 1818 1819 1820
	encode_putfh(&xdr, args->old_dir, &hdr);
	encode_savefh(&xdr, &hdr);
	encode_putfh(&xdr, args->new_dir, &hdr);
	encode_rename(&xdr, args->old_name, args->new_name, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
	encode_restorefh(&xdr, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1821
	encode_nops(&hdr);
1822
	return 0;
L
Linus Torvalds 已提交
1823 1824 1825 1826 1827
}

/*
 * Encode LINK request
 */
A
Al Viro 已提交
1828
static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_link_arg *args)
L
Linus Torvalds 已提交
1829 1830 1831
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1832
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1833 1834 1835
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1836
	encode_compound_hdr(&xdr, req, &hdr);
1837
	encode_sequence(&xdr, &args->seq_args, &hdr);
1838 1839 1840 1841 1842 1843 1844
	encode_putfh(&xdr, args->fh, &hdr);
	encode_savefh(&xdr, &hdr);
	encode_putfh(&xdr, args->dir_fh, &hdr);
	encode_link(&xdr, args->name, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
	encode_restorefh(&xdr, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1845
	encode_nops(&hdr);
1846
	return 0;
L
Linus Torvalds 已提交
1847 1848 1849 1850 1851
}

/*
 * Encode CREATE request
 */
A
Al Viro 已提交
1852
static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
L
Linus Torvalds 已提交
1853 1854 1855
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1856
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1857 1858 1859
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1860
	encode_compound_hdr(&xdr, req, &hdr);
1861
	encode_sequence(&xdr, &args->seq_args, &hdr);
1862 1863 1864 1865 1866 1867 1868
	encode_putfh(&xdr, args->dir_fh, &hdr);
	encode_savefh(&xdr, &hdr);
	encode_create(&xdr, args, &hdr);
	encode_getfh(&xdr, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
	encode_restorefh(&xdr, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1869
	encode_nops(&hdr);
1870
	return 0;
L
Linus Torvalds 已提交
1871 1872 1873 1874 1875
}

/*
 * Encode SYMLINK request
 */
A
Al Viro 已提交
1876
static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
L
Linus Torvalds 已提交
1877 1878 1879 1880 1881 1882 1883
{
	return nfs4_xdr_enc_create(req, p, args);
}

/*
 * Encode GETATTR request
 */
A
Al Viro 已提交
1884
static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nfs4_getattr_arg *args)
L
Linus Torvalds 已提交
1885 1886 1887
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1888
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1889 1890 1891
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1892
	encode_compound_hdr(&xdr, req, &hdr);
1893
	encode_sequence(&xdr, &args->seq_args, &hdr);
1894 1895
	encode_putfh(&xdr, args->fh, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1896
	encode_nops(&hdr);
1897
	return 0;
L
Linus Torvalds 已提交
1898 1899 1900 1901 1902
}

/*
 * Encode a CLOSE request
 */
A
Al Viro 已提交
1903
static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
L
Linus Torvalds 已提交
1904
{
A
Andy Adamson 已提交
1905 1906
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1907
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
A
Andy Adamson 已提交
1908 1909 1910
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1911
	encode_compound_hdr(&xdr, req, &hdr);
1912
	encode_sequence(&xdr, &args->seq_args, &hdr);
1913 1914 1915
	encode_putfh(&xdr, args->fh, &hdr);
	encode_close(&xdr, args, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1916
	encode_nops(&hdr);
1917
	return 0;
L
Linus Torvalds 已提交
1918 1919 1920 1921 1922
}

/*
 * Encode an OPEN request
 */
A
Al Viro 已提交
1923
static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
L
Linus Torvalds 已提交
1924 1925 1926
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1927
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1928 1929 1930
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1931
	encode_compound_hdr(&xdr, req, &hdr);
1932
	encode_sequence(&xdr, &args->seq_args, &hdr);
1933 1934 1935 1936 1937 1938 1939
	encode_putfh(&xdr, args->fh, &hdr);
	encode_savefh(&xdr, &hdr);
	encode_open(&xdr, args, &hdr);
	encode_getfh(&xdr, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
	encode_restorefh(&xdr, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1940
	encode_nops(&hdr);
1941
	return 0;
L
Linus Torvalds 已提交
1942 1943 1944 1945 1946
}

/*
 * Encode an OPEN_CONFIRM request
 */
A
Al Viro 已提交
1947
static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_open_confirmargs *args)
L
Linus Torvalds 已提交
1948 1949 1950
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1951
		.nops   = 0,
L
Linus Torvalds 已提交
1952 1953 1954
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1955
	encode_compound_hdr(&xdr, req, &hdr);
1956 1957
	encode_putfh(&xdr, args->fh, &hdr);
	encode_open_confirm(&xdr, args, &hdr);
1958
	encode_nops(&hdr);
1959
	return 0;
L
Linus Torvalds 已提交
1960 1961 1962 1963 1964
}

/*
 * Encode an OPEN request with no attributes.
 */
A
Al Viro 已提交
1965
static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
L
Linus Torvalds 已提交
1966 1967 1968
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1969
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1970 1971 1972
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1973
	encode_compound_hdr(&xdr, req, &hdr);
1974
	encode_sequence(&xdr, &args->seq_args, &hdr);
1975 1976 1977
	encode_putfh(&xdr, args->fh, &hdr);
	encode_open(&xdr, args, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1978
	encode_nops(&hdr);
1979
	return 0;
L
Linus Torvalds 已提交
1980 1981 1982 1983 1984
}

/*
 * Encode an OPEN_DOWNGRADE request
 */
A
Al Viro 已提交
1985
static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
L
Linus Torvalds 已提交
1986 1987 1988
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1989
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1990 1991 1992
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1993
	encode_compound_hdr(&xdr, req, &hdr);
1994
	encode_sequence(&xdr, &args->seq_args, &hdr);
1995 1996 1997
	encode_putfh(&xdr, args->fh, &hdr);
	encode_open_downgrade(&xdr, args, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1998
	encode_nops(&hdr);
1999
	return 0;
L
Linus Torvalds 已提交
2000 2001 2002 2003 2004
}

/*
 * Encode a LOCK request
 */
A
Al Viro 已提交
2005
static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_args *args)
L
Linus Torvalds 已提交
2006 2007 2008
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2009
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2010 2011 2012
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2013
	encode_compound_hdr(&xdr, req, &hdr);
2014
	encode_sequence(&xdr, &args->seq_args, &hdr);
2015 2016
	encode_putfh(&xdr, args->fh, &hdr);
	encode_lock(&xdr, args, &hdr);
2017
	encode_nops(&hdr);
2018
	return 0;
L
Linus Torvalds 已提交
2019 2020 2021 2022 2023
}

/*
 * Encode a LOCKT request
 */
A
Al Viro 已提交
2024
static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_args *args)
L
Linus Torvalds 已提交
2025 2026 2027
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2028
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2029 2030 2031
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2032
	encode_compound_hdr(&xdr, req, &hdr);
2033
	encode_sequence(&xdr, &args->seq_args, &hdr);
2034 2035
	encode_putfh(&xdr, args->fh, &hdr);
	encode_lockt(&xdr, args, &hdr);
2036
	encode_nops(&hdr);
2037
	return 0;
L
Linus Torvalds 已提交
2038 2039 2040 2041 2042
}

/*
 * Encode a LOCKU request
 */
A
Al Viro 已提交
2043
static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_args *args)
L
Linus Torvalds 已提交
2044 2045 2046
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2047
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2048 2049 2050
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2051
	encode_compound_hdr(&xdr, req, &hdr);
2052
	encode_sequence(&xdr, &args->seq_args, &hdr);
2053 2054
	encode_putfh(&xdr, args->fh, &hdr);
	encode_locku(&xdr, args, &hdr);
2055
	encode_nops(&hdr);
2056
	return 0;
L
Linus Torvalds 已提交
2057 2058 2059 2060 2061
}

/*
 * Encode a READLINK request
 */
A
Al Viro 已提交
2062
static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_readlink *args)
L
Linus Torvalds 已提交
2063 2064 2065
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2066
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2067 2068 2069
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2070
	encode_compound_hdr(&xdr, req, &hdr);
2071
	encode_sequence(&xdr, &args->seq_args, &hdr);
2072 2073
	encode_putfh(&xdr, args->fh, &hdr);
	encode_readlink(&xdr, args, req, &hdr);
2074

2075
	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
2076
			args->pgbase, args->pglen);
2077
	encode_nops(&hdr);
2078
	return 0;
L
Linus Torvalds 已提交
2079 2080 2081 2082 2083
}

/*
 * Encode a READDIR request
 */
A
Al Viro 已提交
2084
static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nfs4_readdir_arg *args)
L
Linus Torvalds 已提交
2085 2086 2087
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2088
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2089 2090 2091
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2092
	encode_compound_hdr(&xdr, req, &hdr);
2093
	encode_sequence(&xdr, &args->seq_args, &hdr);
2094 2095
	encode_putfh(&xdr, args->fh, &hdr);
	encode_readdir(&xdr, args, req, &hdr);
2096

2097
	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
2098 2099
			 args->pgbase, args->count);
	dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
2100
			__func__, hdr.replen << 2, args->pages,
2101
			args->pgbase, args->count);
2102
	encode_nops(&hdr);
2103
	return 0;
L
Linus Torvalds 已提交
2104 2105 2106 2107 2108
}

/*
 * Encode a READ request
 */
A
Al Viro 已提交
2109
static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
L
Linus Torvalds 已提交
2110 2111 2112
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2113
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2114 2115 2116
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2117
	encode_compound_hdr(&xdr, req, &hdr);
2118
	encode_sequence(&xdr, &args->seq_args, &hdr);
2119 2120
	encode_putfh(&xdr, args->fh, &hdr);
	encode_read(&xdr, args, &hdr);
L
Linus Torvalds 已提交
2121

2122
	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2,
L
Linus Torvalds 已提交
2123
			 args->pages, args->pgbase, args->count);
2124
	req->rq_rcv_buf.flags |= XDRBUF_READ;
2125
	encode_nops(&hdr);
2126
	return 0;
L
Linus Torvalds 已提交
2127 2128 2129 2130 2131
}

/*
 * Encode an SETATTR request
 */
A
Al Viro 已提交
2132
static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args)
L
Linus Torvalds 已提交
2133
{
A
Andy Adamson 已提交
2134 2135
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2136
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
A
Andy Adamson 已提交
2137 2138 2139
	};

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

2149 2150 2151 2152
/*
 * Encode a GETACL request
 */
static int
A
Al Viro 已提交
2153
nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
2154 2155 2156 2157
		struct nfs_getaclargs *args)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2158
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
2159
	};
2160
	uint32_t replen;
2161 2162

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2163
	encode_compound_hdr(&xdr, req, &hdr);
2164
	encode_sequence(&xdr, &args->seq_args, &hdr);
2165
	encode_putfh(&xdr, args->fh, &hdr);
2166
	replen = hdr.replen + op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz + 1;
2167 2168
	encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr);

2169
	xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
2170
		args->acl_pages, args->acl_pgbase, args->acl_len);
2171
	encode_nops(&hdr);
2172
	return 0;
2173 2174
}

L
Linus Torvalds 已提交
2175 2176 2177
/*
 * Encode a WRITE request
 */
A
Al Viro 已提交
2178
static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
L
Linus Torvalds 已提交
2179 2180 2181
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2182
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2183 2184 2185
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2186
	encode_compound_hdr(&xdr, req, &hdr);
2187
	encode_sequence(&xdr, &args->seq_args, &hdr);
2188 2189
	encode_putfh(&xdr, args->fh, &hdr);
	encode_write(&xdr, args, &hdr);
2190
	req->rq_snd_buf.flags |= XDRBUF_WRITE;
2191
	encode_getfattr(&xdr, args->bitmask, &hdr);
2192
	encode_nops(&hdr);
2193
	return 0;
L
Linus Torvalds 已提交
2194 2195 2196 2197 2198
}

/*
 *  a COMMIT request
 */
A
Al Viro 已提交
2199
static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
L
Linus Torvalds 已提交
2200 2201 2202
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2203
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2204 2205 2206
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2207
	encode_compound_hdr(&xdr, req, &hdr);
2208
	encode_sequence(&xdr, &args->seq_args, &hdr);
2209 2210 2211
	encode_putfh(&xdr, args->fh, &hdr);
	encode_commit(&xdr, args, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
2212
	encode_nops(&hdr);
2213
	return 0;
L
Linus Torvalds 已提交
2214 2215 2216 2217 2218
}

/*
 * FSINFO request
 */
A
Al Viro 已提交
2219
static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsinfo_arg *args)
L
Linus Torvalds 已提交
2220 2221 2222
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2223
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2224 2225 2226
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2227
	encode_compound_hdr(&xdr, req, &hdr);
2228
	encode_sequence(&xdr, &args->seq_args, &hdr);
2229 2230
	encode_putfh(&xdr, args->fh, &hdr);
	encode_fsinfo(&xdr, args->bitmask, &hdr);
2231
	encode_nops(&hdr);
2232
	return 0;
L
Linus Torvalds 已提交
2233 2234 2235 2236 2237
}

/*
 * a PATHCONF request
 */
A
Al Viro 已提交
2238
static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct nfs4_pathconf_arg *args)
L
Linus Torvalds 已提交
2239 2240 2241
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2242
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2243 2244 2245
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2246
	encode_compound_hdr(&xdr, req, &hdr);
2247
	encode_sequence(&xdr, &args->seq_args, &hdr);
2248 2249 2250
	encode_putfh(&xdr, args->fh, &hdr);
	encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0],
			   &hdr);
2251
	encode_nops(&hdr);
2252
	return 0;
L
Linus Torvalds 已提交
2253 2254 2255 2256 2257
}

/*
 * a STATFS request
 */
A
Al Viro 已提交
2258
static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs4_statfs_arg *args)
L
Linus Torvalds 已提交
2259 2260 2261
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2262
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2263 2264 2265
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2266
	encode_compound_hdr(&xdr, req, &hdr);
2267
	encode_sequence(&xdr, &args->seq_args, &hdr);
2268 2269 2270
	encode_putfh(&xdr, args->fh, &hdr);
	encode_getattr_two(&xdr, args->bitmask[0] & nfs4_statfs_bitmap[0],
			   args->bitmask[1] & nfs4_statfs_bitmap[1], &hdr);
2271
	encode_nops(&hdr);
2272
	return 0;
L
Linus Torvalds 已提交
2273 2274 2275 2276 2277
}

/*
 * GETATTR_BITMAP request
 */
B
Benny Halevy 已提交
2278 2279
static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p,
				    struct nfs4_server_caps_arg *args)
L
Linus Torvalds 已提交
2280 2281 2282
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2283
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2284 2285 2286
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2287
	encode_compound_hdr(&xdr, req, &hdr);
2288
	encode_sequence(&xdr, &args->seq_args, &hdr);
B
Benny Halevy 已提交
2289
	encode_putfh(&xdr, args->fhandle, &hdr);
2290 2291 2292 2293
	encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
			   FATTR4_WORD0_LINK_SUPPORT|
			   FATTR4_WORD0_SYMLINK_SUPPORT|
			   FATTR4_WORD0_ACLSUPPORT, &hdr);
2294
	encode_nops(&hdr);
2295
	return 0;
L
Linus Torvalds 已提交
2296 2297 2298 2299 2300
}

/*
 * a RENEW request
 */
A
Al Viro 已提交
2301
static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
L
Linus Torvalds 已提交
2302 2303 2304
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2305
		.nops	= 0,
L
Linus Torvalds 已提交
2306 2307 2308
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2309
	encode_compound_hdr(&xdr, req, &hdr);
2310
	encode_renew(&xdr, clp, &hdr);
2311
	encode_nops(&hdr);
2312
	return 0;
L
Linus Torvalds 已提交
2313 2314 2315 2316 2317
}

/*
 * a SETCLIENTID request
 */
A
Al Viro 已提交
2318
static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid *sc)
L
Linus Torvalds 已提交
2319 2320 2321
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2322
		.nops	= 0,
L
Linus Torvalds 已提交
2323 2324 2325
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2326
	encode_compound_hdr(&xdr, req, &hdr);
2327
	encode_setclientid(&xdr, sc, &hdr);
2328
	encode_nops(&hdr);
2329
	return 0;
L
Linus Torvalds 已提交
2330 2331 2332 2333 2334
}

/*
 * a SETCLIENTID_CONFIRM request
 */
2335
static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid_res *arg)
L
Linus Torvalds 已提交
2336 2337 2338
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2339
		.nops	= 0,
L
Linus Torvalds 已提交
2340 2341 2342 2343
	};
	const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2344
	encode_compound_hdr(&xdr, req, &hdr);
2345
	encode_setclientid_confirm(&xdr, arg, &hdr);
2346 2347
	encode_putrootfh(&xdr, &hdr);
	encode_fsinfo(&xdr, lease_bitmap, &hdr);
2348
	encode_nops(&hdr);
2349
	return 0;
L
Linus Torvalds 已提交
2350 2351 2352 2353 2354
}

/*
 * DELEGRETURN request
 */
A
Al Viro 已提交
2355
static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struct nfs4_delegreturnargs *args)
L
Linus Torvalds 已提交
2356 2357 2358
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2359
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2360 2361 2362
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2363
	encode_compound_hdr(&xdr, req, &hdr);
2364
	encode_sequence(&xdr, &args->seq_args, &hdr);
2365 2366 2367
	encode_putfh(&xdr, args->fhandle, &hdr);
	encode_delegreturn(&xdr, args->stateid, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
2368
	encode_nops(&hdr);
2369
	return 0;
L
Linus Torvalds 已提交
2370 2371
}

2372 2373 2374
/*
 * Encode FS_LOCATIONS request
 */
A
Al Viro 已提交
2375
static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations_arg *args)
2376 2377 2378
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2379
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
2380
	};
2381
	uint32_t replen;
2382 2383

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2384
	encode_compound_hdr(&xdr, req, &hdr);
2385
	encode_sequence(&xdr, &args->seq_args, &hdr);
2386 2387
	encode_putfh(&xdr, args->dir_fh, &hdr);
	encode_lookup(&xdr, args->name, &hdr);
2388
	replen = hdr.replen;	/* get the attribute into args->page */
2389 2390
	encode_fs_locations(&xdr, args->bitmask, &hdr);

2391
	xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page,
2392
			0, PAGE_SIZE);
2393
	encode_nops(&hdr);
2394
	return 0;
2395 2396
}

B
Benny Halevy 已提交
2397 2398 2399 2400 2401 2402 2403 2404 2405
#if defined(CONFIG_NFS_V4_1)
/*
 * EXCHANGE_ID request
 */
static int nfs4_xdr_enc_exchange_id(struct rpc_rqst *req, uint32_t *p,
				    struct nfs41_exchange_id_args *args)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2406
		.minorversion = args->client->cl_mvops->minor_version,
B
Benny Halevy 已提交
2407 2408 2409 2410 2411 2412 2413 2414
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
	encode_compound_hdr(&xdr, req, &hdr);
	encode_exchange_id(&xdr, args, &hdr);
	encode_nops(&hdr);
	return 0;
}
A
Andy Adamson 已提交
2415

A
Andy Adamson 已提交
2416 2417 2418 2419 2420 2421 2422 2423
/*
 * a CREATE_SESSION request
 */
static int nfs4_xdr_enc_create_session(struct rpc_rqst *req, uint32_t *p,
				       struct nfs41_create_session_args *args)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2424
		.minorversion = args->client->cl_mvops->minor_version,
A
Andy Adamson 已提交
2425 2426 2427 2428 2429 2430 2431 2432 2433
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
	encode_compound_hdr(&xdr, req, &hdr);
	encode_create_session(&xdr, args, &hdr);
	encode_nops(&hdr);
	return 0;
}

A
Andy Adamson 已提交
2434 2435 2436 2437 2438 2439 2440 2441
/*
 * a DESTROY_SESSION request
 */
static int nfs4_xdr_enc_destroy_session(struct rpc_rqst *req, uint32_t *p,
					struct nfs4_session *session)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2442
		.minorversion = session->clp->cl_mvops->minor_version,
A
Andy Adamson 已提交
2443 2444 2445 2446 2447 2448 2449 2450 2451
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
	encode_compound_hdr(&xdr, req, &hdr);
	encode_destroy_session(&xdr, session, &hdr);
	encode_nops(&hdr);
	return 0;
}

A
Andy Adamson 已提交
2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469
/*
 * a SEQUENCE request
 */
static int nfs4_xdr_enc_sequence(struct rpc_rqst *req, uint32_t *p,
				 struct nfs4_sequence_args *args)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(args),
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
	encode_compound_hdr(&xdr, req, &hdr);
	encode_sequence(&xdr, args, &hdr);
	encode_nops(&hdr);
	return 0;
}

A
Andy Adamson 已提交
2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489
/*
 * a GET_LEASE_TIME request
 */
static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p,
				       struct nfs4_get_lease_time_args *args)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->la_seq_args),
	};
	const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
	encode_compound_hdr(&xdr, req, &hdr);
	encode_sequence(&xdr, &args->la_seq_args, &hdr);
	encode_putrootfh(&xdr, &hdr);
	encode_fsinfo(&xdr, lease_bitmap, &hdr);
	encode_nops(&hdr);
	return 0;
}
2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509

/*
 * a RECLAIM_COMPLETE request
 */
static int nfs4_xdr_enc_reclaim_complete(struct rpc_rqst *req, uint32_t *p,
				     struct nfs41_reclaim_complete_args *args)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
		.minorversion = nfs4_xdr_minorversion(&args->seq_args)
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
	encode_compound_hdr(&xdr, req, &hdr);
	encode_sequence(&xdr, &args->seq_args, &hdr);
	encode_reclaim_complete(&xdr, args, &hdr);
	encode_nops(&hdr);
	return 0;
}

B
Benny Halevy 已提交
2510 2511
#endif /* CONFIG_NFS_V4_1 */

2512 2513 2514 2515 2516 2517
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 已提交
2518

2519
static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
L
Linus Torvalds 已提交
2520
{
A
Al Viro 已提交
2521
	__be32 *p;
L
Linus Torvalds 已提交
2522

B
Benny Halevy 已提交
2523 2524 2525
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
2526
	*len = be32_to_cpup(p);
B
Benny Halevy 已提交
2527 2528 2529
	p = xdr_inline_decode(xdr, *len);
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
2530 2531
	*string = (char *)p;
	return 0;
B
Benny Halevy 已提交
2532 2533 2534
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2535 2536 2537 2538
}

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

B
Benny Halevy 已提交
2541 2542 2543
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
2544
	hdr->status = be32_to_cpup(p++);
2545
	hdr->taglen = be32_to_cpup(p);
2546

B
Benny Halevy 已提交
2547 2548 2549
	p = xdr_inline_decode(xdr, hdr->taglen + 4);
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
2550 2551
	hdr->tag = (char *)p;
	p += XDR_QUADLEN(hdr->taglen);
2552
	hdr->nops = be32_to_cpup(p);
2553 2554
	if (unlikely(hdr->nops < 1))
		return nfs4_stat_to_errno(hdr->status);
L
Linus Torvalds 已提交
2555
	return 0;
B
Benny Halevy 已提交
2556 2557 2558
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2559 2560 2561 2562
}

static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
{
A
Al Viro 已提交
2563
	__be32 *p;
L
Linus Torvalds 已提交
2564 2565 2566
	uint32_t opnum;
	int32_t nfserr;

B
Benny Halevy 已提交
2567 2568 2569
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
2570
	opnum = be32_to_cpup(p++);
L
Linus Torvalds 已提交
2571
	if (opnum != expected) {
2572 2573
		dprintk("nfs: Server returned operation"
			" %d but we issued a request for %d\n",
L
Linus Torvalds 已提交
2574 2575 2576
				opnum, expected);
		return -EIO;
	}
2577
	nfserr = be32_to_cpup(p);
L
Linus Torvalds 已提交
2578
	if (nfserr != NFS_OK)
2579
		return nfs4_stat_to_errno(nfserr);
L
Linus Torvalds 已提交
2580
	return 0;
B
Benny Halevy 已提交
2581 2582 2583
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2584 2585 2586
}

/* Dummy routine */
2587
static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp)
L
Linus Torvalds 已提交
2588
{
A
Al Viro 已提交
2589
	__be32 *p;
2590
	unsigned int strlen;
L
Linus Torvalds 已提交
2591 2592
	char *str;

B
Benny Halevy 已提交
2593 2594 2595 2596 2597
	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 已提交
2598 2599 2600 2601
}

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

B
Benny Halevy 已提交
2605 2606 2607
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
2608
	bmlen = be32_to_cpup(p);
L
Linus Torvalds 已提交
2609 2610

	bitmap[0] = bitmap[1] = 0;
B
Benny Halevy 已提交
2611 2612 2613
	p = xdr_inline_decode(xdr, (bmlen << 2));
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
2614
	if (bmlen > 0) {
B
Benny Halevy 已提交
2615
		bitmap[0] = be32_to_cpup(p++);
L
Linus Torvalds 已提交
2616
		if (bmlen > 1)
2617
			bitmap[1] = be32_to_cpup(p);
L
Linus Torvalds 已提交
2618 2619
	}
	return 0;
B
Benny Halevy 已提交
2620 2621 2622
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2623 2624
}

A
Al Viro 已提交
2625
static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep)
L
Linus Torvalds 已提交
2626
{
A
Al Viro 已提交
2627
	__be32 *p;
L
Linus Torvalds 已提交
2628

B
Benny Halevy 已提交
2629 2630 2631
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
2632
	*attrlen = be32_to_cpup(p);
L
Linus Torvalds 已提交
2633 2634
	*savep = xdr->p;
	return 0;
B
Benny Halevy 已提交
2635 2636 2637
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2638 2639 2640 2641 2642 2643 2644 2645 2646
}

static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *bitmask)
{
	if (likely(bitmap[0] & FATTR4_WORD0_SUPPORTED_ATTRS)) {
		decode_attr_bitmap(xdr, bitmask);
		bitmap[0] &= ~FATTR4_WORD0_SUPPORTED_ATTRS;
	} else
		bitmask[0] = bitmask[1] = 0;
2647
	dprintk("%s: bitmask=%08x:%08x\n", __func__, bitmask[0], bitmask[1]);
L
Linus Torvalds 已提交
2648 2649 2650 2651 2652
	return 0;
}

static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
{
A
Al Viro 已提交
2653
	__be32 *p;
2654
	int ret = 0;
L
Linus Torvalds 已提交
2655 2656 2657 2658 2659

	*type = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_TYPE)) {
B
Benny Halevy 已提交
2660 2661 2662
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
2663
		*type = be32_to_cpup(p);
L
Linus Torvalds 已提交
2664
		if (*type < NF4REG || *type > NF4NAMEDATTR) {
2665
			dprintk("%s: bad type %d\n", __func__, *type);
L
Linus Torvalds 已提交
2666 2667 2668
			return -EIO;
		}
		bitmap[0] &= ~FATTR4_WORD0_TYPE;
2669
		ret = NFS_ATTR_FATTR_TYPE;
L
Linus Torvalds 已提交
2670
	}
2671
	dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type]);
2672
	return ret;
B
Benny Halevy 已提交
2673 2674 2675
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2676 2677 2678 2679
}

static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
{
A
Al Viro 已提交
2680
	__be32 *p;
2681
	int ret = 0;
L
Linus Torvalds 已提交
2682 2683 2684 2685 2686

	*change = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) {
B
Benny Halevy 已提交
2687 2688 2689
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
2690
		xdr_decode_hyper(p, change);
L
Linus Torvalds 已提交
2691
		bitmap[0] &= ~FATTR4_WORD0_CHANGE;
2692
		ret = NFS_ATTR_FATTR_CHANGE;
L
Linus Torvalds 已提交
2693
	}
2694
	dprintk("%s: change attribute=%Lu\n", __func__,
L
Linus Torvalds 已提交
2695
			(unsigned long long)*change);
2696
	return ret;
B
Benny Halevy 已提交
2697 2698 2699
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2700 2701 2702 2703
}

static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
{
A
Al Viro 已提交
2704
	__be32 *p;
2705
	int ret = 0;
L
Linus Torvalds 已提交
2706 2707 2708 2709 2710

	*size = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) {
B
Benny Halevy 已提交
2711 2712 2713
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
2714
		xdr_decode_hyper(p, size);
L
Linus Torvalds 已提交
2715
		bitmap[0] &= ~FATTR4_WORD0_SIZE;
2716
		ret = NFS_ATTR_FATTR_SIZE;
L
Linus Torvalds 已提交
2717
	}
2718
	dprintk("%s: file size=%Lu\n", __func__, (unsigned long long)*size);
2719
	return ret;
B
Benny Halevy 已提交
2720 2721 2722
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2723 2724 2725 2726
}

static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
2727
	__be32 *p;
L
Linus Torvalds 已提交
2728 2729 2730 2731 2732

	*res = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) {
B
Benny Halevy 已提交
2733 2734 2735
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
2736
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
2737 2738
		bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT;
	}
2739
	dprintk("%s: link support=%s\n", __func__, *res == 0 ? "false" : "true");
L
Linus Torvalds 已提交
2740
	return 0;
B
Benny Halevy 已提交
2741 2742 2743
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2744 2745 2746 2747
}

static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
2748
	__be32 *p;
L
Linus Torvalds 已提交
2749 2750 2751 2752 2753

	*res = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) {
B
Benny Halevy 已提交
2754 2755 2756
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
2757
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
2758 2759
		bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT;
	}
2760
	dprintk("%s: symlink support=%s\n", __func__, *res == 0 ? "false" : "true");
L
Linus Torvalds 已提交
2761
	return 0;
B
Benny Halevy 已提交
2762 2763 2764
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2765 2766
}

2767
static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
L
Linus Torvalds 已提交
2768
{
A
Al Viro 已提交
2769
	__be32 *p;
2770
	int ret = 0;
L
Linus Torvalds 已提交
2771 2772 2773 2774 2775 2776

	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 已提交
2777 2778 2779
		p = xdr_inline_decode(xdr, 16);
		if (unlikely(!p))
			goto out_overflow;
B
Benny Halevy 已提交
2780
		p = xdr_decode_hyper(p, &fsid->major);
2781
		xdr_decode_hyper(p, &fsid->minor);
L
Linus Torvalds 已提交
2782
		bitmap[0] &= ~FATTR4_WORD0_FSID;
2783
		ret = NFS_ATTR_FATTR_FSID;
L
Linus Torvalds 已提交
2784
	}
2785
	dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __func__,
L
Linus Torvalds 已提交
2786 2787
			(unsigned long long)fsid->major,
			(unsigned long long)fsid->minor);
2788
	return ret;
B
Benny Halevy 已提交
2789 2790 2791
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2792 2793 2794 2795
}

static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
2796
	__be32 *p;
L
Linus Torvalds 已提交
2797 2798 2799 2800 2801

	*res = 60;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) {
B
Benny Halevy 已提交
2802 2803 2804
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
2805
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
2806 2807
		bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME;
	}
2808
	dprintk("%s: file size=%u\n", __func__, (unsigned int)*res);
L
Linus Torvalds 已提交
2809
	return 0;
B
Benny Halevy 已提交
2810 2811 2812
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2813 2814 2815 2816
}

static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
2817
	__be32 *p;
L
Linus Torvalds 已提交
2818 2819 2820 2821 2822

	*res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) {
B
Benny Halevy 已提交
2823 2824 2825
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
2826
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
2827 2828
		bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT;
	}
2829
	dprintk("%s: ACLs supported=%u\n", __func__, (unsigned int)*res);
L
Linus Torvalds 已提交
2830
	return 0;
B
Benny Halevy 已提交
2831 2832 2833
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2834 2835 2836 2837
}

static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
{
A
Al Viro 已提交
2838
	__be32 *p;
2839
	int ret = 0;
L
Linus Torvalds 已提交
2840 2841 2842 2843 2844

	*fileid = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) {
B
Benny Halevy 已提交
2845 2846 2847
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
2848
		xdr_decode_hyper(p, fileid);
L
Linus Torvalds 已提交
2849
		bitmap[0] &= ~FATTR4_WORD0_FILEID;
2850
		ret = NFS_ATTR_FATTR_FILEID;
L
Linus Torvalds 已提交
2851
	}
2852
	dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
2853
	return ret;
B
Benny Halevy 已提交
2854 2855 2856
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2857 2858
}

2859 2860
static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
{
A
Al Viro 已提交
2861
	__be32 *p;
2862
	int ret = 0;
2863 2864 2865 2866 2867

	*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 已提交
2868 2869 2870
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
2871
		xdr_decode_hyper(p, fileid);
2872
		bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
2873
		ret = NFS_ATTR_FATTR_FILEID;
2874
	}
2875
	dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
2876
	return ret;
B
Benny Halevy 已提交
2877 2878 2879
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
2880 2881
}

L
Linus Torvalds 已提交
2882 2883
static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
2884
	__be32 *p;
L
Linus Torvalds 已提交
2885 2886 2887 2888 2889 2890
	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 已提交
2891 2892 2893
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
2894
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
2895 2896
		bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL;
	}
2897
	dprintk("%s: files avail=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
2898
	return status;
B
Benny Halevy 已提交
2899 2900 2901
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2902 2903 2904 2905
}

static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
2906
	__be32 *p;
L
Linus Torvalds 已提交
2907 2908 2909 2910 2911 2912
	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 已提交
2913 2914 2915
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
2916
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
2917 2918
		bitmap[0] &= ~FATTR4_WORD0_FILES_FREE;
	}
2919
	dprintk("%s: files free=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
2920
	return status;
B
Benny Halevy 已提交
2921 2922 2923
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2924 2925 2926 2927
}

static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
2928
	__be32 *p;
L
Linus Torvalds 已提交
2929 2930 2931 2932 2933 2934
	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 已提交
2935 2936 2937
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
2938
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
2939 2940
		bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL;
	}
2941
	dprintk("%s: files total=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
2942
	return status;
B
Benny Halevy 已提交
2943 2944 2945
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2946 2947
}

2948 2949
static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
{
2950
	u32 n;
A
Al Viro 已提交
2951
	__be32 *p;
2952 2953
	int status = 0;

B
Benny Halevy 已提交
2954 2955 2956
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
2957
	n = be32_to_cpup(p);
2958 2959
	if (n == 0)
		goto root_path;
2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979
	dprintk("path ");
	path->ncomponents = 0;
	while (path->ncomponents < n) {
		struct nfs4_string *component = &path->components[path->ncomponents];
		status = decode_opaque_inline(xdr, &component->len, &component->data);
		if (unlikely(status != 0))
			goto out_eio;
		if (path->ncomponents != n)
			dprintk("/");
		dprintk("%s", component->data);
		if (path->ncomponents < NFS4_PATHNAME_MAXCOMPONENTS)
			path->ncomponents++;
		else {
			dprintk("cannot parse %d components in path\n", n);
			goto out_eio;
		}
	}
out:
	dprintk("\n");
	return status;
2980 2981 2982 2983 2984 2985 2986
root_path:
/* a root pathname is sent as a zero component4 */
	path->ncomponents = 1;
	path->components[0].len=0;
	path->components[0].data=NULL;
	dprintk("path /\n");
	goto out;
2987 2988 2989 2990
out_eio:
	dprintk(" status %d", status);
	status = -EIO;
	goto out;
B
Benny Halevy 已提交
2991 2992 2993
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
2994 2995 2996
}

static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res)
2997 2998
{
	int n;
A
Al Viro 已提交
2999
	__be32 *p;
3000 3001 3002 3003 3004 3005 3006
	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;
3007
	dprintk("%s: fsroot ", __func__);
3008
	status = decode_pathname(xdr, &res->fs_path);
3009 3010
	if (unlikely(status != 0))
		goto out;
B
Benny Halevy 已提交
3011 3012 3013
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
3014
	n = be32_to_cpup(p);
3015 3016 3017 3018
	if (n <= 0)
		goto out_eio;
	res->nlocations = 0;
	while (res->nlocations < n) {
3019
		u32 m;
3020
		struct nfs4_fs_location *loc = &res->locations[res->nlocations];
3021

B
Benny Halevy 已提交
3022 3023 3024
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3025
		m = be32_to_cpup(p);
3026 3027

		loc->nservers = 0;
3028
		dprintk("%s: servers ", __func__);
3029 3030 3031 3032 3033 3034 3035 3036 3037
		while (loc->nservers < m) {
			struct nfs4_string *server = &loc->servers[loc->nservers];
			status = decode_opaque_inline(xdr, &server->len, &server->data);
			if (unlikely(status != 0))
				goto out_eio;
			dprintk("%s ", server->data);
			if (loc->nservers < NFS4_FS_LOCATION_MAXSERVERS)
				loc->nservers++;
			else {
3038 3039 3040
				unsigned int i;
				dprintk("%s: using first %u of %u servers "
					"returned for location %u\n",
3041
						__func__,
3042 3043
						NFS4_FS_LOCATION_MAXSERVERS,
						m, res->nlocations);
3044
				for (i = loc->nservers; i < m; i++) {
T
Trond Myklebust 已提交
3045
					unsigned int len;
3046 3047 3048 3049 3050 3051 3052 3053
					char *data;
					status = decode_opaque_inline(xdr, &len, &data);
					if (unlikely(status != 0))
						goto out_eio;
				}
			}
		}
		status = decode_pathname(xdr, &loc->rootpath);
3054 3055
		if (unlikely(status != 0))
			goto out_eio;
3056
		if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
3057 3058
			res->nlocations++;
	}
3059 3060
	if (res->nlocations != 0)
		status = NFS_ATTR_FATTR_V4_REFERRAL;
3061
out:
3062
	dprintk("%s: fs_locations done, error = %d\n", __func__, status);
3063
	return status;
B
Benny Halevy 已提交
3064 3065
out_overflow:
	print_overflow_msg(__func__, xdr);
3066 3067 3068 3069 3070
out_eio:
	status = -EIO;
	goto out;
}

L
Linus Torvalds 已提交
3071 3072
static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3073
	__be32 *p;
L
Linus Torvalds 已提交
3074 3075 3076 3077 3078 3079
	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 已提交
3080 3081 3082
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3083
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3084 3085
		bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE;
	}
3086
	dprintk("%s: maxfilesize=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3087
	return status;
B
Benny Halevy 已提交
3088 3089 3090
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3091 3092 3093 3094
}

static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink)
{
A
Al Viro 已提交
3095
	__be32 *p;
L
Linus Torvalds 已提交
3096 3097 3098 3099 3100 3101
	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 已提交
3102 3103 3104
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3105
		*maxlink = be32_to_cpup(p);
L
Linus Torvalds 已提交
3106 3107
		bitmap[0] &= ~FATTR4_WORD0_MAXLINK;
	}
3108
	dprintk("%s: maxlink=%u\n", __func__, *maxlink);
L
Linus Torvalds 已提交
3109
	return status;
B
Benny Halevy 已提交
3110 3111 3112
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3113 3114 3115 3116
}

static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname)
{
A
Al Viro 已提交
3117
	__be32 *p;
L
Linus Torvalds 已提交
3118 3119 3120 3121 3122 3123
	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 已提交
3124 3125 3126
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3127
		*maxname = be32_to_cpup(p);
L
Linus Torvalds 已提交
3128 3129
		bitmap[0] &= ~FATTR4_WORD0_MAXNAME;
	}
3130
	dprintk("%s: maxname=%u\n", __func__, *maxname);
L
Linus Torvalds 已提交
3131
	return status;
B
Benny Halevy 已提交
3132 3133 3134
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3135 3136 3137 3138
}

static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
3139
	__be32 *p;
L
Linus Torvalds 已提交
3140 3141 3142 3143 3144 3145 3146
	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 已提交
3147 3148 3149
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3150
		xdr_decode_hyper(p, &maxread);
L
Linus Torvalds 已提交
3151 3152 3153 3154 3155
		if (maxread > 0x7FFFFFFF)
			maxread = 0x7FFFFFFF;
		*res = (uint32_t)maxread;
		bitmap[0] &= ~FATTR4_WORD0_MAXREAD;
	}
3156
	dprintk("%s: maxread=%lu\n", __func__, (unsigned long)*res);
L
Linus Torvalds 已提交
3157
	return status;
B
Benny Halevy 已提交
3158 3159 3160
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3161 3162 3163 3164
}

static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
3165
	__be32 *p;
L
Linus Torvalds 已提交
3166 3167 3168 3169 3170 3171 3172
	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 已提交
3173 3174 3175
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3176
		xdr_decode_hyper(p, &maxwrite);
L
Linus Torvalds 已提交
3177 3178 3179 3180 3181
		if (maxwrite > 0x7FFFFFFF)
			maxwrite = 0x7FFFFFFF;
		*res = (uint32_t)maxwrite;
		bitmap[0] &= ~FATTR4_WORD0_MAXWRITE;
	}
3182
	dprintk("%s: maxwrite=%lu\n", __func__, (unsigned long)*res);
L
Linus Torvalds 已提交
3183
	return status;
B
Benny Halevy 已提交
3184 3185 3186
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3187 3188
}

3189
static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *mode)
L
Linus Torvalds 已提交
3190
{
3191
	uint32_t tmp;
A
Al Viro 已提交
3192
	__be32 *p;
3193
	int ret = 0;
L
Linus Torvalds 已提交
3194 3195 3196 3197 3198

	*mode = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_MODE)) {
B
Benny Halevy 已提交
3199 3200 3201
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3202
		tmp = be32_to_cpup(p);
3203
		*mode = tmp & ~S_IFMT;
L
Linus Torvalds 已提交
3204
		bitmap[1] &= ~FATTR4_WORD1_MODE;
3205
		ret = NFS_ATTR_FATTR_MODE;
L
Linus Torvalds 已提交
3206
	}
3207
	dprintk("%s: file mode=0%o\n", __func__, (unsigned int)*mode);
3208
	return ret;
B
Benny Halevy 已提交
3209 3210 3211
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3212 3213 3214 3215
}

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

	*nlink = 1;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) {
B
Benny Halevy 已提交
3223 3224 3225
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3226
		*nlink = be32_to_cpup(p);
L
Linus Torvalds 已提交
3227
		bitmap[1] &= ~FATTR4_WORD1_NUMLINKS;
3228
		ret = NFS_ATTR_FATTR_NLINK;
L
Linus Torvalds 已提交
3229
	}
3230
	dprintk("%s: nlink=%u\n", __func__, (unsigned int)*nlink);
3231
	return ret;
B
Benny Halevy 已提交
3232 3233 3234
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3235 3236
}

3237 3238
static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap,
		struct nfs_client *clp, uint32_t *uid, int may_sleep)
L
Linus Torvalds 已提交
3239
{
A
Al Viro 已提交
3240 3241
	uint32_t len;
	__be32 *p;
3242
	int ret = 0;
L
Linus Torvalds 已提交
3243 3244 3245 3246 3247

	*uid = -2;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) {
B
Benny Halevy 已提交
3248 3249 3250
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3251
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
3252 3253 3254
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
3255 3256 3257
		if (!may_sleep) {
			/* do nothing */
		} else if (len < XDR_MAX_NETOBJ) {
3258 3259 3260
			if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0)
				ret = NFS_ATTR_FATTR_OWNER;
			else
L
Linus Torvalds 已提交
3261
				dprintk("%s: nfs_map_name_to_uid failed!\n",
3262
						__func__);
L
Linus Torvalds 已提交
3263
		} else
3264
			dprintk("%s: name too long (%u)!\n",
3265
					__func__, len);
L
Linus Torvalds 已提交
3266 3267
		bitmap[1] &= ~FATTR4_WORD1_OWNER;
	}
3268
	dprintk("%s: uid=%d\n", __func__, (int)*uid);
3269
	return ret;
B
Benny Halevy 已提交
3270 3271 3272
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3273 3274
}

3275 3276
static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap,
		struct nfs_client *clp, uint32_t *gid, int may_sleep)
L
Linus Torvalds 已提交
3277
{
A
Al Viro 已提交
3278 3279
	uint32_t len;
	__be32 *p;
3280
	int ret = 0;
L
Linus Torvalds 已提交
3281 3282 3283 3284 3285

	*gid = -2;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) {
B
Benny Halevy 已提交
3286 3287 3288
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3289
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
3290 3291 3292
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
3293 3294 3295
		if (!may_sleep) {
			/* do nothing */
		} else if (len < XDR_MAX_NETOBJ) {
3296 3297 3298
			if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0)
				ret = NFS_ATTR_FATTR_GROUP;
			else
L
Linus Torvalds 已提交
3299
				dprintk("%s: nfs_map_group_to_gid failed!\n",
3300
						__func__);
L
Linus Torvalds 已提交
3301
		} else
3302
			dprintk("%s: name too long (%u)!\n",
3303
					__func__, len);
L
Linus Torvalds 已提交
3304 3305
		bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
	}
3306
	dprintk("%s: gid=%d\n", __func__, (int)*gid);
3307
	return ret;
B
Benny Halevy 已提交
3308 3309 3310
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3311 3312 3313 3314
}

static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
{
A
Al Viro 已提交
3315 3316
	uint32_t major = 0, minor = 0;
	__be32 *p;
3317
	int ret = 0;
L
Linus Torvalds 已提交
3318 3319 3320 3321 3322 3323 3324

	*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 已提交
3325 3326 3327
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
B
Benny Halevy 已提交
3328
		major = be32_to_cpup(p++);
3329
		minor = be32_to_cpup(p);
L
Linus Torvalds 已提交
3330 3331 3332 3333
		tmp = MKDEV(major, minor);
		if (MAJOR(tmp) == major && MINOR(tmp) == minor)
			*rdev = tmp;
		bitmap[1] &= ~ FATTR4_WORD1_RAWDEV;
3334
		ret = NFS_ATTR_FATTR_RDEV;
L
Linus Torvalds 已提交
3335
	}
3336
	dprintk("%s: rdev=(0x%x:0x%x)\n", __func__, major, minor);
3337
	return ret;
B
Benny Halevy 已提交
3338 3339 3340
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3341 3342 3343 3344
}

static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3345
	__be32 *p;
L
Linus Torvalds 已提交
3346 3347 3348 3349 3350 3351
	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 已提交
3352 3353 3354
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3355
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3356 3357
		bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL;
	}
3358
	dprintk("%s: space avail=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3359
	return status;
B
Benny Halevy 已提交
3360 3361 3362
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3363 3364 3365 3366
}

static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3367
	__be32 *p;
L
Linus Torvalds 已提交
3368 3369 3370 3371 3372 3373
	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 已提交
3374 3375 3376
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3377
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3378 3379
		bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE;
	}
3380
	dprintk("%s: space free=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3381
	return status;
B
Benny Halevy 已提交
3382 3383 3384
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3385 3386 3387 3388
}

static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3389
	__be32 *p;
L
Linus Torvalds 已提交
3390 3391 3392 3393 3394 3395
	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 已提交
3396 3397 3398
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3399
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3400 3401
		bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL;
	}
3402
	dprintk("%s: space total=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3403
	return status;
B
Benny Halevy 已提交
3404 3405 3406
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3407 3408 3409 3410
}

static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
{
A
Al Viro 已提交
3411
	__be32 *p;
3412
	int ret = 0;
L
Linus Torvalds 已提交
3413 3414 3415 3416 3417

	*used = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) {
B
Benny Halevy 已提交
3418 3419 3420
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3421
		xdr_decode_hyper(p, used);
L
Linus Torvalds 已提交
3422
		bitmap[1] &= ~FATTR4_WORD1_SPACE_USED;
3423
		ret = NFS_ATTR_FATTR_SPACE_USED;
L
Linus Torvalds 已提交
3424
	}
3425
	dprintk("%s: space used=%Lu\n", __func__,
L
Linus Torvalds 已提交
3426
			(unsigned long long)*used);
3427
	return ret;
B
Benny Halevy 已提交
3428 3429 3430
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3431 3432 3433 3434
}

static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
{
A
Al Viro 已提交
3435
	__be32 *p;
L
Linus Torvalds 已提交
3436 3437 3438
	uint64_t sec;
	uint32_t nsec;

B
Benny Halevy 已提交
3439 3440 3441
	p = xdr_inline_decode(xdr, 12);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3442
	p = xdr_decode_hyper(p, &sec);
3443
	nsec = be32_to_cpup(p);
L
Linus Torvalds 已提交
3444 3445 3446
	time->tv_sec = (time_t)sec;
	time->tv_nsec = (long)nsec;
	return 0;
B
Benny Halevy 已提交
3447 3448 3449
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461
}

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);
3462 3463
		if (status == 0)
			status = NFS_ATTR_FATTR_ATIME;
L
Linus Torvalds 已提交
3464 3465
		bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS;
	}
3466
	dprintk("%s: atime=%ld\n", __func__, (long)time->tv_sec);
L
Linus Torvalds 已提交
3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479
	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);
3480 3481
		if (status == 0)
			status = NFS_ATTR_FATTR_CTIME;
L
Linus Torvalds 已提交
3482 3483
		bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
	}
3484
	dprintk("%s: ctime=%ld\n", __func__, (long)time->tv_sec);
L
Linus Torvalds 已提交
3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497
	return status;
}

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);
3498 3499
		if (status == 0)
			status = NFS_ATTR_FATTR_MTIME;
L
Linus Torvalds 已提交
3500 3501
		bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
	}
3502
	dprintk("%s: mtime=%ld\n", __func__, (long)time->tv_sec);
L
Linus Torvalds 已提交
3503 3504 3505
	return status;
}

A
Al Viro 已提交
3506
static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
L
Linus Torvalds 已提交
3507 3508 3509 3510 3511
{
	unsigned int attrwords = XDR_QUADLEN(attrlen);
	unsigned int nwords = xdr->p - savep;

	if (unlikely(attrwords != nwords)) {
3512 3513
		dprintk("%s: server returned incorrect attribute length: "
			"%u %c %u\n",
3514
				__func__,
L
Linus Torvalds 已提交
3515 3516 3517 3518 3519 3520 3521 3522 3523 3524
				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 已提交
3525
	__be32 *p;
L
Linus Torvalds 已提交
3526

B
Benny Halevy 已提交
3527 3528 3529
	p = xdr_inline_decode(xdr, 20);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3530
	cinfo->atomic = be32_to_cpup(p++);
B
Benny Halevy 已提交
3531
	p = xdr_decode_hyper(p, &cinfo->before);
3532
	xdr_decode_hyper(p, &cinfo->after);
L
Linus Torvalds 已提交
3533
	return 0;
B
Benny Halevy 已提交
3534 3535 3536
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3537 3538 3539 3540
}

static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
{
A
Al Viro 已提交
3541
	__be32 *p;
L
Linus Torvalds 已提交
3542 3543 3544 3545 3546 3547
	uint32_t supp, acc;
	int status;

	status = decode_op_hdr(xdr, OP_ACCESS);
	if (status)
		return status;
B
Benny Halevy 已提交
3548 3549 3550
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3551
	supp = be32_to_cpup(p++);
3552
	acc = be32_to_cpup(p);
L
Linus Torvalds 已提交
3553 3554 3555
	access->supported = supp;
	access->access = acc;
	return 0;
B
Benny Halevy 已提交
3556 3557 3558
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3559 3560
}

3561
static int decode_opaque_fixed(struct xdr_stream *xdr, void *buf, size_t len)
L
Linus Torvalds 已提交
3562
{
A
Al Viro 已提交
3563
	__be32 *p;
3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580

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

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

static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
{
L
Linus Torvalds 已提交
3581 3582 3583
	int status;

	status = decode_op_hdr(xdr, OP_CLOSE);
3584 3585
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
3586 3587 3588
	if (!status)
		status = decode_stateid(xdr, &res->stateid);
	return status;
L
Linus Torvalds 已提交
3589 3590
}

3591 3592 3593
static int decode_verifier(struct xdr_stream *xdr, void *verifier)
{
	return decode_opaque_fixed(xdr, verifier, 8);
L
Linus Torvalds 已提交
3594 3595 3596 3597 3598 3599 3600
}

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

	status = decode_op_hdr(xdr, OP_COMMIT);
3601 3602 3603
	if (!status)
		status = decode_verifier(xdr, res->verf->verifier);
	return status;
L
Linus Torvalds 已提交
3604 3605 3606 3607
}

static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
A
Al Viro 已提交
3608
	__be32 *p;
L
Linus Torvalds 已提交
3609 3610 3611 3612 3613 3614 3615 3616
	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 已提交
3617 3618 3619
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
3620
	bmlen = be32_to_cpup(p);
B
Benny Halevy 已提交
3621 3622 3623 3624 3625 3626
	p = xdr_inline_decode(xdr, bmlen << 2);
	if (likely(p))
		return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3627 3628 3629 3630
}

static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
{
A
Al Viro 已提交
3631
	__be32 *savep;
3632
	uint32_t attrlen, bitmap[2] = {0};
L
Linus Torvalds 已提交
3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650
	int status;

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

L
Linus Torvalds 已提交
3655 3656
static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
{
A
Al Viro 已提交
3657
	__be32 *savep;
3658
	uint32_t attrlen, bitmap[2] = {0};
L
Linus Torvalds 已提交
3659
	int status;
3660

L
Linus Torvalds 已提交
3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682
	if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
		goto xdr_error;
	if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
		goto xdr_error;
	if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
		goto xdr_error;

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

	status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
3683
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
3684 3685 3686 3687 3688
	return status;
}

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

L
Linus Torvalds 已提交
3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706
	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:
3707
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
3708 3709 3710
	return status;
}

3711 3712
static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
		const struct nfs_server *server, int may_sleep)
L
Linus Torvalds 已提交
3713
{
A
Al Viro 已提交
3714
	__be32 *savep;
L
Linus Torvalds 已提交
3715 3716 3717
	uint32_t attrlen,
		 bitmap[2] = {0},
		 type;
3718 3719
	int status;
	umode_t fmode = 0;
3720
	uint64_t fileid;
L
Linus Torvalds 已提交
3721

3722 3723
	status = decode_op_hdr(xdr, OP_GETATTR);
	if (status < 0)
L
Linus Torvalds 已提交
3724
		goto xdr_error;
3725 3726 3727

	status = decode_attr_bitmap(xdr, bitmap);
	if (status < 0)
L
Linus Torvalds 已提交
3728 3729
		goto xdr_error;

3730 3731
	status = decode_attr_length(xdr, &attrlen, &savep);
	if (status < 0)
L
Linus Torvalds 已提交
3732 3733 3734
		goto xdr_error;


3735 3736
	status = decode_attr_type(xdr, bitmap, &type);
	if (status < 0)
L
Linus Torvalds 已提交
3737
		goto xdr_error;
3738 3739 3740 3741 3742
	fattr->mode = 0;
	if (status != 0) {
		fattr->mode |= nfs_type2fmt[type];
		fattr->valid |= status;
	}
L
Linus Torvalds 已提交
3743

3744 3745
	status = decode_attr_change(xdr, bitmap, &fattr->change_attr);
	if (status < 0)
L
Linus Torvalds 已提交
3746
		goto xdr_error;
3747
	fattr->valid |= status;
3748 3749 3750

	status = decode_attr_size(xdr, bitmap, &fattr->size);
	if (status < 0)
L
Linus Torvalds 已提交
3751
		goto xdr_error;
3752
	fattr->valid |= status;
3753 3754 3755

	status = decode_attr_fsid(xdr, bitmap, &fattr->fsid);
	if (status < 0)
L
Linus Torvalds 已提交
3756
		goto xdr_error;
3757
	fattr->valid |= status;
3758 3759 3760

	status = decode_attr_fileid(xdr, bitmap, &fattr->fileid);
	if (status < 0)
L
Linus Torvalds 已提交
3761
		goto xdr_error;
3762
	fattr->valid |= status;
3763 3764

	status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
3765
						struct nfs4_fs_locations,
3766 3767
						fattr));
	if (status < 0)
3768
		goto xdr_error;
3769
	fattr->valid |= status;
3770 3771 3772

	status = decode_attr_mode(xdr, bitmap, &fmode);
	if (status < 0)
L
Linus Torvalds 已提交
3773
		goto xdr_error;
3774 3775 3776 3777
	if (status != 0) {
		fattr->mode |= fmode;
		fattr->valid |= status;
	}
3778 3779 3780

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

3784 3785
	status = decode_attr_owner(xdr, bitmap, server->nfs_client,
			&fattr->uid, may_sleep);
3786
	if (status < 0)
L
Linus Torvalds 已提交
3787
		goto xdr_error;
3788
	fattr->valid |= status;
3789

3790 3791
	status = decode_attr_group(xdr, bitmap, server->nfs_client,
			&fattr->gid, may_sleep);
3792
	if (status < 0)
L
Linus Torvalds 已提交
3793
		goto xdr_error;
3794
	fattr->valid |= status;
3795 3796 3797

	status = decode_attr_rdev(xdr, bitmap, &fattr->rdev);
	if (status < 0)
L
Linus Torvalds 已提交
3798
		goto xdr_error;
3799
	fattr->valid |= status;
3800 3801 3802

	status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used);
	if (status < 0)
L
Linus Torvalds 已提交
3803
		goto xdr_error;
3804
	fattr->valid |= status;
3805 3806 3807

	status = decode_attr_time_access(xdr, bitmap, &fattr->atime);
	if (status < 0)
L
Linus Torvalds 已提交
3808
		goto xdr_error;
3809
	fattr->valid |= status;
3810 3811 3812

	status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
	if (status < 0)
L
Linus Torvalds 已提交
3813
		goto xdr_error;
3814
	fattr->valid |= status;
3815 3816 3817

	status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime);
	if (status < 0)
L
Linus Torvalds 已提交
3818
		goto xdr_error;
3819
	fattr->valid |= status;
3820 3821 3822

	status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid);
	if (status < 0)
3823
		goto xdr_error;
3824
	if (status != 0 && !(fattr->valid & status)) {
3825
		fattr->fileid = fileid;
3826 3827
		fattr->valid |= status;
	}
3828 3829

	status = verify_attr_len(xdr, savep, attrlen);
L
Linus Torvalds 已提交
3830
xdr_error:
3831
	dprintk("%s: xdr returned %d\n", __func__, -status);
L
Linus Torvalds 已提交
3832 3833 3834 3835 3836 3837
	return status;
}


static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
{
A
Al Viro 已提交
3838
	__be32 *savep;
L
Linus Torvalds 已提交
3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863
	uint32_t attrlen, bitmap[2];
	int status;

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

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

	if ((status = decode_attr_lease_time(xdr, bitmap, &fsinfo->lease_time)) != 0)
		goto xdr_error;
	if ((status = decode_attr_maxfilesize(xdr, bitmap, &fsinfo->maxfilesize)) != 0)
		goto xdr_error;
	if ((status = decode_attr_maxread(xdr, bitmap, &fsinfo->rtmax)) != 0)
		goto xdr_error;
	fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax;
	if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0)
		goto xdr_error;
	fsinfo->wtpref = fsinfo->wtmax;

	status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
3864
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
3865 3866 3867 3868 3869
	return status;
}

static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
{
A
Al Viro 已提交
3870
	__be32 *p;
L
Linus Torvalds 已提交
3871 3872 3873
	uint32_t len;
	int status;

3874 3875 3876
	/* Zero handle first to allow comparisons */
	memset(fh, 0, sizeof(*fh));

L
Linus Torvalds 已提交
3877 3878 3879 3880
	status = decode_op_hdr(xdr, OP_GETFH);
	if (status)
		return status;

B
Benny Halevy 已提交
3881 3882 3883
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
3884
	len = be32_to_cpup(p);
L
Linus Torvalds 已提交
3885 3886 3887
	if (len > NFS4_FHSIZE)
		return -EIO;
	fh->size = len;
B
Benny Halevy 已提交
3888 3889 3890
	p = xdr_inline_decode(xdr, len);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3891
	memcpy(fh->data, p, len);
L
Linus Torvalds 已提交
3892
	return 0;
B
Benny Halevy 已提交
3893 3894 3895
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3896 3897 3898 3899 3900
}

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

L
Linus Torvalds 已提交
3902 3903 3904 3905 3906 3907 3908 3909 3910
	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 已提交
3911
static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
L
Linus Torvalds 已提交
3912
{
T
Trond Myklebust 已提交
3913
	uint64_t offset, length, clientid;
A
Al Viro 已提交
3914
	__be32 *p;
T
Trond Myklebust 已提交
3915
	uint32_t namelen, type;
L
Linus Torvalds 已提交
3916

B
Benny Halevy 已提交
3917 3918 3919
	p = xdr_inline_decode(xdr, 32);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3920 3921
	p = xdr_decode_hyper(p, &offset);
	p = xdr_decode_hyper(p, &length);
B
Benny Halevy 已提交
3922
	type = be32_to_cpup(p++);
T
Trond Myklebust 已提交
3923 3924 3925 3926 3927 3928 3929 3930 3931 3932
	if (fl != NULL) {
		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;
	}
B
Benny Halevy 已提交
3933
	p = xdr_decode_hyper(p, &clientid);
3934
	namelen = be32_to_cpup(p);
B
Benny Halevy 已提交
3935 3936 3937 3938 3939 3940
	p = xdr_inline_decode(xdr, namelen);
	if (likely(p))
		return -NFS4ERR_DENIED;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3941 3942
}

T
Trond Myklebust 已提交
3943
static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
L
Linus Torvalds 已提交
3944 3945 3946 3947
{
	int status;

	status = decode_op_hdr(xdr, OP_LOCK);
3948 3949
	if (status == -EIO)
		goto out;
L
Linus Torvalds 已提交
3950
	if (status == 0) {
3951 3952 3953
		status = decode_stateid(xdr, &res->stateid);
		if (unlikely(status))
			goto out;
L
Linus Torvalds 已提交
3954
	} else if (status == -NFS4ERR_DENIED)
3955 3956 3957 3958 3959
		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 已提交
3960 3961 3962
	return status;
}

T
Trond Myklebust 已提交
3963
static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res)
L
Linus Torvalds 已提交
3964 3965 3966 3967
{
	int status;
	status = decode_op_hdr(xdr, OP_LOCKT);
	if (status == -NFS4ERR_DENIED)
T
Trond Myklebust 已提交
3968
		return decode_lock_denied(xdr, res->denied);
L
Linus Torvalds 已提交
3969 3970 3971
	return status;
}

T
Trond Myklebust 已提交
3972
static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
L
Linus Torvalds 已提交
3973 3974 3975 3976
{
	int status;

	status = decode_op_hdr(xdr, OP_LOCKU);
3977 3978
	if (status != -EIO)
		nfs_increment_lock_seqid(status, res->seqid);
3979 3980
	if (status == 0)
		status = decode_stateid(xdr, &res->stateid);
L
Linus Torvalds 已提交
3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991
	return status;
}

static int decode_lookup(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_LOOKUP);
}

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

B
Benny Halevy 已提交
3995 3996 3997
	p = xdr_inline_decode(xdr, 12);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3998
	limit_type = be32_to_cpup(p++);
L
Linus Torvalds 已提交
3999
	switch (limit_type) {
A
Andy Adamson 已提交
4000
	case 1:
4001
		xdr_decode_hyper(p, maxsize);
A
Andy Adamson 已提交
4002 4003
		break;
	case 2:
B
Benny Halevy 已提交
4004
		nblocks = be32_to_cpup(p++);
4005
		blocksize = be32_to_cpup(p);
A
Andy Adamson 已提交
4006
		*maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
L
Linus Torvalds 已提交
4007 4008
	}
	return 0;
B
Benny Halevy 已提交
4009 4010 4011
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4012 4013 4014 4015
}

static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
{
A
Andy Adamson 已提交
4016 4017
	__be32 *p;
	uint32_t delegation_type;
4018
	int status;
L
Linus Torvalds 已提交
4019

B
Benny Halevy 已提交
4020 4021 4022
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4023
	delegation_type = be32_to_cpup(p);
L
Linus Torvalds 已提交
4024 4025 4026 4027
	if (delegation_type == NFS4_OPEN_DELEGATE_NONE) {
		res->delegation_type = 0;
		return 0;
	}
4028 4029 4030
	status = decode_stateid(xdr, &res->delegation);
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
4031 4032 4033
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4034
	res->do_recall = be32_to_cpup(p);
A
Andy Adamson 已提交
4035

L
Linus Torvalds 已提交
4036
	switch (delegation_type) {
A
Andy Adamson 已提交
4037 4038 4039 4040 4041 4042
	case NFS4_OPEN_DELEGATE_READ:
		res->delegation_type = FMODE_READ;
		break;
	case NFS4_OPEN_DELEGATE_WRITE:
		res->delegation_type = FMODE_WRITE|FMODE_READ;
		if (decode_space_limit(xdr, &res->maxsize) < 0)
L
Linus Torvalds 已提交
4043 4044
				return -EIO;
	}
4045
	return decode_ace(xdr, NULL, res->server->nfs_client);
B
Benny Halevy 已提交
4046 4047 4048
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4049 4050 4051 4052
}

static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
{
A
Andy Adamson 已提交
4053
	__be32 *p;
4054
	uint32_t savewords, bmlen, i;
A
Andy Adamson 已提交
4055
	int status;
L
Linus Torvalds 已提交
4056

A
Andy Adamson 已提交
4057
	status = decode_op_hdr(xdr, OP_OPEN);
4058 4059
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
4060 4061 4062
	if (!status)
		status = decode_stateid(xdr, &res->stateid);
	if (unlikely(status))
A
Andy Adamson 已提交
4063
		return status;
L
Linus Torvalds 已提交
4064

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

B
Benny Halevy 已提交
4067 4068 4069
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4070
	res->rflags = be32_to_cpup(p++);
4071
	bmlen = be32_to_cpup(p);
A
Andy Adamson 已提交
4072 4073
	if (bmlen > 10)
		goto xdr_error;
L
Linus Torvalds 已提交
4074

B
Benny Halevy 已提交
4075 4076 4077
	p = xdr_inline_decode(xdr, bmlen << 2);
	if (unlikely(!p))
		goto out_overflow;
4078 4079
	savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE);
	for (i = 0; i < savewords; ++i)
B
Benny Halevy 已提交
4080
		res->attrset[i] = be32_to_cpup(p++);
4081 4082 4083
	for (; i < NFS4_BITMAP_SIZE; i++)
		res->attrset[i] = 0;

L
Linus Torvalds 已提交
4084 4085
	return decode_delegation(xdr, res);
xdr_error:
4086
	dprintk("%s: Bitmap too large! Length = %u\n", __func__, bmlen);
L
Linus Torvalds 已提交
4087
	return -EIO;
B
Benny Halevy 已提交
4088 4089 4090
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4091 4092 4093 4094 4095 4096
}

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

A
Andy Adamson 已提交
4097
	status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
4098 4099
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
4100 4101 4102
	if (!status)
		status = decode_stateid(xdr, &res->stateid);
	return status;
L
Linus Torvalds 已提交
4103 4104 4105 4106 4107 4108 4109
}

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

	status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE);
4110 4111
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
4112 4113 4114
	if (!status)
		status = decode_stateid(xdr, &res->stateid);
	return status;
L
Linus Torvalds 已提交
4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129
}

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

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

static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
{
	struct kvec *iov = req->rq_rcv_buf.head;
A
Al Viro 已提交
4130
	__be32 *p;
L
Linus Torvalds 已提交
4131 4132 4133 4134 4135 4136
	uint32_t count, eof, recvd, hdrlen;
	int status;

	status = decode_op_hdr(xdr, OP_READ);
	if (status)
		return status;
B
Benny Halevy 已提交
4137 4138 4139
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4140
	eof = be32_to_cpup(p++);
4141
	count = be32_to_cpup(p);
L
Linus Torvalds 已提交
4142 4143 4144
	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
	recvd = req->rq_rcv_buf.len - hdrlen;
	if (count > recvd) {
4145
		dprintk("NFS: server cheating in read reply: "
L
Linus Torvalds 已提交
4146 4147 4148 4149 4150 4151 4152 4153
				"count %u > recvd %u\n", count, recvd);
		count = recvd;
		eof = 0;
	}
	xdr_read_pages(xdr, count);
	res->eof = eof;
	res->count = count;
	return 0;
B
Benny Halevy 已提交
4154 4155 4156
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4157 4158 4159 4160 4161 4162 4163
}

static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
{
	struct xdr_buf	*rcvbuf = &req->rq_rcv_buf;
	struct page	*page = *rcvbuf->pages;
	struct kvec	*iov = rcvbuf->head;
4164 4165
	size_t		hdrlen;
	u32		recvd, pglen = rcvbuf->page_len;
A
Al Viro 已提交
4166
	__be32		*end, *entry, *p, *kaddr;
4167
	unsigned int	nr = 0;
4168
	int		status;
L
Linus Torvalds 已提交
4169 4170

	status = decode_op_hdr(xdr, OP_READDIR);
4171 4172 4173
	if (!status)
		status = decode_verifier(xdr, readdir->verifier.data);
	if (unlikely(status))
L
Linus Torvalds 已提交
4174
		return status;
4175 4176
	dprintk("%s: verifier = %08x:%08x\n",
			__func__,
4177 4178 4179
			((u32 *)readdir->verifier.data)[0],
			((u32 *)readdir->verifier.data)[1]);

L
Linus Torvalds 已提交
4180

4181
	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
L
Linus Torvalds 已提交
4182 4183 4184 4185 4186 4187
	recvd = rcvbuf->len - hdrlen;
	if (pglen > recvd)
		pglen = recvd;
	xdr_read_pages(xdr, pglen);

	BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
A
Al Viro 已提交
4188
	kaddr = p = kmap_atomic(page, KM_USER0);
4189
	end = p + ((pglen + readdir->pgbase) >> 2);
L
Linus Torvalds 已提交
4190
	entry = p;
4191 4192 4193 4194 4195 4196

	/* Make sure the packet actually has a value_follows and EOF entry */
	if ((entry + 1) > end)
		goto short_pkt;

	for (; *p++; nr++) {
4197
		u32 len, attrlen, xlen;
4198
		if (end - p < 3)
L
Linus Torvalds 已提交
4199
			goto short_pkt;
4200
		dprintk("cookie = %Lu, ", *((unsigned long long *)p));
L
Linus Torvalds 已提交
4201 4202 4203
		p += 2;			/* cookie */
		len = ntohl(*p++);	/* filename length */
		if (len > NFS4_MAXNAMLEN) {
4204 4205
			dprintk("NFS: giant filename in readdir (len 0x%x)\n",
					len);
L
Linus Torvalds 已提交
4206 4207
			goto err_unmap;
		}
4208 4209
		xlen = XDR_QUADLEN(len);
		if (end - p < xlen + 1)
L
Linus Torvalds 已提交
4210
			goto short_pkt;
4211 4212
		dprintk("filename = %*s\n", len, (char *)p);
		p += xlen;
L
Linus Torvalds 已提交
4213
		len = ntohl(*p++);	/* bitmap length */
4214
		if (end - p < len + 1)
L
Linus Torvalds 已提交
4215
			goto short_pkt;
4216
		p += len;
L
Linus Torvalds 已提交
4217
		attrlen = XDR_QUADLEN(ntohl(*p++));
4218
		if (end - p < attrlen + 2)
L
Linus Torvalds 已提交
4219
			goto short_pkt;
4220
		p += attrlen;		/* attributes */
L
Linus Torvalds 已提交
4221 4222
		entry = p;
	}
4223 4224 4225 4226 4227 4228 4229 4230 4231
	/*
	 * Apparently some server sends responses that are a valid size, but
	 * contain no entries, and have value_follows==0 and EOF==0. For
	 * those, just set the EOF marker.
	 */
	if (!nr && entry[1] == 0) {
		dprintk("NFS: readdir reply truncated!\n");
		entry[1] = 1;
	}
4232
out:
L
Linus Torvalds 已提交
4233 4234 4235
	kunmap_atomic(kaddr, KM_USER0);
	return 0;
short_pkt:
4236 4237 4238 4239 4240 4241 4242 4243 4244
	/*
	 * When we get a short packet there are 2 possibilities. We can
	 * return an error, or fix up the response to look like a valid
	 * response and return what we have so far. If there are no
	 * entries and the packet was short, then return -EIO. If there
	 * are valid entries in the response, return them and pretend that
	 * the call was successful, but incomplete. The caller can retry the
	 * readdir starting at the last cookie.
	 */
4245
	dprintk("%s: short packet at entry %d\n", __func__, nr);
L
Linus Torvalds 已提交
4246
	entry[0] = entry[1] = 0;
4247 4248
	if (nr)
		goto out;
L
Linus Torvalds 已提交
4249 4250 4251 4252 4253 4254 4255 4256 4257
err_unmap:
	kunmap_atomic(kaddr, KM_USER0);
	return -errno_NFSERR_IO;
}

static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
{
	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
	struct kvec *iov = rcvbuf->head;
4258 4259
	size_t hdrlen;
	u32 len, recvd;
A
Al Viro 已提交
4260
	__be32 *p;
L
Linus Torvalds 已提交
4261 4262 4263 4264 4265 4266 4267 4268
	char *kaddr;
	int status;

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

	/* Convert length of symlink */
B
Benny Halevy 已提交
4269 4270 4271
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4272
	len = be32_to_cpup(p);
L
Linus Torvalds 已提交
4273
	if (len >= rcvbuf->page_len || len <= 0) {
4274
		dprintk("nfs: server returned giant symlink!\n");
L
Linus Torvalds 已提交
4275 4276 4277 4278 4279
		return -ENAMETOOLONG;
	}
	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
	recvd = req->rq_rcv_buf.len - hdrlen;
	if (recvd < len) {
4280
		dprintk("NFS: server cheating in readlink reply: "
L
Linus Torvalds 已提交
4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295
				"count %u > recvd %u\n", len, recvd);
		return -EIO;
	}
	xdr_read_pages(xdr, len);
	/*
	 * The XDR encode routine has set things up so that
	 * the link text will be copied directly into the
	 * buffer.  We just have to do overflow-checking,
	 * and and null-terminate the text (the VFS expects
	 * null-termination).
	 */
	kaddr = (char *)kmap_atomic(rcvbuf->pages[0], KM_USER0);
	kaddr[len+rcvbuf->page_base] = '\0';
	kunmap_atomic(kaddr, KM_USER0);
	return 0;
B
Benny Halevy 已提交
4296 4297 4298
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332
}

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

4333 4334 4335 4336 4337 4338
static int
decode_restorefh(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_RESTOREFH);
}

4339 4340 4341
static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
		size_t *acl_len)
{
A
Al Viro 已提交
4342
	__be32 *savep;
4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358
	uint32_t attrlen,
		 bitmap[2] = {0};
	struct kvec *iov = req->rq_rcv_buf.head;
	int status;

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

	if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
4359 4360
		size_t hdrlen;
		u32 recvd;
4361 4362 4363 4364 4365 4366

		/* We ignore &savep and don't do consistency checks on
		 * the attr length.  Let userspace figure it out.... */
		hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
		recvd = req->rq_rcv_buf.len - hdrlen;
		if (attrlen > recvd) {
4367
			dprintk("NFS: server cheating in getattr"
4368 4369 4370 4371
					" acl reply: attrlen %u > recvd %u\n",
					attrlen, recvd);
			return -EINVAL;
		}
4372
		xdr_read_pages(xdr, attrlen);
4373
		*acl_len = attrlen;
J
J. Bruce Fields 已提交
4374 4375
	} else
		status = -EOPNOTSUPP;
4376 4377 4378 4379 4380

out:
	return status;
}

L
Linus Torvalds 已提交
4381 4382 4383 4384 4385 4386
static int
decode_savefh(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_SAVEFH);
}

4387
static int decode_setattr(struct xdr_stream *xdr)
L
Linus Torvalds 已提交
4388
{
A
Al Viro 已提交
4389
	__be32 *p;
L
Linus Torvalds 已提交
4390 4391 4392 4393 4394 4395
	uint32_t bmlen;
	int status;

	status = decode_op_hdr(xdr, OP_SETATTR);
	if (status)
		return status;
B
Benny Halevy 已提交
4396 4397 4398
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4399
	bmlen = be32_to_cpup(p);
B
Benny Halevy 已提交
4400 4401 4402 4403 4404 4405
	p = xdr_inline_decode(xdr, bmlen << 2);
	if (likely(p))
		return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4406 4407
}

4408
static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid_res *res)
L
Linus Torvalds 已提交
4409
{
A
Al Viro 已提交
4410
	__be32 *p;
L
Linus Torvalds 已提交
4411 4412 4413
	uint32_t opnum;
	int32_t nfserr;

B
Benny Halevy 已提交
4414 4415 4416
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4417
	opnum = be32_to_cpup(p++);
L
Linus Torvalds 已提交
4418
	if (opnum != OP_SETCLIENTID) {
4419
		dprintk("nfs: decode_setclientid: Server returned operation"
4420
			" %d\n", opnum);
L
Linus Torvalds 已提交
4421 4422
		return -EIO;
	}
4423
	nfserr = be32_to_cpup(p);
L
Linus Torvalds 已提交
4424
	if (nfserr == NFS_OK) {
B
Benny Halevy 已提交
4425 4426 4427
		p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE);
		if (unlikely(!p))
			goto out_overflow;
4428 4429
		p = xdr_decode_hyper(p, &res->clientid);
		memcpy(res->confirm.data, p, NFS4_VERIFIER_SIZE);
L
Linus Torvalds 已提交
4430 4431 4432 4433
	} else if (nfserr == NFSERR_CLID_INUSE) {
		uint32_t len;

		/* skip netid string */
B
Benny Halevy 已提交
4434 4435 4436
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
4437
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
4438 4439 4440
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
L
Linus Torvalds 已提交
4441 4442

		/* skip uaddr string */
B
Benny Halevy 已提交
4443 4444 4445
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
4446
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
4447 4448 4449
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
L
Linus Torvalds 已提交
4450 4451
		return -NFSERR_CLID_INUSE;
	} else
4452
		return nfs4_stat_to_errno(nfserr);
L
Linus Torvalds 已提交
4453 4454

	return 0;
B
Benny Halevy 已提交
4455 4456 4457
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4458 4459 4460 4461 4462 4463 4464 4465 4466
}

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

static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
{
A
Al Viro 已提交
4467
	__be32 *p;
L
Linus Torvalds 已提交
4468 4469 4470 4471 4472 4473
	int status;

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

B
Benny Halevy 已提交
4474 4475 4476
	p = xdr_inline_decode(xdr, 16);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4477 4478
	res->count = be32_to_cpup(p++);
	res->verf->committed = be32_to_cpup(p++);
B
Benny Halevy 已提交
4479
	memcpy(res->verf->verifier, p, 8);
L
Linus Torvalds 已提交
4480
	return 0;
B
Benny Halevy 已提交
4481 4482 4483
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4484 4485 4486 4487 4488 4489 4490
}

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

B
Benny Halevy 已提交
4491 4492 4493 4494 4495 4496
#if defined(CONFIG_NFS_V4_1)
static int decode_exchange_id(struct xdr_stream *xdr,
			      struct nfs41_exchange_id_res *res)
{
	__be32 *p;
	uint32_t dummy;
4497
	char *dummy_str;
B
Benny Halevy 已提交
4498 4499 4500 4501 4502 4503 4504
	int status;
	struct nfs_client *clp = res->client;

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

B
Benny Halevy 已提交
4505 4506 4507
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
4508
	xdr_decode_hyper(p, &clp->cl_ex_clid);
B
Benny Halevy 已提交
4509 4510 4511
	p = xdr_inline_decode(xdr, 12);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4512 4513
	clp->cl_seqid = be32_to_cpup(p++);
	clp->cl_exchange_flags = be32_to_cpup(p++);
B
Benny Halevy 已提交
4514 4515

	/* We ask for SP4_NONE */
4516
	dummy = be32_to_cpup(p);
B
Benny Halevy 已提交
4517 4518 4519 4520
	if (dummy != SP4_NONE)
		return -EIO;

	/* Throw away minor_id */
B
Benny Halevy 已提交
4521 4522 4523
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4524 4525

	/* Throw away Major id */
4526 4527 4528
	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
4529 4530

	/* Throw away server_scope */
4531 4532 4533
	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
4534 4535

	/* Throw away Implementation id array */
4536 4537 4538
	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
4539 4540

	return 0;
B
Benny Halevy 已提交
4541 4542 4543
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
B
Benny Halevy 已提交
4544
}
A
Andy Adamson 已提交
4545 4546 4547 4548 4549 4550 4551

static int decode_chan_attrs(struct xdr_stream *xdr,
			     struct nfs4_channel_attrs *attrs)
{
	__be32 *p;
	u32 nr_attrs;

B
Benny Halevy 已提交
4552 4553 4554
	p = xdr_inline_decode(xdr, 28);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4555 4556 4557 4558 4559 4560
	attrs->headerpadsz = be32_to_cpup(p++);
	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++);
4561
	nr_attrs = be32_to_cpup(p);
A
Andy Adamson 已提交
4562 4563 4564 4565 4566
	if (unlikely(nr_attrs > 1)) {
		printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n",
			__func__, nr_attrs);
		return -EINVAL;
	}
B
Benny Halevy 已提交
4567 4568 4569 4570 4571
	if (nr_attrs == 1) {
		p = xdr_inline_decode(xdr, 4); /* skip rdma_attrs */
		if (unlikely(!p))
			goto out_overflow;
	}
A
Andy Adamson 已提交
4572
	return 0;
B
Benny Halevy 已提交
4573 4574 4575
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
A
Andy Adamson 已提交
4576 4577
}

4578 4579 4580
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 已提交
4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591
}

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

	status = decode_op_hdr(xdr, OP_CREATE_SESSION);
4592 4593 4594
	if (!status)
		status = decode_sessionid(xdr, &session->sess_id);
	if (unlikely(status))
A
Andy Adamson 已提交
4595 4596 4597
		return status;

	/* seqid, flags */
B
Benny Halevy 已提交
4598 4599 4600
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4601
	clp->cl_seqid = be32_to_cpup(p++);
4602
	session->flags = be32_to_cpup(p);
A
Andy Adamson 已提交
4603 4604 4605 4606 4607 4608

	/* Channel attributes */
	status = decode_chan_attrs(xdr, &session->fc_attrs);
	if (!status)
		status = decode_chan_attrs(xdr, &session->bc_attrs);
	return status;
B
Benny Halevy 已提交
4609 4610 4611
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
A
Andy Adamson 已提交
4612
}
A
Andy Adamson 已提交
4613 4614 4615 4616 4617

static int decode_destroy_session(struct xdr_stream *xdr, void *dummy)
{
	return decode_op_hdr(xdr, OP_DESTROY_SESSION);
}
4618 4619 4620 4621 4622

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

4625 4626 4627 4628 4629
static int decode_sequence(struct xdr_stream *xdr,
			   struct nfs4_sequence_res *res,
			   struct rpc_rqst *rqstp)
{
#if defined(CONFIG_NFS_V4_1)
A
Andy Adamson 已提交
4630 4631 4632 4633 4634 4635
	struct nfs4_slot *slot;
	struct nfs4_sessionid id;
	u32 dummy;
	int status;
	__be32 *p;

4636 4637 4638
	if (!res->sr_session)
		return 0;

A
Andy Adamson 已提交
4639
	status = decode_op_hdr(xdr, OP_SEQUENCE);
4640 4641 4642
	if (!status)
		status = decode_sessionid(xdr, &id);
	if (unlikely(status))
A
Andy Adamson 已提交
4643
		goto out_err;
4644

A
Andy Adamson 已提交
4645 4646 4647 4648
	/*
	 * If the server returns different values for sessionID, slotID or
	 * sequence number, the server is looney tunes.
	 */
4649
	status = -EREMOTEIO;
A
Andy Adamson 已提交
4650 4651 4652 4653 4654 4655

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

B
Benny Halevy 已提交
4657 4658 4659
	p = xdr_inline_decode(xdr, 20);
	if (unlikely(!p))
		goto out_overflow;
4660

A
Andy Adamson 已提交
4661
	/* seqid */
4662
	slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid];
B
Benny Halevy 已提交
4663
	dummy = be32_to_cpup(p++);
A
Andy Adamson 已提交
4664 4665 4666 4667 4668
	if (dummy != slot->seq_nr) {
		dprintk("%s Invalid sequence number\n", __func__);
		goto out_err;
	}
	/* slot id */
B
Benny Halevy 已提交
4669
	dummy = be32_to_cpup(p++);
A
Andy Adamson 已提交
4670 4671 4672 4673 4674
	if (dummy != res->sr_slotid) {
		dprintk("%s Invalid slot id\n", __func__);
		goto out_err;
	}
	/* highest slot id - currently not processed */
B
Benny Halevy 已提交
4675
	dummy = be32_to_cpup(p++);
A
Andy Adamson 已提交
4676
	/* target highest slot id - currently not processed */
B
Benny Halevy 已提交
4677
	dummy = be32_to_cpup(p++);
4678 4679
	/* result flags */
	res->sr_status_flags = be32_to_cpup(p);
A
Andy Adamson 已提交
4680 4681 4682 4683
	status = 0;
out_err:
	res->sr_status = status;
	return status;
B
Benny Halevy 已提交
4684 4685 4686 4687
out_overflow:
	print_overflow_msg(__func__, xdr);
	status = -EIO;
	goto out_err;
A
Andy Adamson 已提交
4688
#else  /* CONFIG_NFS_V4_1 */
4689
	return 0;
A
Andy Adamson 已提交
4690
#endif /* CONFIG_NFS_V4_1 */
4691 4692
}

4693 4694 4695 4696
/*
 * END OF "GENERIC" DECODE ROUTINES.
 */

L
Linus Torvalds 已提交
4697 4698 4699
/*
 * Decode OPEN_DOWNGRADE response
 */
A
Al Viro 已提交
4700
static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
L
Linus Torvalds 已提交
4701
{
A
Andy Adamson 已提交
4702 4703 4704 4705 4706 4707
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
4708 4709 4710
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
4711 4712 4713 4714 4715 4716
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_open_downgrade(&xdr, res);
4717 4718
	if (status != 0)
		goto out;
4719 4720
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4721
out:
A
Andy Adamson 已提交
4722
	return status;
L
Linus Torvalds 已提交
4723 4724 4725 4726 4727
}

/*
 * Decode ACCESS response
 */
A
Al Viro 已提交
4728
static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res)
L
Linus Torvalds 已提交
4729 4730 4731 4732
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4733

L
Linus Torvalds 已提交
4734
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4735 4736 4737 4738 4739
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4740
		goto out;
4741 4742 4743 4744 4745 4746
	status = decode_putfh(&xdr);
	if (status != 0)
		goto out;
	status = decode_access(&xdr, res);
	if (status != 0)
		goto out;
4747 4748
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4749 4750 4751 4752 4753 4754 4755
out:
	return status;
}

/*
 * Decode LOOKUP response
 */
A
Al Viro 已提交
4756
static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
L
Linus Torvalds 已提交
4757 4758 4759 4760
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4761

L
Linus Torvalds 已提交
4762
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4763 4764 4765 4766 4767
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4768 4769 4770 4771 4772 4773 4774
		goto out;
	if ((status = decode_putfh(&xdr)) != 0)
		goto out;
	if ((status = decode_lookup(&xdr)) != 0)
		goto out;
	if ((status = decode_getfh(&xdr, res->fh)) != 0)
		goto out;
4775 4776
	status = decode_getfattr(&xdr, res->fattr, res->server
			,!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4777 4778 4779 4780 4781 4782 4783
out:
	return status;
}

/*
 * Decode LOOKUP_ROOT response
 */
A
Al Viro 已提交
4784
static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
L
Linus Torvalds 已提交
4785 4786 4787 4788
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4789

L
Linus Torvalds 已提交
4790
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4791 4792 4793 4794 4795
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4796 4797 4798 4799
		goto out;
	if ((status = decode_putrootfh(&xdr)) != 0)
		goto out;
	if ((status = decode_getfh(&xdr, res->fh)) == 0)
4800 4801
		status = decode_getfattr(&xdr, res->fattr, res->server,
				!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4802 4803 4804 4805 4806 4807 4808
out:
	return status;
}

/*
 * Decode REMOVE response
 */
4809
static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_removeres *res)
L
Linus Torvalds 已提交
4810 4811 4812 4813
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4814

L
Linus Torvalds 已提交
4815
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4816 4817 4818 4819 4820
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4821
		goto out;
4822 4823 4824 4825
	if ((status = decode_putfh(&xdr)) != 0)
		goto out;
	if ((status = decode_remove(&xdr, &res->cinfo)) != 0)
		goto out;
4826
	decode_getfattr(&xdr, res->dir_attr, res->server,
4827
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4828 4829 4830 4831 4832 4833 4834
out:
	return status;
}

/*
 * Decode RENAME response
 */
A
Al Viro 已提交
4835
static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res)
L
Linus Torvalds 已提交
4836 4837 4838 4839
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4840

L
Linus Torvalds 已提交
4841
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4842 4843 4844 4845 4846
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4847 4848 4849 4850 4851 4852 4853
		goto out;
	if ((status = decode_putfh(&xdr)) != 0)
		goto out;
	if ((status = decode_savefh(&xdr)) != 0)
		goto out;
	if ((status = decode_putfh(&xdr)) != 0)
		goto out;
4854 4855 4856
	if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0)
		goto out;
	/* Current FH is target directory */
4857 4858
	if (decode_getfattr(&xdr, res->new_fattr, res->server,
				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
4859 4860 4861
		goto out;
	if ((status = decode_restorefh(&xdr)) != 0)
		goto out;
4862 4863
	decode_getfattr(&xdr, res->old_fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4864 4865 4866 4867 4868 4869 4870
out:
	return status;
}

/*
 * Decode LINK response
 */
A
Al Viro 已提交
4871
static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link_res *res)
L
Linus Torvalds 已提交
4872 4873 4874 4875
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4876

L
Linus Torvalds 已提交
4877
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4878 4879 4880 4881 4882
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4883 4884 4885 4886 4887 4888 4889
		goto out;
	if ((status = decode_putfh(&xdr)) != 0)
		goto out;
	if ((status = decode_savefh(&xdr)) != 0)
		goto out;
	if ((status = decode_putfh(&xdr)) != 0)
		goto out;
4890 4891 4892 4893 4894 4895
	if ((status = decode_link(&xdr, &res->cinfo)) != 0)
		goto out;
	/*
	 * Note order: OP_LINK leaves the directory as the current
	 *             filehandle.
	 */
4896 4897
	if (decode_getfattr(&xdr, res->dir_attr, res->server,
				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
4898 4899 4900
		goto out;
	if ((status = decode_restorefh(&xdr)) != 0)
		goto out;
4901 4902
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4903 4904 4905 4906 4907 4908 4909
out:
	return status;
}

/*
 * Decode CREATE response
 */
A
Al Viro 已提交
4910
static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
L
Linus Torvalds 已提交
4911 4912 4913 4914
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4915

L
Linus Torvalds 已提交
4916
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4917 4918 4919 4920 4921
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4922 4923 4924
		goto out;
	if ((status = decode_putfh(&xdr)) != 0)
		goto out;
4925 4926
	if ((status = decode_savefh(&xdr)) != 0)
		goto out;
L
Linus Torvalds 已提交
4927 4928 4929 4930
	if ((status = decode_create(&xdr,&res->dir_cinfo)) != 0)
		goto out;
	if ((status = decode_getfh(&xdr, res->fh)) != 0)
		goto out;
4931 4932
	if (decode_getfattr(&xdr, res->fattr, res->server,
				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
4933 4934 4935
		goto out;
	if ((status = decode_restorefh(&xdr)) != 0)
		goto out;
4936 4937
	decode_getfattr(&xdr, res->dir_fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4938 4939 4940 4941 4942 4943 4944
out:
	return status;
}

/*
 * Decode SYMLINK response
 */
A
Al Viro 已提交
4945
static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
L
Linus Torvalds 已提交
4946 4947 4948 4949 4950 4951 4952
{
	return nfs4_xdr_dec_create(rqstp, p, res);
}

/*
 * Decode GETATTR response
 */
A
Al Viro 已提交
4953
static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_getattr_res *res)
L
Linus Torvalds 已提交
4954 4955 4956 4957
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4958

L
Linus Torvalds 已提交
4959 4960
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
4961 4962 4963
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
4964 4965 4966 4967 4968
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
4969 4970
	status = decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4971 4972 4973 4974
out:
	return status;
}

4975 4976 4977 4978
/*
 * Encode an SETACL request
 */
static int
A
Al Viro 已提交
4979
nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args)
4980
{
A
Andy Adamson 已提交
4981 4982
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
4983
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
A
Andy Adamson 已提交
4984 4985 4986 4987
	};
	int status;

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
4988
	encode_compound_hdr(&xdr, req, &hdr);
4989
	encode_sequence(&xdr, &args->seq_args, &hdr);
4990
	encode_putfh(&xdr, args->fh, &hdr);
4991 4992
	status = encode_setacl(&xdr, args, &hdr);
	encode_nops(&hdr);
A
Andy Adamson 已提交
4993
	return status;
4994
}
A
Andy Adamson 已提交
4995

4996 4997 4998 4999
/*
 * Decode SETACL response
 */
static int
B
Benny Halevy 已提交
5000 5001
nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p,
		    struct nfs_setaclres *res)
5002 5003 5004 5005 5006 5007 5008
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5009 5010 5011
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
5012 5013 5014 5015 5016
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
5017
	status = decode_setattr(&xdr);
5018 5019 5020
out:
	return status;
}
L
Linus Torvalds 已提交
5021

5022 5023 5024 5025
/*
 * Decode GETACL response
 */
static int
B
Benny Halevy 已提交
5026 5027
nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p,
		    struct nfs_getaclres *res)
5028 5029 5030 5031 5032 5033 5034
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5035 5036 5037
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
5038 5039 5040 5041 5042
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
B
Benny Halevy 已提交
5043
	status = decode_getacl(&xdr, rqstp, &res->acl_len);
5044 5045 5046 5047 5048

out:
	return status;
}

L
Linus Torvalds 已提交
5049 5050 5051
/*
 * Decode CLOSE response
 */
A
Al Viro 已提交
5052
static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
L
Linus Torvalds 已提交
5053
{
A
Andy Adamson 已提交
5054 5055 5056 5057 5058 5059
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5060 5061 5062
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
5063 5064 5065 5066 5067 5068
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_close(&xdr, res);
5069 5070 5071 5072 5073 5074 5075 5076
	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.
	 */
5077 5078
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5079
out:
A
Andy Adamson 已提交
5080
	return status;
L
Linus Torvalds 已提交
5081 5082 5083 5084 5085
}

/*
 * Decode OPEN response
 */
A
Al Viro 已提交
5086
static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
L
Linus Torvalds 已提交
5087
{
A
Andy Adamson 已提交
5088 5089 5090 5091 5092 5093
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5094 5095 5096
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
5097 5098 5099 5100 5101 5102 5103 5104 5105
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_savefh(&xdr);
	if (status)
		goto out;
	status = decode_open(&xdr, res);
5106 5107
	if (status)
		goto out;
5108
	if (decode_getfh(&xdr, &res->fh) != 0)
L
Linus Torvalds 已提交
5109
		goto out;
5110 5111
	if (decode_getfattr(&xdr, res->f_attr, res->server,
				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
5112
		goto out;
5113
	if (decode_restorefh(&xdr) != 0)
5114
		goto out;
5115 5116
	decode_getfattr(&xdr, res->dir_attr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5117
out:
A
Andy Adamson 已提交
5118
	return status;
L
Linus Torvalds 已提交
5119 5120 5121 5122 5123
}

/*
 * Decode OPEN_CONFIRM response
 */
A
Al Viro 已提交
5124
static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, __be32 *p, struct nfs_open_confirmres *res)
L
Linus Torvalds 已提交
5125
{
A
Andy Adamson 已提交
5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_open_confirm(&xdr, res);
L
Linus Torvalds 已提交
5138
out:
A
Andy Adamson 已提交
5139
	return status;
L
Linus Torvalds 已提交
5140 5141 5142 5143 5144
}

/*
 * Decode OPEN response
 */
A
Al Viro 已提交
5145
static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
L
Linus Torvalds 已提交
5146
{
A
Andy Adamson 已提交
5147 5148 5149 5150 5151 5152
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5153 5154 5155
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
5156 5157 5158 5159 5160 5161 5162 5163
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_open(&xdr, res);
	if (status)
		goto out;
5164 5165
	decode_getfattr(&xdr, res->f_attr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5166
out:
A
Andy Adamson 已提交
5167
	return status;
L
Linus Torvalds 已提交
5168 5169 5170 5171 5172
}

/*
 * Decode SETATTR response
 */
A
Al Viro 已提交
5173
static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res)
L
Linus Torvalds 已提交
5174
{
A
Andy Adamson 已提交
5175 5176 5177 5178 5179 5180
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5181 5182 5183
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
5184 5185 5186 5187 5188
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
5189
	status = decode_setattr(&xdr);
A
Andy Adamson 已提交
5190 5191
	if (status)
		goto out;
5192 5193
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5194
out:
A
Andy Adamson 已提交
5195
	return status;
L
Linus Torvalds 已提交
5196 5197 5198 5199 5200
}

/*
 * Decode LOCK response
 */
A
Al Viro 已提交
5201
static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_res *res)
L
Linus Torvalds 已提交
5202 5203 5204 5205 5206 5207 5208
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5209 5210 5211
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_lock(&xdr, res);
out:
	return status;
}

/*
 * Decode LOCKT response
 */
A
Al Viro 已提交
5225
static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lockt_res *res)
L
Linus Torvalds 已提交
5226 5227 5228 5229 5230 5231 5232
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5233 5234 5235
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_lockt(&xdr, res);
out:
	return status;
}

/*
 * Decode LOCKU response
 */
A
Al Viro 已提交
5249
static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_locku_res *res)
L
Linus Torvalds 已提交
5250 5251 5252 5253 5254 5255 5256
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5257 5258 5259
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_locku(&xdr, res);
out:
	return status;
}

/*
 * Decode READLINK response
 */
B
Benny Halevy 已提交
5273 5274
static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p,
				 struct nfs4_readlink_res *res)
L
Linus Torvalds 已提交
5275 5276 5277 5278 5279 5280 5281
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5282 5283 5284
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_readlink(&xdr, rqstp);
out:
	return status;
}

/*
 * Decode READDIR response
 */
A
Al Viro 已提交
5298
static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_readdir_res *res)
L
Linus Torvalds 已提交
5299 5300 5301 5302 5303 5304 5305
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5306 5307 5308
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_readdir(&xdr, rqstp, res);
out:
	return status;
}

/*
 * Decode Read response
 */
A
Al Viro 已提交
5322
static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readres *res)
L
Linus Torvalds 已提交
5323 5324 5325 5326 5327 5328 5329
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5330 5331 5332
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_read(&xdr, rqstp, res);
	if (!status)
		status = res->count;
out:
	return status;
}

/*
 * Decode WRITE response
 */
A
Al Viro 已提交
5348
static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
L
Linus Torvalds 已提交
5349 5350 5351 5352 5353 5354 5355
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5356 5357 5358
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5359 5360 5361 5362 5363 5364
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_write(&xdr, res);
5365 5366
	if (status)
		goto out;
5367 5368
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5369 5370 5371 5372 5373 5374 5375 5376 5377
	if (!status)
		status = res->count;
out:
	return status;
}

/*
 * Decode COMMIT response
 */
A
Al Viro 已提交
5378
static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
L
Linus Torvalds 已提交
5379 5380 5381 5382 5383 5384 5385
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5386 5387 5388
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5389 5390 5391 5392 5393 5394
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_commit(&xdr, res);
5395 5396
	if (status)
		goto out;
5397 5398
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5399 5400 5401 5402 5403
out:
	return status;
}

/*
5404
 * Decode FSINFO response
L
Linus Torvalds 已提交
5405
 */
B
Benny Halevy 已提交
5406 5407
static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p,
			       struct nfs4_fsinfo_res *res)
L
Linus Torvalds 已提交
5408 5409 5410 5411 5412 5413 5414
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5415 5416
	if (!status)
		status = decode_sequence(&xdr, &res->seq_res, req);
L
Linus Torvalds 已提交
5417 5418 5419
	if (!status)
		status = decode_putfh(&xdr);
	if (!status)
B
Benny Halevy 已提交
5420
		status = decode_fsinfo(&xdr, res->fsinfo);
L
Linus Torvalds 已提交
5421 5422 5423 5424
	return status;
}

/*
5425
 * Decode PATHCONF response
L
Linus Torvalds 已提交
5426
 */
B
Benny Halevy 已提交
5427 5428
static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p,
				 struct nfs4_pathconf_res *res)
L
Linus Torvalds 已提交
5429 5430 5431 5432 5433 5434 5435
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5436 5437
	if (!status)
		status = decode_sequence(&xdr, &res->seq_res, req);
L
Linus Torvalds 已提交
5438 5439 5440
	if (!status)
		status = decode_putfh(&xdr);
	if (!status)
B
Benny Halevy 已提交
5441
		status = decode_pathconf(&xdr, res->pathconf);
L
Linus Torvalds 已提交
5442 5443 5444 5445
	return status;
}

/*
5446
 * Decode STATFS response
L
Linus Torvalds 已提交
5447
 */
B
Benny Halevy 已提交
5448 5449
static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p,
			       struct nfs4_statfs_res *res)
L
Linus Torvalds 已提交
5450 5451 5452 5453 5454 5455 5456
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5457 5458
	if (!status)
		status = decode_sequence(&xdr, &res->seq_res, req);
L
Linus Torvalds 已提交
5459 5460 5461
	if (!status)
		status = decode_putfh(&xdr);
	if (!status)
B
Benny Halevy 已提交
5462
		status = decode_statfs(&xdr, res->fsstat);
L
Linus Torvalds 已提交
5463 5464 5465 5466
	return status;
}

/*
5467
 * Decode GETATTR_BITMAP response
L
Linus Torvalds 已提交
5468
 */
A
Al Viro 已提交
5469
static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4_server_caps_res *res)
L
Linus Torvalds 已提交
5470 5471 5472 5473 5474 5475
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
5476 5477 5478 5479 5480
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, req);
	if (status)
L
Linus Torvalds 已提交
5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491
		goto out;
	if ((status = decode_putfh(&xdr)) != 0)
		goto out;
	status = decode_server_caps(&xdr, res);
out:
	return status;
}

/*
 * Decode RENEW response
 */
A
Al Viro 已提交
5492
static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy)
L
Linus Torvalds 已提交
5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
	if (!status)
		status = decode_renew(&xdr);
	return status;
}

/*
5506
 * Decode SETCLIENTID response
L
Linus Torvalds 已提交
5507
 */
A
Al Viro 已提交
5508
static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p,
5509
		struct nfs4_setclientid_res *res)
L
Linus Torvalds 已提交
5510 5511 5512 5513 5514 5515 5516 5517
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
	if (!status)
5518
		status = decode_setclientid(&xdr, res);
L
Linus Torvalds 已提交
5519 5520 5521 5522
	return status;
}

/*
5523
 * Decode SETCLIENTID_CONFIRM response
L
Linus Torvalds 已提交
5524
 */
A
Al Viro 已提交
5525
static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
L
Linus Torvalds 已提交
5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
	if (!status)
		status = decode_setclientid_confirm(&xdr);
	if (!status)
		status = decode_putrootfh(&xdr);
	if (!status)
		status = decode_fsinfo(&xdr, fsinfo);
	return status;
}

/*
5543
 * Decode DELEGRETURN response
L
Linus Torvalds 已提交
5544
 */
A
Al Viro 已提交
5545
static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_delegreturnres *res)
L
Linus Torvalds 已提交
5546 5547 5548 5549 5550 5551 5552
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5553 5554 5555 5556
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
5557 5558 5559 5560 5561
		goto out;
	status = decode_putfh(&xdr);
	if (status != 0)
		goto out;
	status = decode_delegreturn(&xdr);
5562 5563
	if (status != 0)
		goto out;
5564 5565
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
5566
out:
L
Linus Torvalds 已提交
5567 5568 5569
	return status;
}

5570
/*
5571
 * Decode FS_LOCATIONS response
5572
 */
B
Benny Halevy 已提交
5573 5574
static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p,
				     struct nfs4_fs_locations_res *res)
5575 5576 5577 5578 5579 5580 5581
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
5582 5583 5584 5585
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, req);
	if (status)
5586 5587 5588 5589 5590 5591
		goto out;
	if ((status = decode_putfh(&xdr)) != 0)
		goto out;
	if ((status = decode_lookup(&xdr)) != 0)
		goto out;
	xdr_enter_page(&xdr, PAGE_SIZE);
B
Benny Halevy 已提交
5592
	status = decode_getfattr(&xdr, &res->fs_locations->fattr,
5593 5594
				 res->fs_locations->server,
				 !RPC_IS_ASYNC(req->rq_task));
5595 5596 5597 5598
out:
	return status;
}

B
Benny Halevy 已提交
5599 5600
#if defined(CONFIG_NFS_V4_1)
/*
5601
 * Decode EXCHANGE_ID response
B
Benny Halevy 已提交
5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615
 */
static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp, uint32_t *p,
				    void *res)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
	if (!status)
		status = decode_exchange_id(&xdr, res);
	return status;
}
A
Andy Adamson 已提交
5616

A
Andy Adamson 已提交
5617
/*
5618
 * Decode CREATE_SESSION response
A
Andy Adamson 已提交
5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633
 */
static int nfs4_xdr_dec_create_session(struct rpc_rqst *rqstp, uint32_t *p,
				       struct nfs41_create_session_res *res)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
	if (!status)
		status = decode_create_session(&xdr, res);
	return status;
}

A
Andy Adamson 已提交
5634
/*
5635
 * Decode DESTROY_SESSION response
A
Andy Adamson 已提交
5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650
 */
static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp, uint32_t *p,
					void *dummy)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
	if (!status)
		status = decode_destroy_session(&xdr, dummy);
	return status;
}

A
Andy Adamson 已提交
5651
/*
5652
 * Decode SEQUENCE response
A
Andy Adamson 已提交
5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667
 */
static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp, uint32_t *p,
				 struct nfs4_sequence_res *res)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
	if (!status)
		status = decode_sequence(&xdr, res, rqstp);
	return status;
}

A
Andy Adamson 已提交
5668
/*
5669
 * Decode GET_LEASE_TIME response
A
Andy Adamson 已提交
5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687
 */
static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p,
				       struct nfs4_get_lease_time_res *res)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
	if (!status)
		status = decode_sequence(&xdr, &res->lr_seq_res, rqstp);
	if (!status)
		status = decode_putrootfh(&xdr);
	if (!status)
		status = decode_fsinfo(&xdr, res->lr_fsinfo);
	return status;
}
5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706

/*
 * Decode RECLAIM_COMPLETE response
 */
static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp, uint32_t *p,
					 struct nfs41_reclaim_complete_res *res)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
	if (!status)
		status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (!status)
		status = decode_reclaim_complete(&xdr, (void *)NULL);
	return status;
}
B
Benny Halevy 已提交
5707 5708
#endif /* CONFIG_NFS_V4_1 */

5709
__be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
L
Linus Torvalds 已提交
5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743
{
	uint32_t bitmap[2] = {0};
	uint32_t len;

	if (!*p++) {
		if (!*p)
			return ERR_PTR(-EAGAIN);
		entry->eof = 1;
		return ERR_PTR(-EBADCOOKIE);
	}

	entry->prev_cookie = entry->cookie;
	p = xdr_decode_hyper(p, &entry->cookie);
	entry->len = ntohl(*p++);
	entry->name = (const char *) p;
	p += XDR_QUADLEN(entry->len);

	/*
	 * 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;

	len = ntohl(*p++);		/* bitmap length */
	if (len-- > 0) {
		bitmap[0] = ntohl(*p++);
		if (len-- > 0) {
			bitmap[1] = ntohl(*p++);
			p += len;
		}
	}
	len = XDR_QUADLEN(ntohl(*p++));	/* attribute buffer length */
	if (len > 0) {
5744 5745 5746 5747 5748 5749
		if (bitmap[0] & FATTR4_WORD0_RDATTR_ERROR) {
			bitmap[0] &= ~FATTR4_WORD0_RDATTR_ERROR;
			/* Ignore the return value of rdattr_error for now */
			p++;
			len--;
		}
L
Linus Torvalds 已提交
5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769
		if (bitmap[0] == 0 && bitmap[1] == FATTR4_WORD1_MOUNTED_ON_FILEID)
			xdr_decode_hyper(p, &entry->ino);
		else if (bitmap[0] == FATTR4_WORD0_FILEID)
			xdr_decode_hyper(p, &entry->ino);
		p += len;
	}

	entry->eof = !p[0] && p[1];
	return p;
}

/*
 * 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		},
5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793
	{ 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_BADOWNER,	-EINVAL		},
	{ NFS4ERR_BADNAME,	-EINVAL		},
	{ NFS4ERR_BAD_COOKIE,	-EBADCOOKIE	},
	{ NFS4ERR_NOTSUPP,	-ENOTSUPP	},
	{ NFS4ERR_TOOSMALL,	-ETOOSMALL	},
5794
	{ NFS4ERR_SERVERFAULT,	-EREMOTEIO	},
5795 5796 5797 5798 5799 5800
	{ NFS4ERR_BADTYPE,	-EBADTYPE	},
	{ NFS4ERR_LOCKED,	-EAGAIN		},
	{ NFS4ERR_SYMLINK,	-ELOOP		},
	{ NFS4ERR_OP_ILLEGAL,	-EOPNOTSUPP	},
	{ NFS4ERR_DEADLOCK,	-EDEADLK	},
	{ NFS4ERR_WRONGSEC,	-EPERM		}, /* FIXME: this needs
L
Linus Torvalds 已提交
5801 5802 5803
						    * to be handled by a
						    * middle-layer.
						    */
5804
	{ -1,			-EIO		}
L
Linus Torvalds 已提交
5805 5806 5807 5808 5809 5810 5811
};

/*
 * Convert an NFS error code to a local one.
 * This one is used jointly by NFSv2 and NFSv3.
 */
static int
5812
nfs4_stat_to_errno(int stat)
L
Linus Torvalds 已提交
5813 5814 5815 5816 5817 5818 5819 5820
{
	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. */
5821
		return -EREMOTEIO;
L
Linus Torvalds 已提交
5822 5823 5824 5825 5826 5827
	}
	/* 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.
	 */
5828
	return -stat;
L
Linus Torvalds 已提交
5829 5830 5831 5832 5833 5834 5835
}

#define PROC(proc, argtype, restype)				\
[NFSPROC4_CLNT_##proc] = {					\
	.p_proc   = NFSPROC4_COMPOUND,				\
	.p_encode = (kxdrproc_t) nfs4_xdr_##argtype,		\
	.p_decode = (kxdrproc_t) nfs4_xdr_##restype,		\
5836 5837
	.p_arglen = NFS4_##argtype##_sz,			\
	.p_replen = NFS4_##restype##_sz,			\
5838 5839
	.p_statidx = NFSPROC4_CLNT_##proc,			\
	.p_name   = #proc,					\
A
Andy Adamson 已提交
5840
}
L
Linus Torvalds 已提交
5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873

struct rpc_procinfo	nfs4_procedures[] = {
  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),
5874
  PROC(GETACL,		enc_getacl,	dec_getacl),
5875
  PROC(SETACL,		enc_setacl,	dec_setacl),
5876
  PROC(FS_LOCATIONS,	enc_fs_locations, dec_fs_locations),
B
Benny Halevy 已提交
5877 5878
#if defined(CONFIG_NFS_V4_1)
  PROC(EXCHANGE_ID,	enc_exchange_id,	dec_exchange_id),
A
Andy Adamson 已提交
5879
  PROC(CREATE_SESSION,	enc_create_session,	dec_create_session),
A
Andy Adamson 已提交
5880
  PROC(DESTROY_SESSION,	enc_destroy_session,	dec_destroy_session),
A
Andy Adamson 已提交
5881
  PROC(SEQUENCE,	enc_sequence,	dec_sequence),
A
Andy Adamson 已提交
5882
  PROC(GET_LEASE_TIME,	enc_get_lease_time,	dec_get_lease_time),
5883
  PROC(RECLAIM_COMPLETE, enc_reclaim_complete,  dec_reclaim_complete),
B
Benny Halevy 已提交
5884
#endif /* CONFIG_NFS_V4_1 */
L
Linus Torvalds 已提交
5885 5886 5887 5888
};

struct rpc_version		nfs_version4 = {
	.number			= 4,
5889
	.nrprocs		= ARRAY_SIZE(nfs4_procedures),
L
Linus Torvalds 已提交
5890 5891 5892 5893 5894 5895 5896 5897
	.procs			= nfs4_procedures
};

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