nfs4xdr.c 154.3 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
#define encode_reclaim_complete_maxsz	(op_encode_hdr_maxsz + 4)
#define decode_reclaim_complete_maxsz	(op_decode_hdr_maxsz + 4)
306 307 308 309 310
#else /* CONFIG_NFS_V4_1 */
#define encode_sequence_maxsz	0
#define decode_sequence_maxsz	0
#endif /* CONFIG_NFS_V4_1 */

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

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

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

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

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

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

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

743 744 745
static void encode_compound_hdr(struct xdr_stream *xdr,
				struct rpc_rqst *req,
				struct compound_hdr *hdr)
L
Linus Torvalds 已提交
746
{
A
Al Viro 已提交
747
	__be32 *p;
748 749 750 751 752 753
	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 已提交
754 755 756

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

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

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

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

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

	/*
	 * 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 已提交
842
	*p++ = cpu_to_be32(2);
L
Linus Torvalds 已提交
843 844 845 846 847
	q = p;
	p += 3;

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

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

/* out: */
}

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

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

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

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

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

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

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

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

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

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

	default:
		break;
	}

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

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

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

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

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

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

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

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

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

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

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

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

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

T
Trond Myklebust 已提交
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
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 已提交
1046 1047 1048 1049
/*
 * opcode,type,reclaim,offset,length,new_lock_owner = 32
 * open_seqid,open_stateid,lock_seqid,lock_owner.clientid, lock_owner.id = 40
 */
1050
static void encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1051
{
A
Al Viro 已提交
1052
	__be32 *p;
L
Linus Torvalds 已提交
1053

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

1080
static void encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1081
{
A
Al Viro 已提交
1082
	__be32 *p;
L
Linus Torvalds 已提交
1083

1084
	p = reserve_space(xdr, 52);
B
Benny Halevy 已提交
1085 1086
	*p++ = cpu_to_be32(OP_LOCKT);
	*p++ = cpu_to_be32(nfs4_lock_type(args->fl, 0));
B
Benny Halevy 已提交
1087 1088 1089
	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 已提交
1090
	*p++ = cpu_to_be32(16);
B
Benny Halevy 已提交
1091
	p = xdr_encode_opaque_fixed(p, "lock id:", 8);
1092
	xdr_encode_hyper(p, args->lock_owner.id);
1093
	hdr->nops++;
1094
	hdr->replen += decode_lockt_maxsz;
L
Linus Torvalds 已提交
1095 1096
}

1097
static void encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1098
{
A
Al Viro 已提交
1099
	__be32 *p;
L
Linus Torvalds 已提交
1100

1101
	p = reserve_space(xdr, 12+NFS4_STATEID_SIZE+16);
B
Benny Halevy 已提交
1102 1103 1104
	*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 已提交
1105
	p = xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1106
	p = xdr_encode_hyper(p, args->fl->fl_start);
1107
	xdr_encode_hyper(p, nfs4_lock_length(args->fl));
1108
	hdr->nops++;
1109
	hdr->replen += decode_locku_maxsz;
L
Linus Torvalds 已提交
1110 1111
}

1112
static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1113 1114
{
	int len = name->len;
A
Al Viro 已提交
1115
	__be32 *p;
L
Linus Torvalds 已提交
1116

1117
	p = reserve_space(xdr, 8 + len);
B
Benny Halevy 已提交
1118
	*p++ = cpu_to_be32(OP_LOOKUP);
1119
	xdr_encode_opaque(p, name->name, len);
1120
	hdr->nops++;
1121
	hdr->replen += decode_lookup_maxsz;
L
Linus Torvalds 已提交
1122 1123
}

1124
static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode)
L
Linus Torvalds 已提交
1125
{
A
Al Viro 已提交
1126
	__be32 *p;
L
Linus Torvalds 已提交
1127

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

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

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

1168
	p = reserve_space(xdr, 4);
L
Linus Torvalds 已提交
1169
	switch(arg->open_flags & O_EXCL) {
A
Andy Adamson 已提交
1170
	case 0:
1171
		*p = cpu_to_be32(NFS4_CREATE_UNCHECKED);
A
Andy Adamson 已提交
1172 1173 1174
		encode_attrs(xdr, arg->u.attrs, arg->server);
		break;
	default:
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191
		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 已提交
1192 1193 1194 1195 1196
	}
}

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

1199
	p = reserve_space(xdr, 4);
L
Linus Torvalds 已提交
1200
	switch (arg->open_flags & O_CREAT) {
A
Andy Adamson 已提交
1201
	case 0:
1202
		*p = cpu_to_be32(NFS4_OPEN_NOCREATE);
A
Andy Adamson 已提交
1203 1204 1205
		break;
	default:
		BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL);
1206
		*p = cpu_to_be32(NFS4_OPEN_CREATE);
A
Andy Adamson 已提交
1207
		encode_createmode(xdr, arg);
L
Linus Torvalds 已提交
1208 1209 1210
	}
}

1211
static inline void encode_delegation_type(struct xdr_stream *xdr, fmode_t delegation_type)
L
Linus Torvalds 已提交
1212
{
A
Al Viro 已提交
1213
	__be32 *p;
L
Linus Torvalds 已提交
1214

1215
	p = reserve_space(xdr, 4);
L
Linus Torvalds 已提交
1216
	switch (delegation_type) {
A
Andy Adamson 已提交
1217
	case 0:
1218
		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_NONE);
A
Andy Adamson 已提交
1219 1220
		break;
	case FMODE_READ:
1221
		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_READ);
A
Andy Adamson 已提交
1222 1223
		break;
	case FMODE_WRITE|FMODE_READ:
1224
		*p = cpu_to_be32(NFS4_OPEN_DELEGATE_WRITE);
A
Andy Adamson 已提交
1225 1226 1227
		break;
	default:
		BUG();
L
Linus Torvalds 已提交
1228 1229 1230 1231 1232
	}
}

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

1235
	p = reserve_space(xdr, 4);
1236
	*p = cpu_to_be32(NFS4_OPEN_CLAIM_NULL);
L
Linus Torvalds 已提交
1237 1238 1239
	encode_string(xdr, name->len, name->name);
}

1240
static inline void encode_claim_previous(struct xdr_stream *xdr, fmode_t type)
L
Linus Torvalds 已提交
1241
{
A
Al Viro 已提交
1242
	__be32 *p;
L
Linus Torvalds 已提交
1243

1244
	p = reserve_space(xdr, 4);
1245
	*p = cpu_to_be32(NFS4_OPEN_CLAIM_PREVIOUS);
L
Linus Torvalds 已提交
1246 1247 1248 1249 1250
	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 已提交
1251
	__be32 *p;
L
Linus Torvalds 已提交
1252

1253
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1254
	*p++ = cpu_to_be32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
1255
	xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1256 1257 1258
	encode_string(xdr, name->len, name->name);
}

1259
static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1260 1261 1262 1263
{
	encode_openhdr(xdr, arg);
	encode_opentype(xdr, arg);
	switch (arg->claim) {
A
Andy Adamson 已提交
1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274
	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 已提交
1275
	}
1276
	hdr->nops++;
1277
	hdr->replen += decode_open_maxsz;
L
Linus Torvalds 已提交
1278 1279
}

1280
static void encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1281
{
A
Al Viro 已提交
1282
	__be32 *p;
L
Linus Torvalds 已提交
1283

1284
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
B
Benny Halevy 已提交
1285
	*p++ = cpu_to_be32(OP_OPEN_CONFIRM);
B
Benny Halevy 已提交
1286
	p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
1287
	*p = cpu_to_be32(arg->seqid->sequence->counter);
1288
	hdr->nops++;
1289
	hdr->replen += decode_open_confirm_maxsz;
L
Linus Torvalds 已提交
1290 1291
}

1292
static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1293
{
A
Al Viro 已提交
1294
	__be32 *p;
L
Linus Torvalds 已提交
1295

1296
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE+4);
B
Benny Halevy 已提交
1297
	*p++ = cpu_to_be32(OP_OPEN_DOWNGRADE);
B
Benny Halevy 已提交
1298
	p = xdr_encode_opaque_fixed(p, arg->stateid->data, NFS4_STATEID_SIZE);
1299
	*p = cpu_to_be32(arg->seqid->sequence->counter);
1300
	encode_share_access(xdr, arg->fmode);
1301
	hdr->nops++;
1302
	hdr->replen += decode_open_downgrade_maxsz;
L
Linus Torvalds 已提交
1303 1304
}

1305
static void
1306
encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1307 1308
{
	int len = fh->size;
A
Al Viro 已提交
1309
	__be32 *p;
L
Linus Torvalds 已提交
1310

1311
	p = reserve_space(xdr, 8 + len);
B
Benny Halevy 已提交
1312
	*p++ = cpu_to_be32(OP_PUTFH);
1313
	xdr_encode_opaque(p, fh->data, len);
1314
	hdr->nops++;
1315
	hdr->replen += decode_putfh_maxsz;
L
Linus Torvalds 已提交
1316 1317
}

1318
static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1319
{
A
Andy Adamson 已提交
1320
	__be32 *p;
1321

1322
	p = reserve_space(xdr, 4);
1323
	*p = cpu_to_be32(OP_PUTROOTFH);
1324
	hdr->nops++;
1325
	hdr->replen += decode_putrootfh_maxsz;
L
Linus Torvalds 已提交
1326 1327 1328 1329 1330
}

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

