nfs4xdr.c 152.2 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 48
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the University nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <linux/param.h>
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/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>
49
#include <linux/sunrpc/msg_prot.h>
L
Linus Torvalds 已提交
50 51 52 53
#include <linux/nfs.h>
#include <linux/nfs4.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_idmap.h>
54
#include "nfs4_fs.h"
55
#include "internal.h"
L
Linus Torvalds 已提交
56 57 58 59 60 61

#define NFSDBG_FACILITY		NFSDBG_XDR

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

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

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

71
/* lock,open owner id:
72
 * we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT  >> 2)
L
Linus Torvalds 已提交
73
 */
74 75
#define open_owner_id_maxsz	(1 + 4)
#define lock_owner_id_maxsz	(1 + 4)
T
Trond Myklebust 已提交
76
#define decode_lockowner_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
L
Linus Torvalds 已提交
77 78 79 80
#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 已提交
81 82 83 84
#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 已提交
85 86 87 88 89 90 91 92
#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))
93 94
#define nfs4_fattr_bitmap_maxsz 3
#define encode_getattr_maxsz    (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
L
Linus Torvalds 已提交
95 96
#define nfs4_name_maxsz		(1 + ((3 + NFS4_MAXNAMLEN) >> 2))
#define nfs4_path_maxsz		(1 + ((3 + NFS4_MAXPATHLEN) >> 2))
97 98
#define nfs4_owner_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
#define nfs4_group_maxsz	(1 + XDR_QUADLEN(IDMAP_NAMESZ))
99 100
/* 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 + \
101
				3 + 3 + 3 + nfs4_owner_maxsz + nfs4_group_maxsz))
102 103 104
#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 已提交
105 106 107 108 109
#define encode_attrs_maxsz	(nfs4_fattr_bitmap_maxsz + \
				 1 + 2 + 1 + \
				nfs4_owner_maxsz + \
				nfs4_group_maxsz + \
				4 + 4)
L
Linus Torvalds 已提交
110 111
#define encode_savefh_maxsz     (op_encode_hdr_maxsz)
#define decode_savefh_maxsz     (op_decode_hdr_maxsz)
112 113
#define encode_restorefh_maxsz  (op_encode_hdr_maxsz)
#define decode_restorefh_maxsz  (op_decode_hdr_maxsz)
F
Fred Isaman 已提交
114
#define encode_fsinfo_maxsz	(encode_getattr_maxsz)
L
Linus Torvalds 已提交
115 116 117 118 119
#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 + \
120 121 122 123 124 125
				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 已提交
126 127 128 129 130 131 132 133 134
#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)
135 136
#define encode_lookup_maxsz	(op_encode_hdr_maxsz + nfs4_name_maxsz)
#define decode_lookup_maxsz	(op_decode_hdr_maxsz)
137 138
#define encode_share_access_maxsz \
				(2)
139
#define encode_createmode_maxsz	(1 + encode_attrs_maxsz + encode_verifier_maxsz)
140 141 142 143 144 145 146 147
#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 已提交
148
#define decode_delegation_maxsz	(1 + decode_stateid_maxsz + 1 + \
149 150 151
				decode_ace_maxsz)
#define decode_change_info_maxsz	(5)
#define decode_open_maxsz	(op_decode_hdr_maxsz + \
T
Trond Myklebust 已提交
152
				decode_stateid_maxsz + \
153 154 155
				decode_change_info_maxsz + 1 + \
				nfs4_fattr_bitmap_maxsz + \
				decode_delegation_maxsz)
T
Trond Myklebust 已提交
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 193
#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 已提交
194 195
#define encode_remove_maxsz	(op_encode_hdr_maxsz + \
				nfs4_name_maxsz)
196 197
#define decode_remove_maxsz	(op_decode_hdr_maxsz + \
				 decode_change_info_maxsz)
L
Linus Torvalds 已提交
198 199
#define encode_rename_maxsz	(op_encode_hdr_maxsz + \
				2 * nfs4_name_maxsz)
200 201 202
#define decode_rename_maxsz	(op_decode_hdr_maxsz + \
				 decode_change_info_maxsz + \
				 decode_change_info_maxsz)
L
Linus Torvalds 已提交
203 204
#define encode_link_maxsz	(op_encode_hdr_maxsz + \
				nfs4_name_maxsz)
205
#define decode_link_maxsz	(op_decode_hdr_maxsz + decode_change_info_maxsz)
T
Trond Myklebust 已提交
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
#define encode_lock_maxsz	(op_encode_hdr_maxsz + \
				 7 + \
				 1 + encode_stateid_maxsz + 8)
#define decode_lock_denied_maxsz \
				(8 + decode_lockowner_maxsz)
#define decode_lock_maxsz	(op_decode_hdr_maxsz + \
				 decode_lock_denied_maxsz)
#define encode_lockt_maxsz	(op_encode_hdr_maxsz + 12)
#define decode_lockt_maxsz	(op_decode_hdr_maxsz + \
				 decode_lock_denied_maxsz)
#define encode_locku_maxsz	(op_encode_hdr_maxsz + 3 + \
				 encode_stateid_maxsz + \
				 4)
#define decode_locku_maxsz	(op_decode_hdr_maxsz + \
				 decode_stateid_maxsz)
#define encode_access_maxsz	(op_encode_hdr_maxsz + 1)
#define decode_access_maxsz	(op_decode_hdr_maxsz + 2)
L
Linus Torvalds 已提交
223 224
#define encode_symlink_maxsz	(op_encode_hdr_maxsz + \
				1 + nfs4_name_maxsz + \
225
				1 + \
226
				nfs4_fattr_maxsz)
L
Linus Torvalds 已提交
227 228
#define decode_symlink_maxsz	(op_decode_hdr_maxsz + 8)
#define encode_create_maxsz	(op_encode_hdr_maxsz + \
T
Trond Myklebust 已提交
229 230
				1 + 2 + nfs4_name_maxsz + \
				encode_attrs_maxsz)
231 232 233
#define decode_create_maxsz	(op_decode_hdr_maxsz + \
				decode_change_info_maxsz + \
				nfs4_fattr_bitmap_maxsz)
T
Trond Myklebust 已提交
234 235
#define encode_statfs_maxsz	(encode_getattr_maxsz)
#define decode_statfs_maxsz	(decode_getattr_maxsz)
L
Linus Torvalds 已提交
236 237
#define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4)
#define decode_delegreturn_maxsz (op_decode_hdr_maxsz)
T
Trond Myklebust 已提交
238 239 240 241 242 243
#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)
244 245 246 247
#define encode_fs_locations_maxsz \
				(encode_getattr_maxsz)
#define decode_fs_locations_maxsz \
				(0)
248 249

#if defined(CONFIG_NFS_V4_1)
A
Andy Adamson 已提交
250 251
#define NFS4_MAX_MACHINE_NAME_LEN (64)

B
Benny Halevy 已提交
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
#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 已提交
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
#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 已提交
298 299
#define encode_destroy_session_maxsz    (op_encode_hdr_maxsz + 4)
#define decode_destroy_session_maxsz    (op_decode_hdr_maxsz)
A
Andy Adamson 已提交
300 301 302 303
#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)
304 305 306 307 308
#else /* CONFIG_NFS_V4_1 */
#define encode_sequence_maxsz	0
#define decode_sequence_maxsz	0
#endif /* CONFIG_NFS_V4_1 */

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

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 已提交
694
#endif /* CONFIG_NFS_V4_1 */
L
Linus Torvalds 已提交
695

696 697 698 699 700 701 702 703 704 705 706
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 已提交
707 708 709 710 711
};

struct compound_hdr {
	int32_t		status;
	uint32_t	nops;
712
	__be32 *	nops_p;
L
Linus Torvalds 已提交
713 714
	uint32_t	taglen;
	char *		tag;
715
	uint32_t	replen;		/* expected reply words */
716
	u32		minorversion;
L
Linus Torvalds 已提交
717 718
};

719 720 721 722 723 724
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 已提交
725 726 727

static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
{
A
Al Viro 已提交
728
	__be32 *p;
L
Linus Torvalds 已提交
729 730 731 732 733 734

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

735 736 737
static void encode_compound_hdr(struct xdr_stream *xdr,
				struct rpc_rqst *req,
				struct compound_hdr *hdr)
L
Linus Torvalds 已提交
738
{
A
Al Viro 已提交
739
	__be32 *p;
740 741 742 743 744 745
	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 已提交
746 747 748

	dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
	BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
749 750
	p = reserve_space(xdr, 4 + hdr->taglen + 8);
	p = xdr_encode_opaque(p, hdr->tag, hdr->taglen);
B
Benny Halevy 已提交
751
	*p++ = cpu_to_be32(hdr->minorversion);
752
	hdr->nops_p = p;
753
	*p = cpu_to_be32(hdr->nops);
754 755 756 757
}

static void encode_nops(struct compound_hdr *hdr)
{
A
Andy Adamson 已提交
758
	BUG_ON(hdr->nops > NFS4_MAX_OPS);
759
	*hdr->nops_p = htonl(hdr->nops);
L
Linus Torvalds 已提交
760 761 762 763
}

static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
{
A
Al Viro 已提交
764
	__be32 *p;
L
Linus Torvalds 已提交
765 766 767 768 769 770

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

771
static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
L
Linus Torvalds 已提交
772 773 774 775 776
{
	char owner_name[IDMAP_NAMESZ];
	char owner_group[IDMAP_NAMESZ];
	int owner_namelen = 0;
	int owner_grouplen = 0;
A
Al Viro 已提交
777 778
	__be32 *p;
	__be32 *q;
L
Linus Torvalds 已提交
779 780 781 782 783 784 785 786 787
	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
788
	 *            such as owner/group.
L
Linus Torvalds 已提交
789 790 791 792 793 794 795 796 797
	 */
	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) {
798
		owner_namelen = nfs_map_uid_to_name(server->nfs_client, iap->ia_uid, owner_name);
L
Linus Torvalds 已提交
799
		if (owner_namelen < 0) {
800 801
			dprintk("nfs: couldn't resolve uid %d to string\n",
					iap->ia_uid);
L
Linus Torvalds 已提交
802 803 804 805 806 807 808 809
			/* 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) {
810
		owner_grouplen = nfs_map_gid_to_group(server->nfs_client, iap->ia_gid, owner_group);
L
Linus Torvalds 已提交
811
		if (owner_grouplen < 0) {
812 813
			dprintk("nfs: couldn't resolve gid %d to string\n",
					iap->ia_gid);
L
Linus Torvalds 已提交
814 815 816 817 818 819 820 821 822 823 824 825 826 827
			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;
828
	p = reserve_space(xdr, len);
L
Linus Torvalds 已提交
829 830 831 832 833

	/*
	 * 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 已提交
834
	*p++ = cpu_to_be32(2);
L
Linus Torvalds 已提交
835 836 837 838 839
	q = p;
	p += 3;

	if (iap->ia_valid & ATTR_SIZE) {
		bmval0 |= FATTR4_WORD0_SIZE;
B
Benny Halevy 已提交
840
		p = xdr_encode_hyper(p, iap->ia_size);
L
Linus Torvalds 已提交
841 842 843
	}
	if (iap->ia_valid & ATTR_MODE) {
		bmval1 |= FATTR4_WORD1_MODE;
B
Benny Halevy 已提交
844
		*p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO);
L
Linus Torvalds 已提交
845 846 847
	}
	if (iap->ia_valid & ATTR_UID) {
		bmval1 |= FATTR4_WORD1_OWNER;
848
		p = xdr_encode_opaque(p, owner_name, owner_namelen);
L
Linus Torvalds 已提交
849 850 851
	}
	if (iap->ia_valid & ATTR_GID) {
		bmval1 |= FATTR4_WORD1_OWNER_GROUP;
852
		p = xdr_encode_opaque(p, owner_group, owner_grouplen);
L
Linus Torvalds 已提交
853 854 855
	}
	if (iap->ia_valid & ATTR_ATIME_SET) {
		bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
B
Benny Halevy 已提交
856 857 858 859
		*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 已提交
860 861 862
	}
	else if (iap->ia_valid & ATTR_ATIME) {
		bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
B
Benny Halevy 已提交
863
		*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
L
Linus Torvalds 已提交
864 865 866
	}
	if (iap->ia_valid & ATTR_MTIME_SET) {
		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
B
Benny Halevy 已提交
867 868 869 870
		*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 已提交
871 872 873
	}
	else if (iap->ia_valid & ATTR_MTIME) {
		bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
B
Benny Halevy 已提交
874
		*p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
L
Linus Torvalds 已提交
875
	}
876

L
Linus Torvalds 已提交
877 878 879 880
	/*
	 * Now we backfill the bitmap and the attribute buffer length.
	 */
	if (len != ((char *)p - (char *)q) + 4) {
881
		printk(KERN_ERR "nfs: Attr length error, %u != %Zu\n",
L
Linus Torvalds 已提交
882 883 884 885 886 887
				len, ((char *)p - (char *)q) + 4);
		BUG();
	}
	len = (char *)p - (char *)q - 12;
	*q++ = htonl(bmval0);
	*q++ = htonl(bmval1);
888
	*q = htonl(len);
L
Linus Torvalds 已提交
889 890 891 892

/* out: */
}

893
static void encode_access(struct xdr_stream *xdr, u32 access, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
894
{
A
Al Viro 已提交
895
	__be32 *p;
L
Linus Torvalds 已提交
896

897
	p = reserve_space(xdr, 8);
B
Benny Halevy 已提交
898
	*p++ = cpu_to_be32(OP_ACCESS);
899
	*p = cpu_to_be32(access);
900
	hdr->nops++;
901
	hdr->replen += decode_access_maxsz;
L
Linus Torvalds 已提交
902 903
}

904
static void encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
905
{
A
Al Viro 已提交
906
	__be32 *p;
L
Linus Torvalds 已提交
907

908
	p = reserve_space(xdr, 8+NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
909 910
	*p++ = cpu_to_be32(OP_CLOSE);
	*p++ = cpu_to_be32(arg->seqid->sequence->counter);
911
	xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
912
	hdr->nops++;
913
	hdr->replen += decode_close_maxsz;
L
Linus Torvalds 已提交
914 915
}

916
static void encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
917
{
A
Al Viro 已提交
918
	__be32 *p;
919

920
	p = reserve_space(xdr, 16);
B
Benny Halevy 已提交
921
	*p++ = cpu_to_be32(OP_COMMIT);
B
Benny Halevy 已提交
922
	p = xdr_encode_hyper(p, args->offset);
923
	*p = cpu_to_be32(args->count);
924
	hdr->nops++;
925
	hdr->replen += decode_commit_maxsz;
L
Linus Torvalds 已提交
926 927
}

928
static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
929
{
A
Al Viro 已提交
930
	__be32 *p;
931

932
	p = reserve_space(xdr, 8);
B
Benny Halevy 已提交
933
	*p++ = cpu_to_be32(OP_CREATE);
934
	*p = cpu_to_be32(create->ftype);
L
Linus Torvalds 已提交
935 936 937

	switch (create->ftype) {
	case NF4LNK:
938
		p = reserve_space(xdr, 4);
939
		*p = cpu_to_be32(create->u.symlink.len);
940
		xdr_write_pages(xdr, create->u.symlink.pages, 0, create->u.symlink.len);
L
Linus Torvalds 已提交
941 942 943
		break;

	case NF4BLK: case NF4CHR:
944
		p = reserve_space(xdr, 8);
B
Benny Halevy 已提交
945
		*p++ = cpu_to_be32(create->u.device.specdata1);
946
		*p = cpu_to_be32(create->u.device.specdata2);
L
Linus Torvalds 已提交
947 948 949 950 951 952
		break;

	default:
		break;
	}

953
	encode_string(xdr, create->name->len, create->name->name);
954
	hdr->nops++;
955
	hdr->replen += decode_create_maxsz;
L
Linus Torvalds 已提交
956

957
	encode_attrs(xdr, create->attrs, create->server);
L
Linus Torvalds 已提交
958 959
}

960
static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
961
{
A
Andy Adamson 已提交
962
	__be32 *p;
L
Linus Torvalds 已提交
963

964
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
965 966
	*p++ = cpu_to_be32(OP_GETATTR);
	*p++ = cpu_to_be32(1);
967
	*p = cpu_to_be32(bitmap);
968
	hdr->nops++;
969
	hdr->replen += decode_getattr_maxsz;
L
Linus Torvalds 已提交
970 971
}

972
static void encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
973
{
A
Andy Adamson 已提交
974
	__be32 *p;
L
Linus Torvalds 已提交
975

976
	p = reserve_space(xdr, 16);
B
Benny Halevy 已提交
977 978 979
	*p++ = cpu_to_be32(OP_GETATTR);
	*p++ = cpu_to_be32(2);
	*p++ = cpu_to_be32(bm0);
980
	*p = cpu_to_be32(bm1);
981
	hdr->nops++;
982
	hdr->replen += decode_getattr_maxsz;
L
Linus Torvalds 已提交
983 984
}

985
static void encode_getfattr(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
986
{
987 988
	encode_getattr_two(xdr, bitmask[0] & nfs4_fattr_bitmap[0],
			   bitmask[1] & nfs4_fattr_bitmap[1], hdr);
L
Linus Torvalds 已提交
989 990
}

991
static void encode_fsinfo(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
992
{
993 994
	encode_getattr_two(xdr, bitmask[0] & nfs4_fsinfo_bitmap[0],
			   bitmask[1] & nfs4_fsinfo_bitmap[1], hdr);
L
Linus Torvalds 已提交
995 996
}

997
static void encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask, struct compound_hdr *hdr)
998
{
999 1000
	encode_getattr_two(xdr, bitmask[0] & nfs4_fs_locations_bitmap[0],
			   bitmask[1] & nfs4_fs_locations_bitmap[1], hdr);
1001 1002
}

1003
static void encode_getfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1004
{
A
Al Viro 已提交
1005
	__be32 *p;
L
Linus Torvalds 已提交
1006

1007
	p = reserve_space(xdr, 4);
1008
	*p = cpu_to_be32(OP_GETFH);
1009
	hdr->nops++;
1010
	hdr->replen += decode_getfh_maxsz;
L
Linus Torvalds 已提交
1011 1012
}

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

1017
	p = reserve_space(xdr, 8 + name->len);
B
Benny Halevy 已提交
1018
	*p++ = cpu_to_be32(OP_LINK);
1019
	xdr_encode_opaque(p, name->name, name->len);
1020
	hdr->nops++;
1021
	hdr->replen += decode_link_maxsz;
L
Linus Torvalds 已提交
1022 1023
}

T
Trond Myklebust 已提交
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
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;
}

L
Linus Torvalds 已提交
1038 1039 1040 1041
/*
 * opcode,type,reclaim,offset,length,new_lock_owner = 32
 * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
 */
1042
static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1043
{
A
Al Viro 已提交
1044
	__be32 *p;
L
Linus Torvalds 已提交
1045

1046
	p = reserve_space(xdr, 32);
B
Benny Halevy 已提交
1047 1048 1049
	*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 已提交
1050 1051
	p = xdr_encode_hyper(p, args->fl->fl_start);
	p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
1052
	*p = cpu_to_be32(args->new_lock_owner);
T
Trond Myklebust 已提交
1053
	if (args->new_lock_owner){
1054
		p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+32);
B
Benny Halevy 已提交
1055
		*p++ = cpu_to_be32(args->open_seqid->sequence->counter);
B
Benny Halevy 已提交
1056
		p = xdr_encode_opaque_fixed(p, args->open_stateid->data, NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1057
		*p++ = cpu_to_be32(args->lock_seqid->sequence->counter);
B
Benny Halevy 已提交
1058
		p = xdr_encode_hyper(p, args->lock_owner.clientid);
B
Benny Halevy 已提交
1059
		*p++ = cpu_to_be32(16);
B
Benny Halevy 已提交
1060
		p = xdr_encode_opaque_fixed(p, "lock id:", 8);
1061
		xdr_encode_hyper(p, args->lock_owner.id);
L
Linus Torvalds 已提交
1062 1063
	}
	else {
1064
		p = reserve_space(xdr, NFS4_STATEID_SIZE+4);
B
Benny Halevy 已提交
1065
		p = xdr_encode_opaque_fixed(p, args->lock_stateid->data, NFS4_STATEID_SIZE);
1066
		*p = cpu_to_be32(args->lock_seqid->sequence->counter);
L
Linus Torvalds 已提交
1067
	}
1068
	hdr->nops++;
1069
	hdr->replen += decode_lock_maxsz;
L
Linus Torvalds 已提交
1070 1071
}

1072
static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1073
{
A
Al Viro 已提交
1074
	__be32 *p;
L
Linus Torvalds 已提交
1075

1076
	p = reserve_space(xdr, 52);
B
Benny Halevy 已提交
1077 1078
	*p++ = cpu_to_be32(OP_LOCKT);
	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
B
Benny Halevy 已提交
1079 1080 1081
	p = xdr_encode_hyper(p, args->fl->fl_start);
	p = xdr_encode_hyper(p, nfs4_lock_length(args->fl));
	p = xdr_encode_hyper(p, args->lock_owner.clientid);
B
Benny Halevy 已提交
1082
	*p++ = cpu_to_be32(16);
B
Benny Halevy 已提交
1083
	p = xdr_encode_opaque_fixed(p, "lock id:", 8);
1084
	xdr_encode_hyper(p, args->lock_owner.id);
1085
	hdr->nops++;
1086
	hdr->replen += decode_lockt_maxsz;
L
Linus Torvalds 已提交
1087 1088
}

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

1093
	p = reserve_space(xdr, 12+NFS4_STATEID_SIZE+16);
B
Benny Halevy 已提交
1094 1095 1096
	*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 已提交
1097
	p = xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1098
	p = xdr_encode_hyper(p, args->fl->fl_start);
1099
	xdr_encode_hyper(p, nfs4_lock_length(args->fl));
1100
	hdr->nops++;
1101
	hdr->replen += decode_locku_maxsz;
L
Linus Torvalds 已提交
1102 1103
}

1104
static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1105 1106
{
	int len = name->len;
A
Al Viro 已提交
1107
	__be32 *p;
L
Linus Torvalds 已提交
1108

1109
	p = reserve_space(xdr, 8 + len);
B
Benny Halevy 已提交
1110
	*p++ = cpu_to_be32(OP_LOOKUP);
1111
	xdr_encode_opaque(p, name->name, len);
1112
	hdr->nops++;
1113
	hdr->replen += decode_lookup_maxsz;
L
Linus Torvalds 已提交
1114 1115
}

1116
static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode)
L
Linus Torvalds 已提交
1117
{
A
Al Viro 已提交
1118
	__be32 *p;
L
Linus Torvalds 已提交
1119

1120
	p = reserve_space(xdr, 8);
1121
	switch (fmode & (FMODE_READ|FMODE_WRITE)) {
A
Andy Adamson 已提交
1122
	case FMODE_READ:
B
Benny Halevy 已提交
1123
		*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_READ);
A
Andy Adamson 已提交
1124 1125
		break;
	case FMODE_WRITE:
B
Benny Halevy 已提交
1126
		*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_WRITE);
A
Andy Adamson 已提交
1127 1128
		break;
	case FMODE_READ|FMODE_WRITE:
B
Benny Halevy 已提交
1129
		*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_BOTH);
A
Andy Adamson 已提交
1130 1131
		break;
	default:
B
Benny Halevy 已提交
1132
		*p++ = cpu_to_be32(0);
L
Linus Torvalds 已提交
1133
	}