1333
	p = reserve_space(xdr, NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1334 1335
	if (ctx->state != NULL) {
		nfs4_copy_stateid(&stateid, ctx->state, ctx->lockowner);
1336
		xdr_encode_opaque_fixed(p, stateid.data, NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1337
	} else
1338
		xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
L
Linus Torvalds 已提交
1339 1340
}

1341
static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1342
{
A
Al Viro 已提交
1343
	__be32 *p;
L
Linus Torvalds 已提交
1344

1345
	p = reserve_space(xdr, 4);
1346
	*p = cpu_to_be32(OP_READ);
L
Linus Torvalds 已提交
1347 1348 1349

	encode_stateid(xdr, args->context);

1350
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
1351
	p = xdr_encode_hyper(p, args->offset);
1352
	*p = cpu_to_be32(args->count);
1353
	hdr->nops++;
1354
	hdr->replen += decode_read_maxsz;
L
Linus Torvalds 已提交
1355 1356
}

1357
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 已提交
1358
{
1359 1360 1361 1362
	uint32_t attrs[2] = {
		FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID,
		FATTR4_WORD1_MOUNTED_ON_FILEID,
	};
A
Al Viro 已提交
1363
	__be32 *p;
L
Linus Torvalds 已提交
1364

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

1390
static void encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1391
{
A
Al Viro 已提交
1392
	__be32 *p;
L
Linus Torvalds 已提交
1393

1394
	p = reserve_space(xdr, 4);
1395
	*p = cpu_to_be32(OP_READLINK);
1396
	hdr->nops++;
1397
	hdr->replen += decode_readlink_maxsz;
L
Linus Torvalds 已提交
1398 1399
}

1400
static void encode_remove(struct xdr_stream *xdr, const struct qstr *name, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1401
{
A
Al Viro 已提交
1402
	__be32 *p;
L
Linus Torvalds 已提交
1403

1404
	p = reserve_space(xdr, 8 + name->len);
B
Benny Halevy 已提交
1405
	*p++ = cpu_to_be32(OP_REMOVE);
1406
	xdr_encode_opaque(p, name->name, name->len);
1407
	hdr->nops++;
1408
	hdr->replen += decode_remove_maxsz;
L
Linus Torvalds 已提交
1409 1410
}

1411
static void encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1412
{
A
Al Viro 已提交
1413
	__be32 *p;
L
Linus Torvalds 已提交
1414

1415 1416 1417 1418
	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);
1419
	hdr->nops++;
1420
	hdr->replen += decode_rename_maxsz;
L
Linus Torvalds 已提交
1421 1422
}

1423
static void encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1424
{
A
Al Viro 已提交
1425
	__be32 *p;
L
Linus Torvalds 已提交
1426

1427
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
1428
	*p++ = cpu_to_be32(OP_RENEW);
1429
	xdr_encode_hyper(p, client_stateid->cl_clientid);
1430
	hdr->nops++;
1431
	hdr->replen += decode_renew_maxsz;
L
Linus Torvalds 已提交
1432 1433
}

1434
static void
1435
encode_restorefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
1436
{
A
Al Viro 已提交
1437
	__be32 *p;
1438

1439
	p = reserve_space(xdr, 4);
1440
	*p = cpu_to_be32(OP_RESTOREFH);
1441
	hdr->nops++;
1442
	hdr->replen += decode_restorefh_maxsz;
1443 1444
}

1445
static int
1446
encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg, struct compound_hdr *hdr)
1447
{
A
Al Viro 已提交
1448
	__be32 *p;
1449

1450
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1451
	*p++ = cpu_to_be32(OP_SETATTR);
1452
	xdr_encode_opaque_fixed(p, zero_stateid.data, NFS4_STATEID_SIZE);
1453
	p = reserve_space(xdr, 2*4);
B
Benny Halevy 已提交
1454
	*p++ = cpu_to_be32(1);
1455
	*p = cpu_to_be32(FATTR4_WORD0_ACL);
1456 1457
	if (arg->acl_len % 4)
		return -EINVAL;
1458
	p = reserve_space(xdr, 4);
1459
	*p = cpu_to_be32(arg->acl_len);
1460
	xdr_write_pages(xdr, arg->acl_pages, arg->acl_pgbase, arg->acl_len);
1461
	hdr->nops++;
1462
	hdr->replen += decode_setacl_maxsz;
1463 1464 1465
	return 0;
}

1466
static void
1467
encode_savefh(struct xdr_stream *xdr, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1468
{
A
Al Viro 已提交
1469
	__be32 *p;
L
Linus Torvalds 已提交
1470

1471
	p = reserve_space(xdr, 4);
1472
	*p = cpu_to_be32(OP_SAVEFH);
1473
	hdr->nops++;
1474
	hdr->replen += decode_savefh_maxsz;
L
Linus Torvalds 已提交
1475 1476
}

1477
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 已提交
1478
{
A
Al Viro 已提交
1479
	__be32 *p;
1480

1481
	p = reserve_space(xdr, 4+NFS4_STATEID_SIZE);
B
Benny Halevy 已提交
1482
	*p++ = cpu_to_be32(OP_SETATTR);
1483
	xdr_encode_opaque_fixed(p, arg->stateid.data, NFS4_STATEID_SIZE);
1484
	hdr->nops++;
1485
	hdr->replen += decode_setattr_maxsz;
1486
	encode_attrs(xdr, arg->iap, server);
L
Linus Torvalds 已提交
1487 1488
}

1489
static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1490
{
A
Al Viro 已提交
1491
	__be32 *p;
L
Linus Torvalds 已提交
1492

1493
	p = reserve_space(xdr, 4 + NFS4_VERIFIER_SIZE);
B
Benny Halevy 已提交
1494
	*p++ = cpu_to_be32(OP_SETCLIENTID);
1495
	xdr_encode_opaque_fixed(p, setclientid->sc_verifier->data, NFS4_VERIFIER_SIZE);
L
Linus Torvalds 已提交
1496 1497

	encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
1498
	p = reserve_space(xdr, 4);
1499
	*p = cpu_to_be32(setclientid->sc_prog);
L
Linus Torvalds 已提交
1500 1501
	encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid);
	encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
1502
	p = reserve_space(xdr, 4);
1503
	*p = cpu_to_be32(setclientid->sc_cb_ident);
1504
	hdr->nops++;
1505
	hdr->replen += decode_setclientid_maxsz;
L
Linus Torvalds 已提交
1506 1507
}

1508
static void encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1509
{
A
Andy Adamson 已提交
1510
	__be32 *p;
L
Linus Torvalds 已提交
1511

1512
	p = reserve_space(xdr, 12 + NFS4_VERIFIER_SIZE);
B
Benny Halevy 已提交
1513
	*p++ = cpu_to_be32(OP_SETCLIENTID_CONFIRM);
B
Benny Halevy 已提交
1514
	p = xdr_encode_hyper(p, client_state->cl_clientid);
1515
	xdr_encode_opaque_fixed(p, client_state->cl_confirm.data, NFS4_VERIFIER_SIZE);
1516
	hdr->nops++;
1517
	hdr->replen += decode_setclientid_confirm_maxsz;
L
Linus Torvalds 已提交
1518 1519
}

1520
static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1521
{
A
Al Viro 已提交
1522
	__be32 *p;
L
Linus Torvalds 已提交
1523

1524
	p = reserve_space(xdr, 4);
1525
	*p = cpu_to_be32(OP_WRITE);
L
Linus Torvalds 已提交
1526 1527 1528

	encode_stateid(xdr, args->context);

1529
	p = reserve_space(xdr, 16);
B
Benny Halevy 已提交
1530
	p = xdr_encode_hyper(p, args->offset);
B
Benny Halevy 已提交
1531
	*p++ = cpu_to_be32(args->stable);
1532
	*p = cpu_to_be32(args->count);
L
Linus Torvalds 已提交
1533 1534

	xdr_write_pages(xdr, args->pages, args->pgbase, args->count);
1535
	hdr->nops++;
1536
	hdr->replen += decode_write_maxsz;
L
Linus Torvalds 已提交
1537 1538
}

1539
static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid, struct compound_hdr *hdr)
L
Linus Torvalds 已提交
1540
{
A
Al Viro 已提交
1541
	__be32 *p;
L
Linus Torvalds 已提交
1542

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

B
Benny Halevy 已提交
1545
	*p++ = cpu_to_be32(OP_DELEGRETURN);
1546
	xdr_encode_opaque_fixed(p, stateid->data, NFS4_STATEID_SIZE);
1547
	hdr->nops++;
1548
	hdr->replen += decode_delegreturn_maxsz;
L
Linus Torvalds 已提交
1549
}
1550

B
Benny Halevy 已提交
1551
#if defined(CONFIG_NFS_V4_1)
1552
/* NFSv4.1 operations */
B
Benny Halevy 已提交
1553 1554 1555 1556 1557 1558
static void encode_exchange_id(struct xdr_stream *xdr,
			       struct nfs41_exchange_id_args *args,
			       struct compound_hdr *hdr)
{
	__be32 *p;

1559
	p = reserve_space(xdr, 4 + sizeof(args->verifier->data));
B
Benny Halevy 已提交
1560
	*p++ = cpu_to_be32(OP_EXCHANGE_ID);
1561
	xdr_encode_opaque_fixed(p, args->verifier->data, sizeof(args->verifier->data));
B
Benny Halevy 已提交
1562 1563 1564

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

1565
	p = reserve_space(xdr, 12);
B
Benny Halevy 已提交
1566 1567
	*p++ = cpu_to_be32(args->flags);
	*p++ = cpu_to_be32(0);	/* zero length state_protect4_a */
1568
	*p = cpu_to_be32(0);	/* zero length implementation id array */
B
Benny Halevy 已提交
1569 1570 1571
	hdr->nops++;
	hdr->replen += decode_exchange_id_maxsz;
}
A
Andy Adamson 已提交
1572 1573 1574 1575 1576 1577 1578 1579 1580

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;
1581 1582 1583 1584 1585 1586 1587 1588
	u32 max_resp_sz_cached;

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

1590 1591
	len = scnprintf(machine_name, sizeof(machine_name), "%s",
			clp->cl_ipaddr);
A
Andy Adamson 已提交
1592

1593
	p = reserve_space(xdr, 20 + 2*28 + 20 + len + 12);
1594
	*p++ = cpu_to_be32(OP_CREATE_SESSION);
B
Benny Halevy 已提交
1595
	p = xdr_encode_hyper(p, clp->cl_ex_clid);
B
Benny Halevy 已提交
1596 1597
	*p++ = cpu_to_be32(clp->cl_seqid);			/*Sequence id */
	*p++ = cpu_to_be32(args->flags);			/*flags */
A
Andy Adamson 已提交
1598 1599

	/* Fore Channel */
B
Benny Halevy 已提交
1600 1601 1602
	*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 */
1603
	*p++ = cpu_to_be32(max_resp_sz_cached);		/* Max resp sz cached */
B
Benny Halevy 已提交
1604 1605 1606
	*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 已提交
1607 1608

	/* Back Channel */
B
Benny Halevy 已提交
1609 1610 1611 1612 1613 1614 1615
	*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 已提交
1616

B
Benny Halevy 已提交
1617 1618 1619
	*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 已提交
1620 1621

	/* authsys_parms rfc1831 */
B
Benny Halevy 已提交
1622
	*p++ = cpu_to_be32((u32)clp->cl_boot_time.tv_nsec);	/* stamp */
1623
	p = xdr_encode_opaque(p, machine_name, len);
B
Benny Halevy 已提交
1624 1625
	*p++ = cpu_to_be32(0);				/* UID */
	*p++ = cpu_to_be32(0);				/* GID */
1626
	*p = cpu_to_be32(0);				/* No more gids */
A
Andy Adamson 已提交
1627 1628 1629
	hdr->nops++;
	hdr->replen += decode_create_session_maxsz;
}
A
Andy Adamson 已提交
1630 1631 1632 1633 1634 1635

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

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

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

1657 1658 1659 1660 1661 1662
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 已提交
1663 1664 1665
	struct nfs4_slot_table *tp;
	struct nfs4_slot *slot;
	__be32 *p;
1666 1667 1668 1669

	if (!session)
		return;

A
Andy Adamson 已提交
1670 1671 1672 1673 1674
	tp = &session->fc_slot_table;

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

1675
	p = reserve_space(xdr, 4 + NFS4_MAX_SESSIONID_LEN + 16);
B
Benny Halevy 已提交
1676
	*p++ = cpu_to_be32(OP_SEQUENCE);
A
Andy Adamson 已提交
1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689

	/*
	 * 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 已提交
1690
	p = xdr_encode_opaque_fixed(p, session->sess_id.data, NFS4_MAX_SESSIONID_LEN);
B
Benny Halevy 已提交
1691 1692 1693
	*p++ = cpu_to_be32(slot->seq_nr);
	*p++ = cpu_to_be32(args->sa_slotid);
	*p++ = cpu_to_be32(tp->highest_used_slotid);
1694
	*p = cpu_to_be32(args->sa_cache_this);
1695 1696 1697 1698 1699
	hdr->nops++;
	hdr->replen += decode_sequence_maxsz;
#endif /* CONFIG_NFS_V4_1 */
}

L
Linus Torvalds 已提交
1700 1701 1702 1703
/*
 * END OF "GENERIC" ENCODE ROUTINES.
 */

1704 1705 1706 1707 1708 1709 1710 1711 1712
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 已提交
1713 1714 1715
/*
 * Encode an ACCESS request
 */
A
Al Viro 已提交
1716
static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs4_accessargs *args)
L
Linus Torvalds 已提交
1717 1718 1719
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1720
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1721 1722 1723
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1724
	encode_compound_hdr(&xdr, req, &hdr);
1725
	encode_sequence(&xdr, &args->seq_args, &hdr);
1726 1727 1728
	encode_putfh(&xdr, args->fh, &hdr);
	encode_access(&xdr, args->access, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1729
	encode_nops(&hdr);
1730
	return 0;
L
Linus Torvalds 已提交
1731 1732 1733 1734 1735
}

/*
 * Encode LOOKUP request
 */
A
Al Viro 已提交
1736
static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_arg *args)
L
Linus Torvalds 已提交
1737 1738 1739
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1740
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1741 1742 1743
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1744
	encode_compound_hdr(&xdr, req, &hdr);
1745
	encode_sequence(&xdr, &args->seq_args, &hdr);
1746 1747 1748 1749
	encode_putfh(&xdr, args->dir_fh, &hdr);
	encode_lookup(&xdr, args->name, &hdr);
	encode_getfh(&xdr, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1750
	encode_nops(&hdr);
1751
	return 0;
L
Linus Torvalds 已提交
1752 1753 1754 1755 1756
}

/*
 * Encode LOOKUP_ROOT request
 */
A
Al Viro 已提交
1757
static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_root_arg *args)
L
Linus Torvalds 已提交
1758 1759 1760
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1761
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1762 1763 1764
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1765
	encode_compound_hdr(&xdr, req, &hdr);
1766
	encode_sequence(&xdr, &args->seq_args, &hdr);
1767 1768 1769
	encode_putrootfh(&xdr, &hdr);
	encode_getfh(&xdr, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1770
	encode_nops(&hdr);
1771
	return 0;
L
Linus Torvalds 已提交
1772 1773 1774 1775 1776
}

/*
 * Encode REMOVE request
 */
1777
static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
L
Linus Torvalds 已提交
1778 1779 1780
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1781
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1782 1783 1784
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1785
	encode_compound_hdr(&xdr, req, &hdr);