1134
	*p = cpu_to_be32(0);		/* for linux, share_deny = 0 always */
L
Linus Torvalds 已提交
1135 1136 1137 1138
}

static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg)
{
A
Al Viro 已提交
1139
	__be32 *p;
L
Linus Torvalds 已提交
1140 1141 1142 1143
 /*
 * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
 * owner 4 = 32
 */
1144
	p = reserve_space(xdr, 8);
B
Benny Halevy 已提交
1145
	*p++ = cpu_to_be32(OP_OPEN);
1146
	*p = cpu_to_be32(arg->seqid->sequence->counter);
1147
	encode_share_access(xdr, arg->fmode);
1148
	p = reserve_space(xdr, 28);
B
Benny Halevy 已提交
1149
	p = xdr_encode_hyper(p, arg->clientid);
B
Benny Halevy 已提交
1150
	*p++ = cpu_to_be32(16);
B
Benny Halevy 已提交
1151
	p = xdr_encode_opaque_fixed(p, "open id:", 8);
1152
	xdr_encode_hyper(p, arg->id);
L
Linus Torvalds 已提交
1153 1154 1155 1156
}

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

1160
	p = reserve_space(xdr, 4);
L
Linus Torvalds 已提交
1161
	switch(arg->open_flags & O_EXCL) {
A
Andy Adamson 已提交
1162
	case 0:
1163
		*p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
A
Andy Adamson 已提交
1164 1165 1166
		encode_attrs(xdr, arg->u.attrs, arg->server);
		break;
	default:
1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183
		clp = arg->server->nfs_client;
		if (clp->cl_minorversion > 0) {
			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 已提交
1184 1185 1186 1187 1188
	}
}

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

1191
	p = reserve_space(xdr, 4);
L
Linus Torvalds 已提交
1192
	switch (arg->open_flags & O_CREAT) {
A
Andy Adamson 已提交
1193
	case 0:
1194
		*p = cpu_to_be32(NFS4_OPEN_NOCREATE);
A
Andy Adamson 已提交
1195 1196 1197
		break;
	default:
		BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL);
1198
		*p = cpu_to_be32(NFS4_OPEN_CREATE);
A
Andy Adamson 已提交
1199
		encode_createmode(xdr, arg);
L
Linus Torvalds 已提交
1200 1201 1202
	}
}

1203
static inline void encode_delegation_type(struct xdr_stream *xdr, fmode_t delegation_type)
L
Linus Torvalds 已提交
1204
{
A
Al Viro 已提交
1205
	__be32 *p;
L
Linus Torvalds 已提交
1206

1207
	p = reserve_space(xdr, 4);
L
Linus Torvalds 已提交
1208
	switch (delegation_type) {
A
Andy Adamson 已提交
1209
	case 0:
1210
		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_NONE);
A
Andy Adamson 已提交
1211 1212
		break;
	case FMODE_READ:
1213
		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_READ);
A
Andy Adamson 已提交
1214 1215
		break;
	case FMODE_WRITE|FMODE_READ:
1216
		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_WRITE);
A
Andy Adamson 已提交
1217 1218 1219
		break;
	default:
		BUG();
L
Linus Torvalds 已提交
1220 1221 1222 1223 1224
	}
}

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

1227
	p = reserve_space(xdr, 4);
1228
	*p = cpu_to_be32(NFS4_OPEN_CLAIM_NULL);
L
Linus Torvalds 已提交
1229 1230 1231
	encode_string(xdr, name->len, name->name);
}

1232
static inline void encode_claim_previous(struct xdr_stream *xdr, fmode_t type)
L
Linus Torvalds 已提交
1233
{
A
Al Viro 已提交
1234
	__be32 *p;
L
Linus Torvalds 已提交
1235

1236
	p = reserve_space(xdr, 4);
1237
	*p = cpu_to_be32(NFS4_OPEN_CLAIM_PREVIOUS);
L
Linus Torvalds 已提交
1238 1239 1240 1241 1242
	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 已提交
1243
	__be32 *p;
L
Linus Torvalds 已提交
1244

1245
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1246
	*p++ = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
1247
	xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1248 1249 1250
	encode_string(xdr, name->len, name->name);
}

1251
static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1252 1253 1254 1255
{
	encode_openhdr(xdr, arg);
	encode_opentype(xdr, arg);
	switch (arg->claim) {
A
Andy Adamson 已提交
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
	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 已提交
1267
	}
1268
	hdr->nops++;
1269
	hdr->replen += decode_open_maxsz;
L
Linus Torvalds 已提交
1270 1271
}

1272
static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1273
{
A
Al Viro 已提交
1274
	__be32 *p;
L
Linus Torvalds 已提交
1275

1276
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
B
Benny Halevy 已提交
1277
	*p++ = cpu_to_be32(OP_OPEN_CONFIRM);
B
Benny Halevy 已提交
1278
	p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
1279
	*p = cpu_to_be32(arg->seqid->sequence->counter);
1280
	hdr->nops++;
1281
	hdr->replen += decode_open_confirm_maxsz;
L
Linus Torvalds 已提交
1282 1283
}

1284
static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1285
{
A
Al Viro 已提交
1286
	__be32 *p;
L
Linus Torvalds 已提交
1287

1288
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
B
Benny Halevy 已提交
1289
	*p++ = cpu_to_be32(OP_OPEN_DOWNGRADE);
B
Benny Halevy 已提交
1290
	p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
1291
	*p = cpu_to_be32(arg->seqid->sequence->counter);
1292
	encode_share_access(xdr, arg->fmode);
1293
	hdr->nops++;
1294
	hdr->replen += decode_open_downgrade_maxsz;
L
Linus Torvalds 已提交
1295 1296
}

1297
static void
1298
encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1299 1300
{
	int len = fh->size;
A
Al Viro 已提交
1301
	__be32 *p;
L
Linus Torvalds 已提交
1302

1303
	p = reserve_space(xdr, 8 + len);
B
Benny Halevy 已提交
1304
	*p++ = cpu_to_be32(OP_PUTFH);
1305
	xdr_encode_opaque(p, fh->data, len);
1306
	hdr->nops++;
1307
	hdr->replen += decode_putfh_maxsz;
L
Linus Torvalds 已提交
1308 1309
}

1310
static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1311
{
A
Andy Adamson 已提交
1312
	__be32 *p;
1313

1314
	p = reserve_space(xdr, 4);
1315
	*p = cpu_to_be32(OP_PUTROOTFH);
1316
	hdr->nops++;
1317
	hdr->replen += decode_putrootfh_maxsz;
L
Linus Torvalds 已提交
1318 1319 1320 1321 1322
}

static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx)
{
	nfs4_stateid stateid;
A
Al Viro 已提交
1323
	__be32 *p;
L
Linus Torvalds 已提交
1324

1325
	p = reserve_space(xdr, NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1326 1327
	if (ctx->state != NULL) {
		nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner);
1328
		xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1329
	} else
1330
		xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1331 1332
}

1333
static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1334
{
A
Al Viro 已提交
1335
	__be32 *p;
L
Linus Torvalds 已提交
1336

1337
	p = reserve_space(xdr, 4);
1338
	*p = cpu_to_be32(OP_READ);
L
Linus Torvalds 已提交
1339 1340 1341

	encode_stateid(xdr, args->context);

1342
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
1343
	p = xdr_encode_hyper(p, args->offset);
1344
	*p = cpu_to_be32(args->count);
1345
	hdr->nops++;
1346
	hdr->replen += decode_read_maxsz;
L
Linus Torvalds 已提交
1347 1348
}

1349
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 已提交
1350
{
1351 1352 1353 1354
	uint32_t attrs[2] = {
		FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID,
		FATTR4_WORD1_MOUNTED_ON_FILEID,
	};
A
Al Viro 已提交
1355
	__be32 *p;
L
Linus Torvalds 已提交
1356

1357
	p = reserve_space(xdr, 12+NFS4_VERIFIER_SIZE+20);
B
Benny Halevy 已提交
1358
	*p++ = cpu_to_be32(OP_READDIR);
B
Benny Halevy 已提交
1359
	p = xdr_encode_hyper(p, readdir->cookie);
B
Benny Halevy 已提交
1360
	p = xdr_encode_opaque_fixed(p, readdir->verifier.data, NFS4_VERIFIER_SIZE);
B
Benny Halevy 已提交
1361 1362 1363
	*p++ = cpu_to_be32(readdir->count >> 1);  /* We're not doing readdirplus */
	*p++ = cpu_to_be32(readdir->count);
	*p++ = cpu_to_be32(2);
1364 1365 1366 1367 1368
	/* 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 已提交
1369
	*p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]);
1370
	*p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
1371
	hdr->nops++;
1372
	hdr->replen += decode_readdir_maxsz;
1373 1374
	dprintk("%s: cookie = %Lu, verifier = %08x:%08x, bitmap = %08x:%08x\n",
			__func__,
1375 1376 1377 1378 1379
			(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 已提交
1380 1381
}

1382
static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1383
{
A
Al Viro 已提交
1384
	__be32 *p;
L
Linus Torvalds 已提交
1385

1386
	p = reserve_space(xdr, 4);
1387
	*p = cpu_to_be32(OP_READLINK);
1388
	hdr->nops++;
1389
	hdr->replen += decode_readlink_maxsz;
L
Linus Torvalds 已提交
1390 1391
}

1392
static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1393
{
A
Al Viro 已提交
1394
	__be32 *p;
L
Linus Torvalds 已提交
1395

1396
	p = reserve_space(xdr, 8 + name->len);
B
Benny Halevy 已提交
1397
	*p++ = cpu_to_be32(OP_REMOVE);
1398
	xdr_encode_opaque(p, name->name, name->len);
1399
	hdr->nops++;
1400
	hdr->replen += decode_remove_maxsz;
L
Linus Torvalds 已提交
1401 1402
}

1403
static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1404
{
A
Al Viro 已提交
1405
	__be32 *p;
L
Linus Torvalds 已提交
1406

1407 1408 1409 1410
	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);
1411
	hdr->nops++;
1412
	hdr->replen += decode_rename_maxsz;
L
Linus Torvalds 已提交
1413 1414
}

1415
static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1416
{
A
Al Viro 已提交
1417
	__be32 *p;
L
Linus Torvalds 已提交
1418

1419
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
1420
	*p++ = cpu_to_be32(OP_RENEW);
1421
	xdr_encode_hyper(p, client_stateid->cl_clientid);
1422
	hdr->nops++;
1423
	hdr->replen += decode_renew_maxsz;
L
Linus Torvalds 已提交
1424 1425
}

1426
static void
1427
encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
1428
{
A
Al Viro 已提交
1429
	__be32 *p;
1430

1431
	p = reserve_space(xdr, 4);
1432
	*p = cpu_to_be32(OP_RESTOREFH);
1433
	hdr->nops++;
1434
	hdr->replen += decode_restorefh_maxsz;
1435 1436
}

1437
static int
1438
encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compound_hdr *hdr)
1439
{
A
Al Viro 已提交
1440
	__be32 *p;
1441

1442
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1443
	*p++ = cpu_to_be32(OP_SETATTR);
1444
	xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
1445
	p = reserve_space(xdr, 2*4);
B
Benny Halevy 已提交
1446
	*p++ = cpu_to_be32(1);
1447
	*p = cpu_to_be32(FATTR4_WORD0_ACL);
1448 1449
	if (arg->acl_len % 4)
		return -EINVAL;
1450
	p = reserve_space(xdr, 4);
1451
	*p = cpu_to_be32(arg->acl_len);
1452
	xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
1453
	hdr->nops++;
1454
	hdr->replen += decode_setacl_maxsz;
1455 1456 1457
	return 0;
}

1458
static void
1459
encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1460
{
A
Al Viro 已提交
1461
	__be32 *p;
L
Linus Torvalds 已提交
1462

1463
	p = reserve_space(xdr, 4);
1464
	*p = cpu_to_be32(OP_SAVEFH);
1465
	hdr->nops++;
1466
	hdr->replen += decode_savefh_maxsz;
L
Linus Torvalds 已提交
1467 1468
}

1469
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 已提交
1470
{
A
Al Viro 已提交
1471
	__be32 *p;
1472

1473
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1474
	*p++ = cpu_to_be32(OP_SETATTR);
1475
	xdr_encode_opaque_fixed(p, arg->stateid.data, NFS4_STATEID_SIZE);
1476
	hdr->nops++;
1477
	hdr->replen += decode_setattr_maxsz;
1478
	encode_attrs(xdr, arg->iap, server);
L
Linus Torvalds 已提交
1479 1480
}

1481
static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1482
{
A
Al Viro 已提交
1483
	__be32 *p;
L
Linus Torvalds 已提交
1484

1485
	p = reserve_space(xdr, 4 + NFS4_VERIFIER_SIZE);
B
Benny Halevy 已提交
1486
	*p++ = cpu_to_be32(OP_SETCLIENTID);
1487
	xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE);
L
Linus Torvalds 已提交
1488 1489

	encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
1490
	p = reserve_space(xdr, 4);
1491
	*p = cpu_to_be32(setclientid->sc_prog);
L
Linus Torvalds 已提交
1492 1493
	encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid);
	encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
1494
	p = reserve_space(xdr, 4);
1495
	*p = cpu_to_be32(setclientid->sc_cb_ident);
1496
	hdr->nops++;
1497
	hdr->replen += decode_setclientid_maxsz;
L
Linus Torvalds 已提交
1498 1499
}

1500
static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1501
{
A
Andy Adamson 已提交
1502
	__be32 *p;
L
Linus Torvalds 已提交
1503

1504
	p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE);
B
Benny Halevy 已提交
1505
	*p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM);
B
Benny Halevy 已提交
1506
	p = xdr_encode_hyper(p, client_state->cl_clientid);
1507
	xdr_encode_opaque_fixed(p, client_state->cl_confirm.data, NFS4_VERIFIER_SIZE);
1508
	hdr->nops++;
1509
	hdr->replen += decode_setclientid_confirm_maxsz;
L
Linus Torvalds 已提交
1510 1511
}

1512
static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1513
{
A
Al Viro 已提交
1514
	__be32 *p;
L
Linus Torvalds 已提交
1515

1516
	p = reserve_space(xdr, 4);
1517
	*p = cpu_to_be32(OP_WRITE);
L
Linus Torvalds 已提交
1518 1519 1520

	encode_stateid(xdr, args->context);

1521
	p = reserve_space(xdr, 16);
B
Benny Halevy 已提交
1522
	p = xdr_encode_hyper(p, args->offset);
B
Benny Halevy 已提交
1523
	*p++ = cpu_to_be32(args->stable);
1524
	*p = cpu_to_be32(args->count);
L
Linus Torvalds 已提交
1525 1526

	xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
1527
	hdr->nops++;
1528
	hdr->replen += decode_write_maxsz;
L
Linus Torvalds 已提交
1529 1530
}

1531
static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1532
{
A
Al Viro 已提交
1533
	__be32 *p;
L
Linus Torvalds 已提交
1534

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

B
Benny Halevy 已提交
1537
	*p++ = cpu_to_be32(OP_DELEGRETURN);
1538
	xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
1539
	hdr->nops++;
1540
	hdr->replen += decode_delegreturn_maxsz;
L
Linus Torvalds 已提交
1541
}
1542

B
Benny Halevy 已提交
1543
#if defined(CONFIG_NFS_V4_1)
1544
/* NFSv4.1 operations */
B
Benny Halevy 已提交
1545 1546 1547 1548 1549 1550
static void encode_exchange_id(struct xdr_stream *xdr,
			       struct nfs41_exchange_id_args *args,
			       struct compound_hdr *hdr)
{
	__be32 *p;

1551
	p = reserve_space(xdr, 4 + sizeof(args->verifier->data));
B
Benny Halevy 已提交
1552
	*p++ = cpu_to_be32(OP_EXCHANGE_ID);
1553
	xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data));