1786
	encode_sequence(&xdr, &args->seq_args, &hdr);
1787 1788 1789
	encode_putfh(&xdr, args->fh, &hdr);
	encode_remove(&xdr, &args->name, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1790
	encode_nops(&hdr);
1791
	return 0;
L
Linus Torvalds 已提交
1792 1793 1794 1795 1796
}

/*
 * Encode RENAME request
 */
A
Al Viro 已提交
1797
static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs4_rename_arg *args)
L
Linus Torvalds 已提交
1798 1799 1800
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1801
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1802 1803 1804
	};

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

/*
 * Encode LINK request
 */
A
Al Viro 已提交
1821
static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_link_arg *args)
L
Linus Torvalds 已提交
1822 1823 1824
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1825
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1826 1827 1828
	};

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

/*
 * Encode CREATE request
 */
A
Al Viro 已提交
1845
static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
L
Linus Torvalds 已提交
1846 1847 1848
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1849
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1850 1851 1852
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1853
	encode_compound_hdr(&xdr, req, &hdr);
1854
	encode_sequence(&xdr, &args->seq_args, &hdr);
1855 1856 1857 1858 1859 1860 1861
	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);
1862
	encode_nops(&hdr);
1863
	return 0;
L
Linus Torvalds 已提交
1864 1865 1866 1867 1868
}

/*
 * Encode SYMLINK request
 */
A
Al Viro 已提交
1869
static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
L
Linus Torvalds 已提交
1870 1871 1872 1873 1874 1875 1876
{
	return nfs4_xdr_enc_create(req, p, args);
}

/*
 * Encode GETATTR request
 */
A
Al Viro 已提交
1877
static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nfs4_getattr_arg *args)
L
Linus Torvalds 已提交
1878 1879 1880
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1881
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1882 1883 1884
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1885
	encode_compound_hdr(&xdr, req, &hdr);
1886
	encode_sequence(&xdr, &args->seq_args, &hdr);
1887 1888
	encode_putfh(&xdr, args->fh, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1889
	encode_nops(&hdr);
1890
	return 0;
L
Linus Torvalds 已提交
1891 1892 1893 1894 1895
}

/*
 * Encode a CLOSE request
 */
A
Al Viro 已提交
1896
static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
L
Linus Torvalds 已提交
1897
{
A
Andy Adamson 已提交
1898 1899
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1900
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
A
Andy Adamson 已提交
1901 1902 1903
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1904
	encode_compound_hdr(&xdr, req, &hdr);
1905
	encode_sequence(&xdr, &args->seq_args, &hdr);
1906 1907 1908
	encode_putfh(&xdr, args->fh, &hdr);
	encode_close(&xdr, args, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1909
	encode_nops(&hdr);
1910
	return 0;
L
Linus Torvalds 已提交
1911 1912 1913 1914 1915
}

/*
 * Encode an OPEN request
 */
A
Al Viro 已提交
1916
static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
L
Linus Torvalds 已提交
1917 1918 1919
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1920
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1921 1922 1923
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1924
	encode_compound_hdr(&xdr, req, &hdr);
1925
	encode_sequence(&xdr, &args->seq_args, &hdr);
1926 1927 1928 1929 1930 1931 1932
	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);
1933
	encode_nops(&hdr);
1934
	return 0;
L
Linus Torvalds 已提交
1935 1936 1937 1938 1939
}

/*
 * Encode an OPEN_CONFIRM request
 */
A
Al Viro 已提交
1940
static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_open_confirmargs *args)
L
Linus Torvalds 已提交
1941 1942 1943
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1944
		.nops   = 0,
L
Linus Torvalds 已提交
1945 1946 1947
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1948
	encode_compound_hdr(&xdr, req, &hdr);
1949 1950
	encode_putfh(&xdr, args->fh, &hdr);
	encode_open_confirm(&xdr, args, &hdr);
1951
	encode_nops(&hdr);
1952
	return 0;
L
Linus Torvalds 已提交
1953 1954 1955 1956 1957
}

/*
 * Encode an OPEN request with no attributes.
 */
A
Al Viro 已提交
1958
static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
L
Linus Torvalds 已提交
1959 1960 1961
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1962
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1963 1964 1965
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1966
	encode_compound_hdr(&xdr, req, &hdr);
1967
	encode_sequence(&xdr, &args->seq_args, &hdr);
1968 1969 1970
	encode_putfh(&xdr, args->fh, &hdr);
	encode_open(&xdr, args, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1971
	encode_nops(&hdr);
1972
	return 0;
L
Linus Torvalds 已提交
1973 1974 1975 1976 1977
}

/*
 * Encode an OPEN_DOWNGRADE request
 */
A
Al Viro 已提交
1978
static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
L
Linus Torvalds 已提交
1979 1980 1981
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
1982
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
1983 1984 1985
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
1986
	encode_compound_hdr(&xdr, req, &hdr);
1987
	encode_sequence(&xdr, &args->seq_args, &hdr);
1988 1989 1990
	encode_putfh(&xdr, args->fh, &hdr);
	encode_open_downgrade(&xdr, args, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
1991
	encode_nops(&hdr);
1992
	return 0;
L
Linus Torvalds 已提交
1993 1994 1995 1996 1997
}

/*
 * Encode a LOCK request
 */
A
Al Viro 已提交
1998
static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_args *args)
L
Linus Torvalds 已提交
1999 2000 2001
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2002
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2003 2004 2005
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2006
	encode_compound_hdr(&xdr, req, &hdr);
2007
	encode_sequence(&xdr, &args->seq_args, &hdr);
2008 2009
	encode_putfh(&xdr, args->fh, &hdr);
	encode_lock(&xdr, args, &hdr);
2010
	encode_nops(&hdr);
2011
	return 0;
L
Linus Torvalds 已提交
2012 2013 2014 2015 2016
}

/*
 * Encode a LOCKT request
 */
A
Al Viro 已提交
2017
static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_args *args)
L
Linus Torvalds 已提交
2018 2019 2020
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2021
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2022 2023 2024
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2025
	encode_compound_hdr(&xdr, req, &hdr);
2026
	encode_sequence(&xdr, &args->seq_args, &hdr);
2027 2028
	encode_putfh(&xdr, args->fh, &hdr);
	encode_lockt(&xdr, args, &hdr);
2029
	encode_nops(&hdr);
2030
	return 0;
L
Linus Torvalds 已提交
2031 2032 2033 2034 2035
}

/*
 * Encode a LOCKU request
 */
A
Al Viro 已提交
2036
static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_args *args)
L
Linus Torvalds 已提交
2037 2038 2039
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2040
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2041 2042 2043
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2044
	encode_compound_hdr(&xdr, req, &hdr);
2045
	encode_sequence(&xdr, &args->seq_args, &hdr);
2046 2047
	encode_putfh(&xdr, args->fh, &hdr);
	encode_locku(&xdr, args, &hdr);
2048
	encode_nops(&hdr);
2049
	return 0;
L
Linus Torvalds 已提交
2050 2051 2052 2053 2054
}

/*
 * Encode a READLINK request
 */
A
Al Viro 已提交
2055
static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_readlink *args)
L
Linus Torvalds 已提交
2056 2057 2058
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2059
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2060 2061 2062
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2063
	encode_compound_hdr(&xdr, req, &hdr);
2064
	encode_sequence(&xdr, &args->seq_args, &hdr);
2065 2066
	encode_putfh(&xdr, args->fh, &hdr);
	encode_readlink(&xdr, args, req, &hdr);
2067

2068
	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
2069
			args->pgbase, args->pglen);
2070
	encode_nops(&hdr);
2071
	return 0;
L
Linus Torvalds 已提交
2072 2073 2074 2075 2076
}

/*
 * Encode a READDIR request
 */
A
Al Viro 已提交
2077
static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nfs4_readdir_arg *args)
L
Linus Torvalds 已提交
2078 2079 2080
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2081
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2082 2083 2084
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2085
	encode_compound_hdr(&xdr, req, &hdr);
2086
	encode_sequence(&xdr, &args->seq_args, &hdr);
2087 2088
	encode_putfh(&xdr, args->fh, &hdr);
	encode_readdir(&xdr, args, req, &hdr);
2089

2090
	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2, args->pages,
2091 2092
			 args->pgbase, args->count);
	dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
2093
			__func__, hdr.replen << 2, args->pages,
2094
			args->pgbase, args->count);
2095
	encode_nops(&hdr);
2096
	return 0;
L
Linus Torvalds 已提交
2097 2098 2099 2100 2101
}

/*
 * Encode a READ request
 */
A
Al Viro 已提交
2102
static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
L
Linus Torvalds 已提交
2103 2104 2105
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2106
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2107 2108 2109
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2110
	encode_compound_hdr(&xdr, req, &hdr);
2111
	encode_sequence(&xdr, &args->seq_args, &hdr);
2112 2113
	encode_putfh(&xdr, args->fh, &hdr);
	encode_read(&xdr, args, &hdr);
L
Linus Torvalds 已提交
2114

2115
	xdr_inline_pages(&req->rq_rcv_buf, hdr.replen << 2,
L
Linus Torvalds 已提交
2116
			 args->pages, args->pgbase, args->count);
2117
	req->rq_rcv_buf.flags |= XDRBUF_READ;
2118
	encode_nops(&hdr);
2119
	return 0;
L
Linus Torvalds 已提交
2120 2121 2122 2123 2124
}

/*
 * Encode an SETATTR request
 */
A
Al Viro 已提交
2125
static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args)
L
Linus Torvalds 已提交
2126
{
A
Andy Adamson 已提交
2127 2128
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2129
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
A
Andy Adamson 已提交
2130 2131 2132
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2133
	encode_compound_hdr(&xdr, req, &hdr);
2134
	encode_sequence(&xdr, &args->seq_args, &hdr);
2135 2136 2137
	encode_putfh(&xdr, args->fh, &hdr);
	encode_setattr(&xdr, args, args->server, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
2138
	encode_nops(&hdr);
2139
	return 0;
L
Linus Torvalds 已提交
2140 2141
}

2142 2143 2144 2145
/*
 * Encode a GETACL request
 */
static int
A
Al Viro 已提交
2146
nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
2147 2148 2149 2150
		struct nfs_getaclargs *args)
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2151
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
2152
	};
2153
	uint32_t replen;
2154 2155

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2156
	encode_compound_hdr(&xdr, req, &hdr);
2157
	encode_sequence(&xdr, &args->seq_args, &hdr);
2158
	encode_putfh(&xdr, args->fh, &hdr);
2159
	replen = hdr.replen + op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz + 1;
2160 2161
	encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0, &hdr);

2162
	xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
2163
		args->acl_pages, args->acl_pgbase, args->acl_len);
2164
	encode_nops(&hdr);
2165
	return 0;
2166 2167
}

L
Linus Torvalds 已提交
2168 2169 2170
/*
 * Encode a WRITE request
 */
A
Al Viro 已提交
2171
static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
L
Linus Torvalds 已提交
2172 2173 2174
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2175
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2176 2177 2178
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2179
	encode_compound_hdr(&xdr, req, &hdr);
2180
	encode_sequence(&xdr, &args->seq_args, &hdr);
2181 2182
	encode_putfh(&xdr, args->fh, &hdr);
	encode_write(&xdr, args, &hdr);
2183
	req->rq_snd_buf.flags |= XDRBUF_WRITE;
2184
	encode_getfattr(&xdr, args->bitmask, &hdr);
2185
	encode_nops(&hdr);
2186
	return 0;
L
Linus Torvalds 已提交
2187 2188 2189 2190 2191
}

/*
 *  a COMMIT request
 */
A
Al Viro 已提交
2192
static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
L
Linus Torvalds 已提交
2193 2194 2195
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2196
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2197 2198 2199
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2200
	encode_compound_hdr(&xdr, req, &hdr);
2201
	encode_sequence(&xdr, &args->seq_args, &hdr);
2202 2203 2204
	encode_putfh(&xdr, args->fh, &hdr);
	encode_commit(&xdr, args, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
2205
	encode_nops(&hdr);
2206
	return 0;
L
Linus Torvalds 已提交
2207 2208 2209 2210 2211
}

/*
 * FSINFO request
 */
A
Al Viro 已提交
2212
static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsinfo_arg *args)
L
Linus Torvalds 已提交
2213 2214 2215
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2216
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2217 2218 2219
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2220
	encode_compound_hdr(&xdr, req, &hdr);
2221
	encode_sequence(&xdr, &args->seq_args, &hdr);