B
Benny Halevy 已提交
1554 1555 1556

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

1557
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
1558 1559
	*p++ = cpu_to_be32(args->flags);
	*p++ = cpu_to_be32(0);	/* zero length state_protect4_a */
1560
	*p = cpu_to_be32(0);	/* zero length implementation id array */
B
Benny Halevy 已提交
1561 1562 1563
	hdr->nops++;
	hdr->replen += decode_exchange_id_maxsz;
}
A
Andy Adamson 已提交
1564 1565 1566 1567 1568 1569 1570 1571 1572 1573

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;

1574 1575
	len = scnprintf(machine_name, sizeof(machine_name), "%s",
			clp->cl_ipaddr);
A
Andy Adamson 已提交
1576

1577
	p = reserve_space(xdr, 20 + 2*28 + 20 + len + 12);
1578
	*p++ = cpu_to_be32(OP_CREATE_SESSION);
B
Benny Halevy 已提交
1579
	p = xdr_encode_hyper(p, clp->cl_ex_clid);
B
Benny Halevy 已提交
1580 1581
	*p++ = cpu_to_be32(clp->cl_seqid);			/*Sequence id */
	*p++ = cpu_to_be32(args->flags);			/*flags */
A
Andy Adamson 已提交
1582 1583

	/* Fore Channel */
B
Benny Halevy 已提交
1584 1585 1586 1587 1588 1589 1590
	*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 */
	*p++ = cpu_to_be32(args->fc_attrs.max_resp_sz_cached);	/* Max resp sz cached */
	*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 已提交
1591 1592

	/* Back Channel */
B
Benny Halevy 已提交
1593 1594 1595 1596 1597 1598 1599
	*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 已提交
1600

B
Benny Halevy 已提交
1601 1602 1603
	*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 已提交
1604 1605

	/* authsys_parms rfc1831 */
B
Benny Halevy 已提交
1606
	*p++ = cpu_to_be32((u32)clp->cl_boot_time.tv_nsec);	/* stamp */
1607
	p = xdr_encode_opaque(p, machine_name, len);
B
Benny Halevy 已提交
1608 1609
	*p++ = cpu_to_be32(0);				/* UID */
	*p++ = cpu_to_be32(0);				/* GID */
1610
	*p = cpu_to_be32(0);				/* No more gids */
A
Andy Adamson 已提交
1611 1612 1613
	hdr->nops++;
	hdr->replen += decode_create_session_maxsz;
}
A
Andy Adamson 已提交
1614 1615 1616 1617 1618 1619

static void encode_destroy_session(struct xdr_stream *xdr,
				   struct nfs4_session *session,
				   struct compound_hdr *hdr)
{
	__be32 *p;
1620
	p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN);
B
Benny Halevy 已提交
1621
	*p++ = cpu_to_be32(OP_DESTROY_SESSION);
1622
	xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
A
Andy Adamson 已提交
1623 1624 1625
	hdr->nops++;
	hdr->replen += decode_destroy_session_maxsz;
}
B
Benny Halevy 已提交
1626 1627
#endif /* CONFIG_NFS_V4_1 */

1628 1629 1630 1631 1632 1633
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 已提交
1634 1635 1636
	struct nfs4_slot_table *tp;
	struct nfs4_slot *slot;
	__be32 *p;
1637 1638 1639 1640

	if (!session)
		return;

A
Andy Adamson 已提交
1641 1642 1643 1644 1645
	tp = &session->fc_slot_table;

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

1646
	p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN + 16);
B
Benny Halevy 已提交
1647
	*p++ = cpu_to_be32(OP_SEQUENCE);
A
Andy Adamson 已提交
1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660

	/*
	 * 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 已提交
1661
	p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
B
Benny Halevy 已提交
1662 1663 1664
	*p++ = cpu_to_be32(slot->seq_nr);
	*p++ = cpu_to_be32(args->sa_slotid);
	*p++ = cpu_to_be32(tp->highest_used_slotid);
1665
	*p = cpu_to_be32(args->sa_cache_this);
1666 1667 1668 1669 1670
	hdr->nops++;
	hdr->replen += decode_sequence_maxsz;
#endif /* CONFIG_NFS_V4_1 */
}

L
Linus Torvalds 已提交
1671 1672 1673 1674
/*
 * END OF "GENERIC" ENCODE ROUTINES.
 */

1675 1676 1677 1678 1679 1680 1681 1682 1683
static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args)
{
#if defined(CONFIG_NFS_V4_1)
	if (args->sa_session)
		return args->sa_session->clp->cl_minorversion;
#endif /* CONFIG_NFS_V4_1 */
	return 0;
}

L
Linus Torvalds 已提交
1684 1685 1686
/*
 * Encode an ACCESS request
 */
A
Al Viro 已提交
1687
static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs4_accessargs *args)
L
Linus Torvalds 已提交
1688 1689 1690
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1691
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1692 1693 1694
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1695
	encode_compound_hdr(&xdr, req, &hdr);
1696
	encode_sequence(&xdr, &args->seq_args, &hdr);
1697 1698 1699
	encode_putfh(&xdr, args->fh, &hdr);
	encode_access(&xdr, args->access, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1700
	encode_nops(&hdr);
1701
	return 0;
L
Linus Torvalds 已提交
1702 1703 1704 1705 1706
}

/*
 * Encode LOOKUP request
 */
A
Al Viro 已提交
1707
static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_arg *args)
L
Linus Torvalds 已提交
1708 1709 1710
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1711
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1712 1713 1714
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1715
	encode_compound_hdr(&xdr, req, &hdr);
1716
	encode_sequence(&xdr, &args->seq_args, &hdr);
1717 1718 1719 1720
	encode_putfh(&xdr, args->dir_fh, &hdr);
	encode_lookup(&xdr, args->name, &hdr);
	encode_getfh(&xdr, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1721
	encode_nops(&hdr);
1722
	return 0;
L
Linus Torvalds 已提交
1723 1724 1725 1726 1727
}

/*
 * Encode LOOKUP_ROOT request
 */
A
Al Viro 已提交
1728
static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_root_arg *args)
L
Linus Torvalds 已提交
1729 1730 1731
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1732
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1733 1734 1735
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1736
	encode_compound_hdr(&xdr, req, &hdr);
1737
	encode_sequence(&xdr, &args->seq_args, &hdr);
1738 1739 1740
	encode_putrootfh(&xdr, &hdr);
	encode_getfh(&xdr, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1741
	encode_nops(&hdr);
1742
	return 0;
L
Linus Torvalds 已提交
1743 1744 1745 1746 1747
}

/*
 * Encode REMOVE request
 */
1748
static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
L
Linus Torvalds 已提交
1749 1750 1751
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1752
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1753 1754 1755
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1756
	encode_compound_hdr(&xdr, req, &hdr);
1757
	encode_sequence(&xdr, &args->seq_args, &hdr);
1758 1759 1760
	encode_putfh(&xdr, args->fh, &hdr);
	encode_remove(&xdr, &args->name, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1761
	encode_nops(&hdr);
1762
	return 0;
L
Linus Torvalds 已提交
1763 1764 1765 1766 1767
}

/*
 * Encode RENAME request
 */
A
Al Viro 已提交
1768
static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs4_rename_arg *args)
L
Linus Torvalds 已提交
1769 1770 1771
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1772
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1773 1774 1775
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1776
	encode_compound_hdr(&xdr, req, &hdr);
1777
	encode_sequence(&xdr, &args->seq_args, &hdr);
1778 1779 1780 1781 1782 1783 1784
	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);
1785
	encode_nops(&hdr);
1786
	return 0;
L
Linus Torvalds 已提交
1787 1788 1789 1790 1791
}

/*
 * Encode LINK request
 */
A
Al Viro 已提交
1792
static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_link_arg *args)
L
Linus Torvalds 已提交
1793 1794 1795
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1796
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1797 1798 1799
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1800
	encode_compound_hdr(&xdr, req, &hdr);
1801
	encode_sequence(&xdr, &args->seq_args, &hdr);
1802 1803 1804 1805 1806 1807 1808
	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);
1809
	encode_nops(&hdr);
1810
	return 0;
L
Linus Torvalds 已提交
1811 1812 1813 1814 1815
}

/*
 * Encode CREATE request
 */
A
Al Viro 已提交
1816
static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
L
Linus Torvalds 已提交
1817 1818 1819
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1820
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1821 1822 1823
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1824
	encode_compound_hdr(&xdr, req, &hdr);
1825
	encode_sequence(&xdr, &args->seq_args, &hdr);
1826 1827 1828 1829 1830 1831 1832
	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);
1833
	encode_nops(&hdr);
1834
	return 0;
L
Linus Torvalds 已提交
1835 1836 1837 1838 1839
}

/*
 * Encode SYMLINK request
 */
A
Al Viro 已提交
1840
static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
L
Linus Torvalds 已提交
1841 1842 1843 1844 1845 1846 1847
{
	return nfs4_xdr_enc_create(req, p, args);
}

/*
 * Encode GETATTR request
 */
A
Al Viro 已提交
1848
static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nfs4_getattr_arg *args)
L
Linus Torvalds 已提交
1849 1850 1851
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1852
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1853 1854 1855
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1856
	encode_compound_hdr(&xdr, req, &hdr);
1857
	encode_sequence(&xdr, &args->seq_args, &hdr);
1858 1859
	encode_putfh(&xdr, args->fh, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1860
	encode_nops(&hdr);
1861
	return 0;
L
Linus Torvalds 已提交
1862 1863 1864 1865 1866
}

/*
 * Encode a CLOSE request
 */
A
Al Viro 已提交
1867
static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
L
Linus Torvalds 已提交
1868
{
A
Andy Adamson 已提交
1869 1870
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1871
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
A
Andy Adamson 已提交
1872 1873 1874
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1875
	encode_compound_hdr(&xdr, req, &hdr);
1876
	encode_sequence(&xdr, &args->seq_args, &hdr);
1877 1878 1879
	encode_putfh(&xdr, args->fh, &hdr);
	encode_close(&xdr, args, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1880
	encode_nops(&hdr);
1881
	return 0;
L
Linus Torvalds 已提交
1882 1883 1884 1885 1886
}

/*
 * Encode an OPEN request
 */
A
Al Viro 已提交
1887
static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
L
Linus Torvalds 已提交
1888 1889 1890
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1891
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1892 1893 1894
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1895
	encode_compound_hdr(&xdr, req, &hdr);
1896
	encode_sequence(&xdr, &args->seq_args, &hdr);
1897 1898 1899 1900 1901 1902 1903
	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);
1904
	encode_nops(&hdr);
1905
	return 0;
L
Linus Torvalds 已提交
1906 1907 1908 1909 1910
}

/*
 * Encode an OPEN_CONFIRM request
 */
A
Al Viro 已提交
1911
static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_open_confirmargs *args)
L
Linus Torvalds 已提交
1912 1913 1914
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1915
		.nops   = 0,
L
Linus Torvalds 已提交
1916 1917 1918
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1919
	encode_compound_hdr(&xdr, req, &hdr);
1920 1921
	encode_putfh(&xdr, args->fh, &hdr);
	encode_open_confirm(&xdr, args, &hdr);
1922
	encode_nops(&hdr);
1923
	return 0;
L
Linus Torvalds 已提交
1924 1925 1926 1927 1928
}

/*
 * Encode an OPEN request with no attributes.
 */
A
Al Viro 已提交
1929
static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
L
Linus Torvalds 已提交
1930 1931 1932
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1933
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1934 1935 1936
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1937
	encode_compound_hdr(&xdr, req, &hdr);
1938
	encode_sequence(&xdr, &args->seq_args, &hdr);
1939 1940 1941
	encode_putfh(&xdr, args->fh, &hdr);
	encode_open(&xdr, args, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1942
	encode_nops(&hdr);
1943
	return 0;
L
Linus Torvalds 已提交
1944 1945 1946 1947 1948
}

/*
 * Encode an OPEN_DOWNGRADE request
 */
A
Al Viro 已提交
1949
static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
L
Linus Torvalds 已提交
1950 1951 1952
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1953
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1954 1955 1956
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1957
	encode_compound_hdr(&xdr, req, &hdr);
1958
	encode_sequence(&xdr, &args->seq_args, &hdr);
1959 1960 1961
	encode_putfh(&xdr, args->fh, &hdr);
	encode_open_downgrade(&xdr, args, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1962
	encode_nops(&hdr);
1963
	return 0;
L
Linus Torvalds 已提交
1964 1965 1966 1967 1968
}

/*
 * Encode a LOCK request
 */
A
Al Viro 已提交
1969
static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_args *args)
L
Linus Torvalds 已提交
1970 1971 1972
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1973
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1974 1975 1976
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1977
	encode_compound_hdr(&xdr, req, &hdr);
1978
	encode_sequence(&xdr, &args->seq_args, &hdr);
1979 1980
	encode_putfh(&xdr, args->fh, &hdr);
	encode_lock(&xdr, args, &hdr);
1981
	encode_nops(&hdr);
1982
	return 0;
L
Linus Torvalds 已提交
1983 1984 1985 1986 1987
}

/*
 * Encode a LOCKT request
 */
A
Al Viro 已提交
1988
static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_args *args)
L
Linus Torvalds 已提交
1989 1990 1991
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1992
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1993 1994 1995
	};

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

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

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

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

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2034
	encode_compound_hdr(&xdr, req, &hdr);
2035
	encode_sequence(&xdr, &args->seq_args, &hdr);
2036 2037
	encode_putfh(&xdr, args->fh, &hdr);
	encode_readlink(&xdr, args, req, &hdr);
2038

2039
	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
2040
			args->pgbase, args->pglen);
2041
	encode_nops(&hdr);
2042
	return 0;
L
Linus Torvalds 已提交
2043 2044 2045 2046 2047
}

/*
 * Encode a READDIR request
 */
A
Al Viro 已提交
2048
static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nfs4_readdir_arg *args)
L
Linus Torvalds 已提交
2049 2050 2051
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2052
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2053 2054 2055
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2056
	encode_compound_hdr(&xdr, req, &hdr);
2057
	encode_sequence(&xdr, &args->seq_args, &hdr);
2058 2059
	encode_putfh(&xdr, args->fh, &hdr);
	encode_readdir(&xdr, args, req, &hdr);
2060

2061
	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
2062 2063
			 args->pgbase, args->count);
	dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
2064
			__func__, hdr.replen << 2, args->pages,
2065
			args->pgbase, args->count);
2066
	encode_nops(&hdr);
2067
	return 0;
L
Linus Torvalds 已提交
2068 2069 2070 2071 2072
}

/*
 * Encode a READ request
 */
A
Al Viro 已提交
2073
static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
L
Linus Torvalds 已提交
2074 2075 2076
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2077
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2078 2079 2080
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2081
	encode_compound_hdr(&xdr, req, &hdr);
2082
	encode_sequence(&xdr, &args->seq_args, &hdr);
2083 2084
	encode_putfh(&xdr, args->fh, &hdr);
	encode_read(&xdr, args, &hdr);
L
Linus Torvalds 已提交
2085

2086
	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2,
L
Linus Torvalds 已提交
2087
			 args->pages, args->pgbase, args->count);
2088
	req->rq_rcv_buf.flags |= XDRBUF_READ;
2089
	encode_nops(&hdr);
2090
	return 0;
L
Linus Torvalds 已提交
2091 2092 2093 2094 2095
}

/*
 * Encode an SETATTR request
 */
A
Al Viro 已提交
2096
static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args)
L
Linus Torvalds 已提交
2097
{
A
Andy Adamson 已提交
2098 2099
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2100
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
A
Andy Adamson 已提交
2101 2102 2103
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2104
	encode_compound_hdr(&xdr, req, &hdr);
2105
	encode_sequence(&xdr, &args->seq_args, &hdr);
2106 2107 2108
	encode_putfh(&xdr, args->fh, &hdr);
	encode_setattr(&xdr, args, args->server, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
2109
	encode_nops(&hdr);
2110
	return 0;
L
Linus Torvalds 已提交
2111 2112
}

2113 2114 2115 2116
/*
 * Encode a GETACL request
 */
static int
A
Al Viro 已提交
2117
nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
2118 2119 2120 2121
		struct nfs_getaclargs *args)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2122
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
2123
	};
2124
	uint32_t replen;
2125 2126

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2127
	encode_compound_hdr(&xdr, req, &hdr);
2128
	encode_sequence(&xdr, &args->seq_args, &hdr);
2129
	encode_putfh(&xdr, args->fh, &hdr);
2130
	replen = hdr.replen + op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz + 1;
2131 2132
	encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr);

2133
	xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
2134
		args->acl_pages, args->acl_pgbase, args->acl_len);
2135
	encode_nops(&hdr);
2136
	return 0;
2137 2138
}

L
Linus Torvalds 已提交
2139 2140 2141
/*
 * Encode a WRITE request
 */
A
Al Viro 已提交
2142
static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
L
Linus Torvalds 已提交
2143 2144 2145
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2146
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2147 2148 2149
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2150
	encode_compound_hdr(&xdr, req, &hdr);
2151
	encode_sequence(&xdr, &args->seq_args, &hdr);
2152 2153
	encode_putfh(&xdr, args->fh, &hdr);
	encode_write(&xdr, args, &hdr);
2154
	req->rq_snd_buf.flags |= XDRBUF_WRITE;
2155
	encode_getfattr(&xdr, args->bitmask, &hdr);
2156
	encode_nops(&hdr);
2157
	return 0;
L
Linus Torvalds 已提交
2158 2159 2160 2161 2162
}

/*
 *  a COMMIT request
 */
A
Al Viro 已提交
2163
static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
L
Linus Torvalds 已提交
2164 2165 2166
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2167
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2168 2169 2170
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2171
	encode_compound_hdr(&xdr, req, &hdr);
2172
	encode_sequence(&xdr, &args->seq_args, &hdr);
2173 2174 2175
	encode_putfh(&xdr, args->fh, &hdr);
	encode_commit(&xdr, args, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
2176
	encode_nops(&hdr);
2177
	return 0;
L
Linus Torvalds 已提交
2178 2179 2180 2181 2182
}

/*
 * FSINFO request
 */
A
Al Viro 已提交
2183
static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsinfo_arg *args)
L
Linus Torvalds 已提交
2184 2185 2186
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2187
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2188 2189 2190
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2191
	encode_compound_hdr(&xdr, req, &hdr);
2192
	encode_sequence(&xdr, &args->seq_args, &hdr);
2193 2194
	encode_putfh(&xdr, args->fh, &hdr);
	encode_fsinfo(&xdr, args->bitmask, &hdr);
2195
	encode_nops(&hdr);
2196
	return 0;
L
Linus Torvalds 已提交
2197 2198 2199 2200 2201
}

/*
 * a PATHCONF request
 */
A
Al Viro 已提交
2202
static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct nfs4_pathconf_arg *args)
L
Linus Torvalds 已提交
2203 2204 2205
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2206
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2207 2208 2209
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2210
	encode_compound_hdr(&xdr, req, &hdr);
2211
	encode_sequence(&xdr, &args->seq_args, &hdr);
2212 2213 2214
	encode_putfh(&xdr, args->fh, &hdr);
	encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0],
			   &hdr);
2215
	encode_nops(&hdr);
2216
	return 0;
L
Linus Torvalds 已提交
2217 2218 2219 2220 2221
}

/*
 * a STATFS request
 */
A
Al Viro 已提交
2222
static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs4_statfs_arg *args)
L
Linus Torvalds 已提交
2223 2224 2225
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2226
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2227 2228 2229
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2230
	encode_compound_hdr(&xdr, req, &hdr);
2231
	encode_sequence(&xdr, &args->seq_args, &hdr);
2232 2233 2234
	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);
2235
	encode_nops(&hdr);
2236
	return 0;
L
Linus Torvalds 已提交
2237 2238 2239 2240 2241
}

/*
 * GETATTR_BITMAP request
 */
B
Benny Halevy 已提交
2242 2243
static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p,
				    struct nfs4_server_caps_arg *args)
L
Linus Torvalds 已提交
2244 2245 2246
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2247
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2248 2249 2250
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2251
	encode_compound_hdr(&xdr, req, &hdr);
2252
	encode_sequence(&xdr, &args->seq_args, &hdr);
B
Benny Halevy 已提交
2253
	encode_putfh(&xdr, args->fhandle, &hdr);
2254 2255 2256 2257
	encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
			   FATTR4_WORD0_LINK_SUPPORT|
			   FATTR4_WORD0_SYMLINK_SUPPORT|
			   FATTR4_WORD0_ACLSUPPORT, &hdr);
2258
	encode_nops(&hdr);
2259
	return 0;
L
Linus Torvalds 已提交
2260 2261 2262 2263 2264
}

/*
 * a RENEW request
 */
A
Al Viro 已提交
2265
static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
L
Linus Torvalds 已提交
2266 2267 2268
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2269
		.nops	= 0,
L
Linus Torvalds 已提交
2270 2271 2272
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2273
	encode_compound_hdr(&xdr, req, &hdr);
2274
	encode_renew(&xdr, clp, &hdr);
2275
	encode_nops(&hdr);
2276
	return 0;
L
Linus Torvalds 已提交
2277 2278 2279 2280 2281
}

/*
 * a SETCLIENTID request
 */
A
Al Viro 已提交
2282
static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid *sc)
L
Linus Torvalds 已提交
2283 2284 2285
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2286
		.nops	= 0,
L
Linus Torvalds 已提交
2287 2288 2289
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2290
	encode_compound_hdr(&xdr, req, &hdr);
2291
	encode_setclientid(&xdr, sc, &hdr);
2292
	encode_nops(&hdr);
2293
	return 0;
L
Linus Torvalds 已提交
2294 2295 2296 2297 2298
}

/*
 * a SETCLIENTID_CONFIRM request
 */
A
Al Viro 已提交
2299
static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
L
Linus Torvalds 已提交
2300 2301 2302
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2303
		.nops	= 0,
L
Linus Torvalds 已提交
2304 2305 2306 2307
	};
	const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };

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

/*
 * DELEGRETURN request
 */
A
Al Viro 已提交
2319
static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struct nfs4_delegreturnargs *args)
L
Linus Torvalds 已提交
2320 2321 2322
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2323
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2324 2325 2326
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2327
	encode_compound_hdr(&xdr, req, &hdr);
2328
	encode_sequence(&xdr, &args->seq_args, &hdr);
2329 2330 2331
	encode_putfh(&xdr, args->fhandle, &hdr);
	encode_delegreturn(&xdr, args->stateid, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
2332
	encode_nops(&hdr);
2333
	return 0;
L
Linus Torvalds 已提交
2334 2335
}

2336 2337 2338
/*
 * Encode FS_LOCATIONS request
 */
A
Al Viro 已提交
2339
static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations_arg *args)
2340 2341 2342
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2343
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
2344
	};
2345
	uint32_t replen;
2346 2347

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2348
	encode_compound_hdr(&xdr, req, &hdr);
2349
	encode_sequence(&xdr, &args->seq_args, &hdr);
2350 2351
	encode_putfh(&xdr, args->dir_fh, &hdr);
	encode_lookup(&xdr, args->name, &hdr);
2352
	replen = hdr.replen;	/* get the attribute into args->page */
2353 2354
	encode_fs_locations(&xdr, args->bitmask, &hdr);

2355
	xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page,
2356
			0, PAGE_SIZE);
2357
	encode_nops(&hdr);
2358
	return 0;
2359 2360
}

B
Benny Halevy 已提交
2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378
#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 = {
		.minorversion = args->client->cl_minorversion,
	};

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

A
Andy Adamson 已提交
2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397
/*
 * 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 = {
		.minorversion = args->client->cl_minorversion,
	};

	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 已提交
2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415
/*
 * 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 = {
		.minorversion = session->clp->cl_minorversion,
	};

	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 已提交
2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433
/*
 * 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 已提交
2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453
/*
 * 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;
}
B
Benny Halevy 已提交
2454 2455
#endif /* CONFIG_NFS_V4_1 */

2456 2457 2458 2459 2460 2461
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 已提交
2462

2463
static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
L
Linus Torvalds 已提交
2464
{
A
Al Viro 已提交
2465
	__be32 *p;
L
Linus Torvalds 已提交
2466

B
Benny Halevy 已提交
2467 2468 2469
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
2470
	*len = be32_to_cpup(p);
B
Benny Halevy 已提交
2471 2472 2473
	p = xdr_inline_decode(xdr, *len);
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
2474 2475
	*string = (char *)p;
	return 0;
B
Benny Halevy 已提交
2476 2477 2478
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2479 2480 2481 2482
}

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

B
Benny Halevy 已提交
2485 2486 2487
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
2488
	hdr->status = be32_to_cpup(p++);
2489
	hdr->taglen = be32_to_cpup(p);
2490

B
Benny Halevy 已提交
2491 2492 2493
	p = xdr_inline_decode(xdr, hdr->taglen + 4);
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
2494 2495
	hdr->tag = (char *)p;
	p += XDR_QUADLEN(hdr->taglen);
2496
	hdr->nops = be32_to_cpup(p);
2497 2498
	if (unlikely(hdr->nops < 1))
		return nfs4_stat_to_errno(hdr->status);
L
Linus Torvalds 已提交
2499
	return 0;
B
Benny Halevy 已提交
2500 2501 2502
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2503 2504 2505 2506
}

static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
{
A
Al Viro 已提交
2507
	__be32 *p;
L
Linus Torvalds 已提交
2508 2509 2510
	uint32_t opnum;
	int32_t nfserr;

B
Benny Halevy 已提交
2511 2512 2513
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
2514
	opnum = be32_to_cpup(p++);
L
Linus Torvalds 已提交
2515
	if (opnum != expected) {
2516 2517
		dprintk("nfs: Server returned operation"
			" %d but we issued a request for %d\n",
L
Linus Torvalds 已提交
2518 2519 2520
				opnum, expected);
		return -EIO;
	}
2521
	nfserr = be32_to_cpup(p);
L
Linus Torvalds 已提交
2522
	if (nfserr != NFS_OK)
2523
		return nfs4_stat_to_errno(nfserr);
L
Linus Torvalds 已提交
2524
	return 0;
B
Benny Halevy 已提交
2525 2526 2527
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2528 2529 2530
}

/* Dummy routine */
2531
static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp)
L
Linus Torvalds 已提交
2532
{
A
Al Viro 已提交
2533
	__be32 *p;
2534
	unsigned int strlen;
L
Linus Torvalds 已提交
2535 2536
	char *str;

B
Benny Halevy 已提交
2537 2538 2539 2540 2541
	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 已提交
2542 2543 2544 2545
}

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

B
Benny Halevy 已提交
2549 2550 2551
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
2552
	bmlen = be32_to_cpup(p);
L
Linus Torvalds 已提交
2553 2554

	bitmap[0] = bitmap[1] = 0;
B
Benny Halevy 已提交
2555 2556 2557
	p = xdr_inline_decode(xdr, (bmlen << 2));
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
2558
	if (bmlen > 0) {
B
Benny Halevy 已提交
2559
		bitmap[0] = be32_to_cpup(p++);
L
Linus Torvalds 已提交
2560
		if (bmlen > 1)
2561
			bitmap[1] = be32_to_cpup(p);
L
Linus Torvalds 已提交
2562 2563
	}
	return 0;
B
Benny Halevy 已提交
2564 2565 2566
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2567 2568
}

A
Al Viro 已提交
2569
static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep)
L
Linus Torvalds 已提交
2570
{
A
Al Viro 已提交
2571
	__be32 *p;
L
Linus Torvalds 已提交
2572

B
Benny Halevy 已提交
2573 2574 2575
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
2576
	*attrlen = be32_to_cpup(p);
L
Linus Torvalds 已提交
2577 2578
	*savep = xdr->p;
	return 0;
B
Benny Halevy 已提交
2579 2580 2581
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2582 2583 2584 2585 2586 2587 2588 2589 2590
}

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;
2591
	dprintk("%s: bitmask=%08x:%08x\n", __func__, bitmask[0], bitmask[1]);
L
Linus Torvalds 已提交
2592 2593 2594 2595 2596
	return 0;
}

static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
{
A
Al Viro 已提交
2597
	__be32 *p;
2598
	int ret = 0;
L
Linus Torvalds 已提交
2599 2600 2601 2602 2603

	*type = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_TYPE)) {
B
Benny Halevy 已提交
2604 2605 2606
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
2607
		*type = be32_to_cpup(p);
L
Linus Torvalds 已提交
2608
		if (*type < NF4REG || *type > NF4NAMEDATTR) {
2609
			dprintk("%s: bad type %d\n", __func__, *type);
L
Linus Torvalds 已提交
2610 2611 2612
			return -EIO;
		}
		bitmap[0] &= ~FATTR4_WORD0_TYPE;
2613
		ret = NFS_ATTR_FATTR_TYPE;
L
Linus Torvalds 已提交
2614
	}
2615
	dprintk("%s: type=0%o\n", __func__, nfs_type2fmt[*type]);
2616
	return ret;
B
Benny Halevy 已提交
2617 2618 2619
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2620 2621 2622 2623
}

static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
{
A
Al Viro 已提交
2624
	__be32 *p;
2625
	int ret = 0;
L
Linus Torvalds 已提交
2626 2627 2628 2629 2630

	*change = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_CHANGE)) {
B
Benny Halevy 已提交
2631 2632 2633
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
2634
		xdr_decode_hyper(p, change);
L
Linus Torvalds 已提交
2635
		bitmap[0] &= ~FATTR4_WORD0_CHANGE;
2636
		ret = NFS_ATTR_FATTR_CHANGE;
L
Linus Torvalds 已提交
2637
	}
2638
	dprintk("%s: change attribute=%Lu\n", __func__,
L
Linus Torvalds 已提交
2639
			(unsigned long long)*change);
2640
	return ret;
B
Benny Halevy 已提交
2641 2642 2643
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2644 2645 2646 2647
}

static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
{
A
Al Viro 已提交
2648
	__be32 *p;
2649
	int ret = 0;
L
Linus Torvalds 已提交
2650 2651 2652 2653 2654

	*size = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_SIZE)) {
B
Benny Halevy 已提交
2655 2656 2657
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
2658
		xdr_decode_hyper(p, size);
L
Linus Torvalds 已提交
2659
		bitmap[0] &= ~FATTR4_WORD0_SIZE;
2660
		ret = NFS_ATTR_FATTR_SIZE;
L
Linus Torvalds 已提交
2661
	}
2662
	dprintk("%s: file size=%Lu\n", __func__, (unsigned long long)*size);
2663
	return ret;
B
Benny Halevy 已提交
2664 2665 2666
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2667 2668 2669 2670
}

static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
2671
	__be32 *p;
L
Linus Torvalds 已提交
2672 2673 2674 2675 2676

	*res = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_LINK_SUPPORT)) {
B
Benny Halevy 已提交
2677 2678 2679
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
2680
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
2681 2682
		bitmap[0] &= ~FATTR4_WORD0_LINK_SUPPORT;
	}
2683
	dprintk("%s: link support=%s\n", __func__, *res == 0 ? "false" : "true");
L
Linus Torvalds 已提交
2684
	return 0;
B
Benny Halevy 已提交
2685 2686 2687
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2688 2689 2690 2691
}

static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
2692
	__be32 *p;
L
Linus Torvalds 已提交
2693 2694 2695 2696 2697

	*res = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_SYMLINK_SUPPORT)) {
B
Benny Halevy 已提交
2698 2699 2700
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
2701
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
2702 2703
		bitmap[0] &= ~FATTR4_WORD0_SYMLINK_SUPPORT;
	}
2704
	dprintk("%s: symlink support=%s\n", __func__, *res == 0 ? "false" : "true");
L
Linus Torvalds 已提交
2705
	return 0;
B
Benny Halevy 已提交
2706 2707 2708
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2709 2710
}

2711
static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
L
Linus Torvalds 已提交
2712
{
A
Al Viro 已提交
2713
	__be32 *p;
2714
	int ret = 0;
L
Linus Torvalds 已提交
2715 2716 2717 2718 2719 2720

	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 已提交
2721 2722 2723
		p = xdr_inline_decode(xdr, 16);
		if (unlikely(!p))
			goto out_overflow;
B
Benny Halevy 已提交
2724
		p = xdr_decode_hyper(p, &fsid->major);
2725
		xdr_decode_hyper(p, &fsid->minor);
L
Linus Torvalds 已提交
2726
		bitmap[0] &= ~FATTR4_WORD0_FSID;
2727
		ret = NFS_ATTR_FATTR_FSID;
L
Linus Torvalds 已提交
2728
	}