2222 2223
	encode_putfh(&xdr, args->fh, &hdr);
	encode_fsinfo(&xdr, args->bitmask, &hdr);
2224
	encode_nops(&hdr);
2225
	return 0;
L
Linus Torvalds 已提交
2226 2227 2228 2229 2230
}

/*
 * a PATHCONF request
 */
A
Al Viro 已提交
2231
static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct nfs4_pathconf_arg *args)
L
Linus Torvalds 已提交
2232 2233 2234
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2235
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2236 2237 2238
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2239
	encode_compound_hdr(&xdr, req, &hdr);
2240
	encode_sequence(&xdr, &args->seq_args, &hdr);
2241 2242 2243
	encode_putfh(&xdr, args->fh, &hdr);
	encode_getattr_one(&xdr, args->bitmask[0] & nfs4_pathconf_bitmap[0],
			   &hdr);
2244
	encode_nops(&hdr);
2245
	return 0;
L
Linus Torvalds 已提交
2246 2247 2248 2249 2250
}

/*
 * a STATFS request
 */
A
Al Viro 已提交
2251
static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs4_statfs_arg *args)
L
Linus Torvalds 已提交
2252 2253 2254
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2255
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2256 2257 2258
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2259
	encode_compound_hdr(&xdr, req, &hdr);
2260
	encode_sequence(&xdr, &args->seq_args, &hdr);
2261 2262 2263
	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);
2264
	encode_nops(&hdr);
2265
	return 0;
L
Linus Torvalds 已提交
2266 2267 2268 2269 2270
}

/*
 * GETATTR_BITMAP request
 */
B
Benny Halevy 已提交
2271 2272
static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p,
				    struct nfs4_server_caps_arg *args)
L
Linus Torvalds 已提交
2273 2274 2275
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2276
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2277 2278 2279
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2280
	encode_compound_hdr(&xdr, req, &hdr);
2281
	encode_sequence(&xdr, &args->seq_args, &hdr);
B
Benny Halevy 已提交
2282
	encode_putfh(&xdr, args->fhandle, &hdr);
2283 2284 2285 2286
	encode_getattr_one(&xdr, FATTR4_WORD0_SUPPORTED_ATTRS|
			   FATTR4_WORD0_LINK_SUPPORT|
			   FATTR4_WORD0_SYMLINK_SUPPORT|
			   FATTR4_WORD0_ACLSUPPORT, &hdr);
2287
	encode_nops(&hdr);
2288
	return 0;
L
Linus Torvalds 已提交
2289 2290 2291 2292 2293
}

/*
 * a RENEW request
 */
A
Al Viro 已提交
2294
static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
L
Linus Torvalds 已提交
2295 2296 2297
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2298
		.nops	= 0,
L
Linus Torvalds 已提交
2299 2300 2301
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2302
	encode_compound_hdr(&xdr, req, &hdr);
2303
	encode_renew(&xdr, clp, &hdr);
2304
	encode_nops(&hdr);
2305
	return 0;
L
Linus Torvalds 已提交
2306 2307 2308 2309 2310
}

/*
 * a SETCLIENTID request
 */
A
Al Viro 已提交
2311
static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid *sc)
L
Linus Torvalds 已提交
2312 2313 2314
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2315
		.nops	= 0,
L
Linus Torvalds 已提交
2316 2317 2318
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2319
	encode_compound_hdr(&xdr, req, &hdr);
2320
	encode_setclientid(&xdr, sc, &hdr);
2321
	encode_nops(&hdr);
2322
	return 0;
L
Linus Torvalds 已提交
2323 2324 2325 2326 2327
}

/*
 * a SETCLIENTID_CONFIRM request
 */
A
Al Viro 已提交
2328
static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
L
Linus Torvalds 已提交
2329 2330 2331
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2332
		.nops	= 0,
L
Linus Torvalds 已提交
2333 2334 2335 2336
	};
	const u32 lease_bitmap[2] = { FATTR4_WORD0_LEASE_TIME, 0 };

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2337
	encode_compound_hdr(&xdr, req, &hdr);
2338 2339 2340
	encode_setclientid_confirm(&xdr, clp, &hdr);
	encode_putrootfh(&xdr, &hdr);
	encode_fsinfo(&xdr, lease_bitmap, &hdr);
2341
	encode_nops(&hdr);
2342
	return 0;
L
Linus Torvalds 已提交
2343 2344 2345 2346 2347
}

/*
 * DELEGRETURN request
 */
A
Al Viro 已提交
2348
static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struct nfs4_delegreturnargs *args)
L
Linus Torvalds 已提交
2349 2350 2351
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2352
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
L
Linus Torvalds 已提交
2353 2354 2355
	};

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2356
	encode_compound_hdr(&xdr, req, &hdr);
2357
	encode_sequence(&xdr, &args->seq_args, &hdr);
2358 2359 2360
	encode_putfh(&xdr, args->fhandle, &hdr);
	encode_delegreturn(&xdr, args->stateid, &hdr);
	encode_getfattr(&xdr, args->bitmask, &hdr);
2361
	encode_nops(&hdr);
2362
	return 0;
L
Linus Torvalds 已提交
2363 2364
}

2365 2366 2367
/*
 * Encode FS_LOCATIONS request
 */
A
Al Viro 已提交
2368
static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations_arg *args)
2369 2370 2371
{
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
2372
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
2373
	};
2374
	uint32_t replen;
2375 2376

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
2377
	encode_compound_hdr(&xdr, req, &hdr);
2378
	encode_sequence(&xdr, &args->seq_args, &hdr);
2379 2380
	encode_putfh(&xdr, args->dir_fh, &hdr);
	encode_lookup(&xdr, args->name, &hdr);
2381
	replen = hdr.replen;	/* get the attribute into args->page */
2382 2383
	encode_fs_locations(&xdr, args->bitmask, &hdr);

2384
	xdr_inline_pages(&req->rq_rcv_buf, replen << 2, &args->page,
2385
			0, PAGE_SIZE);
2386
	encode_nops(&hdr);
2387
	return 0;
2388 2389
}

B
Benny Halevy 已提交
2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407
#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 已提交
2408

A
Andy Adamson 已提交
2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426
/*
 * 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 已提交
2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444
/*
 * 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 已提交
2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462
/*
 * 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 已提交
2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482
/*
 * 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;
}
2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502

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

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

B
Benny Halevy 已提交
2503 2504
#endif /* CONFIG_NFS_V4_1 */

2505 2506 2507 2508 2509 2510
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 已提交
2511

2512
static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
L
Linus Torvalds 已提交
2513
{
A
Al Viro 已提交
2514
	__be32 *p;
L
Linus Torvalds 已提交
2515

B
Benny Halevy 已提交
2516 2517 2518
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
2519
	*len = be32_to_cpup(p);
B
Benny Halevy 已提交
2520 2521 2522
	p = xdr_inline_decode(xdr, *len);
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
2523 2524
	*string = (char *)p;
	return 0;
B
Benny Halevy 已提交
2525 2526 2527
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2528 2529 2530 2531
}

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

B
Benny Halevy 已提交
2534 2535 2536
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
2537
	hdr->status = be32_to_cpup(p++);
2538
	hdr->taglen = be32_to_cpup(p);
2539

B
Benny Halevy 已提交
2540 2541 2542
	p = xdr_inline_decode(xdr, hdr->taglen + 4);
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
2543 2544
	hdr->tag = (char *)p;
	p += XDR_QUADLEN(hdr->taglen);
2545
	hdr->nops = be32_to_cpup(p);
2546 2547
	if (unlikely(hdr->nops < 1))
		return nfs4_stat_to_errno(hdr->status);
L
Linus Torvalds 已提交
2548
	return 0;
B
Benny Halevy 已提交
2549 2550 2551
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2552 2553 2554 2555
}

static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
{
A
Al Viro 已提交
2556
	__be32 *p;
L
Linus Torvalds 已提交
2557 2558 2559
	uint32_t opnum;
	int32_t nfserr;

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

/* Dummy routine */
2580
static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp)
L
Linus Torvalds 已提交
2581
{
A
Al Viro 已提交
2582
	__be32 *p;
2583
	unsigned int strlen;
L
Linus Torvalds 已提交
2584 2585
	char *str;

B
Benny Halevy 已提交
2586 2587 2588 2589 2590
	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 已提交
2591 2592 2593 2594
}

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

B
Benny Halevy 已提交
2598 2599 2600
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
2601
	bmlen = be32_to_cpup(p);
L
Linus Torvalds 已提交
2602 2603

	bitmap[0] = bitmap[1] = 0;
B
Benny Halevy 已提交
2604 2605 2606
	p = xdr_inline_decode(xdr, (bmlen << 2));
	if (unlikely(!p))
		goto out_overflow;
L
Linus Torvalds 已提交
2607
	if (bmlen > 0) {
B
Benny Halevy 已提交
2608
		bitmap[0] = be32_to_cpup(p++);
L
Linus Torvalds 已提交
2609
		if (bmlen > 1)
2610
			bitmap[1] = be32_to_cpup(p);
L
Linus Torvalds 已提交
2611 2612
	}
	return 0;
B
Benny Halevy 已提交
2613 2614 2615
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2616 2617
}

A
Al Viro 已提交
2618
static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep)
L
Linus Torvalds 已提交
2619
{
A
Al Viro 已提交
2620
	__be32 *p;
L
Linus Torvalds 已提交
2621

B
Benny Halevy 已提交
2622 2623 2624
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
2625
	*attrlen = be32_to_cpup(p);
L
Linus Torvalds 已提交
2626 2627
	*savep = xdr->p;
	return 0;
B
Benny Halevy 已提交
2628 2629 2630
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2631 2632 2633 2634 2635 2636 2637 2638 2639
}

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;
2640
	dprintk("%s: bitmask=%08x:%08x\n", __func__, bitmask[0], bitmask[1]);
L
Linus Torvalds 已提交
2641 2642 2643 2644 2645
	return 0;
}