2729
	dprintk("%s: fsid=(0x%Lx/0x%Lx)\n", __func__,
L
Linus Torvalds 已提交
2730 2731
			(unsigned long long)fsid->major,
			(unsigned long long)fsid->minor);
2732
	return ret;
B
Benny Halevy 已提交
2733 2734 2735
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2736 2737 2738 2739
}

static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
2740
	__be32 *p;
L
Linus Torvalds 已提交
2741 2742 2743 2744 2745

	*res = 60;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_LEASE_TIME)) {
B
Benny Halevy 已提交
2746 2747 2748
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
2749
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
2750 2751
		bitmap[0] &= ~FATTR4_WORD0_LEASE_TIME;
	}
2752
	dprintk("%s: file size=%u\n", __func__, (unsigned int)*res);
L
Linus Torvalds 已提交
2753
	return 0;
B
Benny Halevy 已提交
2754 2755 2756
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2757 2758 2759 2760
}

static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
2761
	__be32 *p;
L
Linus Torvalds 已提交
2762 2763 2764 2765 2766

	*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 已提交
2767 2768 2769
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
2770
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
2771 2772
		bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT;
	}
2773
	dprintk("%s: ACLs supported=%u\n", __func__, (unsigned int)*res);
L
Linus Torvalds 已提交
2774
	return 0;
B
Benny Halevy 已提交
2775 2776 2777
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2778 2779 2780 2781
}

static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
{
A
Al Viro 已提交
2782
	__be32 *p;
2783
	int ret = 0;
L
Linus Torvalds 已提交
2784 2785 2786 2787 2788

	*fileid = 0;
	if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
		return -EIO;
	if (likely(bitmap[0] & FATTR4_WORD0_FILEID)) {
B
Benny Halevy 已提交
2789 2790 2791
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
2792
		xdr_decode_hyper(p, fileid);
L
Linus Torvalds 已提交
2793
		bitmap[0] &= ~FATTR4_WORD0_FILEID;
2794
		ret = NFS_ATTR_FATTR_FILEID;
L
Linus Torvalds 已提交
2795
	}
2796
	dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
2797
	return ret;
B
Benny Halevy 已提交
2798 2799 2800
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2801 2802
}

2803 2804
static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
{
A
Al Viro 已提交
2805
	__be32 *p;
2806
	int ret = 0;
2807 2808 2809 2810 2811

	*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 已提交
2812 2813 2814
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
2815
		xdr_decode_hyper(p, fileid);
2816
		bitmap[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
2817
		ret = NFS_ATTR_FATTR_FILEID;
2818
	}
2819
	dprintk("%s: fileid=%Lu\n", __func__, (unsigned long long)*fileid);
2820
	return ret;
B
Benny Halevy 已提交
2821 2822 2823
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
2824 2825
}

L
Linus Torvalds 已提交
2826 2827
static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
2828
	__be32 *p;
L
Linus Torvalds 已提交
2829 2830 2831 2832 2833 2834
	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 已提交
2835 2836 2837
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
2838
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
2839 2840
		bitmap[0] &= ~FATTR4_WORD0_FILES_AVAIL;
	}
2841
	dprintk("%s: files avail=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
2842
	return status;
B
Benny Halevy 已提交
2843 2844 2845
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2846 2847 2848 2849
}

static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
2850
	__be32 *p;
L
Linus Torvalds 已提交
2851 2852 2853 2854 2855 2856
	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 已提交
2857 2858 2859
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
2860
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
2861 2862
		bitmap[0] &= ~FATTR4_WORD0_FILES_FREE;
	}
2863
	dprintk("%s: files free=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
2864
	return status;
B
Benny Halevy 已提交
2865 2866 2867
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2868 2869 2870 2871
}

static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
2872
	__be32 *p;
L
Linus Torvalds 已提交
2873 2874 2875 2876 2877 2878
	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 已提交
2879 2880 2881
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
2882
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
2883 2884
		bitmap[0] &= ~FATTR4_WORD0_FILES_TOTAL;
	}
2885
	dprintk("%s: files total=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
2886
	return status;
B
Benny Halevy 已提交
2887 2888 2889
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2890 2891
}

2892 2893
static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
{
2894
	u32 n;
A
Al Viro 已提交
2895
	__be32 *p;
2896 2897
	int status = 0;

B
Benny Halevy 已提交
2898 2899 2900
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
2901
	n = be32_to_cpup(p);
2902 2903
	if (n == 0)
		goto root_path;
2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923
	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;
2924 2925 2926 2927 2928 2929 2930
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;
2931 2932 2933 2934
out_eio:
	dprintk(" status %d", status);
	status = -EIO;
	goto out;
B
Benny Halevy 已提交
2935 2936 2937
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
2938 2939 2940
}

static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res)
2941 2942
{
	int n;
A
Al Viro 已提交
2943
	__be32 *p;
2944 2945 2946 2947 2948 2949 2950
	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;
2951
	dprintk("%s: fsroot ", __func__);
2952
	status = decode_pathname(xdr, &res->fs_path);
2953 2954
	if (unlikely(status != 0))
		goto out;
B
Benny Halevy 已提交
2955 2956 2957
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
2958
	n = be32_to_cpup(p);
2959 2960 2961 2962
	if (n <= 0)
		goto out_eio;
	res->nlocations = 0;
	while (res->nlocations < n) {
2963
		u32 m;
2964
		struct nfs4_fs_location *loc = &res->locations[res->nlocations];
2965

B
Benny Halevy 已提交
2966 2967 2968
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
2969
		m = be32_to_cpup(p);
2970 2971

		loc->nservers = 0;
2972
		dprintk("%s: servers ", __func__);
2973 2974 2975 2976 2977 2978 2979 2980 2981
		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 {
2982 2983 2984
				unsigned int i;
				dprintk("%s: using first %u of %u servers "
					"returned for location %u\n",
2985
						__func__,
2986 2987
						NFS4_FS_LOCATION_MAXSERVERS,
						m, res->nlocations);
2988
				for (i = loc->nservers; i < m; i++) {
T
Trond Myklebust 已提交
2989
					unsigned int len;
2990 2991 2992 2993 2994 2995 2996 2997
					char *data;
					status = decode_opaque_inline(xdr, &len, &data);
					if (unlikely(status != 0))
						goto out_eio;
				}
			}
		}
		status = decode_pathname(xdr, &loc->rootpath);
2998 2999
		if (unlikely(status != 0))
			goto out_eio;
3000
		if (res->nlocations < NFS4_FS_LOCATIONS_MAXENTRIES)
3001 3002
			res->nlocations++;
	}
3003 3004
	if (res->nlocations != 0)
		status = NFS_ATTR_FATTR_V4_REFERRAL;
3005
out:
3006
	dprintk("%s: fs_locations done, error = %d\n", __func__, status);
3007
	return status;
B
Benny Halevy 已提交
3008 3009
out_overflow:
	print_overflow_msg(__func__, xdr);
3010 3011 3012 3013 3014
out_eio:
	status = -EIO;
	goto out;
}

L
Linus Torvalds 已提交
3015 3016
static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3017
	__be32 *p;
L
Linus Torvalds 已提交
3018 3019 3020 3021 3022 3023
	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 已提交
3024 3025 3026
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3027
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3028 3029
		bitmap[0] &= ~FATTR4_WORD0_MAXFILESIZE;
	}
3030
	dprintk("%s: maxfilesize=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3031
	return status;
B
Benny Halevy 已提交
3032 3033 3034
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3035 3036 3037 3038
}

static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink)
{
A
Al Viro 已提交
3039
	__be32 *p;
L
Linus Torvalds 已提交
3040 3041 3042 3043 3044 3045
	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 已提交
3046 3047 3048
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3049
		*maxlink = be32_to_cpup(p);
L
Linus Torvalds 已提交
3050 3051
		bitmap[0] &= ~FATTR4_WORD0_MAXLINK;
	}
3052
	dprintk("%s: maxlink=%u\n", __func__, *maxlink);
L
Linus Torvalds 已提交
3053
	return status;
B
Benny Halevy 已提交
3054 3055 3056
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3057 3058 3059 3060
}

static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname)
{
A
Al Viro 已提交
3061
	__be32 *p;
L
Linus Torvalds 已提交
3062 3063 3064 3065 3066 3067
	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 已提交
3068 3069 3070
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3071
		*maxname = be32_to_cpup(p);
L
Linus Torvalds 已提交
3072 3073
		bitmap[0] &= ~FATTR4_WORD0_MAXNAME;
	}
3074
	dprintk("%s: maxname=%u\n", __func__, *maxname);
L
Linus Torvalds 已提交
3075
	return status;
B
Benny Halevy 已提交
3076 3077 3078
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3079 3080 3081 3082
}

static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
3083
	__be32 *p;
L
Linus Torvalds 已提交
3084 3085 3086 3087 3088 3089 3090
	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 已提交
3091 3092 3093
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3094
		xdr_decode_hyper(p, &maxread);
L
Linus Torvalds 已提交
3095 3096 3097 3098 3099
		if (maxread > 0x7FFFFFFF)
			maxread = 0x7FFFFFFF;
		*res = (uint32_t)maxread;
		bitmap[0] &= ~FATTR4_WORD0_MAXREAD;
	}
3100
	dprintk("%s: maxread=%lu\n", __func__, (unsigned long)*res);
L
Linus Torvalds 已提交
3101
	return status;
B
Benny Halevy 已提交
3102 3103 3104
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3105 3106 3107 3108
}

static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
3109
	__be32 *p;
L
Linus Torvalds 已提交
3110 3111 3112 3113 3114 3115 3116
	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 已提交
3117 3118 3119
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3120
		xdr_decode_hyper(p, &maxwrite);
L
Linus Torvalds 已提交
3121 3122 3123 3124 3125
		if (maxwrite > 0x7FFFFFFF)
			maxwrite = 0x7FFFFFFF;
		*res = (uint32_t)maxwrite;
		bitmap[0] &= ~FATTR4_WORD0_MAXWRITE;
	}
3126
	dprintk("%s: maxwrite=%lu\n", __func__, (unsigned long)*res);
L
Linus Torvalds 已提交
3127
	return status;
B
Benny Halevy 已提交
3128 3129 3130
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3131 3132
}

3133
static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *mode)
L
Linus Torvalds 已提交
3134
{
3135
	uint32_t tmp;
A
Al Viro 已提交
3136
	__be32 *p;
3137
	int ret = 0;
L
Linus Torvalds 已提交
3138 3139 3140 3141 3142

	*mode = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_MODE)) {
B
Benny Halevy 已提交
3143 3144 3145
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3146
		tmp = be32_to_cpup(p);
3147
		*mode = tmp & ~S_IFMT;
L
Linus Torvalds 已提交
3148
		bitmap[1] &= ~FATTR4_WORD1_MODE;
3149
		ret = NFS_ATTR_FATTR_MODE;
L
Linus Torvalds 已提交
3150
	}
3151
	dprintk("%s: file mode=0%o\n", __func__, (unsigned int)*mode);
3152
	return ret;
B
Benny Halevy 已提交
3153 3154 3155
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3156 3157 3158 3159
}

static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
{
A
Al Viro 已提交
3160
	__be32 *p;
3161
	int ret = 0;
L
Linus Torvalds 已提交
3162 3163 3164 3165 3166

	*nlink = 1;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_NUMLINKS)) {
B
Benny Halevy 已提交
3167 3168 3169
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3170
		*nlink = be32_to_cpup(p);
L
Linus Torvalds 已提交
3171
		bitmap[1] &= ~FATTR4_WORD1_NUMLINKS;
3172
		ret = NFS_ATTR_FATTR_NLINK;
L
Linus Torvalds 已提交
3173
	}
3174
	dprintk("%s: nlink=%u\n", __func__, (unsigned int)*nlink);
3175
	return ret;
B
Benny Halevy 已提交
3176 3177 3178
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3179 3180
}

3181 3182
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 已提交
3183
{
A
Al Viro 已提交
3184 3185
	uint32_t len;
	__be32 *p;
3186
	int ret = 0;
L
Linus Torvalds 已提交
3187 3188 3189 3190 3191

	*uid = -2;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_OWNER)) {
B
Benny Halevy 已提交
3192 3193 3194
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3195
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
3196 3197 3198
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
3199 3200 3201
		if (!may_sleep) {
			/* do nothing */
		} else if (len < XDR_MAX_NETOBJ) {
3202 3203 3204
			if (nfs_map_name_to_uid(clp, (char *)p, len, uid) == 0)
				ret = NFS_ATTR_FATTR_OWNER;
			else
L
Linus Torvalds 已提交
3205
				dprintk("%s: nfs_map_name_to_uid failed!\n",
3206
						__func__);
L
Linus Torvalds 已提交
3207
		} else
3208
			dprintk("%s: name too long (%u)!\n",
3209
					__func__, len);
L
Linus Torvalds 已提交
3210 3211
		bitmap[1] &= ~FATTR4_WORD1_OWNER;
	}
3212
	dprintk("%s: uid=%d\n", __func__, (int)*uid);
3213
	return ret;
B
Benny Halevy 已提交
3214 3215 3216
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3217 3218
}

3219 3220
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 已提交
3221
{
A
Al Viro 已提交
3222 3223
	uint32_t len;
	__be32 *p;
3224
	int ret = 0;
L
Linus Torvalds 已提交
3225 3226 3227 3228 3229

	*gid = -2;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_OWNER_GROUP)) {
B
Benny Halevy 已提交
3230 3231 3232
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3233
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
3234 3235 3236
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
3237 3238 3239
		if (!may_sleep) {
			/* do nothing */
		} else if (len < XDR_MAX_NETOBJ) {
3240 3241 3242
			if (nfs_map_group_to_gid(clp, (char *)p, len, gid) == 0)
				ret = NFS_ATTR_FATTR_GROUP;
			else
L
Linus Torvalds 已提交
3243
				dprintk("%s: nfs_map_group_to_gid failed!\n",
3244
						__func__);
L
Linus Torvalds 已提交
3245
		} else
3246
			dprintk("%s: name too long (%u)!\n",
3247
					__func__, len);
L
Linus Torvalds 已提交
3248 3249
		bitmap[1] &= ~FATTR4_WORD1_OWNER_GROUP;
	}
3250
	dprintk("%s: gid=%d\n", __func__, (int)*gid);
3251
	return ret;
B
Benny Halevy 已提交
3252 3253 3254
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3255 3256 3257 3258
}

static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
{
A
Al Viro 已提交
3259 3260
	uint32_t major = 0, minor = 0;
	__be32 *p;
3261
	int ret = 0;
L
Linus Torvalds 已提交
3262 3263 3264 3265 3266 3267 3268

	*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 已提交
3269 3270 3271
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
B
Benny Halevy 已提交
3272
		major = be32_to_cpup(p++);
3273
		minor = be32_to_cpup(p);
L
Linus Torvalds 已提交
3274 3275 3276 3277
		tmp = MKDEV(major, minor);
		if (MAJOR(tmp) == major && MINOR(tmp) == minor)
			*rdev = tmp;
		bitmap[1] &= ~ FATTR4_WORD1_RAWDEV;
3278
		ret = NFS_ATTR_FATTR_RDEV;
L
Linus Torvalds 已提交
3279
	}
3280
	dprintk("%s: rdev=(0x%x:0x%x)\n", __func__, major, minor);
3281
	return ret;
B
Benny Halevy 已提交
3282 3283 3284
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3285 3286 3287 3288
}

static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3289
	__be32 *p;
L
Linus Torvalds 已提交
3290 3291 3292 3293 3294 3295
	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 已提交
3296 3297 3298
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3299
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3300 3301
		bitmap[1] &= ~FATTR4_WORD1_SPACE_AVAIL;
	}
3302
	dprintk("%s: space avail=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3303
	return status;
B
Benny Halevy 已提交
3304 3305 3306
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3307 3308 3309 3310
}

static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3311
	__be32 *p;
L
Linus Torvalds 已提交
3312 3313 3314 3315 3316 3317
	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 已提交
3318 3319 3320
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3321
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3322 3323
		bitmap[1] &= ~FATTR4_WORD1_SPACE_FREE;
	}
3324
	dprintk("%s: space free=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3325
	return status;
B
Benny Halevy 已提交
3326 3327 3328
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3329 3330 3331 3332
}

static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
A
Al Viro 已提交
3333
	__be32 *p;
L
Linus Torvalds 已提交
3334 3335 3336 3337 3338 3339
	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 已提交
3340 3341 3342
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3343
		xdr_decode_hyper(p, res);
L
Linus Torvalds 已提交
3344 3345
		bitmap[1] &= ~FATTR4_WORD1_SPACE_TOTAL;
	}
3346
	dprintk("%s: space total=%Lu\n", __func__, (unsigned long long)*res);
L
Linus Torvalds 已提交
3347
	return status;
B
Benny Halevy 已提交
3348 3349 3350
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3351 3352 3353 3354
}

static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
{
A
Al Viro 已提交
3355
	__be32 *p;
3356
	int ret = 0;
L
Linus Torvalds 已提交
3357 3358 3359 3360 3361

	*used = 0;
	if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
		return -EIO;
	if (likely(bitmap[1] & FATTR4_WORD1_SPACE_USED)) {
B
Benny Halevy 已提交
3362 3363 3364
		p = xdr_inline_decode(xdr, 8);
		if (unlikely(!p))
			goto out_overflow;
3365
		xdr_decode_hyper(p, used);
L
Linus Torvalds 已提交
3366
		bitmap[1] &= ~FATTR4_WORD1_SPACE_USED;
3367
		ret = NFS_ATTR_FATTR_SPACE_USED;
L
Linus Torvalds 已提交
3368
	}
3369
	dprintk("%s: space used=%Lu\n", __func__,
L
Linus Torvalds 已提交
3370
			(unsigned long long)*used);
3371
	return ret;
B
Benny Halevy 已提交
3372 3373 3374
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3375 3376 3377 3378
}