static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
{
A
Al Viro 已提交
2646
	__be32 *p;
2647
	int ret = 0;
L
Linus Torvalds 已提交
2648 2649 2650 2651 2652

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

static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
{
A
Al Viro 已提交
2673
	__be32 *p;
2674
	int ret = 0;
L
Linus Torvalds 已提交
2675 2676 2677 2678 2679

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

static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
{
A
Al Viro 已提交
2697
	__be32 *p;
2698
	int ret = 0;
L
Linus Torvalds 已提交
2699 2700 2701 2702 2703

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

static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
2720
	__be32 *p;
L
Linus Torvalds 已提交
2721 2722 2723 2724 2725

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

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

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

2760
static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
L
Linus Torvalds 已提交
2761
{
A
Al Viro 已提交
2762
	__be32 *p;
2763
	int ret = 0;
L
Linus Torvalds 已提交
2764 2765 2766 2767 2768 2769

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

static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
2789
	__be32 *p;
L
Linus Torvalds 已提交
2790 2791 2792 2793 2794

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

static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
A
Al Viro 已提交
2810
	__be32 *p;
L
Linus Torvalds 已提交
2811 2812 2813 2814 2815

	*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 已提交
2816 2817 2818
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
2819
		*res = be32_to_cpup(p);
L
Linus Torvalds 已提交
2820 2821
		bitmap[0] &= ~FATTR4_WORD0_ACLSUPPORT;
	}
2822
	dprintk("%s: ACLs supported=%u\n", __func__, (unsigned int)*res);
L
Linus Torvalds 已提交
2823
	return 0;
B
Benny Halevy 已提交
2824 2825 2826
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
2827 2828 2829 2830
}

static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
{
A
Al Viro 已提交
2831
	__be32 *p;
2832
	int ret = 0;
L
Linus Torvalds 已提交
2833 2834 2835 2836 2837

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

2852 2853
static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
{
A
Al Viro 已提交
2854
	__be32 *p;
2855
	int ret = 0;
2856 2857 2858 2859 2860

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

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

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

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

2941 2942
static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
{
2943
	u32 n;
A
Al Viro 已提交
2944
	__be32 *p;
2945 2946
	int status = 0;

B
Benny Halevy 已提交
2947 2948 2949
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
2950
	n = be32_to_cpup(p);
2951 2952
	if (n == 0)
		goto root_path;
2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972
	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;
2973 2974 2975 2976 2977 2978 2979
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;
2980 2981 2982 2983
out_eio:
	dprintk(" status %d", status);
	status = -EIO;
	goto out;
B
Benny Halevy 已提交
2984 2985 2986
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
2987 2988 2989
}

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

B
Benny Halevy 已提交
3015 3016 3017
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
3018
		m = be32_to_cpup(p);
3019 3020

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

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

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

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

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

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

3182
static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, umode_t *mode)
L
Linus Torvalds 已提交
3183
{
3184
	uint32_t tmp;
A
Al Viro 已提交
3185
	__be32 *p;
3186
	int ret = 0;
L
Linus Torvalds 已提交
3187 3188 3189 3190 3191

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

static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
{
A
Al Viro 已提交
3209
	__be32 *p;
3210
	int ret = 0;
L
Linus Torvalds 已提交
3211 3212 3213 3214 3215

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

3230 3231
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 已提交
3232
{
A
Al Viro 已提交
3233 3234
	uint32_t len;
	__be32 *p;
3235
	int ret = 0;
L
Linus Torvalds 已提交
3236 3237 3238 3239 3240

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

3268 3269
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 已提交
3270
{
A
Al Viro 已提交
3271 3272
	uint32_t len;
	__be32 *p;
3273
	int ret = 0;
L
Linus Torvalds 已提交
3274 3275 3276 3277 3278

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

static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
{
A
Al Viro 已提交
3308 3309
	uint32_t major = 0, minor = 0;
	__be32 *p;
3310
	int ret = 0;
L
Linus Torvalds 已提交
3311 3312 3313 3314 3315 3316 3317

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

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

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

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

static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
{
A
Al Viro 已提交
3404
	__be32 *p;
3405
	int ret = 0;
L
Linus Torvalds 已提交
3406 3407 3408 3409 3410

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

static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
{
A
Al Viro 已提交
3428
	__be32 *p;
L
Linus Torvalds 已提交
3429 3430 3431
	uint64_t sec;
	uint32_t nsec;

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

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

A
Al Viro 已提交
3499
static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
L
Linus Torvalds 已提交
3500 3501 3502 3503 3504
{
	unsigned int attrwords = XDR_QUADLEN(attrlen);
	unsigned int nwords = xdr->p - savep;

	if (unlikely(attrwords != nwords)) {
3505 3506
		dprintk("%s: server returned incorrect attribute length: "
			"%u %c %u\n",
3507
				__func__,
L
Linus Torvalds 已提交
3508 3509 3510 3511 3512 3513 3514 3515 3516 3517
				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 已提交
3518
	__be32 *p;
L
Linus Torvalds 已提交
3519

B
Benny Halevy 已提交
3520 3521 3522
	p = xdr_inline_decode(xdr, 20);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3523
	cinfo->atomic = be32_to_cpup(p++);
B
Benny Halevy 已提交
3524
	p = xdr_decode_hyper(p, &cinfo->before);
3525
	xdr_decode_hyper(p, &cinfo->after);
L
Linus Torvalds 已提交
3526
	return 0;
B
Benny Halevy 已提交
3527 3528 3529
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3530 3531 3532 3533
}

static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
{
A
Al Viro 已提交
3534
	__be32 *p;
L
Linus Torvalds 已提交
3535 3536 3537 3538 3539 3540
	uint32_t supp, acc;
	int status;

	status = decode_op_hdr(xdr, OP_ACCESS);
	if (status)
		return status;
B
Benny Halevy 已提交
3541 3542 3543
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3544
	supp = be32_to_cpup(p++);
3545
	acc = be32_to_cpup(p);
L
Linus Torvalds 已提交
3546 3547 3548
	access->supported = supp;
	access->access = acc;
	return 0;
B
Benny Halevy 已提交
3549 3550 3551
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3552 3553
}

3554
static int decode_opaque_fixed(struct xdr_stream *xdr, void *buf, size_t len)
L
Linus Torvalds 已提交
3555
{
A
Al Viro 已提交
3556
	__be32 *p;
3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573

	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 已提交
3574 3575 3576
	int status;

	status = decode_op_hdr(xdr, OP_CLOSE);
3577 3578
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
3579 3580 3581
	if (!status)
		status = decode_stateid(xdr, &res->stateid);
	return status;
L
Linus Torvalds 已提交
3582 3583
}

3584 3585 3586
static int decode_verifier(struct xdr_stream *xdr, void *verifier)
{
	return decode_opaque_fixed(xdr, verifier, 8);
L
Linus Torvalds 已提交
3587 3588 3589 3590 3591 3592 3593
}

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

	status = decode_op_hdr(xdr, OP_COMMIT);
3594 3595 3596
	if (!status)
		status = decode_verifier(xdr, res->verf->verifier);
	return status;
L
Linus Torvalds 已提交
3597 3598 3599 3600
}

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

static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
{
A
Al Viro 已提交
3624
	__be32 *savep;
3625
	uint32_t attrlen, bitmap[2] = {0};
L
Linus Torvalds 已提交
3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643
	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:
3644
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
3645 3646
	return status;
}
3647

L
Linus Torvalds 已提交
3648 3649
static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
{
A
Al Viro 已提交
3650
	__be32 *savep;
3651
	uint32_t attrlen, bitmap[2] = {0};
L
Linus Torvalds 已提交
3652
	int status;
3653

L
Linus Torvalds 已提交
3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675
	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:
3676
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
3677 3678 3679 3680 3681
	return status;
}

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

L
Linus Torvalds 已提交
3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699
	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:
3700
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
3701 3702 3703
	return status;
}

3704 3705
static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
		const struct nfs_server *server, int may_sleep)
L
Linus Torvalds 已提交
3706
{
A
Al Viro 已提交
3707
	__be32 *savep;
L
Linus Torvalds 已提交
3708 3709 3710
	uint32_t attrlen,
		 bitmap[2] = {0},
		 type;
3711 3712
	int status;
	umode_t fmode = 0;
3713
	uint64_t fileid;
L
Linus Torvalds 已提交
3714

3715 3716
	status = decode_op_hdr(xdr, OP_GETATTR);
	if (status < 0)
L
Linus Torvalds 已提交
3717
		goto xdr_error;
3718 3719 3720

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

3723 3724
	status = decode_attr_length(xdr, &attrlen, &savep);
	if (status < 0)
L
Linus Torvalds 已提交
3725 3726 3727
		goto xdr_error;


3728 3729
	status = decode_attr_type(xdr, bitmap, &type);
	if (status < 0)
L
Linus Torvalds 已提交
3730
		goto xdr_error;
3731 3732 3733 3734 3735
	fattr->mode = 0;
	if (status != 0) {
		fattr->mode |= nfs_type2fmt[type];
		fattr->valid |= status;
	}
L
Linus Torvalds 已提交
3736

3737 3738
	status = decode_attr_change(xdr, bitmap, &fattr->change_attr);
	if (status < 0)
L
Linus Torvalds 已提交
3739
		goto xdr_error;
3740
	fattr->valid |= status;
3741 3742 3743

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

	status = decode_attr_fsid(xdr, bitmap, &fattr->fsid);
	if (status < 0)
L
Linus Torvalds 已提交
3749
		goto xdr_error;
3750
	fattr->valid |= status;
3751 3752 3753

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

	status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
3758
						struct nfs4_fs_locations,
3759 3760
						fattr));
	if (status < 0)
3761
		goto xdr_error;
3762
	fattr->valid |= status;
3763 3764 3765

	status = decode_attr_mode(xdr, bitmap, &fmode);
	if (status < 0)
L
Linus Torvalds 已提交
3766
		goto xdr_error;
3767 3768 3769 3770
	if (status != 0) {
		fattr->mode |= fmode;
		fattr->valid |= status;
	}
3771 3772 3773

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

3777 3778
	status = decode_attr_owner(xdr, bitmap, server->nfs_client,
			&fattr->uid, may_sleep);
3779
	if (status < 0)
L
Linus Torvalds 已提交
3780
		goto xdr_error;
3781
	fattr->valid |= status;
3782

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

	status = decode_attr_rdev(xdr, bitmap, &fattr->rdev);
	if (status < 0)
L
Linus Torvalds 已提交
3791
		goto xdr_error;
3792
	fattr->valid |= status;
3793 3794 3795

	status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used);
	if (status < 0)
L
Linus Torvalds 已提交
3796
		goto xdr_error;
3797
	fattr->valid |= status;
3798 3799 3800

	status = decode_attr_time_access(xdr, bitmap, &fattr->atime);
	if (status < 0)
L
Linus Torvalds 已提交
3801
		goto xdr_error;
3802
	fattr->valid |= status;
3803 3804 3805

	status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
	if (status < 0)
L
Linus Torvalds 已提交
3806
		goto xdr_error;
3807
	fattr->valid |= status;
3808 3809 3810

	status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime);
	if (status < 0)
L
Linus Torvalds 已提交
3811
		goto xdr_error;
3812
	fattr->valid |= status;
3813 3814 3815

	status = decode_attr_mounted_on_fileid(xdr, bitmap, &fileid);
	if (status < 0)
3816
		goto xdr_error;
3817
	if (status != 0 && !(fattr->valid & status)) {
3818
		fattr->fileid = fileid;
3819 3820
		fattr->valid |= status;
	}
3821 3822

	status = verify_attr_len(xdr, savep, attrlen);
L
Linus Torvalds 已提交
3823
xdr_error:
3824
	dprintk("%s: xdr returned %d\n", __func__, -status);
L
Linus Torvalds 已提交
3825 3826 3827 3828 3829 3830
	return status;
}


static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
{
A
Al Viro 已提交
3831
	__be32 *savep;
L
Linus Torvalds 已提交
3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856
	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:
3857
	dprintk("%s: xdr returned %d!\n", __func__, -status);
L
Linus Torvalds 已提交
3858 3859 3860 3861 3862
	return status;
}

static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
{
A
Al Viro 已提交
3863
	__be32 *p;
L
Linus Torvalds 已提交
3864 3865 3866
	uint32_t len;
	int status;

3867 3868 3869
	/* Zero handle first to allow comparisons */
	memset(fh, 0, sizeof(*fh));

L
Linus Torvalds 已提交
3870 3871 3872 3873
	status = decode_op_hdr(xdr, OP_GETFH);
	if (status)
		return status;

B
Benny Halevy 已提交
3874 3875 3876
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
3877
	len = be32_to_cpup(p);
L
Linus Torvalds 已提交
3878 3879 3880
	if (len > NFS4_FHSIZE)
		return -EIO;
	fh->size = len;
B
Benny Halevy 已提交
3881 3882 3883
	p = xdr_inline_decode(xdr, len);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
3884
	memcpy(fh->data, p, len);
L
Linus Torvalds 已提交
3885
	return 0;
B
Benny Halevy 已提交
3886 3887 3888
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
3889 3890 3891 3892 3893
}

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

L
Linus Torvalds 已提交
3895 3896 3897 3898 3899 3900 3901 3902 3903
	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 已提交
3904
static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
L
Linus Torvalds 已提交
3905
{
T
Trond Myklebust 已提交
3906
	uint64_t offset, length, clientid;
A
Al Viro 已提交
3907
	__be32 *p;
T
Trond Myklebust 已提交
3908
	uint32_t namelen, type;
L
Linus Torvalds 已提交
3909

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

T
Trond Myklebust 已提交
3936
static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
L
Linus Torvalds 已提交
3937 3938 3939 3940
{
	int status;

	status = decode_op_hdr(xdr, OP_LOCK);
3941 3942
	if (status == -EIO)
		goto out;
L
Linus Torvalds 已提交
3943
	if (status == 0) {
3944 3945 3946
		status = decode_stateid(xdr, &res->stateid);
		if (unlikely(status))
			goto out;
L
Linus Torvalds 已提交
3947
	} else if (status == -NFS4ERR_DENIED)
3948 3949 3950 3951 3952
		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 已提交
3953 3954 3955
	return status;
}

T
Trond Myklebust 已提交
3956
static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res)
L
Linus Torvalds 已提交
3957 3958 3959 3960
{
	int status;
	status = decode_op_hdr(xdr, OP_LOCKT);
	if (status == -NFS4ERR_DENIED)
T
Trond Myklebust 已提交
3961
		return decode_lock_denied(xdr, res->denied);
L
Linus Torvalds 已提交
3962 3963 3964
	return status;
}

T
Trond Myklebust 已提交
3965
static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
L
Linus Torvalds 已提交
3966 3967 3968 3969
{
	int status;

	status = decode_op_hdr(xdr, OP_LOCKU);
3970 3971
	if (status != -EIO)
		nfs_increment_lock_seqid(status, res->seqid);
3972 3973
	if (status == 0)
		status = decode_stateid(xdr, &res->stateid);
L
Linus Torvalds 已提交
3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984
	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 已提交
3985
	__be32 *p;
L
Linus Torvalds 已提交
3986 3987
	uint32_t limit_type, nblocks, blocksize;

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

static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
{
A
Andy Adamson 已提交
4009 4010
	__be32 *p;
	uint32_t delegation_type;
4011
	int status;
L
Linus Torvalds 已提交
4012

B
Benny Halevy 已提交
4013 4014 4015
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4016
	delegation_type = be32_to_cpup(p);
L
Linus Torvalds 已提交
4017 4018 4019 4020
	if (delegation_type == NFS4_OPEN_DELEGATE_NONE) {
		res->delegation_type = 0;
		return 0;
	}
4021 4022 4023
	status = decode_stateid(xdr, &res->delegation);
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
4024 4025 4026
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4027
	res->do_recall = be32_to_cpup(p);
A
Andy Adamson 已提交
4028

L
Linus Torvalds 已提交
4029
	switch (delegation_type) {
A
Andy Adamson 已提交
4030 4031 4032 4033 4034 4035
	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 已提交
4036 4037
				return -EIO;
	}
4038
	return decode_ace(xdr, NULL, res->server->nfs_client);
B
Benny Halevy 已提交
4039 4040 4041
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4042 4043 4044 4045
}

static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
{
A
Andy Adamson 已提交
4046
	__be32 *p;
4047
	uint32_t savewords, bmlen, i;
A
Andy Adamson 已提交
4048
	int status;
L
Linus Torvalds 已提交
4049

A
Andy Adamson 已提交
4050
	status = decode_op_hdr(xdr, OP_OPEN);
4051 4052
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
4053 4054 4055
	if (!status)
		status = decode_stateid(xdr, &res->stateid);
	if (unlikely(status))
A
Andy Adamson 已提交
4056
		return status;
L
Linus Torvalds 已提交
4057

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

B
Benny Halevy 已提交
4060 4061 4062
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4063
	res->rflags = be32_to_cpup(p++);
4064
	bmlen = be32_to_cpup(p);
A
Andy Adamson 已提交
4065 4066
	if (bmlen > 10)
		goto xdr_error;
L
Linus Torvalds 已提交
4067

B
Benny Halevy 已提交
4068 4069 4070
	p = xdr_inline_decode(xdr, bmlen << 2);
	if (unlikely(!p))
		goto out_overflow;
4071 4072
	savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE);
	for (i = 0; i < savewords; ++i)
B
Benny Halevy 已提交
4073
		res->attrset[i] = be32_to_cpup(p++);
4074 4075 4076
	for (; i < NFS4_BITMAP_SIZE; i++)
		res->attrset[i] = 0;

L
Linus Torvalds 已提交
4077 4078
	return decode_delegation(xdr, res);
xdr_error:
4079
	dprintk("%s: Bitmap too large! Length = %u\n", __func__, bmlen);
L
Linus Torvalds 已提交
4080
	return -EIO;
B
Benny Halevy 已提交
4081 4082 4083
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4084 4085 4086 4087 4088 4089
}

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

A
Andy Adamson 已提交
4090
	status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
4091 4092
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
4093 4094 4095
	if (!status)
		status = decode_stateid(xdr, &res->stateid);
	return status;
L
Linus Torvalds 已提交
4096 4097 4098 4099 4100 4101 4102
}

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

	status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE);
4103 4104
	if (status != -EIO)
		nfs_increment_open_seqid(status, res->seqid);
4105 4106 4107
	if (!status)
		status = decode_stateid(xdr, &res->stateid);
	return status;
L
Linus Torvalds 已提交
4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122
}

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 已提交
4123
	__be32 *p;
L
Linus Torvalds 已提交
4124 4125 4126 4127 4128 4129
	uint32_t count, eof, recvd, hdrlen;
	int status;

	status = decode_op_hdr(xdr, OP_READ);
	if (status)
		return status;
B
Benny Halevy 已提交
4130 4131 4132
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4133
	eof = be32_to_cpup(p++);
4134
	count = be32_to_cpup(p);
L
Linus Torvalds 已提交
4135 4136 4137
	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
	recvd = req->rq_rcv_buf.len - hdrlen;
	if (count > recvd) {
4138
		dprintk("NFS: server cheating in read reply: "
L
Linus Torvalds 已提交
4139 4140 4141 4142 4143 4144 4145 4146
				"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 已提交
4147 4148 4149
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4150 4151 4152 4153 4154 4155 4156
}

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;
4157 4158
	size_t		hdrlen;
	u32		recvd, pglen = rcvbuf->page_len;
A
Al Viro 已提交
4159
	__be32		*end, *entry, *p, *kaddr;
4160
	unsigned int	nr = 0;
4161
	int		status;
L
Linus Torvalds 已提交
4162 4163

	status = decode_op_hdr(xdr, OP_READDIR);
4164 4165 4166
	if (!status)
		status = decode_verifier(xdr, readdir->verifier.data);
	if (unlikely(status))
L
Linus Torvalds 已提交
4167
		return status;
4168 4169
	dprintk("%s: verifier = %08x:%08x\n",
			__func__,
4170 4171 4172
			((u32 *)readdir->verifier.data)[0],
			((u32 *)readdir->verifier.data)[1]);

L
Linus Torvalds 已提交
4173

4174
	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
L
Linus Torvalds 已提交
4175 4176 4177 4178 4179 4180
	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 已提交
4181
	kaddr = p = kmap_atomic(page, KM_USER0);
4182
	end = p + ((pglen + readdir->pgbase) >> 2);
L
Linus Torvalds 已提交
4183
	entry = p;
4184 4185 4186 4187 4188 4189

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

	for (; *p++; nr++) {
4190
		u32 len, attrlen, xlen;
4191
		if (end - p < 3)
L
Linus Torvalds 已提交
4192
			goto short_pkt;
4193
		dprintk("cookie = %Lu, ", *((unsigned long long *)p));
L
Linus Torvalds 已提交
4194 4195 4196
		p += 2;			/* cookie */
		len = ntohl(*p++);	/* filename length */
		if (len > NFS4_MAXNAMLEN) {
4197 4198
			dprintk("NFS: giant filename in readdir (len 0x%x)\n",
					len);
L
Linus Torvalds 已提交
4199 4200
			goto err_unmap;
		}
4201 4202
		xlen = XDR_QUADLEN(len);
		if (end - p < xlen + 1)
L
Linus Torvalds 已提交
4203
			goto short_pkt;
4204 4205
		dprintk("filename = %*s\n", len, (char *)p);
		p += xlen;
L
Linus Torvalds 已提交
4206
		len = ntohl(*p++);	/* bitmap length */
4207
		if (end - p < len + 1)
L
Linus Torvalds 已提交
4208
			goto short_pkt;
4209
		p += len;
L
Linus Torvalds 已提交
4210
		attrlen = XDR_QUADLEN(ntohl(*p++));
4211
		if (end - p < attrlen + 2)
L
Linus Torvalds 已提交
4212
			goto short_pkt;
4213
		p += attrlen;		/* attributes */
L
Linus Torvalds 已提交
4214 4215
		entry = p;
	}
4216 4217 4218 4219 4220 4221 4222 4223 4224
	/*
	 * 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;
	}
4225
out:
L
Linus Torvalds 已提交
4226 4227 4228
	kunmap_atomic(kaddr, KM_USER0);
	return 0;
short_pkt:
4229 4230 4231 4232 4233 4234 4235 4236 4237
	/*
	 * 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.
	 */
4238
	dprintk("%s: short packet at entry %d\n", __func__, nr);
L
Linus Torvalds 已提交
4239
	entry[0] = entry[1] = 0;
4240 4241
	if (nr)
		goto out;
L
Linus Torvalds 已提交
4242 4243 4244 4245 4246 4247 4248 4249 4250
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;
4251 4252
	size_t hdrlen;
	u32 len, recvd;
A
Al Viro 已提交
4253
	__be32 *p;
L
Linus Torvalds 已提交
4254 4255 4256 4257 4258 4259 4260 4261
	char *kaddr;
	int status;

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

	/* Convert length of symlink */
B
Benny Halevy 已提交
4262 4263 4264
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4265
	len = be32_to_cpup(p);
L
Linus Torvalds 已提交
4266
	if (len >= rcvbuf->page_len || len <= 0) {
4267
		dprintk("nfs: server returned giant symlink!\n");
L
Linus Torvalds 已提交
4268 4269 4270 4271 4272
		return -ENAMETOOLONG;
	}
	hdrlen = (char *) xdr->p - (char *) iov->iov_base;
	recvd = req->rq_rcv_buf.len - hdrlen;
	if (recvd < len) {
4273
		dprintk("NFS: server cheating in readlink reply: "
L
Linus Torvalds 已提交
4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288
				"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 已提交
4289 4290 4291
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325
}

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

4326 4327 4328 4329 4330 4331
static int
decode_restorefh(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_RESTOREFH);
}

4332 4333 4334
static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
		size_t *acl_len)
{
A
Al Viro 已提交
4335
	__be32 *savep;
4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351
	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)) {
4352 4353
		size_t hdrlen;
		u32 recvd;
4354 4355 4356 4357 4358 4359

		/* 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) {
4360
			dprintk("NFS: server cheating in getattr"
4361 4362 4363 4364
					" acl reply: attrlen %u > recvd %u\n",
					attrlen, recvd);
			return -EINVAL;
		}
4365
		xdr_read_pages(xdr, attrlen);
4366
		*acl_len = attrlen;
J
J. Bruce Fields 已提交
4367 4368
	} else
		status = -EOPNOTSUPP;
4369 4370 4371 4372 4373

out:
	return status;
}

L
Linus Torvalds 已提交
4374 4375 4376 4377 4378 4379
static int
decode_savefh(struct xdr_stream *xdr)
{
	return decode_op_hdr(xdr, OP_SAVEFH);
}

4380
static int decode_setattr(struct xdr_stream *xdr)
L
Linus Torvalds 已提交
4381
{
A
Al Viro 已提交
4382
	__be32 *p;
L
Linus Torvalds 已提交
4383 4384 4385 4386 4387 4388
	uint32_t bmlen;
	int status;

	status = decode_op_hdr(xdr, OP_SETATTR);
	if (status)
		return status;
B
Benny Halevy 已提交
4389 4390 4391
	p = xdr_inline_decode(xdr, 4);
	if (unlikely(!p))
		goto out_overflow;
4392
	bmlen = be32_to_cpup(p);
B
Benny Halevy 已提交
4393 4394 4395 4396 4397 4398
	p = xdr_inline_decode(xdr, bmlen << 2);
	if (likely(p))
		return 0;
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4399 4400
}

4401
static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp)
L
Linus Torvalds 已提交
4402
{
A
Al Viro 已提交
4403
	__be32 *p;
L
Linus Torvalds 已提交
4404 4405 4406
	uint32_t opnum;
	int32_t nfserr;

B
Benny Halevy 已提交
4407 4408 4409
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4410
	opnum = be32_to_cpup(p++);
L
Linus Torvalds 已提交
4411
	if (opnum != OP_SETCLIENTID) {
4412
		dprintk("nfs: decode_setclientid: Server returned operation"
4413
			" %d\n", opnum);
L
Linus Torvalds 已提交
4414 4415
		return -EIO;
	}
4416
	nfserr = be32_to_cpup(p);
L
Linus Torvalds 已提交
4417
	if (nfserr == NFS_OK) {
B
Benny Halevy 已提交
4418 4419 4420
		p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE);
		if (unlikely(!p))
			goto out_overflow;
B
Benny Halevy 已提交
4421
		p = xdr_decode_hyper(p, &clp->cl_clientid);
B
Benny Halevy 已提交
4422
		memcpy(clp->cl_confirm.data, p, NFS4_VERIFIER_SIZE);
L
Linus Torvalds 已提交
4423 4424 4425 4426
	} else if (nfserr == NFSERR_CLID_INUSE) {
		uint32_t len;

		/* skip netid string */
B
Benny Halevy 已提交
4427 4428 4429
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
4430
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
4431 4432 4433
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
L
Linus Torvalds 已提交
4434 4435

		/* skip uaddr string */
B
Benny Halevy 已提交
4436 4437 4438
		p = xdr_inline_decode(xdr, 4);
		if (unlikely(!p))
			goto out_overflow;
4439
		len = be32_to_cpup(p);
B
Benny Halevy 已提交
4440 4441 4442
		p = xdr_inline_decode(xdr, len);
		if (unlikely(!p))
			goto out_overflow;
L
Linus Torvalds 已提交
4443 4444
		return -NFSERR_CLID_INUSE;
	} else
4445
		return nfs4_stat_to_errno(nfserr);
L
Linus Torvalds 已提交
4446 4447

	return 0;
B
Benny Halevy 已提交
4448 4449 4450
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4451 4452 4453 4454 4455 4456 4457 4458 4459
}

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 已提交
4460
	__be32 *p;
L
Linus Torvalds 已提交
4461 4462 4463 4464 4465 4466
	int status;

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

B
Benny Halevy 已提交
4467 4468 4469
	p = xdr_inline_decode(xdr, 16);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4470 4471
	res->count = be32_to_cpup(p++);
	res->verf->committed = be32_to_cpup(p++);
B
Benny Halevy 已提交
4472
	memcpy(res->verf->verifier, p, 8);
L
Linus Torvalds 已提交
4473
	return 0;
B
Benny Halevy 已提交
4474 4475 4476
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
L
Linus Torvalds 已提交
4477 4478 4479 4480 4481 4482 4483
}

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

B
Benny Halevy 已提交
4484 4485 4486 4487 4488 4489
#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;
4490
	char *dummy_str;
B
Benny Halevy 已提交
4491 4492 4493 4494 4495 4496 4497
	int status;
	struct nfs_client *clp = res->client;

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

B
Benny Halevy 已提交
4498 4499 4500
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
4501
	xdr_decode_hyper(p, &clp->cl_ex_clid);
B
Benny Halevy 已提交
4502 4503 4504
	p = xdr_inline_decode(xdr, 12);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4505 4506
	clp->cl_seqid = be32_to_cpup(p++);
	clp->cl_exchange_flags = be32_to_cpup(p++);