static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
{
A
Al Viro 已提交
3379
	__be32 *p;
L
Linus Torvalds 已提交
3380 3381 3382
	uint64_t sec;
	uint32_t nsec;

B
Benny Halevy 已提交
3383 3384 3385
	p = xdr_inline_decode(xdr, 12);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3386
	p = xdr_decode_hyper(p, &sec);
3387
	nsec = be32_to_cpup(p);
L
Linus Torvalds 已提交
3388 3389 3390
	time->tv_sec = (time_t)sec;
	time->tv_nsec = (long)nsec;
	return 0;
B
Benny Halevy 已提交
3391 3392 3393
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405
}

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);
3406 3407
		if (status == 0)
			status = NFS_ATTR_FATTR_ATIME;
L
Linus Torvalds 已提交
3408 3409
		bitmap[1] &= ~FATTR4_WORD1_TIME_ACCESS;
	}
3410
	dprintk("%s: atime=%ld\n", __func__, (long)time->tv_sec);
L
Linus Torvalds 已提交
3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423
	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);
3424 3425
		if (status == 0)
			status = NFS_ATTR_FATTR_CTIME;
L
Linus Torvalds 已提交
3426 3427
		bitmap[1] &= ~FATTR4_WORD1_TIME_METADATA;
	}
3428
	dprintk("%s: ctime=%ld\n", __func__, (long)time->tv_sec);
L
Linus Torvalds 已提交
3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441
	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);
3442 3443
		if (status == 0)
			status = NFS_ATTR_FATTR_MTIME;
L
Linus Torvalds 已提交
3444 3445
		bitmap[1] &= ~FATTR4_WORD1_TIME_MODIFY;
	}
3446
	dprintk("%s: mtime=%ld\n", __func__, (long)time->tv_sec);
L
Linus Torvalds 已提交
3447 3448 3449
	return status;
}

A
Al Viro 已提交
3450
static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
L
Linus Torvalds 已提交
3451 3452 3453 3454 3455
{
	unsigned int attrwords = XDR_QUADLEN(attrlen);
	unsigned int nwords = xdr->p - savep;

	if (unlikely(attrwords != nwords)) {
3456 3457
		dprintk("%s: server returned incorrect attribute length: "
			"%u %c %u\n",
3458
				__func__,
L
Linus Torvalds 已提交
3459 3460 3461 3462 3463 3464 3465 3466 3467 3468
				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 已提交
3469
	__be32 *p;
L
Linus Torvalds 已提交
3470

B
Benny Halevy 已提交
3471 3472 3473
	p = xdr_inline_decode(xdr, 20);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3474
	cinfo->atomic = be32_to_cpup(p++);
B
Benny Halevy 已提交
3475
	p = xdr_decode_hyper(p, &cinfo->before);
3476
	xdr_decode_hyper(p, &cinfo->after);
L
Linus Torvalds 已提交
3477
	return 0;
B
Benny Halevy 已提交
3478 3479 3480
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3481 3482 3483 3484
}

static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
{
A
Al Viro 已提交
3485
	__be32 *p;
L
Linus Torvalds 已提交
3486 3487 3488 3489 3490 3491
	uint32_t supp, acc;
	int status;

	status = decode_op_hdr(xdr, OP_ACCESS);
	if (status)
		return status;
B
Benny Halevy 已提交
3492 3493 3494
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3495
	supp = be32_to_cpup(p++);
3496
	acc = be32_to_cpup(p);
L
Linus Torvalds 已提交
3497 3498 3499
	access->supported = supp;
	access->access = acc;
	return 0;
B
Benny Halevy 已提交
3500 3501 3502
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3503 3504
}

3505
static int decode_opaque_fixed(struct xdr_stream *xdr, void *buf, size_t len)
L
Linus Torvalds 已提交
3506
{
A
Al Viro 已提交
3507
	__be32 *p;
3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524

	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 已提交
3525 3526 3527
	int status;

	status = decode_op_hdr(xdr, OP_CLOSE);
3528 3529
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
3530 3531 3532
	if (!status)
		status = decode_stateid(xdr, &res->stateid);
	return status;
L
Linus Torvalds 已提交
3533 3534
}

3535 3536 3537
static int decode_verifier(struct xdr_stream *xdr, void *verifier)
{
	return decode_opaque_fixed(xdr, verifier, 8);
L
Linus Torvalds 已提交
3538 3539 3540 3541 3542 3543 3544
}

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

	status = decode_op_hdr(xdr, OP_COMMIT);
3545 3546 3547
	if (!status)
		status = decode_verifier(xdr, res->verf->verifier);
	return status;
L
Linus Torvalds 已提交
3548 3549 3550 3551
}

static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
A
Al Viro 已提交
3552
	__be32 *p;
L
Linus Torvalds 已提交
3553 3554 3555 3556 3557 3558 3559 3560
	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 已提交
3561 3562 3563
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
3564
	bmlen = be32_to_cpup(p);
B
Benny Halevy 已提交
3565 3566 3567 3568 3569 3570
	p = xdr_inline_decode(xdr, bmlen << 2);
	if (likely(p))
		return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3571 3572 3573 3574
}

static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
{
A
Al Viro 已提交
3575
	__be32 *savep;
3576
	uint32_t attrlen, bitmap[2] = {0};
L
Linus Torvalds 已提交
3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594
	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:
3595
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
3596 3597
	return status;
}
3598

L
Linus Torvalds 已提交
3599 3600
static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
{
A
Al Viro 已提交
3601
	__be32 *savep;
3602
	uint32_t attrlen, bitmap[2] = {0};
L
Linus Torvalds 已提交
3603
	int status;
3604

L
Linus Torvalds 已提交
3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626
	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:
3627
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
3628 3629 3630 3631 3632
	return status;
}

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

L
Linus Torvalds 已提交
3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650
	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:
3651
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
3652 3653 3654
	return status;
}

3655 3656
static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
		const struct nfs_server *server, int may_sleep)
L
Linus Torvalds 已提交
3657
{
A
Al Viro 已提交
3658
	__be32 *savep;
L
Linus Torvalds 已提交
3659 3660 3661
	uint32_t attrlen,
		 bitmap[2] = {0},
		 type;
3662 3663
	int status;
	umode_t fmode = 0;
3664
	uint64_t fileid;
L
Linus Torvalds 已提交
3665

3666 3667
	status = decode_op_hdr(xdr, OP_GETATTR);
	if (status < 0)
L
Linus Torvalds 已提交
3668
		goto xdr_error;
3669 3670 3671

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

3674 3675
	status = decode_attr_length(xdr, &attrlen, &savep);
	if (status < 0)
L
Linus Torvalds 已提交
3676 3677 3678
		goto xdr_error;


3679 3680
	status = decode_attr_type(xdr, bitmap, &type);
	if (status < 0)
L
Linus Torvalds 已提交
3681
		goto xdr_error;
3682 3683 3684 3685 3686
	fattr->mode = 0;
	if (status != 0) {
		fattr->mode |= nfs_type2fmt[type];
		fattr->valid |= status;
	}
L
Linus Torvalds 已提交
3687

3688 3689
	status = decode_attr_change(xdr, bitmap, &fattr->change_attr);
	if (status < 0)
L
Linus Torvalds 已提交
3690
		goto xdr_error;
3691
	fattr->valid |= status;
3692 3693 3694

	status = decode_attr_size(xdr, bitmap, &fattr->size);
	if (status < 0)
L
Linus Torvalds 已提交
3695
		goto xdr_error;
3696
	fattr->valid |= status;
3697 3698 3699

	status = decode_attr_fsid(xdr, bitmap, &fattr->fsid);
	if (status < 0)
L
Linus Torvalds 已提交
3700
		goto xdr_error;
3701
	fattr->valid |= status;
3702 3703 3704

	status = decode_attr_fileid(xdr, bitmap, &fattr->fileid);
	if (status < 0)
L
Linus Torvalds 已提交
3705
		goto xdr_error;
3706
	fattr->valid |= status;
3707 3708

	status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
3709
						struct nfs4_fs_locations,
3710 3711
						fattr));
	if (status < 0)
3712
		goto xdr_error;
3713
	fattr->valid |= status;
3714 3715 3716

	status = decode_attr_mode(xdr, bitmap, &fmode);
	if (status < 0)
L
Linus Torvalds 已提交
3717
		goto xdr_error;
3718 3719 3720 3721
	if (status != 0) {
		fattr->mode |= fmode;
		fattr->valid |= status;
	}
3722 3723 3724

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

3728 3729
	status = decode_attr_owner(xdr, bitmap, server->nfs_client,
			&fattr->uid, may_sleep);
3730
	if (status < 0)
L
Linus Torvalds 已提交
3731
		goto xdr_error;
3732
	fattr->valid |= status;
3733

3734 3735
	status = decode_attr_group(xdr, bitmap, server->nfs_client,
			&fattr->gid, may_sleep);
3736
	if (status < 0)
L
Linus Torvalds 已提交
3737
		goto xdr_error;
3738
	fattr->valid |= status;
3739 3740 3741

	status = decode_attr_rdev(xdr, bitmap, &fattr->rdev);
	if (status < 0)
L
Linus Torvalds 已提交
3742
		goto xdr_error;
3743
	fattr->valid |= status;
3744 3745 3746

	status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used);
	if (status < 0)
L
Linus Torvalds 已提交
3747
		goto xdr_error;
3748
	fattr->valid |= status;
3749 3750 3751

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

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

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

	status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid);
	if (status < 0)
3767
		goto xdr_error;
3768
	if (status != 0 && !(fattr->valid & status)) {
3769
		fattr->fileid = fileid;
3770 3771
		fattr->valid |= status;
	}
3772 3773

	status = verify_attr_len(xdr, savep, attrlen);
L
Linus Torvalds 已提交
3774
xdr_error:
3775
	dprintk("%s: xdr returned %d\n", __func__, -status);
L
Linus Torvalds 已提交
3776 3777 3778 3779 3780 3781
	return status;
}


static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
{
A
Al Viro 已提交
3782
	__be32 *savep;
L
Linus Torvalds 已提交
3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807
	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:
3808
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
3809 3810 3811 3812 3813
	return status;
}

static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
{
A
Al Viro 已提交
3814
	__be32 *p;
L
Linus Torvalds 已提交
3815 3816 3817
	uint32_t len;
	int status;

3818 3819 3820
	/* Zero handle first to allow comparisons */
	memset(fh, 0, sizeof(*fh));

L
Linus Torvalds 已提交
3821 3822 3823 3824
	status = decode_op_hdr(xdr, OP_GETFH);
	if (status)
		return status;

B
Benny Halevy 已提交
3825 3826 3827
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
3828
	len = be32_to_cpup(p);
L
Linus Torvalds 已提交
3829 3830 3831
	if (len > NFS4_FHSIZE)
		return -EIO;
	fh->size = len;
B
Benny Halevy 已提交
3832 3833 3834
	p = xdr_inline_decode(xdr, len);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3835
	memcpy(fh->data, p, len);
L
Linus Torvalds 已提交
3836
	return 0;
B
Benny Halevy 已提交
3837 3838 3839
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3840 3841 3842 3843 3844
}

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

L
Linus Torvalds 已提交
3846 3847 3848 3849 3850 3851 3852 3853 3854
	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 已提交
3855
static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
L
Linus Torvalds 已提交
3856
{
T
Trond Myklebust 已提交
3857
	uint64_t offset, length, clientid;
A
Al Viro 已提交
3858
	__be32 *p;
T
Trond Myklebust 已提交
3859
	uint32_t namelen, type;
L
Linus Torvalds 已提交
3860

B
Benny Halevy 已提交
3861 3862 3863
	p = xdr_inline_decode(xdr, 32);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3864 3865
	p = xdr_decode_hyper(p, &offset);
	p = xdr_decode_hyper(p, &length);
B
Benny Halevy 已提交
3866
	type = be32_to_cpup(p++);
T
Trond Myklebust 已提交
3867 3868 3869 3870 3871 3872 3873 3874 3875 3876
	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 已提交
3877
	p = xdr_decode_hyper(p, &clientid);
3878
	namelen = be32_to_cpup(p);
B
Benny Halevy 已提交
3879 3880 3881 3882 3883 3884
	p = xdr_inline_decode(xdr, namelen);
	if (likely(p))
		return -NFS4ERR_DENIED;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3885 3886
}

T
Trond Myklebust 已提交
3887
static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
L
Linus Torvalds 已提交
3888 3889 3890 3891
{
	int status;

	status = decode_op_hdr(xdr, OP_LOCK);
3892 3893
	if (status == -EIO)
		goto out;
L
Linus Torvalds 已提交
3894
	if (status == 0) {
3895 3896 3897
		status = decode_stateid(xdr, &res->stateid);
		if (unlikely(status))
			goto out;
L
Linus Torvalds 已提交
3898
	} else if (status == -NFS4ERR_DENIED)
3899 3900 3901 3902 3903
		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 已提交
3904 3905 3906
	return status;
}

T
Trond Myklebust 已提交
3907
static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res)
L
Linus Torvalds 已提交
3908 3909 3910 3911
{
	int status;
	status = decode_op_hdr(xdr, OP_LOCKT);
	if (status == -NFS4ERR_DENIED)
T
Trond Myklebust 已提交
3912
		return decode_lock_denied(xdr, res->denied);
L
Linus Torvalds 已提交
3913 3914 3915
	return status;
}

T
Trond Myklebust 已提交
3916
static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
L
Linus Torvalds 已提交
3917 3918 3919 3920
{
	int status;

	status = decode_op_hdr(xdr, OP_LOCKU);
3921 3922
	if (status != -EIO)
		nfs_increment_lock_seqid(status, res->seqid);
3923 3924
	if (status == 0)
		status = decode_stateid(xdr, &res->stateid);
L
Linus Torvalds 已提交
3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935
	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 已提交
3936
	__be32 *p;
L
Linus Torvalds 已提交
3937 3938
	uint32_t limit_type, nblocks, blocksize;

B
Benny Halevy 已提交
3939 3940 3941
	p = xdr_inline_decode(xdr, 12);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3942
	limit_type = be32_to_cpup(p++);
L
Linus Torvalds 已提交
3943
	switch (limit_type) {
A
Andy Adamson 已提交
3944
	case 1:
3945
		xdr_decode_hyper(p, maxsize);
A
Andy Adamson 已提交
3946 3947
		break;
	case 2:
B
Benny Halevy 已提交
3948
		nblocks = be32_to_cpup(p++);
3949
		blocksize = be32_to_cpup(p);
A
Andy Adamson 已提交
3950
		*maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
L
Linus Torvalds 已提交
3951 3952
	}
	return 0;
B
Benny Halevy 已提交
3953 3954 3955
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3956 3957 3958 3959
}

static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
{
A
Andy Adamson 已提交
3960 3961
	__be32 *p;
	uint32_t delegation_type;
3962
	int status;
L
Linus Torvalds 已提交
3963

B
Benny Halevy 已提交
3964 3965 3966
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
3967
	delegation_type = be32_to_cpup(p);
L
Linus Torvalds 已提交
3968 3969 3970 3971
	if (delegation_type == NFS4_OPEN_DELEGATE_NONE) {
		res->delegation_type = 0;
		return 0;
	}
3972 3973 3974
	status = decode_stateid(xdr, &res->delegation);
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
3975 3976 3977
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
3978
	res->do_recall = be32_to_cpup(p);
A
Andy Adamson 已提交
3979

L
Linus Torvalds 已提交
3980
	switch (delegation_type) {
A
Andy Adamson 已提交
3981 3982 3983 3984 3985 3986
	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 已提交
3987 3988
				return -EIO;
	}
3989
	return decode_ace(xdr, NULL, res->server->nfs_client);
B
Benny Halevy 已提交
3990 3991 3992
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3993 3994 3995 3996
}

static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
{
A
Andy Adamson 已提交
3997
	__be32 *p;
3998
	uint32_t savewords, bmlen, i;
A
Andy Adamson 已提交
3999
	int status;
L
Linus Torvalds 已提交
4000

A
Andy Adamson 已提交
4001
	status = decode_op_hdr(xdr, OP_OPEN);
4002 4003
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
4004 4005 4006
	if (!status)
		status = decode_stateid(xdr, &res->stateid);
	if (unlikely(status))
A
Andy Adamson 已提交
4007
		return status;
L
Linus Torvalds 已提交
4008

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

B
Benny Halevy 已提交
4011 4012 4013
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4014
	res->rflags = be32_to_cpup(p++);
4015
	bmlen = be32_to_cpup(p);
A
Andy Adamson 已提交
4016 4017
	if (bmlen > 10)
		goto xdr_error;
L
Linus Torvalds 已提交
4018

B
Benny Halevy 已提交
4019 4020 4021
	p = xdr_inline_decode(xdr, bmlen << 2);
	if (unlikely(!p))
		goto out_overflow;
4022 4023
	savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE);
	for (i = 0; i < savewords; ++i)
B
Benny Halevy 已提交
4024
		res->attrset[i] = be32_to_cpup(p++);
4025 4026 4027
	for (; i < NFS4_BITMAP_SIZE; i++)
		res->attrset[i] = 0;

L
Linus Torvalds 已提交
4028 4029
	return decode_delegation(xdr, res);
xdr_error:
4030
	dprintk("%s: Bitmap too large! Length = %u\n", __func__, bmlen);
L
Linus Torvalds 已提交
4031
	return -EIO;
B
Benny Halevy 已提交
4032 4033 4034
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4035 4036 4037 4038 4039 4040
}

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

A
Andy Adamson 已提交
4041
	status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
4042 4043
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
4044 4045 4046
	if (!status)
		status = decode_stateid(xdr, &res->stateid);
	return status;
L
Linus Torvalds 已提交
4047 4048 4049 4050 4051 4052 4053
}

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

	status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE);
4054 4055
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
4056 4057 4058
	if (!status)
		status = decode_stateid(xdr, &res->stateid);
	return status;
L
Linus Torvalds 已提交
4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073
}

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 已提交
4074
	__be32 *p;
L
Linus Torvalds 已提交
4075 4076 4077 4078 4079 4080
	uint32_t count, eof, recvd, hdrlen;
	int status;

	status = decode_op_hdr(xdr, OP_READ);
	if (status)
		return status;
B
Benny Halevy 已提交
4081 4082 4083
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4084
	eof = be32_to_cpup(p++);
4085
	count = be32_to_cpup(p);
L
Linus Torvalds 已提交
4086 4087 4088
	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
	recvd = req->rq_rcv_buf.len - hdrlen;
	if (count > recvd) {
4089
		dprintk("NFS: server cheating in read reply: "
L
Linus Torvalds 已提交
4090 4091 4092 4093 4094 4095 4096 4097
				"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 已提交
4098 4099 4100
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4101 4102 4103 4104 4105 4106 4107
}

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;
4108 4109
	size_t		hdrlen;
	u32		recvd, pglen = rcvbuf->page_len;
A
Al Viro 已提交
4110
	__be32		*end, *entry, *p, *kaddr;
4111
	unsigned int	nr = 0;
4112
	int		status;
L
Linus Torvalds 已提交
4113 4114

	status = decode_op_hdr(xdr, OP_READDIR);
4115 4116 4117
	if (!status)
		status = decode_verifier(xdr, readdir->verifier.data);
	if (unlikely(status))
L
Linus Torvalds 已提交
4118
		return status;
4119 4120
	dprintk("%s: verifier = %08x:%08x\n",
			__func__,
4121 4122 4123
			((u32 *)readdir->verifier.data)[0],
			((u32 *)readdir->verifier.data)[1]);

L
Linus Torvalds 已提交
4124

4125
	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
L
Linus Torvalds 已提交
4126 4127 4128 4129 4130 4131
	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 已提交
4132
	kaddr = p = kmap_atomic(page, KM_USER0);
4133
	end = p + ((pglen + readdir->pgbase) >> 2);
L
Linus Torvalds 已提交
4134
	entry = p;
4135 4136 4137 4138 4139 4140

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

	for (; *p++; nr++) {
4141
		u32 len, attrlen, xlen;
4142
		if (end - p < 3)
L
Linus Torvalds 已提交
4143
			goto short_pkt;
4144
		dprintk("cookie = %Lu, ", *((unsigned long long *)p));
L
Linus Torvalds 已提交
4145 4146 4147
		p += 2;			/* cookie */
		len = ntohl(*p++);	/* filename length */
		if (len > NFS4_MAXNAMLEN) {
4148 4149
			dprintk("NFS: giant filename in readdir (len 0x%x)\n",
					len);
L
Linus Torvalds 已提交
4150 4151
			goto err_unmap;
		}
4152 4153
		xlen = XDR_QUADLEN(len);
		if (end - p < xlen + 1)
L
Linus Torvalds 已提交
4154
			goto short_pkt;
4155 4156
		dprintk("filename = %*s\n", len, (char *)p);
		p += xlen;
L
Linus Torvalds 已提交
4157
		len = ntohl(*p++);	/* bitmap length */
4158
		if (end - p < len + 1)
L
Linus Torvalds 已提交
4159
			goto short_pkt;
4160
		p += len;
L
Linus Torvalds 已提交
4161
		attrlen = XDR_QUADLEN(ntohl(*p++));
4162
		if (end - p < attrlen + 2)
L
Linus Torvalds 已提交
4163
			goto short_pkt;
4164
		p += attrlen;		/* attributes */
L
Linus Torvalds 已提交
4165 4166
		entry = p;
	}
4167 4168 4169 4170 4171 4172 4173 4174 4175
	/*
	 * 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;
	}
4176
out:
L
Linus Torvalds 已提交
4177 4178 4179
	kunmap_atomic(kaddr, KM_USER0);
	return 0;
short_pkt:
4180 4181 4182 4183 4184 4185 4186 4187 4188
	/*
	 * 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.
	 */
4189
	dprintk("%s: short packet at entry %d\n", __func__, nr);
L
Linus Torvalds 已提交
4190
	entry[0] = entry[1] = 0;
4191 4192
	if (nr)
		goto out;
L
Linus Torvalds 已提交
4193 4194 4195 4196 4197 4198 4199 4200 4201
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;
4202 4203
	size_t hdrlen;
	u32 len, recvd;
A
Al Viro 已提交
4204
	__be32 *p;
L
Linus Torvalds 已提交
4205 4206 4207 4208 4209 4210 4211 4212
	char *kaddr;
	int status;

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

	/* Convert length of symlink */
B
Benny Halevy 已提交
4213 4214 4215
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4216
	len = be32_to_cpup(p);
L
Linus Torvalds 已提交
4217
	if (len >= rcvbuf->page_len || len <= 0) {
4218
		dprintk("nfs: server returned giant symlink!\n");
L
Linus Torvalds 已提交
4219 4220 4221 4222 4223
		return -ENAMETOOLONG;
	}
	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
	recvd = req->rq_rcv_buf.len - hdrlen;
	if (recvd < len) {
4224
		dprintk("NFS: server cheating in readlink reply: "
L
Linus Torvalds 已提交
4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239
				"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 已提交
4240 4241 4242
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276
}

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

4277 4278 4279 4280 4281 4282
static int
decode_restorefh(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_RESTOREFH);
}

4283 4284 4285
static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
		size_t *acl_len)
{
A
Al Viro 已提交
4286
	__be32 *savep;
4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302
	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)) {
4303 4304
		size_t hdrlen;
		u32 recvd;
4305 4306 4307 4308 4309 4310

		/* 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) {
4311
			dprintk("NFS: server cheating in getattr"
4312 4313 4314 4315
					" acl reply: attrlen %u > recvd %u\n",
					attrlen, recvd);
			return -EINVAL;
		}
4316
		xdr_read_pages(xdr, attrlen);
4317
		*acl_len = attrlen;
J
J. Bruce Fields 已提交
4318 4319
	} else
		status = -EOPNOTSUPP;
4320 4321 4322 4323 4324

out:
	return status;
}

L
Linus Torvalds 已提交
4325 4326 4327 4328 4329 4330
static int
decode_savefh(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_SAVEFH);
}

4331
static int decode_setattr(struct xdr_stream *xdr)
L
Linus Torvalds 已提交
4332
{
A
Al Viro 已提交
4333
	__be32 *p;
L
Linus Torvalds 已提交
4334 4335 4336 4337 4338 4339
	uint32_t bmlen;
	int status;

	status = decode_op_hdr(xdr, OP_SETATTR);
	if (status)
		return status;
B
Benny Halevy 已提交
4340 4341 4342
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4343
	bmlen = be32_to_cpup(p);
B
Benny Halevy 已提交
4344 4345 4346 4347 4348 4349
	p = xdr_inline_decode(xdr, bmlen << 2);
	if (likely(p))
		return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4350 4351
}

4352
static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp)
L
Linus Torvalds 已提交
4353
{
A
Al Viro 已提交
4354
	__be32 *p;
L
Linus Torvalds 已提交
4355 4356 4357
	uint32_t opnum;
	int32_t nfserr;

B
Benny Halevy 已提交
4358 4359 4360
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4361
	opnum = be32_to_cpup(p++);
L
Linus Torvalds 已提交
4362
	if (opnum != OP_SETCLIENTID) {
4363
		dprintk("nfs: decode_setclientid: Server returned operation"
4364
			" %d\n", opnum);
L
Linus Torvalds 已提交
4365 4366
		return -EIO;
	}
4367
	nfserr = be32_to_cpup(p);
L
Linus Torvalds 已提交
4368
	if (nfserr == NFS_OK) {
B
Benny Halevy 已提交
4369 4370 4371
		p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE);
		if (unlikely(!p))
			goto out_overflow;
B
Benny Halevy 已提交
4372
		p = xdr_decode_hyper(p, &clp->cl_clientid);
B
Benny Halevy 已提交
4373
		memcpy(clp->cl_confirm.data, p, NFS4_VERIFIER_SIZE);
L
Linus Torvalds 已提交
4374 4375 4376 4377
	} else if (nfserr == NFSERR_CLID_INUSE) {
		uint32_t len;

		/* skip netid string */
B
Benny Halevy 已提交
4378 4379 4380
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
4381
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
4382 4383 4384
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
L
Linus Torvalds 已提交
4385 4386

		/* skip uaddr string */
B
Benny Halevy 已提交
4387 4388 4389
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
4390
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
4391 4392 4393
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
L
Linus Torvalds 已提交
4394 4395
		return -NFSERR_CLID_INUSE;
	} else
4396
		return nfs4_stat_to_errno(nfserr);
L
Linus Torvalds 已提交
4397 4398

	return 0;
B
Benny Halevy 已提交
4399 4400 4401
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4402 4403 4404 4405 4406 4407 4408 4409 4410
}

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 已提交
4411
	__be32 *p;
L
Linus Torvalds 已提交
4412 4413 4414 4415 4416 4417
	int status;

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

B
Benny Halevy 已提交
4418 4419 4420
	p = xdr_inline_decode(xdr, 16);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4421 4422
	res->count = be32_to_cpup(p++);
	res->verf->committed = be32_to_cpup(p++);
B
Benny Halevy 已提交
4423
	memcpy(res->verf->verifier, p, 8);
L
Linus Torvalds 已提交
4424
	return 0;
B
Benny Halevy 已提交
4425 4426 4427
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4428 4429 4430 4431 4432 4433 4434
}

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

B
Benny Halevy 已提交
4435 4436 4437 4438 4439 4440
#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;
4441
	char *dummy_str;
B
Benny Halevy 已提交
4442 4443 4444 4445 4446 4447 4448
	int status;
	struct nfs_client *clp = res->client;

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

B
Benny Halevy 已提交
4449 4450 4451
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
4452
	xdr_decode_hyper(p, &clp->cl_ex_clid);
B
Benny Halevy 已提交
4453 4454 4455
	p = xdr_inline_decode(xdr, 12);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4456 4457
	clp->cl_seqid = be32_to_cpup(p++);
	clp->cl_exchange_flags = be32_to_cpup(p++);
B
Benny Halevy 已提交
4458 4459

	/* We ask for SP4_NONE */
4460
	dummy = be32_to_cpup(p);
B
Benny Halevy 已提交
4461 4462 4463 4464
	if (dummy != SP4_NONE)
		return -EIO;

	/* Throw away minor_id */
B
Benny Halevy 已提交
4465 4466 4467
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4468 4469

	/* Throw away Major id */
4470 4471 4472
	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
4473 4474

	/* Throw away server_scope */
4475 4476 4477
	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
4478 4479

	/* Throw away Implementation id array */
4480 4481 4482
	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
4483 4484

	return 0;
B
Benny Halevy 已提交
4485 4486 4487
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
B
Benny Halevy 已提交
4488
}
A
Andy Adamson 已提交
4489 4490 4491 4492 4493 4494 4495

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

B
Benny Halevy 已提交
4496 4497 4498
	p = xdr_inline_decode(xdr, 28);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4499 4500 4501 4502 4503 4504
	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++);
4505
	nr_attrs = be32_to_cpup(p);
A
Andy Adamson 已提交
4506 4507 4508 4509 4510
	if (unlikely(nr_attrs > 1)) {
		printk(KERN_WARNING "%s: Invalid rdma channel attrs count %u\n",
			__func__, nr_attrs);
		return -EINVAL;
	}
B
Benny Halevy 已提交
4511 4512 4513 4514 4515
	if (nr_attrs == 1) {
		p = xdr_inline_decode(xdr, 4); /* skip rdma_attrs */
		if (unlikely(!p))
			goto out_overflow;
	}
A
Andy Adamson 已提交
4516
	return 0;
B
Benny Halevy 已提交
4517 4518 4519
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
A
Andy Adamson 已提交
4520 4521
}

4522 4523 4524
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 已提交
4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535
}

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);
4536 4537 4538
	if (!status)
		status = decode_sessionid(xdr, &session->sess_id);
	if (unlikely(status))
A
Andy Adamson 已提交
4539 4540 4541
		return status;

	/* seqid, flags */
B
Benny Halevy 已提交
4542 4543 4544
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4545
	clp->cl_seqid = be32_to_cpup(p++);
4546
	session->flags = be32_to_cpup(p);
A
Andy Adamson 已提交
4547 4548 4549 4550 4551 4552

	/* 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 已提交
4553 4554 4555
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
A
Andy Adamson 已提交
4556
}
A
Andy Adamson 已提交
4557 4558 4559 4560 4561

static int decode_destroy_session(struct xdr_stream *xdr, void *dummy)
{
	return decode_op_hdr(xdr, OP_DESTROY_SESSION);
}
B
Benny Halevy 已提交
4562 4563
#endif /* CONFIG_NFS_V4_1 */

4564 4565 4566 4567 4568
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 已提交
4569 4570 4571 4572 4573 4574
	struct nfs4_slot *slot;
	struct nfs4_sessionid id;
	u32 dummy;
	int status;
	__be32 *p;

4575 4576 4577
	if (!res->sr_session)
		return 0;

A
Andy Adamson 已提交
4578
	status = decode_op_hdr(xdr, OP_SEQUENCE);
4579 4580 4581
	if (!status)
		status = decode_sessionid(xdr, &id);
	if (unlikely(status))
A
Andy Adamson 已提交
4582
		goto out_err;
4583

A
Andy Adamson 已提交
4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594
	/*
	 * If the server returns different values for sessionID, slotID or
	 * sequence number, the server is looney tunes.
	 */
	status = -ESERVERFAULT;

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

B
Benny Halevy 已提交
4596 4597 4598
	p = xdr_inline_decode(xdr, 20);
	if (unlikely(!p))
		goto out_overflow;
4599

A
Andy Adamson 已提交
4600
	/* seqid */
4601
	slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid];
B
Benny Halevy 已提交
4602
	dummy = be32_to_cpup(p++);
A
Andy Adamson 已提交
4603 4604 4605 4606 4607
	if (dummy != slot->seq_nr) {
		dprintk("%s Invalid sequence number\n", __func__);
		goto out_err;
	}
	/* slot id */
B
Benny Halevy 已提交
4608
	dummy = be32_to_cpup(p++);
A
Andy Adamson 已提交
4609 4610 4611 4612 4613
	if (dummy != res->sr_slotid) {
		dprintk("%s Invalid slot id\n", __func__);
		goto out_err;
	}
	/* highest slot id - currently not processed */
B
Benny Halevy 已提交
4614
	dummy = be32_to_cpup(p++);
A
Andy Adamson 已提交
4615
	/* target highest slot id - currently not processed */
B
Benny Halevy 已提交
4616
	dummy = be32_to_cpup(p++);
4617 4618
	/* result flags */
	res->sr_status_flags = be32_to_cpup(p);
A
Andy Adamson 已提交
4619 4620 4621 4622
	status = 0;
out_err:
	res->sr_status = status;
	return status;
B
Benny Halevy 已提交
4623 4624 4625 4626
out_overflow:
	print_overflow_msg(__func__, xdr);
	status = -EIO;
	goto out_err;
A
Andy Adamson 已提交
4627
#else  /* CONFIG_NFS_V4_1 */
4628
	return 0;
A
Andy Adamson 已提交
4629
#endif /* CONFIG_NFS_V4_1 */
4630 4631
}

4632 4633 4634 4635
/*
 * END OF "GENERIC" DECODE ROUTINES.
 */

L
Linus Torvalds 已提交
4636 4637 4638
/*
 * Decode OPEN_DOWNGRADE response
 */
A
Al Viro 已提交
4639
static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
L
Linus Torvalds 已提交
4640
{
A
Andy Adamson 已提交
4641 4642 4643 4644 4645 4646
	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);
4647 4648 4649
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
4650 4651 4652 4653 4654 4655
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_open_downgrade(&xdr, res);
4656 4657
	if (status != 0)
		goto out;
4658 4659
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4660
out:
A
Andy Adamson 已提交
4661
	return status;
L
Linus Torvalds 已提交
4662 4663 4664 4665 4666
}

/*
 * Decode ACCESS response
 */
A
Al Viro 已提交
4667
static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res)
L
Linus Torvalds 已提交
4668 4669 4670 4671
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4672

L
Linus Torvalds 已提交
4673
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4674 4675 4676 4677 4678
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4679
		goto out;
4680 4681 4682 4683 4684 4685
	status = decode_putfh(&xdr);
	if (status != 0)
		goto out;
	status = decode_access(&xdr, res);
	if (status != 0)
		goto out;
4686 4687
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4688 4689 4690 4691 4692 4693 4694
out:
	return status;
}

/*
 * Decode LOOKUP response
 */
A
Al Viro 已提交
4695
static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
L
Linus Torvalds 已提交
4696 4697 4698 4699
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4700

L
Linus Torvalds 已提交
4701
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4702 4703 4704 4705 4706
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4707 4708 4709 4710 4711 4712 4713
		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;
4714 4715
	status = decode_getfattr(&xdr, res->fattr, res->server
			,!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4716 4717 4718 4719 4720 4721 4722
out:
	return status;
}

/*
 * Decode LOOKUP_ROOT response
 */
A
Al Viro 已提交
4723
static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
L
Linus Torvalds 已提交
4724 4725 4726 4727
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4728

L
Linus Torvalds 已提交
4729
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4730 4731 4732 4733 4734
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4735 4736 4737 4738
		goto out;
	if ((status = decode_putrootfh(&xdr)) != 0)
		goto out;
	if ((status = decode_getfh(&xdr, res->fh)) == 0)
4739 4740
		status = decode_getfattr(&xdr, res->fattr, res->server,
				!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4741 4742 4743 4744 4745 4746 4747
out:
	return status;
}

/*
 * Decode REMOVE response
 */
4748
static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_removeres *res)
L
Linus Torvalds 已提交
4749 4750 4751 4752
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4753

L
Linus Torvalds 已提交
4754
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4755 4756 4757 4758 4759
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4760
		goto out;
4761 4762 4763 4764
	if ((status = decode_putfh(&xdr)) != 0)
		goto out;
	if ((status = decode_remove(&xdr, &res->cinfo)) != 0)
		goto out;
4765 4766
	decode_getfattr(&xdr, &res->dir_attr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4767 4768 4769 4770 4771 4772 4773
out:
	return status;
}

/*
 * Decode RENAME response
 */