B
Benny Halevy 已提交
4507 4508

	/* We ask for SP4_NONE */
4509
	dummy = be32_to_cpup(p);
B
Benny Halevy 已提交
4510 4511 4512 4513
	if (dummy != SP4_NONE)
		return -EIO;

	/* Throw away minor_id */
B
Benny Halevy 已提交
4514 4515 4516
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4517 4518

	/* Throw away Major id */
4519 4520 4521
	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
4522 4523

	/* Throw away server_scope */
4524 4525 4526
	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
4527 4528

	/* Throw away Implementation id array */
4529 4530 4531
	status = decode_opaque_inline(xdr, &dummy, &dummy_str);
	if (unlikely(status))
		return status;
B
Benny Halevy 已提交
4532 4533

	return 0;
B
Benny Halevy 已提交
4534 4535 4536
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
B
Benny Halevy 已提交
4537
}
A
Andy Adamson 已提交
4538 4539 4540 4541 4542 4543 4544

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

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

4571 4572 4573
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 已提交
4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584
}

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);
4585 4586 4587
	if (!status)
		status = decode_sessionid(xdr, &session->sess_id);
	if (unlikely(status))
A
Andy Adamson 已提交
4588 4589 4590
		return status;

	/* seqid, flags */
B
Benny Halevy 已提交
4591 4592 4593
	p = xdr_inline_decode(xdr, 8);
	if (unlikely(!p))
		goto out_overflow;
B
Benny Halevy 已提交
4594
	clp->cl_seqid = be32_to_cpup(p++);
4595
	session->flags = be32_to_cpup(p);
A
Andy Adamson 已提交
4596 4597 4598 4599 4600 4601

	/* 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 已提交
4602 4603 4604
out_overflow:
	print_overflow_msg(__func__, xdr);
	return -EIO;
A
Andy Adamson 已提交
4605
}
A
Andy Adamson 已提交
4606 4607 4608 4609 4610

static int decode_destroy_session(struct xdr_stream *xdr, void *dummy)
{
	return decode_op_hdr(xdr, OP_DESTROY_SESSION);
}
4611 4612 4613 4614 4615

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

4618 4619 4620 4621 4622
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 已提交
4623 4624 4625 4626 4627 4628
	struct nfs4_slot *slot;
	struct nfs4_sessionid id;
	u32 dummy;
	int status;
	__be32 *p;

4629 4630 4631
	if (!res->sr_session)
		return 0;

A
Andy Adamson 已提交
4632
	status = decode_op_hdr(xdr, OP_SEQUENCE);
4633 4634 4635
	if (!status)
		status = decode_sessionid(xdr, &id);
	if (unlikely(status))
A
Andy Adamson 已提交
4636
		goto out_err;
4637

A
Andy Adamson 已提交
4638 4639 4640 4641
	/*
	 * If the server returns different values for sessionID, slotID or
	 * sequence number, the server is looney tunes.
	 */
4642
	status = -EREMOTEIO;
A
Andy Adamson 已提交
4643 4644 4645 4646 4647 4648

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

B
Benny Halevy 已提交
4650 4651 4652
	p = xdr_inline_decode(xdr, 20);
	if (unlikely(!p))
		goto out_overflow;
4653

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

4686 4687 4688 4689
/*
 * END OF "GENERIC" DECODE ROUTINES.
 */

L
Linus Torvalds 已提交
4690 4691 4692
/*
 * Decode OPEN_DOWNGRADE response
 */
A
Al Viro 已提交
4693
static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
L
Linus Torvalds 已提交
4694
{
A
Andy Adamson 已提交
4695 4696 4697 4698 4699 4700
	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);
4701 4702 4703
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
4704 4705 4706 4707 4708 4709
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_open_downgrade(&xdr, res);
4710 4711
	if (status != 0)
		goto out;
4712 4713
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4714
out:
A
Andy Adamson 已提交
4715
	return status;
L
Linus Torvalds 已提交
4716 4717 4718 4719 4720
}

/*
 * Decode ACCESS response
 */
A
Al Viro 已提交
4721
static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res)
L
Linus Torvalds 已提交
4722 4723 4724 4725
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4726

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

/*
 * Decode LOOKUP response
 */
A
Al Viro 已提交
4749
static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
L
Linus Torvalds 已提交
4750 4751 4752 4753
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4754

L
Linus Torvalds 已提交
4755
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4756 4757 4758 4759 4760
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4761 4762 4763 4764 4765 4766 4767
		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;
4768 4769
	status = decode_getfattr(&xdr, res->fattr, res->server
			,!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4770 4771 4772 4773 4774 4775 4776
out:
	return status;
}

/*
 * Decode LOOKUP_ROOT response
 */
A
Al Viro 已提交
4777
static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
L
Linus Torvalds 已提交
4778 4779 4780 4781
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4782

L
Linus Torvalds 已提交
4783
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4784 4785 4786 4787 4788
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4789 4790 4791 4792
		goto out;
	if ((status = decode_putrootfh(&xdr)) != 0)
		goto out;
	if ((status = decode_getfh(&xdr, res->fh)) == 0)
4793 4794
		status = decode_getfattr(&xdr, res->fattr, res->server,
				!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4795 4796 4797 4798 4799 4800 4801
out:
	return status;
}

/*
 * Decode REMOVE response
 */
4802
static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_removeres *res)
L
Linus Torvalds 已提交
4803 4804 4805 4806
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4807

L
Linus Torvalds 已提交
4808
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4809 4810 4811 4812 4813
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4814
		goto out;
4815 4816 4817 4818
	if ((status = decode_putfh(&xdr)) != 0)
		goto out;
	if ((status = decode_remove(&xdr, &res->cinfo)) != 0)
		goto out;
4819 4820
	decode_getfattr(&xdr, &res->dir_attr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4821 4822 4823 4824 4825 4826 4827
out:
	return status;
}

/*
 * Decode RENAME response
 */
A
Al Viro 已提交
4828
static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res)
L
Linus Torvalds 已提交
4829 4830 4831 4832
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4833

L
Linus Torvalds 已提交
4834
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4835 4836 4837 4838 4839
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4840 4841 4842 4843 4844 4845 4846
		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;
4847 4848 4849
	if ((status = decode_rename(&xdr, &res->old_cinfo, &res->new_cinfo)) != 0)
		goto out;
	/* Current FH is target directory */
4850 4851
	if (decode_getfattr(&xdr, res->new_fattr, res->server,
				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
4852 4853 4854
		goto out;
	if ((status = decode_restorefh(&xdr)) != 0)
		goto out;
4855 4856
	decode_getfattr(&xdr, res->old_fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4857 4858 4859 4860 4861 4862 4863
out:
	return status;
}

/*
 * Decode LINK response
 */
A
Al Viro 已提交
4864
static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link_res *res)
L
Linus Torvalds 已提交
4865 4866 4867 4868
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4869

L
Linus Torvalds 已提交
4870
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
4871 4872 4873 4874 4875
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
L
Linus Torvalds 已提交
4876 4877 4878 4879 4880 4881 4882
		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;
4883 4884 4885 4886 4887 4888
	if ((status = decode_link(&xdr, &res->cinfo)) != 0)
		goto out;
	/*
	 * Note order: OP_LINK leaves the directory as the current
	 *             filehandle.
	 */
4889 4890
	if (decode_getfattr(&xdr, res->dir_attr, res->server,
				!RPC_IS_ASYNC(rqstp->rq_task)) != 0)
4891 4892 4893
		goto out;
	if ((status = decode_restorefh(&xdr)) != 0)
		goto out;
4894 4895
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4896 4897 4898 4899 4900 4901 4902
out:
	return status;
}

/*
 * Decode CREATE response
 */
A
Al Viro 已提交
4903
static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
L
Linus Torvalds 已提交
4904 4905 4906 4907
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4908

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

/*
 * Decode SYMLINK response
 */
A
Al Viro 已提交
4938
static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
L
Linus Torvalds 已提交
4939 4940 4941 4942 4943 4944 4945
{
	return nfs4_xdr_dec_create(rqstp, p, res);
}

/*
 * Decode GETATTR response
 */
A
Al Viro 已提交
4946
static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_getattr_res *res)
L
Linus Torvalds 已提交
4947 4948 4949 4950
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;
4951

L
Linus Torvalds 已提交
4952 4953
	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
	status = decode_compound_hdr(&xdr, &hdr);
4954 4955 4956
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
4957 4958 4959 4960 4961
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
4962 4963
	status = decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
4964 4965 4966 4967
out:
	return status;
}

4968 4969 4970 4971
/*
 * Encode an SETACL request
 */
static int
A
Al Viro 已提交
4972
nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args)
4973
{
A
Andy Adamson 已提交
4974 4975
	struct xdr_stream xdr;
	struct compound_hdr hdr = {
4976
		.minorversion = nfs4_xdr_minorversion(&args->seq_args),
A
Andy Adamson 已提交
4977 4978 4979 4980
	};
	int status;

	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
4981
	encode_compound_hdr(&xdr, req, &hdr);
4982
	encode_sequence(&xdr, &args->seq_args, &hdr);
4983
	encode_putfh(&xdr, args->fh, &hdr);
4984 4985
	status = encode_setacl(&xdr, args, &hdr);
	encode_nops(&hdr);
A
Andy Adamson 已提交
4986
	return status;
4987
}
A
Andy Adamson 已提交
4988

4989 4990 4991 4992
/*
 * Decode SETACL response
 */
static int
B
Benny Halevy 已提交
4993 4994
nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p,
		    struct nfs_setaclres *res)
4995 4996 4997 4998 4999 5000 5001
{
	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);
5002 5003 5004
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
5005 5006 5007 5008 5009
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
5010
	status = decode_setattr(&xdr);
5011 5012 5013
out:
	return status;
}
L
Linus Torvalds 已提交
5014

5015 5016 5017 5018
/*
 * Decode GETACL response
 */
static int
B
Benny Halevy 已提交
5019 5020
nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p,
		    struct nfs_getaclres *res)
5021 5022 5023 5024 5025 5026 5027
{
	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);
5028 5029 5030
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
5031 5032 5033 5034 5035
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
B
Benny Halevy 已提交
5036
	status = decode_getacl(&xdr, rqstp, &res->acl_len);
5037 5038 5039 5040 5041

out:
	return status;
}

L
Linus Torvalds 已提交
5042 5043 5044
/*
 * Decode CLOSE response
 */
A
Al Viro 已提交
5045
static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
L
Linus Torvalds 已提交
5046
{
A
Andy Adamson 已提交
5047 5048 5049 5050 5051 5052
	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);
5053 5054 5055
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
5056 5057 5058 5059 5060 5061
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_close(&xdr, res);
5062 5063 5064 5065 5066 5067 5068 5069
	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.
	 */
5070 5071
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5072
out:
A
Andy Adamson 已提交
5073
	return status;
L
Linus Torvalds 已提交
5074 5075 5076 5077 5078
}

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

/*
 * Decode OPEN_CONFIRM response
 */
A
Al Viro 已提交
5117
static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, __be32 *p, struct nfs_open_confirmres *res)
L
Linus Torvalds 已提交
5118
{
A
Andy Adamson 已提交
5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130
	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 已提交
5131
out:
A
Andy Adamson 已提交
5132
	return status;
L
Linus Torvalds 已提交
5133 5134 5135 5136 5137
}

/*
 * Decode OPEN response
 */
A
Al Viro 已提交
5138
static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
L
Linus Torvalds 已提交
5139
{
A
Andy Adamson 已提交
5140 5141 5142 5143 5144 5145
	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);
5146 5147 5148
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
5149 5150 5151 5152 5153 5154 5155 5156
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_open(&xdr, res);
	if (status)
		goto out;
5157 5158
	decode_getfattr(&xdr, res->f_attr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5159
out:
A
Andy Adamson 已提交
5160
	return status;
L
Linus Torvalds 已提交
5161 5162 5163 5164 5165
}

/*
 * Decode SETATTR response
 */
A
Al Viro 已提交
5166
static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res)
L
Linus Torvalds 已提交
5167
{
A
Andy Adamson 已提交
5168 5169 5170 5171 5172 5173
	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);
5174 5175 5176
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
A
Andy Adamson 已提交
5177 5178 5179 5180 5181
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
5182
	status = decode_setattr(&xdr);
A
Andy Adamson 已提交
5183 5184
	if (status)
		goto out;
5185 5186
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5187
out:
A
Andy Adamson 已提交
5188
	return status;
L
Linus Torvalds 已提交
5189 5190 5191 5192 5193
}

/*
 * Decode LOCK response
 */
A
Al Viro 已提交
5194
static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_res *res)
L
Linus Torvalds 已提交
5195 5196 5197 5198 5199 5200 5201
{
	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);
5202 5203 5204
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217
	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 已提交
5218
static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lockt_res *res)
L
Linus Torvalds 已提交
5219 5220 5221 5222 5223 5224 5225
{
	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);
5226 5227 5228
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241
	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 已提交
5242
static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_locku_res *res)
L
Linus Torvalds 已提交
5243 5244 5245 5246 5247 5248 5249
{
	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);
5250 5251 5252
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265
	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 已提交
5266 5267
static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p,
				 struct nfs4_readlink_res *res)
L
Linus Torvalds 已提交
5268 5269 5270 5271 5272 5273 5274
{
	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);
5275 5276 5277
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290
	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 已提交
5291
static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_readdir_res *res)
L
Linus Torvalds 已提交
5292 5293 5294 5295 5296 5297 5298
{
	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);
5299 5300 5301
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314
	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 已提交
5315
static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readres *res)
L
Linus Torvalds 已提交
5316 5317 5318 5319 5320 5321 5322
{
	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);
5323 5324 5325
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340
	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 已提交
5341
static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
L
Linus Torvalds 已提交
5342 5343 5344 5345 5346 5347 5348
{
	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);
5349 5350 5351
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5352 5353 5354 5355 5356 5357
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_write(&xdr, res);
5358 5359
	if (status)
		goto out;
5360 5361
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5362 5363 5364 5365 5366 5367 5368 5369 5370
	if (!status)
		status = res->count;
out:
	return status;
}

/*
 * Decode COMMIT response
 */
A
Al Viro 已提交
5371
static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
L
Linus Torvalds 已提交
5372 5373 5374 5375 5376 5377 5378
{
	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);
5379 5380 5381
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
L
Linus Torvalds 已提交
5382 5383 5384 5385 5386 5387
	if (status)
		goto out;
	status = decode_putfh(&xdr);
	if (status)
		goto out;
	status = decode_commit(&xdr, res);
5388 5389
	if (status)
		goto out;
5390 5391
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
L
Linus Torvalds 已提交
5392 5393 5394 5395 5396
out:
	return status;
}

/*
5397
 * Decode FSINFO response
L
Linus Torvalds 已提交
5398
 */
B
Benny Halevy 已提交
5399 5400
static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p,
			       struct nfs4_fsinfo_res *res)
L
Linus Torvalds 已提交
5401 5402 5403 5404 5405 5406 5407
{
	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);
5408 5409
	if (!status)
		status = decode_sequence(&xdr, &res->seq_res, req);
L
Linus Torvalds 已提交
5410 5411 5412
	if (!status)
		status = decode_putfh(&xdr);
	if (!status)
B
Benny Halevy 已提交
5413
		status = decode_fsinfo(&xdr, res->fsinfo);
L
Linus Torvalds 已提交
5414 5415 5416 5417
	return status;
}

/*
5418
 * Decode PATHCONF response
L
Linus Torvalds 已提交
5419
 */
B
Benny Halevy 已提交
5420 5421
static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p,
				 struct nfs4_pathconf_res *res)
L
Linus Torvalds 已提交
5422 5423 5424 5425 5426 5427 5428
{
	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);
5429 5430
	if (!status)
		status = decode_sequence(&xdr, &res->seq_res, req);
L
Linus Torvalds 已提交
5431 5432 5433
	if (!status)
		status = decode_putfh(&xdr);
	if (!status)
B
Benny Halevy 已提交
5434
		status = decode_pathconf(&xdr, res->pathconf);
L
Linus Torvalds 已提交
5435 5436 5437 5438
	return status;
}

/*
5439
 * Decode STATFS response
L
Linus Torvalds 已提交
5440
 */
B
Benny Halevy 已提交
5441 5442
static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p,
			       struct nfs4_statfs_res *res)
L
Linus Torvalds 已提交
5443 5444 5445 5446 5447 5448 5449
{
	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);
5450 5451
	if (!status)
		status = decode_sequence(&xdr, &res->seq_res, req);
L
Linus Torvalds 已提交
5452 5453 5454
	if (!status)
		status = decode_putfh(&xdr);
	if (!status)
B
Benny Halevy 已提交
5455
		status = decode_statfs(&xdr, res->fsstat);
L
Linus Torvalds 已提交
5456 5457 5458 5459
	return status;
}

/*
5460
 * Decode GETATTR_BITMAP response
L
Linus Torvalds 已提交
5461
 */
A
Al Viro 已提交
5462
static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4_server_caps_res *res)
L
Linus Torvalds 已提交
5463 5464 5465 5466 5467 5468
{
	struct xdr_stream xdr;
	struct compound_hdr hdr;
	int status;

	xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
5469 5470 5471 5472 5473
	status = decode_compound_hdr(&xdr, &hdr);
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, req);
	if (status)
L
Linus Torvalds 已提交
5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484
		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 已提交
5485
static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy)
L
Linus Torvalds 已提交
5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498
{
	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;
}

/*
5499
 * Decode SETCLIENTID response
L
Linus Torvalds 已提交
5500
 */
A
Al Viro 已提交
5501
static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p,
5502
		struct nfs_client *clp)
L
Linus Torvalds 已提交
5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515
{
	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;
}

/*
5516
 * Decode SETCLIENTID_CONFIRM response
L
Linus Torvalds 已提交
5517
 */
A
Al Viro 已提交
5518
static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
L
Linus Torvalds 已提交
5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535
{
	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;
}

/*
5536
 * Decode DELEGRETURN response
L
Linus Torvalds 已提交
5537
 */
A
Al Viro 已提交
5538
static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_delegreturnres *res)
L
Linus Torvalds 已提交
5539 5540 5541 5542 5543 5544 5545
{
	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);
5546 5547 5548 5549
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, rqstp);
	if (status)
5550 5551 5552 5553 5554
		goto out;
	status = decode_putfh(&xdr);
	if (status != 0)
		goto out;
	status = decode_delegreturn(&xdr);
5555 5556
	decode_getfattr(&xdr, res->fattr, res->server,
			!RPC_IS_ASYNC(rqstp->rq_task));
5557
out:
L
Linus Torvalds 已提交
5558 5559 5560
	return status;
}

5561
/*
5562
 * Decode FS_LOCATIONS response
5563
 */
B
Benny Halevy 已提交
5564 5565
static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p,
				     struct nfs4_fs_locations_res *res)
5566 5567 5568 5569 5570 5571 5572
{
	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);
5573 5574 5575 5576
	if (status)
		goto out;
	status = decode_sequence(&xdr, &res->seq_res, req);
	if (status)
5577 5578 5579 5580 5581 5582
		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 已提交
5583
	status = decode_getfattr(&xdr, &res->fs_locations->fattr,
5584 5585
				 res->fs_locations->server,
				 !RPC_IS_ASYNC(req->rq_task));
5586 5587 5588 5589
out:
	return status;
}

B
Benny Halevy 已提交
5590 5591
#if defined(CONFIG_NFS_V4_1)
/*
5592
 * Decode EXCHANGE_ID response
B
Benny Halevy 已提交
5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606
 */
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 已提交
5607

A
Andy Adamson 已提交
5608
/*
5609
 * Decode CREATE_SESSION response
A
Andy Adamson 已提交
5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624
 */
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 已提交
5625
/*
5626
 * Decode DESTROY_SESSION response
A
Andy Adamson 已提交
5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641
 */
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 已提交
5642
/*
5643
 * Decode SEQUENCE response
A
Andy Adamson 已提交
5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658
 */
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 已提交
5659
/*
5660
 * Decode GET_LEASE_TIME response
A
Andy Adamson 已提交
5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678
 */
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;
}
5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697

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

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

5700
__be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
L
Linus Torvalds 已提交
5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734
{
	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) {
5735 5736 5737 5738 5739 5740
		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 已提交
5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760
		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		},
5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784
	{ 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	},
5785
	{ NFS4ERR_SERVERFAULT,	-EREMOTEIO	},
5786 5787 5788 5789 5790 5791
	{ 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 已提交
5792 5793 5794
						    * to be handled by a
						    * middle-layer.
						    */
5795
	{ -1,			-EIO		}
L
Linus Torvalds 已提交
5796 5797 5798 5799 5800 5801 5802
};

/*
 * Convert an NFS error code to a local one.
 * This one is used jointly by NFSv2 and NFSv3.
 */
static int
5803
nfs4_stat_to_errno(int stat)
L
Linus Torvalds 已提交
5804 5805 5806 5807 5808 5809 5810 5811
{
	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. */
5812
		return -EREMOTEIO;
L
Linus Torvalds 已提交
5813 5814 5815 5816 5817 5818
	}
	/* 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.
	 */
5819
	return -stat;
L
Linus Torvalds 已提交
5820 5821 5822 5823 5824 5825 5826
}

#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,		\
5827 5828
	.p_arglen = NFS4_##argtype##_sz,			\
	.p_replen = NFS4_##restype##_sz,			\
5829 5830
	.p_statidx = NFSPROC4_CLNT_##proc,			\
	.p_name   = #proc,					\
A
Andy Adamson 已提交
5831
}
L
Linus Torvalds 已提交
5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864

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),
5865
  PROC(GETACL,		enc_getacl,	dec_getacl),
5866
  PROC(SETACL,		enc_setacl,	dec_setacl),
5867
  PROC(FS_LOCATIONS,	enc_fs_locations, dec_fs_locations),
B
Benny Halevy 已提交
5868 5869
#if defined(CONFIG_NFS_V4_1)
  PROC(EXCHANGE_ID,	enc_exchange_id,	dec_exchange_id),
A
Andy Adamson 已提交
5870
  PROC(CREATE_SESSION,	enc_create_session,	dec_create_session),
A
Andy Adamson 已提交
5871
  PROC(DESTROY_SESSION,	enc_destroy_session,	dec_destroy_session),
A
Andy Adamson 已提交
5872
  PROC(SEQUENCE,	enc_sequence,	dec_sequence),
A
Andy Adamson 已提交
5873
  PROC(GET_LEASE_TIME,	enc_get_lease_time,	dec_get_lease_time),
5874
  PROC(RECLAIM_COMPLETE, enc_reclaim_complete,  dec_reclaim_complete),
B
Benny Halevy 已提交
5875
#endif /* CONFIG_NFS_V4_1 */
L
Linus Torvalds 已提交
5876 5877 5878 5879
};

struct rpc_version		nfs_version4 = {
	.number			= 4,
5880
	.nrprocs		= ARRAY_SIZE(nfs4_procedures),
L
Linus Torvalds 已提交
5881 5882 5883 5884 5885 5886 5887 5888
	.procs			= nfs4_procedures
};

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