A
Al Viro 已提交
4774
static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res)
L
Linus Torvalds 已提交
4775 4776 4777 4778
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4779

L
Linus Torvalds 已提交
4780
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4781 4782 4783 4784 4785
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4786 4787 4788 4789 4790 4791 4792
		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;
4793 4794 4795
	if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0)
		goto out;
	/* Current FH is target directory */
4796 4797
	if (decode_getfattr(&xdr, res->new_fattr, res->server,
				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
4798 4799 4800
		goto out;
	if ((status = decode_restorefh(&xdr)) != 0)
		goto out;
4801 4802
	decode_getfattr(&xdr, res->old_fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4803 4804 4805 4806 4807 4808 4809
out:
	return status;
}

/*
 * Decode LINK response
 */
A
Al Viro 已提交
4810
static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link_res *res)
L
Linus Torvalds 已提交
4811 4812 4813 4814
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4815

L
Linus Torvalds 已提交
4816
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4817 4818 4819 4820 4821
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4822 4823 4824 4825 4826 4827 4828
		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;
4829 4830 4831 4832 4833 4834
	if ((status = decode_link(&xdr, &res->cinfo)) != 0)
		goto out;
	/*
	 * Note order: OP_LINK leaves the directory as the current
	 *             filehandle.
	 */
4835 4836
	if (decode_getfattr(&xdr, res->dir_attr, res->server,
				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
4837 4838 4839
		goto out;
	if ((status = decode_restorefh(&xdr)) != 0)
		goto out;
4840 4841
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4842 4843 4844 4845 4846 4847 4848
out:
	return status;
}

/*
 * Decode CREATE response
 */
A
Al Viro 已提交
4849
static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
L
Linus Torvalds 已提交
4850 4851 4852 4853
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4854

L
Linus Torvalds 已提交
4855
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4856 4857 4858 4859 4860
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4861 4862 4863
		goto out;
	if ((status = decode_putfh(&xdr)) != 0)
		goto out;
4864 4865
	if ((status = decode_savefh(&xdr)) != 0)
		goto out;
L
Linus Torvalds 已提交
4866 4867 4868 4869
	if ((status = decode_create(&xdr,&res->dir_cinfo)) != 0)
		goto out;
	if ((status = decode_getfh(&xdr, res->fh)) != 0)
		goto out;
4870 4871
	if (decode_getfattr(&xdr, res->fattr, res->server,
				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
4872 4873 4874
		goto out;
	if ((status = decode_restorefh(&xdr)) != 0)
		goto out;
4875 4876
	decode_getfattr(&xdr, res->dir_fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4877 4878 4879 4880 4881 4882 4883
out:
	return status;
}

/*
 * Decode SYMLINK response
 */
A
Al Viro 已提交
4884
static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
L
Linus Torvalds 已提交
4885 4886 4887 4888 4889 4890 4891
{
	return nfs4_xdr_dec_create(rqstp, p, res);
}

/*
 * Decode GETATTR response
 */
A
Al Viro 已提交
4892
static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_getattr_res *res)
L
Linus Torvalds 已提交
4893 4894 4895 4896
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4897

L
Linus Torvalds 已提交
4898 4899
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
4900 4901 4902
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
4903 4904 4905 4906 4907
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
4908 4909
	status = decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4910 4911 4912 4913
out:
	return status;
}

4914 4915 4916 4917
/*
 * Encode an SETACL request
 */
static int
A
Al Viro 已提交
4918
nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args)
4919
{
A
Andy Adamson 已提交
4920 4921
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
4922
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
A
Andy Adamson 已提交
4923 4924 4925 4926
	};
	int status;

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
4927
	encode_compound_hdr(&xdr, req, &hdr);
4928
	encode_sequence(&xdr, &args->seq_args, &hdr);
4929
	encode_putfh(&xdr, args->fh, &hdr);
4930 4931
	status = encode_setacl(&xdr, args, &hdr);
	encode_nops(&hdr);
A
Andy Adamson 已提交
4932
	return status;
4933
}
A
Andy Adamson 已提交
4934

4935 4936 4937 4938
/*
 * Decode SETACL response
 */
static int
B
Benny Halevy 已提交
4939 4940
nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p,
		    struct nfs_setaclres *res)
4941 4942 4943 4944 4945 4946 4947
{
	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);
4948 4949 4950
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
4951 4952 4953 4954 4955
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
4956
	status = decode_setattr(&xdr);
4957 4958 4959
out:
	return status;
}
L
Linus Torvalds 已提交
4960

4961 4962 4963 4964
/*
 * Decode GETACL response
 */
static int
B
Benny Halevy 已提交
4965 4966
nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p,
		    struct nfs_getaclres *res)
4967 4968 4969 4970 4971 4972 4973
{
	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);
4974 4975 4976
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
4977 4978 4979 4980 4981
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
B
Benny Halevy 已提交
4982
	status = decode_getacl(&xdr, rqstp, &res->acl_len);
4983 4984 4985 4986 4987

out:
	return status;
}

L
Linus Torvalds 已提交
4988 4989 4990
/*
 * Decode CLOSE response
 */
A
Al Viro 已提交
4991
static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
L
Linus Torvalds 已提交
4992
{
A
Andy Adamson 已提交
4993 4994 4995 4996 4997 4998
	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);
4999 5000 5001
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
5002 5003 5004 5005 5006 5007
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_close(&xdr, res);
5008 5009 5010 5011 5012 5013 5014 5015
	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.
	 */
5016 5017
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5018
out:
A
Andy Adamson 已提交
5019
	return status;
L
Linus Torvalds 已提交
5020 5021 5022 5023 5024
}

/*
 * Decode OPEN response
 */
A
Al Viro 已提交
5025
static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
L
Linus Torvalds 已提交
5026
{
A
Andy Adamson 已提交
5027 5028 5029 5030 5031 5032
	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);
5033 5034 5035
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
5036 5037 5038 5039 5040 5041 5042 5043 5044
	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);
5045 5046
	if (status)
		goto out;
5047
	if (decode_getfh(&xdr, &res->fh) != 0)
L
Linus Torvalds 已提交
5048
		goto out;
5049 5050
	if (decode_getfattr(&xdr, res->f_attr, res->server,
				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
5051
		goto out;
5052
	if (decode_restorefh(&xdr) != 0)
5053
		goto out;
5054 5055
	decode_getfattr(&xdr, res->dir_attr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5056
out:
A
Andy Adamson 已提交
5057
	return status;
L
Linus Torvalds 已提交
5058 5059 5060 5061 5062
}

/*
 * Decode OPEN_CONFIRM response
 */
A
Al Viro 已提交
5063
static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, __be32 *p, struct nfs_open_confirmres *res)
L
Linus Torvalds 已提交
5064
{
A
Andy Adamson 已提交
5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076
	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 已提交
5077
out:
A
Andy Adamson 已提交
5078
	return status;
L
Linus Torvalds 已提交
5079 5080 5081 5082 5083
}

/*
 * Decode OPEN response
 */
A
Al Viro 已提交
5084
static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
L
Linus Torvalds 已提交
5085
{
A
Andy Adamson 已提交
5086 5087 5088 5089 5090 5091
	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);
5092 5093 5094
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
5095 5096 5097 5098 5099 5100 5101 5102
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_open(&xdr, res);
	if (status)
		goto out;
5103 5104
	decode_getfattr(&xdr, res->f_attr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5105
out:
A
Andy Adamson 已提交
5106
	return status;
L
Linus Torvalds 已提交
5107 5108 5109 5110 5111
}

/*
 * Decode SETATTR response
 */
A
Al Viro 已提交
5112
static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res)
L
Linus Torvalds 已提交
5113
{
A
Andy Adamson 已提交
5114 5115 5116 5117 5118 5119
	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);
5120 5121 5122
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
5123 5124 5125 5126 5127
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
5128
	status = decode_setattr(&xdr);
A
Andy Adamson 已提交
5129 5130
	if (status)
		goto out;
5131 5132
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5133
out:
A
Andy Adamson 已提交
5134
	return status;
L
Linus Torvalds 已提交
5135 5136 5137 5138 5139
}

/*
 * Decode LOCK response
 */
A
Al Viro 已提交
5140
static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_res *res)
L
Linus Torvalds 已提交
5141 5142 5143 5144 5145 5146 5147
{
	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);
5148 5149 5150
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163
	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 已提交
5164
static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lockt_res *res)
L
Linus Torvalds 已提交
5165 5166 5167 5168 5169 5170 5171
{
	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);
5172 5173 5174
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187
	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 已提交
5188
static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_locku_res *res)
L
Linus Torvalds 已提交
5189 5190 5191 5192 5193 5194 5195
{
	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);
5196 5197 5198
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211
	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 已提交
5212 5213
static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p,
				 struct nfs4_readlink_res *res)
L
Linus Torvalds 已提交
5214 5215 5216 5217 5218 5219 5220
{
	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);
5221 5222 5223
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236
	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 已提交
5237
static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_readdir_res *res)
L
Linus Torvalds 已提交
5238 5239 5240 5241 5242 5243 5244
{
	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);
5245 5246 5247
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260
	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 已提交
5261
static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readres *res)
L
Linus Torvalds 已提交
5262 5263 5264 5265 5266 5267 5268
{
	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);
5269 5270 5271
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286
	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 已提交
5287
static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
L
Linus Torvalds 已提交
5288 5289 5290 5291 5292 5293 5294
{
	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);
5295 5296 5297
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5298 5299 5300 5301 5302 5303
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_write(&xdr, res);
5304 5305
	if (status)
		goto out;
5306 5307
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5308 5309 5310 5311 5312 5313 5314 5315 5316
	if (!status)
		status = res->count;
out:
	return status;
}

/*
 * Decode COMMIT response
 */
A
Al Viro 已提交
5317
static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
L
Linus Torvalds 已提交
5318 5319 5320 5321 5322 5323 5324
{
	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);
5325 5326 5327
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5328 5329 5330 5331 5332 5333
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_commit(&xdr, res);
5334 5335
	if (status)
		goto out;
5336 5337
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5338 5339 5340 5341 5342
out:
	return status;
}

/*
5343
 * Decode FSINFO response
L
Linus Torvalds 已提交
5344
 */
B
Benny Halevy 已提交
5345 5346
static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p,
			       struct nfs4_fsinfo_res *res)
L
Linus Torvalds 已提交
5347 5348 5349 5350 5351 5352 5353
{
	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);
5354 5355
	if (!status)
		status = decode_sequence(&xdr, &res->seq_res, req);
L
Linus Torvalds 已提交
5356 5357 5358
	if (!status)
		status = decode_putfh(&xdr);
	if (!status)
B
Benny Halevy 已提交
5359
		status = decode_fsinfo(&xdr, res->fsinfo);
L
Linus Torvalds 已提交
5360 5361 5362 5363
	return status;
}

/*
5364
 * Decode PATHCONF response
L
Linus Torvalds 已提交
5365
 */
B
Benny Halevy 已提交
5366 5367
static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p,
				 struct nfs4_pathconf_res *res)
L
Linus Torvalds 已提交
5368 5369 5370 5371 5372 5373 5374
{
	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);
5375 5376
	if (!status)
		status = decode_sequence(&xdr, &res->seq_res, req);
L
Linus Torvalds 已提交
5377 5378 5379
	if (!status)
		status = decode_putfh(&xdr);
	if (!status)
B
Benny Halevy 已提交
5380
		status = decode_pathconf(&xdr, res->pathconf);
L
Linus Torvalds 已提交
5381 5382 5383 5384
	return status;
}

/*
5385
 * Decode STATFS response
L
Linus Torvalds 已提交
5386
 */
B
Benny Halevy 已提交
5387 5388
static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p,
			       struct nfs4_statfs_res *res)
L
Linus Torvalds 已提交
5389 5390 5391 5392 5393 5394 5395
{
	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);
5396 5397
	if (!status)
		status = decode_sequence(&xdr, &res->seq_res, req);
L
Linus Torvalds 已提交
5398 5399 5400
	if (!status)
		status = decode_putfh(&xdr);
	if (!status)
B
Benny Halevy 已提交
5401
		status = decode_statfs(&xdr, res->fsstat);
L
Linus Torvalds 已提交
5402 5403 5404 5405
	return status;
}

/*
5406
 * Decode GETATTR_BITMAP response
L
Linus Torvalds 已提交
5407
 */
A
Al Viro 已提交
5408
static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4_server_caps_res *res)
L
Linus Torvalds 已提交
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);
5415 5416 5417 5418 5419
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, req);
	if (status)
L
Linus Torvalds 已提交
5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430
		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 已提交
5431
static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy)
L
Linus Torvalds 已提交
5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444
{
	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;
}

/*
5445
 * Decode SETCLIENTID response
L
Linus Torvalds 已提交
5446
 */
A
Al Viro 已提交
5447
static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p,
5448
		struct nfs_client *clp)
L
Linus Torvalds 已提交
5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461
{
	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(&xdr, clp);
	return status;
}

/*
5462
 * Decode SETCLIENTID_CONFIRM response
L
Linus Torvalds 已提交
5463
 */
A
Al Viro 已提交
5464
static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
L
Linus Torvalds 已提交
5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481
{
	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;
}

/*
5482
 * Decode DELEGRETURN response
L
Linus Torvalds 已提交
5483
 */
A
Al Viro 已提交
5484
static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_delegreturnres *res)
L
Linus Torvalds 已提交
5485 5486 5487 5488 5489 5490 5491
{
	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);
5492 5493 5494 5495
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
5496 5497 5498 5499 5500
		goto out;
	status = decode_putfh(&xdr);
	if (status != 0)
		goto out;
	status = decode_delegreturn(&xdr);
5501 5502
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
5503
out:
L
Linus Torvalds 已提交
5504 5505 5506
	return status;
}

5507
/*
5508
 * Decode FS_LOCATIONS response
5509
 */
B
Benny Halevy 已提交
5510 5511
static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p,
				     struct nfs4_fs_locations_res *res)
5512 5513 5514 5515 5516 5517 5518
{
	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);
5519 5520 5521 5522
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, req);
	if (status)
5523 5524 5525 5526 5527 5528
		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 已提交
5529
	status = decode_getfattr(&xdr, &res->fs_locations->fattr,
5530 5531
				 res->fs_locations->server,
				 !RPC_IS_ASYNC(req->rq_task));
5532 5533 5534 5535
out:
	return status;
}

B
Benny Halevy 已提交
5536 5537
#if defined(CONFIG_NFS_V4_1)
/*
5538
 * Decode EXCHANGE_ID response
B
Benny Halevy 已提交
5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552
 */
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 已提交
5553

A
Andy Adamson 已提交
5554
/*
5555
 * Decode CREATE_SESSION response
A
Andy Adamson 已提交
5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570
 */
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 已提交
5571
/*
5572
 * Decode DESTROY_SESSION response
A
Andy Adamson 已提交
5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587
 */
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 已提交
5588
/*
5589
 * Decode SEQUENCE response
A
Andy Adamson 已提交
5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604
 */
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 已提交
5605
/*
5606
 * Decode GET_LEASE_TIME response
A
Andy Adamson 已提交
5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624
 */
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;
}
B
Benny Halevy 已提交
5625 5626
#endif /* CONFIG_NFS_V4_1 */

5627
__be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
L
Linus Torvalds 已提交
5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661
{
	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) {
5662 5663 5664 5665 5666 5667
		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 已提交
5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687
		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		},
5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718
	{ 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	},
	{ NFS4ERR_SERVERFAULT,	-ESERVERFAULT	},
	{ 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 已提交
5719 5720 5721
						    * to be handled by a
						    * middle-layer.
						    */
5722
	{ -1,			-EIO		}
L
Linus Torvalds 已提交
5723 5724 5725 5726 5727 5728 5729
};

/*
 * Convert an NFS error code to a local one.
 * This one is used jointly by NFSv2 and NFSv3.
 */
static int
5730
nfs4_stat_to_errno(int stat)
L
Linus Torvalds 已提交
5731 5732 5733 5734 5735 5736 5737 5738
{
	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. */
5739
		return -ESERVERFAULT;
L
Linus Torvalds 已提交
5740 5741 5742 5743 5744 5745
	}
	/* 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.
	 */
5746
	return -stat;
L
Linus Torvalds 已提交
5747 5748 5749 5750 5751 5752 5753
}

#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,		\
5754 5755
	.p_arglen = NFS4_##argtype##_sz,			\
	.p_replen = NFS4_##restype##_sz,			\
5756 5757
	.p_statidx = NFSPROC4_CLNT_##proc,			\
	.p_name   = #proc,					\
A
Andy Adamson 已提交
5758
}
L
Linus Torvalds 已提交
5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791

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),
5792
  PROC(GETACL,		enc_getacl,	dec_getacl),
5793
  PROC(SETACL,		enc_setacl,	dec_setacl),
5794
  PROC(FS_LOCATIONS,	enc_fs_locations, dec_fs_locations),
B
Benny Halevy 已提交
5795 5796
#if defined(CONFIG_NFS_V4_1)
  PROC(EXCHANGE_ID,	enc_exchange_id,	dec_exchange_id),
A
Andy Adamson 已提交
5797
  PROC(CREATE_SESSION,	enc_create_session,	dec_create_session),
A
Andy Adamson 已提交
5798
  PROC(DESTROY_SESSION,	enc_destroy_session,	dec_destroy_session),
A
Andy Adamson 已提交
5799
  PROC(SEQUENCE,	enc_sequence,	dec_sequence),
A
Andy Adamson 已提交
5800
  PROC(GET_LEASE_TIME,	enc_get_lease_time,	dec_get_lease_time),
B
Benny Halevy 已提交
5801
#endif /* CONFIG_NFS_V4_1 */
L
Linus Torvalds 已提交
5802 5803 5804 5805
};

struct rpc_version		nfs_version4 = {
	.number			= 4,
5806
	.nrprocs		= ARRAY_SIZE(nfs4_procedures),
L
Linus Torvalds 已提交
5807 5808 5809 5810 5811 5812 5813 5814
	.procs			= nfs4_procedures
};

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