]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - fs/nfsd/nfs4xdr.c
nfsd: make find_any_file available outside nfs4state.c
[mirror_ubuntu-artful-kernel.git] / fs / nfsd / nfs4xdr.c
CommitLineData
1da177e4 1/*
1da177e4
LT
2 * Server-side XDR for NFSv4
3 *
4 * Copyright (c) 2002 The Regents of the University of Michigan.
5 * All rights reserved.
6 *
7 * Kendrick Smith <kmsmith@umich.edu>
8 * Andy Adamson <andros@umich.edu>
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1da177e4
LT
34 */
35
5a0e3ad6 36#include <linux/slab.h>
1da177e4 37#include <linux/namei.h>
341eb184 38#include <linux/statfs.h>
0733d213 39#include <linux/utsname.h>
17456804 40#include <linux/pagemap.h>
4796f457 41#include <linux/sunrpc/svcauth_gss.h>
9a74af21 42
2ca72e17
BF
43#include "idmap.h"
44#include "acl.h"
9a74af21 45#include "xdr4.h"
0a3adade 46#include "vfs.h"
17456804 47#include "state.h"
1091006c 48#include "cache.h"
3d733711 49#include "netns.h"
2ca72e17 50
18032ca0
DQ
51#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
52#include <linux/security.h>
53#endif
54
55
1da177e4
LT
56#define NFSDDBG_FACILITY NFSDDBG_XDR
57
42ca0993
BF
58/*
59 * As per referral draft, the fsid for a referral MUST be different from the fsid of the containing
60 * directory in order to indicate to the client that a filesystem boundary is present
61 * We use a fixed fsid for a referral
62 */
63#define NFS4_REFERRAL_FSID_MAJOR 0x8000000ULL
64#define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL
65
b37ad28b 66static __be32
a36b1725 67check_filename(char *str, int len)
1da177e4
LT
68{
69 int i;
70
71 if (len == 0)
72 return nfserr_inval;
73 if (isdotent(str, len))
a36b1725 74 return nfserr_badname;
1da177e4
LT
75 for (i = 0; i < len; i++)
76 if (str[i] == '/')
a36b1725 77 return nfserr_badname;
1da177e4
LT
78 return 0;
79}
80
1da177e4 81#define DECODE_HEAD \
2ebbc012 82 __be32 *p; \
b37ad28b 83 __be32 status
1da177e4
LT
84#define DECODE_TAIL \
85 status = 0; \
86out: \
87 return status; \
88xdr_error: \
817cb9d4
CL
89 dprintk("NFSD: xdr error (%s:%d)\n", \
90 __FILE__, __LINE__); \
1da177e4
LT
91 status = nfserr_bad_xdr; \
92 goto out
93
1da177e4
LT
94#define READMEM(x,nbytes) do { \
95 x = (char *)p; \
96 p += XDR_QUADLEN(nbytes); \
97} while (0)
98#define SAVEMEM(x,nbytes) do { \
99 if (!(x = (p==argp->tmp || p == argp->tmpp) ? \
100 savemem(argp, p, nbytes) : \
101 (char *)p)) { \
817cb9d4
CL
102 dprintk("NFSD: xdr error (%s:%d)\n", \
103 __FILE__, __LINE__); \
1da177e4
LT
104 goto xdr_error; \
105 } \
106 p += XDR_QUADLEN(nbytes); \
107} while (0)
108#define COPYMEM(x,nbytes) do { \
109 memcpy((x), p, nbytes); \
110 p += XDR_QUADLEN(nbytes); \
111} while (0)
112
113/* READ_BUF, read_buf(): nbytes must be <= PAGE_SIZE */
114#define READ_BUF(nbytes) do { \
115 if (nbytes <= (u32)((char *)argp->end - (char *)argp->p)) { \
116 p = argp->p; \
117 argp->p += XDR_QUADLEN(nbytes); \
118 } else if (!(p = read_buf(argp, nbytes))) { \
817cb9d4
CL
119 dprintk("NFSD: xdr error (%s:%d)\n", \
120 __FILE__, __LINE__); \
1da177e4
LT
121 goto xdr_error; \
122 } \
123} while (0)
124
590b7431
BF
125static void next_decode_page(struct nfsd4_compoundargs *argp)
126{
590b7431 127 argp->p = page_address(argp->pagelist[0]);
365da4ad 128 argp->pagelist++;
590b7431
BF
129 if (argp->pagelen < PAGE_SIZE) {
130 argp->end = argp->p + (argp->pagelen>>2);
131 argp->pagelen = 0;
132 } else {
133 argp->end = argp->p + (PAGE_SIZE>>2);
134 argp->pagelen -= PAGE_SIZE;
135 }
136}
137
ca2a05aa 138static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes)
1da177e4
LT
139{
140 /* We want more bytes than seem to be available.
141 * Maybe we need a new page, maybe we have just run out
142 */
ca2a05aa 143 unsigned int avail = (char *)argp->end - (char *)argp->p;
2ebbc012 144 __be32 *p;
1da177e4
LT
145 if (avail + argp->pagelen < nbytes)
146 return NULL;
147 if (avail + PAGE_SIZE < nbytes) /* need more than a page !! */
148 return NULL;
149 /* ok, we can do it with the current plus the next page */
150 if (nbytes <= sizeof(argp->tmp))
151 p = argp->tmp;
152 else {
f99d49ad 153 kfree(argp->tmpp);
1da177e4
LT
154 p = argp->tmpp = kmalloc(nbytes, GFP_KERNEL);
155 if (!p)
156 return NULL;
157
158 }
ca2a05aa
BF
159 /*
160 * The following memcpy is safe because read_buf is always
161 * called with nbytes > avail, and the two cases above both
162 * guarantee p points to at least nbytes bytes.
163 */
1da177e4 164 memcpy(p, argp->p, avail);
590b7431 165 next_decode_page(argp);
1da177e4
LT
166 memcpy(((char*)p)+avail, argp->p, (nbytes - avail));
167 argp->p += XDR_QUADLEN(nbytes - avail);
168 return p;
169}
170
60adfc50
AA
171static int zero_clientid(clientid_t *clid)
172{
173 return (clid->cl_boot == 0) && (clid->cl_id == 0);
174}
175
2d8498db 176/**
d5e23383 177 * svcxdr_tmpalloc - allocate memory to be freed after compound processing
ce043ac8
BF
178 * @argp: NFSv4 compound argument structure
179 * @p: pointer to be freed (with kfree())
2d8498db
CH
180 *
181 * Marks @p to be freed when processing the compound operation
182 * described in @argp finishes.
183 */
d5e23383
BF
184static void *
185svcxdr_tmpalloc(struct nfsd4_compoundargs *argp, u32 len)
1da177e4 186{
d5e23383 187 struct svcxdr_tmpbuf *tb;
1da177e4 188
d5e23383 189 tb = kmalloc(sizeof(*tb) + len, GFP_KERNEL);
1da177e4 190 if (!tb)
d5e23383 191 return NULL;
1da177e4
LT
192 tb->next = argp->to_free;
193 argp->to_free = tb;
d5e23383 194 return tb->buf;
1da177e4
LT
195}
196
29c353b3
BF
197/*
198 * For xdr strings that need to be passed to other kernel api's
199 * as null-terminated strings.
200 *
201 * Note null-terminating in place usually isn't safe since the
202 * buffer might end on a page boundary.
203 */
204static char *
205svcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, u32 len)
206{
d5e23383 207 char *p = svcxdr_tmpalloc(argp, len + 1);
29c353b3
BF
208
209 if (!p)
210 return NULL;
211 memcpy(p, buf, len);
212 p[len] = '\0';
29c353b3 213 return p;
1da177e4
LT
214}
215
2d8498db
CH
216/**
217 * savemem - duplicate a chunk of memory for later processing
218 * @argp: NFSv4 compound argument structure to be freed with
219 * @p: pointer to be duplicated
220 * @nbytes: length to be duplicated
221 *
222 * Returns a pointer to a copy of @nbytes bytes of memory at @p
223 * that are preserved until processing of the NFSv4 compound
224 * operation described by @argp finishes.
225 */
2ebbc012 226static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes)
1da177e4 227{
d5e23383
BF
228 void *ret;
229
230 ret = svcxdr_tmpalloc(argp, nbytes);
231 if (!ret)
1da177e4 232 return NULL;
d5e23383
BF
233 memcpy(ret, p, nbytes);
234 return ret;
1da177e4
LT
235}
236
4c94e13e
CH
237/*
238 * We require the high 32 bits of 'seconds' to be 0, and
239 * we ignore all 32 bits of 'nseconds'.
240 */
241static __be32
242nfsd4_decode_time(struct nfsd4_compoundargs *argp, struct timespec *tv)
243{
244 DECODE_HEAD;
245 u64 sec;
246
247 READ_BUF(12);
248 p = xdr_decode_hyper(p, &sec);
249 tv->tv_sec = sec;
250 tv->tv_nsec = be32_to_cpup(p++);
251 if (tv->tv_nsec >= (u32)1000000000)
252 return nfserr_inval;
253
254 DECODE_TAIL;
255}
256
b37ad28b 257static __be32
1da177e4
LT
258nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
259{
260 u32 bmlen;
261 DECODE_HEAD;
262
263 bmval[0] = 0;
264 bmval[1] = 0;
7e705706 265 bmval[2] = 0;
1da177e4
LT
266
267 READ_BUF(4);
06553991 268 bmlen = be32_to_cpup(p++);
1da177e4
LT
269 if (bmlen > 1000)
270 goto xdr_error;
271
272 READ_BUF(bmlen << 2);
273 if (bmlen > 0)
06553991 274 bmval[0] = be32_to_cpup(p++);
1da177e4 275 if (bmlen > 1)
06553991 276 bmval[1] = be32_to_cpup(p++);
7e705706 277 if (bmlen > 2)
06553991 278 bmval[2] = be32_to_cpup(p++);
1da177e4
LT
279
280 DECODE_TAIL;
281}
282
b37ad28b 283static __be32
3c8e0316 284nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
18032ca0
DQ
285 struct iattr *iattr, struct nfs4_acl **acl,
286 struct xdr_netobj *label)
1da177e4
LT
287{
288 int expected_len, len = 0;
289 u32 dummy32;
290 char *buf;
291
292 DECODE_HEAD;
293 iattr->ia_valid = 0;
294 if ((status = nfsd4_decode_bitmap(argp, bmval)))
295 return status;
296
1da177e4 297 READ_BUF(4);
06553991 298 expected_len = be32_to_cpup(p++);
1da177e4
LT
299
300 if (bmval[0] & FATTR4_WORD0_SIZE) {
301 READ_BUF(8);
302 len += 8;
542d1ab3 303 p = xdr_decode_hyper(p, &iattr->ia_size);
1da177e4
LT
304 iattr->ia_valid |= ATTR_SIZE;
305 }
306 if (bmval[0] & FATTR4_WORD0_ACL) {
64a817cf 307 u32 nace;
28e05dd8 308 struct nfs4_ace *ace;
1da177e4
LT
309
310 READ_BUF(4); len += 4;
06553991 311 nace = be32_to_cpup(p++);
1da177e4 312
28e05dd8 313 if (nace > NFS4_ACL_MAX)
798df338 314 return nfserr_fbig;
28e05dd8 315
d5e23383 316 *acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(nace));
eba1c99c
KM
317 if (*acl == NULL)
318 return nfserr_jukebox;
319
28e05dd8
BF
320 (*acl)->naces = nace;
321 for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) {
1da177e4 322 READ_BUF(16); len += 16;
06553991
BF
323 ace->type = be32_to_cpup(p++);
324 ace->flag = be32_to_cpup(p++);
325 ace->access_mask = be32_to_cpup(p++);
326 dummy32 = be32_to_cpup(p++);
1da177e4
LT
327 READ_BUF(dummy32);
328 len += XDR_QUADLEN(dummy32) << 2;
329 READMEM(buf, dummy32);
28e05dd8 330 ace->whotype = nfs4_acl_get_whotype(buf, dummy32);
3c726023 331 status = nfs_ok;
28e05dd8 332 if (ace->whotype != NFS4_ACL_WHO_NAMED)
ab8e4aee 333 ;
28e05dd8 334 else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
3c726023 335 status = nfsd_map_name_to_gid(argp->rqstp,
ab8e4aee 336 buf, dummy32, &ace->who_gid);
1da177e4 337 else
3c726023 338 status = nfsd_map_name_to_uid(argp->rqstp,
ab8e4aee 339 buf, dummy32, &ace->who_uid);
3c726023
BF
340 if (status)
341 return status;
1da177e4
LT
342 }
343 } else
344 *acl = NULL;
345 if (bmval[1] & FATTR4_WORD1_MODE) {
346 READ_BUF(4);
347 len += 4;
06553991 348 iattr->ia_mode = be32_to_cpup(p++);
1da177e4
LT
349 iattr->ia_mode &= (S_IFMT | S_IALLUGO);
350 iattr->ia_valid |= ATTR_MODE;
351 }
352 if (bmval[1] & FATTR4_WORD1_OWNER) {
353 READ_BUF(4);
354 len += 4;
06553991 355 dummy32 = be32_to_cpup(p++);
1da177e4
LT
356 READ_BUF(dummy32);
357 len += (XDR_QUADLEN(dummy32) << 2);
358 READMEM(buf, dummy32);
47c85291
N
359 if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid)))
360 return status;
1da177e4
LT
361 iattr->ia_valid |= ATTR_UID;
362 }
363 if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) {
364 READ_BUF(4);
365 len += 4;
06553991 366 dummy32 = be32_to_cpup(p++);
1da177e4
LT
367 READ_BUF(dummy32);
368 len += (XDR_QUADLEN(dummy32) << 2);
369 READMEM(buf, dummy32);
47c85291
N
370 if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid)))
371 return status;
1da177e4
LT
372 iattr->ia_valid |= ATTR_GID;
373 }
374 if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
375 READ_BUF(4);
376 len += 4;
06553991 377 dummy32 = be32_to_cpup(p++);
1da177e4
LT
378 switch (dummy32) {
379 case NFS4_SET_TO_CLIENT_TIME:
1da177e4 380 len += 12;
4c94e13e
CH
381 status = nfsd4_decode_time(argp, &iattr->ia_atime);
382 if (status)
383 return status;
1da177e4
LT
384 iattr->ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET);
385 break;
386 case NFS4_SET_TO_SERVER_TIME:
387 iattr->ia_valid |= ATTR_ATIME;
388 break;
389 default:
390 goto xdr_error;
391 }
392 }
1da177e4
LT
393 if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
394 READ_BUF(4);
395 len += 4;
06553991 396 dummy32 = be32_to_cpup(p++);
1da177e4
LT
397 switch (dummy32) {
398 case NFS4_SET_TO_CLIENT_TIME:
1da177e4 399 len += 12;
4c94e13e
CH
400 status = nfsd4_decode_time(argp, &iattr->ia_mtime);
401 if (status)
402 return status;
1da177e4
LT
403 iattr->ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET);
404 break;
405 case NFS4_SET_TO_SERVER_TIME:
406 iattr->ia_valid |= ATTR_MTIME;
407 break;
408 default:
409 goto xdr_error;
410 }
411 }
18032ca0
DQ
412
413 label->len = 0;
414#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
415 if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) {
416 READ_BUF(4);
417 len += 4;
06553991 418 dummy32 = be32_to_cpup(p++); /* lfs: we don't use it */
18032ca0
DQ
419 READ_BUF(4);
420 len += 4;
06553991 421 dummy32 = be32_to_cpup(p++); /* pi: we don't use it either */
18032ca0
DQ
422 READ_BUF(4);
423 len += 4;
06553991 424 dummy32 = be32_to_cpup(p++);
18032ca0
DQ
425 READ_BUF(dummy32);
426 if (dummy32 > NFSD4_MAX_SEC_LABEL_LEN)
427 return nfserr_badlabel;
428 len += (XDR_QUADLEN(dummy32) << 2);
429 READMEM(buf, dummy32);
29c353b3
BF
430 label->len = dummy32;
431 label->data = svcxdr_dupstr(argp, buf, dummy32);
18032ca0
DQ
432 if (!label->data)
433 return nfserr_jukebox;
18032ca0
DQ
434 }
435#endif
436
3c8e0316
YZ
437 if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
438 || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
439 || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2)
440 READ_BUF(expected_len - len);
441 else if (len != expected_len)
1da177e4
LT
442 goto xdr_error;
443
444 DECODE_TAIL;
1da177e4
LT
445}
446
e31a1b66
BH
447static __be32
448nfsd4_decode_stateid(struct nfsd4_compoundargs *argp, stateid_t *sid)
449{
450 DECODE_HEAD;
451
452 READ_BUF(sizeof(stateid_t));
06553991 453 sid->si_generation = be32_to_cpup(p++);
e31a1b66
BH
454 COPYMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
455
456 DECODE_TAIL;
457}
458
b37ad28b 459static __be32
1da177e4
LT
460nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access)
461{
462 DECODE_HEAD;
463
464 READ_BUF(4);
06553991 465 access->ac_req_access = be32_to_cpup(p++);
1da177e4
LT
466
467 DECODE_TAIL;
468}
469
acb2887e
BF
470static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs)
471{
472 DECODE_HEAD;
12fc3e92 473 u32 dummy, uid, gid;
acb2887e
BF
474 char *machine_name;
475 int i;
476 int nr_secflavs;
477
478 /* callback_sec_params4 */
479 READ_BUF(4);
06553991 480 nr_secflavs = be32_to_cpup(p++);
57569a70
BF
481 if (nr_secflavs)
482 cbs->flavor = (u32)(-1);
483 else
484 /* Is this legal? Be generous, take it to mean AUTH_NONE: */
485 cbs->flavor = 0;
acb2887e
BF
486 for (i = 0; i < nr_secflavs; ++i) {
487 READ_BUF(4);
06553991 488 dummy = be32_to_cpup(p++);
acb2887e
BF
489 switch (dummy) {
490 case RPC_AUTH_NULL:
491 /* Nothing to read */
12fc3e92
BF
492 if (cbs->flavor == (u32)(-1))
493 cbs->flavor = RPC_AUTH_NULL;
acb2887e
BF
494 break;
495 case RPC_AUTH_UNIX:
496 READ_BUF(8);
497 /* stamp */
06553991 498 dummy = be32_to_cpup(p++);
acb2887e
BF
499
500 /* machine name */
06553991 501 dummy = be32_to_cpup(p++);
acb2887e
BF
502 READ_BUF(dummy);
503 SAVEMEM(machine_name, dummy);
504
505 /* uid, gid */
506 READ_BUF(8);
06553991
BF
507 uid = be32_to_cpup(p++);
508 gid = be32_to_cpup(p++);
acb2887e
BF
509
510 /* more gids */
511 READ_BUF(4);
06553991 512 dummy = be32_to_cpup(p++);
acb2887e 513 READ_BUF(dummy * 4);
12fc3e92 514 if (cbs->flavor == (u32)(-1)) {
03bc6d1c
EB
515 kuid_t kuid = make_kuid(&init_user_ns, uid);
516 kgid_t kgid = make_kgid(&init_user_ns, gid);
517 if (uid_valid(kuid) && gid_valid(kgid)) {
518 cbs->uid = kuid;
519 cbs->gid = kgid;
520 cbs->flavor = RPC_AUTH_UNIX;
521 } else {
522 dprintk("RPC_AUTH_UNIX with invalid"
523 "uid or gid ignoring!\n");
524 }
12fc3e92 525 }
acb2887e
BF
526 break;
527 case RPC_AUTH_GSS:
528 dprintk("RPC_AUTH_GSS callback secflavor "
529 "not supported!\n");
530 READ_BUF(8);
531 /* gcbp_service */
06553991 532 dummy = be32_to_cpup(p++);
acb2887e 533 /* gcbp_handle_from_server */
06553991 534 dummy = be32_to_cpup(p++);
acb2887e
BF
535 READ_BUF(dummy);
536 p += XDR_QUADLEN(dummy);
537 /* gcbp_handle_from_client */
538 READ_BUF(4);
06553991 539 dummy = be32_to_cpup(p++);
acb2887e
BF
540 READ_BUF(dummy);
541 break;
542 default:
543 dprintk("Illegal callback secflavor\n");
544 return nfserr_inval;
545 }
546 }
547 DECODE_TAIL;
548}
549
cb73a9f4
BF
550static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, struct nfsd4_backchannel_ctl *bc)
551{
552 DECODE_HEAD;
553
554 READ_BUF(4);
06553991 555 bc->bc_cb_program = be32_to_cpup(p++);
cb73a9f4
BF
556 nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec);
557
558 DECODE_TAIL;
559}
560
1d1bc8f2
BF
561static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts)
562{
563 DECODE_HEAD;
1d1bc8f2
BF
564
565 READ_BUF(NFS4_MAX_SESSIONID_LEN + 8);
566 COPYMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN);
06553991 567 bcts->dir = be32_to_cpup(p++);
6ce2357f
BS
568 /* XXX: skipping ctsa_use_conn_in_rdma_mode. Perhaps Tom Tucker
569 * could help us figure out we should be using it. */
1d1bc8f2
BF
570 DECODE_TAIL;
571}
572
b37ad28b 573static __be32
1da177e4
LT
574nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
575{
576 DECODE_HEAD;
577
e31a1b66 578 READ_BUF(4);
06553991 579 close->cl_seqid = be32_to_cpup(p++);
e31a1b66 580 return nfsd4_decode_stateid(argp, &close->cl_stateid);
1da177e4
LT
581
582 DECODE_TAIL;
583}
584
585
b37ad28b 586static __be32
1da177e4
LT
587nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit)
588{
589 DECODE_HEAD;
590
591 READ_BUF(12);
542d1ab3 592 p = xdr_decode_hyper(p, &commit->co_offset);
06553991 593 commit->co_count = be32_to_cpup(p++);
1da177e4
LT
594
595 DECODE_TAIL;
596}
597
b37ad28b 598static __be32
1da177e4
LT
599nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create)
600{
601 DECODE_HEAD;
602
603 READ_BUF(4);
06553991 604 create->cr_type = be32_to_cpup(p++);
1da177e4
LT
605 switch (create->cr_type) {
606 case NF4LNK:
607 READ_BUF(4);
7fb84306
BF
608 create->cr_datalen = be32_to_cpup(p++);
609 READ_BUF(create->cr_datalen);
29c353b3 610 create->cr_data = svcxdr_dupstr(argp, p, create->cr_datalen);
7fb84306 611 if (!create->cr_data)
76f47128 612 return nfserr_jukebox;
1da177e4
LT
613 break;
614 case NF4BLK:
615 case NF4CHR:
616 READ_BUF(8);
06553991
BF
617 create->cr_specdata1 = be32_to_cpup(p++);
618 create->cr_specdata2 = be32_to_cpup(p++);
1da177e4
LT
619 break;
620 case NF4SOCK:
621 case NF4FIFO:
622 case NF4DIR:
623 default:
624 break;
625 }
626
627 READ_BUF(4);
06553991 628 create->cr_namelen = be32_to_cpup(p++);
1da177e4
LT
629 READ_BUF(create->cr_namelen);
630 SAVEMEM(create->cr_name, create->cr_namelen);
a36b1725 631 if ((status = check_filename(create->cr_name, create->cr_namelen)))
1da177e4
LT
632 return status;
633
3c8e0316 634 status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr,
18032ca0 635 &create->cr_acl, &create->cr_label);
c0d6fc8a 636 if (status)
1da177e4
LT
637 goto out;
638
639 DECODE_TAIL;
640}
641
b37ad28b 642static inline __be32
1da177e4
LT
643nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr)
644{
e31a1b66 645 return nfsd4_decode_stateid(argp, &dr->dr_stateid);
1da177e4
LT
646}
647
b37ad28b 648static inline __be32
1da177e4
LT
649nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr)
650{
651 return nfsd4_decode_bitmap(argp, getattr->ga_bmval);
652}
653
b37ad28b 654static __be32
1da177e4
LT
655nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link)
656{
657 DECODE_HEAD;
658
659 READ_BUF(4);
06553991 660 link->li_namelen = be32_to_cpup(p++);
1da177e4
LT
661 READ_BUF(link->li_namelen);
662 SAVEMEM(link->li_name, link->li_namelen);
a36b1725 663 if ((status = check_filename(link->li_name, link->li_namelen)))
1da177e4
LT
664 return status;
665
666 DECODE_TAIL;
667}
668
b37ad28b 669static __be32
1da177e4
LT
670nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
671{
672 DECODE_HEAD;
673
1da177e4
LT
674 /*
675 * type, reclaim(boolean), offset, length, new_lock_owner(boolean)
676 */
677 READ_BUF(28);
06553991 678 lock->lk_type = be32_to_cpup(p++);
1da177e4
LT
679 if ((lock->lk_type < NFS4_READ_LT) || (lock->lk_type > NFS4_WRITEW_LT))
680 goto xdr_error;
06553991 681 lock->lk_reclaim = be32_to_cpup(p++);
542d1ab3
BF
682 p = xdr_decode_hyper(p, &lock->lk_offset);
683 p = xdr_decode_hyper(p, &lock->lk_length);
06553991 684 lock->lk_is_new = be32_to_cpup(p++);
1da177e4
LT
685
686 if (lock->lk_is_new) {
e31a1b66 687 READ_BUF(4);
06553991 688 lock->lk_new_open_seqid = be32_to_cpup(p++);
e31a1b66
BH
689 status = nfsd4_decode_stateid(argp, &lock->lk_new_open_stateid);
690 if (status)
691 return status;
692 READ_BUF(8 + sizeof(clientid_t));
06553991 693 lock->lk_new_lock_seqid = be32_to_cpup(p++);
1da177e4 694 COPYMEM(&lock->lk_new_clientid, sizeof(clientid_t));
06553991 695 lock->lk_new_owner.len = be32_to_cpup(p++);
1da177e4
LT
696 READ_BUF(lock->lk_new_owner.len);
697 READMEM(lock->lk_new_owner.data, lock->lk_new_owner.len);
698 } else {
e31a1b66
BH
699 status = nfsd4_decode_stateid(argp, &lock->lk_old_lock_stateid);
700 if (status)
701 return status;
702 READ_BUF(4);
06553991 703 lock->lk_old_lock_seqid = be32_to_cpup(p++);
1da177e4
LT
704 }
705
706 DECODE_TAIL;
707}
708
b37ad28b 709static __be32
1da177e4
LT
710nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt)
711{
712 DECODE_HEAD;
713
714 READ_BUF(32);
06553991 715 lockt->lt_type = be32_to_cpup(p++);
1da177e4
LT
716 if((lockt->lt_type < NFS4_READ_LT) || (lockt->lt_type > NFS4_WRITEW_LT))
717 goto xdr_error;
542d1ab3
BF
718 p = xdr_decode_hyper(p, &lockt->lt_offset);
719 p = xdr_decode_hyper(p, &lockt->lt_length);
1da177e4 720 COPYMEM(&lockt->lt_clientid, 8);
06553991 721 lockt->lt_owner.len = be32_to_cpup(p++);
1da177e4
LT
722 READ_BUF(lockt->lt_owner.len);
723 READMEM(lockt->lt_owner.data, lockt->lt_owner.len);
724
725 DECODE_TAIL;
726}
727
b37ad28b 728static __be32
1da177e4
LT
729nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
730{
731 DECODE_HEAD;
732
e31a1b66 733 READ_BUF(8);
06553991 734 locku->lu_type = be32_to_cpup(p++);
1da177e4
LT
735 if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT))
736 goto xdr_error;
06553991 737 locku->lu_seqid = be32_to_cpup(p++);
e31a1b66
BH
738 status = nfsd4_decode_stateid(argp, &locku->lu_stateid);
739 if (status)
740 return status;
741 READ_BUF(16);
542d1ab3
BF
742 p = xdr_decode_hyper(p, &locku->lu_offset);
743 p = xdr_decode_hyper(p, &locku->lu_length);
1da177e4
LT
744
745 DECODE_TAIL;
746}
747
b37ad28b 748static __be32
1da177e4
LT
749nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup)
750{
751 DECODE_HEAD;
752
753 READ_BUF(4);
06553991 754 lookup->lo_len = be32_to_cpup(p++);
1da177e4
LT
755 READ_BUF(lookup->lo_len);
756 SAVEMEM(lookup->lo_name, lookup->lo_len);
a36b1725 757 if ((status = check_filename(lookup->lo_name, lookup->lo_len)))
1da177e4
LT
758 return status;
759
760 DECODE_TAIL;
761}
762
2c8bd7e0 763static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *share_access, u32 *deleg_want, u32 *deleg_when)
04f9e664
BF
764{
765 __be32 *p;
766 u32 w;
767
768 READ_BUF(4);
06553991 769 w = be32_to_cpup(p++);
2c8bd7e0
BH
770 *share_access = w & NFS4_SHARE_ACCESS_MASK;
771 *deleg_want = w & NFS4_SHARE_WANT_MASK;
772 if (deleg_when)
773 *deleg_when = w & NFS4_SHARE_WHEN_MASK;
774
04f9e664
BF
775 switch (w & NFS4_SHARE_ACCESS_MASK) {
776 case NFS4_SHARE_ACCESS_READ:
777 case NFS4_SHARE_ACCESS_WRITE:
778 case NFS4_SHARE_ACCESS_BOTH:
779 break;
780 default:
781 return nfserr_bad_xdr;
782 }
fc0d14fe 783 w &= ~NFS4_SHARE_ACCESS_MASK;
04f9e664
BF
784 if (!w)
785 return nfs_ok;
786 if (!argp->minorversion)
787 return nfserr_bad_xdr;
788 switch (w & NFS4_SHARE_WANT_MASK) {
789 case NFS4_SHARE_WANT_NO_PREFERENCE:
790 case NFS4_SHARE_WANT_READ_DELEG:
791 case NFS4_SHARE_WANT_WRITE_DELEG:
792 case NFS4_SHARE_WANT_ANY_DELEG:
793 case NFS4_SHARE_WANT_NO_DELEG:
794 case NFS4_SHARE_WANT_CANCEL:
795 break;
796 default:
797 return nfserr_bad_xdr;
798 }
92bac8c5 799 w &= ~NFS4_SHARE_WANT_MASK;
04f9e664
BF
800 if (!w)
801 return nfs_ok;
2c8bd7e0
BH
802
803 if (!deleg_when) /* open_downgrade */
804 return nfserr_inval;
04f9e664
BF
805 switch (w) {
806 case NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL:
807 case NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED:
c668fc6d
BH
808 case (NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL |
809 NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED):
04f9e664
BF
810 return nfs_ok;
811 }
812xdr_error:
813 return nfserr_bad_xdr;
814}
815
816static __be32 nfsd4_decode_share_deny(struct nfsd4_compoundargs *argp, u32 *x)
817{
818 __be32 *p;
819
820 READ_BUF(4);
06553991 821 *x = be32_to_cpup(p++);
04f9e664 822 /* Note: unlinke access bits, deny bits may be zero. */
01cd4afa 823 if (*x & ~NFS4_SHARE_DENY_BOTH)
04f9e664
BF
824 return nfserr_bad_xdr;
825 return nfs_ok;
826xdr_error:
827 return nfserr_bad_xdr;
828}
829
a084daf5
BF
830static __be32 nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o)
831{
832 __be32 *p;
833
834 READ_BUF(4);
06553991 835 o->len = be32_to_cpup(p++);
a084daf5
BF
836
837 if (o->len == 0 || o->len > NFS4_OPAQUE_LIMIT)
838 return nfserr_bad_xdr;
839
840 READ_BUF(o->len);
841 SAVEMEM(o->data, o->len);
842 return nfs_ok;
843xdr_error:
844 return nfserr_bad_xdr;
845}
846
b37ad28b 847static __be32
1da177e4
LT
848nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
849{
850 DECODE_HEAD;
2c8bd7e0 851 u32 dummy;
1da177e4
LT
852
853 memset(open->op_bmval, 0, sizeof(open->op_bmval));
854 open->op_iattr.ia_valid = 0;
fe0750e5 855 open->op_openowner = NULL;
1da177e4 856
9d313b17 857 open->op_xdr_error = 0;
1da177e4 858 /* seqid, share_access, share_deny, clientid, ownerlen */
04f9e664 859 READ_BUF(4);
06553991 860 open->op_seqid = be32_to_cpup(p++);
2c8bd7e0
BH
861 /* decode, yet ignore deleg_when until supported */
862 status = nfsd4_decode_share_access(argp, &open->op_share_access,
863 &open->op_deleg_want, &dummy);
04f9e664
BF
864 if (status)
865 goto xdr_error;
866 status = nfsd4_decode_share_deny(argp, &open->op_share_deny);
867 if (status)
868 goto xdr_error;
a084daf5 869 READ_BUF(sizeof(clientid_t));
1da177e4 870 COPYMEM(&open->op_clientid, sizeof(clientid_t));
a084daf5
BF
871 status = nfsd4_decode_opaque(argp, &open->op_owner);
872 if (status)
873 goto xdr_error;
874 READ_BUF(4);
06553991 875 open->op_create = be32_to_cpup(p++);
1da177e4
LT
876 switch (open->op_create) {
877 case NFS4_OPEN_NOCREATE:
878 break;
879 case NFS4_OPEN_CREATE:
880 READ_BUF(4);
06553991 881 open->op_createmode = be32_to_cpup(p++);
1da177e4
LT
882 switch (open->op_createmode) {
883 case NFS4_CREATE_UNCHECKED:
884 case NFS4_CREATE_GUARDED:
c0d6fc8a 885 status = nfsd4_decode_fattr(argp, open->op_bmval,
18032ca0 886 &open->op_iattr, &open->op_acl, &open->op_label);
c0d6fc8a 887 if (status)
1da177e4
LT
888 goto out;
889 break;
890 case NFS4_CREATE_EXCLUSIVE:
ab4684d1
CL
891 READ_BUF(NFS4_VERIFIER_SIZE);
892 COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE);
1da177e4 893 break;
79fb54ab
BH
894 case NFS4_CREATE_EXCLUSIVE4_1:
895 if (argp->minorversion < 1)
896 goto xdr_error;
ab4684d1
CL
897 READ_BUF(NFS4_VERIFIER_SIZE);
898 COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE);
79fb54ab 899 status = nfsd4_decode_fattr(argp, open->op_bmval,
18032ca0 900 &open->op_iattr, &open->op_acl, &open->op_label);
79fb54ab
BH
901 if (status)
902 goto out;
903 break;
1da177e4
LT
904 default:
905 goto xdr_error;
906 }
907 break;
908 default:
909 goto xdr_error;
910 }
911
912 /* open_claim */
913 READ_BUF(4);
06553991 914 open->op_claim_type = be32_to_cpup(p++);
1da177e4
LT
915 switch (open->op_claim_type) {
916 case NFS4_OPEN_CLAIM_NULL:
917 case NFS4_OPEN_CLAIM_DELEGATE_PREV:
918 READ_BUF(4);
06553991 919 open->op_fname.len = be32_to_cpup(p++);
1da177e4
LT
920 READ_BUF(open->op_fname.len);
921 SAVEMEM(open->op_fname.data, open->op_fname.len);
a36b1725 922 if ((status = check_filename(open->op_fname.data, open->op_fname.len)))
1da177e4
LT
923 return status;
924 break;
925 case NFS4_OPEN_CLAIM_PREVIOUS:
926 READ_BUF(4);
06553991 927 open->op_delegate_type = be32_to_cpup(p++);
1da177e4
LT
928 break;
929 case NFS4_OPEN_CLAIM_DELEGATE_CUR:
e31a1b66
BH
930 status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid);
931 if (status)
932 return status;
933 READ_BUF(4);
06553991 934 open->op_fname.len = be32_to_cpup(p++);
1da177e4
LT
935 READ_BUF(open->op_fname.len);
936 SAVEMEM(open->op_fname.data, open->op_fname.len);
a36b1725 937 if ((status = check_filename(open->op_fname.data, open->op_fname.len)))
1da177e4
LT
938 return status;
939 break;
8b289b2c
BF
940 case NFS4_OPEN_CLAIM_FH:
941 case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
942 if (argp->minorversion < 1)
943 goto xdr_error;
944 /* void */
945 break;
946 case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
947 if (argp->minorversion < 1)
948 goto xdr_error;
949 status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid);
950 if (status)
951 return status;
952 break;
1da177e4
LT
953 default:
954 goto xdr_error;
955 }
956
957 DECODE_TAIL;
958}
959
b37ad28b 960static __be32
1da177e4
LT
961nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf)
962{
963 DECODE_HEAD;
e1a90ebd
AS
964
965 if (argp->minorversion >= 1)
966 return nfserr_notsupp;
967
e31a1b66
BH
968 status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid);
969 if (status)
970 return status;
971 READ_BUF(4);
06553991 972 open_conf->oc_seqid = be32_to_cpup(p++);
e1a90ebd 973
1da177e4
LT
974 DECODE_TAIL;
975}
976
b37ad28b 977static __be32
1da177e4
LT
978nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down)
979{
980 DECODE_HEAD;
981
e31a1b66
BH
982 status = nfsd4_decode_stateid(argp, &open_down->od_stateid);
983 if (status)
984 return status;
04f9e664 985 READ_BUF(4);
06553991 986 open_down->od_seqid = be32_to_cpup(p++);
2c8bd7e0
BH
987 status = nfsd4_decode_share_access(argp, &open_down->od_share_access,
988 &open_down->od_deleg_want, NULL);
04f9e664
BF
989 if (status)
990 return status;
991 status = nfsd4_decode_share_deny(argp, &open_down->od_share_deny);
992 if (status)
993 return status;
1da177e4
LT
994 DECODE_TAIL;
995}
996
b37ad28b 997static __be32
1da177e4
LT
998nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
999{
1000 DECODE_HEAD;
1001
1002 READ_BUF(4);
06553991 1003 putfh->pf_fhlen = be32_to_cpup(p++);
1da177e4
LT
1004 if (putfh->pf_fhlen > NFS4_FHSIZE)
1005 goto xdr_error;
1006 READ_BUF(putfh->pf_fhlen);
1007 SAVEMEM(putfh->pf_fhval, putfh->pf_fhlen);
1008
1009 DECODE_TAIL;
1010}
1011
e1a90ebd
AS
1012static __be32
1013nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, void *p)
1014{
1015 if (argp->minorversion == 0)
1016 return nfs_ok;
1017 return nfserr_notsupp;
1018}
1019
b37ad28b 1020static __be32
1da177e4
LT
1021nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
1022{
1023 DECODE_HEAD;
1024
e31a1b66
BH
1025 status = nfsd4_decode_stateid(argp, &read->rd_stateid);
1026 if (status)
1027 return status;
1028 READ_BUF(12);
542d1ab3 1029 p = xdr_decode_hyper(p, &read->rd_offset);
06553991 1030 read->rd_length = be32_to_cpup(p++);
1da177e4
LT
1031
1032 DECODE_TAIL;
1033}
1034
b37ad28b 1035static __be32
1da177e4
LT
1036nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir)
1037{
1038 DECODE_HEAD;
1039
1040 READ_BUF(24);
542d1ab3 1041 p = xdr_decode_hyper(p, &readdir->rd_cookie);
1da177e4 1042 COPYMEM(readdir->rd_verf.data, sizeof(readdir->rd_verf.data));
06553991
BF
1043 readdir->rd_dircount = be32_to_cpup(p++);
1044 readdir->rd_maxcount = be32_to_cpup(p++);
1da177e4
LT
1045 if ((status = nfsd4_decode_bitmap(argp, readdir->rd_bmval)))
1046 goto out;
1047
1048 DECODE_TAIL;
1049}
1050
b37ad28b 1051static __be32
1da177e4
LT
1052nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove)
1053{
1054 DECODE_HEAD;
1055
1056 READ_BUF(4);
06553991 1057 remove->rm_namelen = be32_to_cpup(p++);
1da177e4
LT
1058 READ_BUF(remove->rm_namelen);
1059 SAVEMEM(remove->rm_name, remove->rm_namelen);
a36b1725 1060 if ((status = check_filename(remove->rm_name, remove->rm_namelen)))
1da177e4
LT
1061 return status;
1062
1063 DECODE_TAIL;
1064}
1065
b37ad28b 1066static __be32
1da177e4
LT
1067nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename)
1068{
1069 DECODE_HEAD;
1070
1071 READ_BUF(4);
06553991 1072 rename->rn_snamelen = be32_to_cpup(p++);
1da177e4
LT
1073 READ_BUF(rename->rn_snamelen + 4);
1074 SAVEMEM(rename->rn_sname, rename->rn_snamelen);
06553991 1075 rename->rn_tnamelen = be32_to_cpup(p++);
1da177e4
LT
1076 READ_BUF(rename->rn_tnamelen);
1077 SAVEMEM(rename->rn_tname, rename->rn_tnamelen);
a36b1725 1078 if ((status = check_filename(rename->rn_sname, rename->rn_snamelen)))
1da177e4 1079 return status;
a36b1725 1080 if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen)))
1da177e4
LT
1081 return status;
1082
1083 DECODE_TAIL;
1084}
1085
b37ad28b 1086static __be32
1da177e4
LT
1087nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
1088{
1089 DECODE_HEAD;
1090
e1a90ebd
AS
1091 if (argp->minorversion >= 1)
1092 return nfserr_notsupp;
1093
1da177e4
LT
1094 READ_BUF(sizeof(clientid_t));
1095 COPYMEM(clientid, sizeof(clientid_t));
1096
1097 DECODE_TAIL;
1098}
1099
dcb488a3
AA
1100static __be32
1101nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
1102 struct nfsd4_secinfo *secinfo)
1103{
1104 DECODE_HEAD;
1105
1106 READ_BUF(4);
06553991 1107 secinfo->si_namelen = be32_to_cpup(p++);
dcb488a3
AA
1108 READ_BUF(secinfo->si_namelen);
1109 SAVEMEM(secinfo->si_name, secinfo->si_namelen);
a36b1725 1110 status = check_filename(secinfo->si_name, secinfo->si_namelen);
dcb488a3
AA
1111 if (status)
1112 return status;
1113 DECODE_TAIL;
1114}
1115
04f4ad16
BF
1116static __be32
1117nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp,
1118 struct nfsd4_secinfo_no_name *sin)
1119{
1120 DECODE_HEAD;
1121
1122 READ_BUF(4);
06553991 1123 sin->sin_style = be32_to_cpup(p++);
04f4ad16
BF
1124 DECODE_TAIL;
1125}
1126
b37ad28b 1127static __be32
1da177e4
LT
1128nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
1129{
e31a1b66 1130 __be32 status;
1da177e4 1131
e31a1b66
BH
1132 status = nfsd4_decode_stateid(argp, &setattr->sa_stateid);
1133 if (status)
1134 return status;
3c8e0316 1135 return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr,
18032ca0 1136 &setattr->sa_acl, &setattr->sa_label);
1da177e4
LT
1137}
1138
b37ad28b 1139static __be32
1da177e4
LT
1140nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid)
1141{
1142 DECODE_HEAD;
1143
e1a90ebd
AS
1144 if (argp->minorversion >= 1)
1145 return nfserr_notsupp;
1146
ab4684d1
CL
1147 READ_BUF(NFS4_VERIFIER_SIZE);
1148 COPYMEM(setclientid->se_verf.data, NFS4_VERIFIER_SIZE);
1da177e4 1149
a084daf5
BF
1150 status = nfsd4_decode_opaque(argp, &setclientid->se_name);
1151 if (status)
1152 return nfserr_bad_xdr;
1153 READ_BUF(8);
06553991
BF
1154 setclientid->se_callback_prog = be32_to_cpup(p++);
1155 setclientid->se_callback_netid_len = be32_to_cpup(p++);
1da177e4
LT
1156
1157 READ_BUF(setclientid->se_callback_netid_len + 4);
1158 SAVEMEM(setclientid->se_callback_netid_val, setclientid->se_callback_netid_len);
06553991 1159 setclientid->se_callback_addr_len = be32_to_cpup(p++);
1da177e4
LT
1160
1161 READ_BUF(setclientid->se_callback_addr_len + 4);
1162 SAVEMEM(setclientid->se_callback_addr_val, setclientid->se_callback_addr_len);
06553991 1163 setclientid->se_callback_ident = be32_to_cpup(p++);
1da177e4
LT
1164
1165 DECODE_TAIL;
1166}
1167
b37ad28b 1168static __be32
1da177e4
LT
1169nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c)
1170{
1171 DECODE_HEAD;
1172
e1a90ebd
AS
1173 if (argp->minorversion >= 1)
1174 return nfserr_notsupp;
1175
ab4684d1 1176 READ_BUF(8 + NFS4_VERIFIER_SIZE);
1da177e4 1177 COPYMEM(&scd_c->sc_clientid, 8);
ab4684d1 1178 COPYMEM(&scd_c->sc_confirm, NFS4_VERIFIER_SIZE);
1da177e4
LT
1179
1180 DECODE_TAIL;
1181}
1182
1183/* Also used for NVERIFY */
b37ad28b 1184static __be32
1da177e4
LT
1185nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify)
1186{
1da177e4
LT
1187 DECODE_HEAD;
1188
1189 if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval)))
1190 goto out;
1191
1192 /* For convenience's sake, we compare raw xdr'd attributes in
e5f95703
BF
1193 * nfsd4_proc_verify */
1194
1da177e4 1195 READ_BUF(4);
06553991 1196 verify->ve_attrlen = be32_to_cpup(p++);
1da177e4
LT
1197 READ_BUF(verify->ve_attrlen);
1198 SAVEMEM(verify->ve_attrval, verify->ve_attrlen);
1199
1200 DECODE_TAIL;
1201}
1202
b37ad28b 1203static __be32
1da177e4
LT
1204nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
1205{
1206 int avail;
1da177e4
LT
1207 int len;
1208 DECODE_HEAD;
1209
e31a1b66
BH
1210 status = nfsd4_decode_stateid(argp, &write->wr_stateid);
1211 if (status)
1212 return status;
1213 READ_BUF(16);
542d1ab3 1214 p = xdr_decode_hyper(p, &write->wr_offset);
06553991 1215 write->wr_stable_how = be32_to_cpup(p++);
1da177e4
LT
1216 if (write->wr_stable_how > 2)
1217 goto xdr_error;
06553991 1218 write->wr_buflen = be32_to_cpup(p++);
1da177e4
LT
1219
1220 /* Sorry .. no magic macros for this.. *
1221 * READ_BUF(write->wr_buflen);
1222 * SAVEMEM(write->wr_buf, write->wr_buflen);
1223 */
1224 avail = (char*)argp->end - (char*)argp->p;
1225 if (avail + argp->pagelen < write->wr_buflen) {
817cb9d4
CL
1226 dprintk("NFSD: xdr error (%s:%d)\n",
1227 __FILE__, __LINE__);
1da177e4
LT
1228 goto xdr_error;
1229 }
70cc7f75
BF
1230 write->wr_head.iov_base = p;
1231 write->wr_head.iov_len = avail;
70cc7f75 1232 write->wr_pagelist = argp->pagelist;
5a80a54d
BF
1233
1234 len = XDR_QUADLEN(write->wr_buflen) << 2;
1235 if (len >= avail) {
1236 int pages;
1237
1238 len -= avail;
1239
1240 pages = len >> PAGE_SHIFT;
1241 argp->pagelist += pages;
1242 argp->pagelen -= pages * PAGE_SIZE;
1243 len -= pages * PAGE_SIZE;
1244
1245 argp->p = (__be32 *)page_address(argp->pagelist[0]);
365da4ad 1246 argp->pagelist++;
5a80a54d 1247 argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE);
1da177e4 1248 }
5a80a54d 1249 argp->p += XDR_QUADLEN(len);
1da177e4
LT
1250
1251 DECODE_TAIL;
1252}
1253
b37ad28b 1254static __be32
1da177e4
LT
1255nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner)
1256{
1257 DECODE_HEAD;
1258
e1a90ebd
AS
1259 if (argp->minorversion >= 1)
1260 return nfserr_notsupp;
1261
1da177e4
LT
1262 READ_BUF(12);
1263 COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t));
06553991 1264 rlockowner->rl_owner.len = be32_to_cpup(p++);
1da177e4
LT
1265 READ_BUF(rlockowner->rl_owner.len);
1266 READMEM(rlockowner->rl_owner.data, rlockowner->rl_owner.len);
1267
60adfc50
AA
1268 if (argp->minorversion && !zero_clientid(&rlockowner->rl_clientid))
1269 return nfserr_inval;
1da177e4
LT
1270 DECODE_TAIL;
1271}
1272
2db134eb
AA
1273static __be32
1274nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
0733d213 1275 struct nfsd4_exchange_id *exid)
2db134eb 1276{
5afa040b 1277 int dummy, tmp;
0733d213
AA
1278 DECODE_HEAD;
1279
1280 READ_BUF(NFS4_VERIFIER_SIZE);
1281 COPYMEM(exid->verifier.data, NFS4_VERIFIER_SIZE);
1282
a084daf5
BF
1283 status = nfsd4_decode_opaque(argp, &exid->clname);
1284 if (status)
1285 return nfserr_bad_xdr;
0733d213
AA
1286
1287 READ_BUF(4);
06553991 1288 exid->flags = be32_to_cpup(p++);
0733d213
AA
1289
1290 /* Ignore state_protect4_a */
1291 READ_BUF(4);
06553991 1292 exid->spa_how = be32_to_cpup(p++);
0733d213
AA
1293 switch (exid->spa_how) {
1294 case SP4_NONE:
1295 break;
1296 case SP4_MACH_CRED:
1297 /* spo_must_enforce */
1298 READ_BUF(4);
06553991 1299 dummy = be32_to_cpup(p++);
0733d213
AA
1300 READ_BUF(dummy * 4);
1301 p += dummy;
1302
1303 /* spo_must_allow */
1304 READ_BUF(4);
06553991 1305 dummy = be32_to_cpup(p++);
0733d213
AA
1306 READ_BUF(dummy * 4);
1307 p += dummy;
1308 break;
1309 case SP4_SSV:
1310 /* ssp_ops */
1311 READ_BUF(4);
06553991 1312 dummy = be32_to_cpup(p++);
0733d213
AA
1313 READ_BUF(dummy * 4);
1314 p += dummy;
1315
1316 READ_BUF(4);
06553991 1317 dummy = be32_to_cpup(p++);
0733d213
AA
1318 READ_BUF(dummy * 4);
1319 p += dummy;
1320
1321 /* ssp_hash_algs<> */
1322 READ_BUF(4);
06553991 1323 tmp = be32_to_cpup(p++);
5afa040b
MJ
1324 while (tmp--) {
1325 READ_BUF(4);
06553991 1326 dummy = be32_to_cpup(p++);
5afa040b
MJ
1327 READ_BUF(dummy);
1328 p += XDR_QUADLEN(dummy);
1329 }
0733d213
AA
1330
1331 /* ssp_encr_algs<> */
1332 READ_BUF(4);
06553991 1333 tmp = be32_to_cpup(p++);
5afa040b
MJ
1334 while (tmp--) {
1335 READ_BUF(4);
06553991 1336 dummy = be32_to_cpup(p++);
5afa040b
MJ
1337 READ_BUF(dummy);
1338 p += XDR_QUADLEN(dummy);
1339 }
0733d213
AA
1340
1341 /* ssp_window and ssp_num_gss_handles */
1342 READ_BUF(8);
06553991
BF
1343 dummy = be32_to_cpup(p++);
1344 dummy = be32_to_cpup(p++);
0733d213
AA
1345 break;
1346 default:
1347 goto xdr_error;
1348 }
1349
1350 /* Ignore Implementation ID */
1351 READ_BUF(4); /* nfs_impl_id4 array length */
06553991 1352 dummy = be32_to_cpup(p++);
0733d213
AA
1353
1354 if (dummy > 1)
1355 goto xdr_error;
1356
1357 if (dummy == 1) {
1358 /* nii_domain */
1359 READ_BUF(4);
06553991 1360 dummy = be32_to_cpup(p++);
0733d213
AA
1361 READ_BUF(dummy);
1362 p += XDR_QUADLEN(dummy);
1363
1364 /* nii_name */
1365 READ_BUF(4);
06553991 1366 dummy = be32_to_cpup(p++);
0733d213
AA
1367 READ_BUF(dummy);
1368 p += XDR_QUADLEN(dummy);
1369
1370 /* nii_date */
1371 READ_BUF(12);
1372 p += 3;
1373 }
1374 DECODE_TAIL;
2db134eb
AA
1375}
1376
1377static __be32
1378nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
1379 struct nfsd4_create_session *sess)
1380{
ec6b5d7b 1381 DECODE_HEAD;
ec6b5d7b 1382 u32 dummy;
ec6b5d7b
AA
1383
1384 READ_BUF(16);
1385 COPYMEM(&sess->clientid, 8);
06553991
BF
1386 sess->seqid = be32_to_cpup(p++);
1387 sess->flags = be32_to_cpup(p++);
ec6b5d7b
AA
1388
1389 /* Fore channel attrs */
1390 READ_BUF(28);
06553991
BF
1391 dummy = be32_to_cpup(p++); /* headerpadsz is always 0 */
1392 sess->fore_channel.maxreq_sz = be32_to_cpup(p++);
1393 sess->fore_channel.maxresp_sz = be32_to_cpup(p++);
1394 sess->fore_channel.maxresp_cached = be32_to_cpup(p++);
1395 sess->fore_channel.maxops = be32_to_cpup(p++);
1396 sess->fore_channel.maxreqs = be32_to_cpup(p++);
1397 sess->fore_channel.nr_rdma_attrs = be32_to_cpup(p++);
ec6b5d7b
AA
1398 if (sess->fore_channel.nr_rdma_attrs == 1) {
1399 READ_BUF(4);
06553991 1400 sess->fore_channel.rdma_attrs = be32_to_cpup(p++);
ec6b5d7b
AA
1401 } else if (sess->fore_channel.nr_rdma_attrs > 1) {
1402 dprintk("Too many fore channel attr bitmaps!\n");
1403 goto xdr_error;
1404 }
1405
1406 /* Back channel attrs */
1407 READ_BUF(28);
06553991
BF
1408 dummy = be32_to_cpup(p++); /* headerpadsz is always 0 */
1409 sess->back_channel.maxreq_sz = be32_to_cpup(p++);
1410 sess->back_channel.maxresp_sz = be32_to_cpup(p++);
1411 sess->back_channel.maxresp_cached = be32_to_cpup(p++);
1412 sess->back_channel.maxops = be32_to_cpup(p++);
1413 sess->back_channel.maxreqs = be32_to_cpup(p++);
1414 sess->back_channel.nr_rdma_attrs = be32_to_cpup(p++);
ec6b5d7b
AA
1415 if (sess->back_channel.nr_rdma_attrs == 1) {
1416 READ_BUF(4);
06553991 1417 sess->back_channel.rdma_attrs = be32_to_cpup(p++);
ec6b5d7b
AA
1418 } else if (sess->back_channel.nr_rdma_attrs > 1) {
1419 dprintk("Too many back channel attr bitmaps!\n");
1420 goto xdr_error;
1421 }
1422
acb2887e 1423 READ_BUF(4);
06553991 1424 sess->callback_prog = be32_to_cpup(p++);
acb2887e 1425 nfsd4_decode_cb_sec(argp, &sess->cb_sec);
ec6b5d7b 1426 DECODE_TAIL;
2db134eb
AA
1427}
1428
1429static __be32
1430nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp,
1431 struct nfsd4_destroy_session *destroy_session)
1432{
e10e0cfc
BH
1433 DECODE_HEAD;
1434 READ_BUF(NFS4_MAX_SESSIONID_LEN);
1435 COPYMEM(destroy_session->sessionid.data, NFS4_MAX_SESSIONID_LEN);
1436
1437 DECODE_TAIL;
2db134eb
AA
1438}
1439
e1ca12df
BS
1440static __be32
1441nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp,
1442 struct nfsd4_free_stateid *free_stateid)
1443{
1444 DECODE_HEAD;
1445
1446 READ_BUF(sizeof(stateid_t));
06553991 1447 free_stateid->fr_stateid.si_generation = be32_to_cpup(p++);
e1ca12df
BS
1448 COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t));
1449
1450 DECODE_TAIL;
1451}
1452
2db134eb
AA
1453static __be32
1454nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
1455 struct nfsd4_sequence *seq)
1456{
b85d4c01
BH
1457 DECODE_HEAD;
1458
1459 READ_BUF(NFS4_MAX_SESSIONID_LEN + 16);
1460 COPYMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN);
06553991
BF
1461 seq->seqid = be32_to_cpup(p++);
1462 seq->slotid = be32_to_cpup(p++);
1463 seq->maxslots = be32_to_cpup(p++);
1464 seq->cachethis = be32_to_cpup(p++);
b85d4c01
BH
1465
1466 DECODE_TAIL;
2db134eb
AA
1467}
1468
17456804
BS
1469static __be32
1470nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid)
1471{
17456804 1472 int i;
03cfb420
BS
1473 __be32 *p, status;
1474 struct nfsd4_test_stateid_id *stateid;
17456804
BS
1475
1476 READ_BUF(4);
1477 test_stateid->ts_num_ids = ntohl(*p++);
1478
03cfb420 1479 INIT_LIST_HEAD(&test_stateid->ts_stateid_list);
17456804
BS
1480
1481 for (i = 0; i < test_stateid->ts_num_ids; i++) {
d5e23383 1482 stateid = svcxdr_tmpalloc(argp, sizeof(*stateid));
03cfb420 1483 if (!stateid) {
afcf6792 1484 status = nfserrno(-ENOMEM);
03cfb420
BS
1485 goto out;
1486 }
1487
03cfb420
BS
1488 INIT_LIST_HEAD(&stateid->ts_id_list);
1489 list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list);
1490
1491 status = nfsd4_decode_stateid(argp, &stateid->ts_id_stateid);
17456804 1492 if (status)
03cfb420 1493 goto out;
17456804
BS
1494 }
1495
1496 status = 0;
1497out:
1498 return status;
1499xdr_error:
1500 dprintk("NFSD: xdr error (%s:%d)\n", __FILE__, __LINE__);
1501 status = nfserr_bad_xdr;
1502 goto out;
1503}
1504
345c2842
MJ
1505static __be32 nfsd4_decode_destroy_clientid(struct nfsd4_compoundargs *argp, struct nfsd4_destroy_clientid *dc)
1506{
1507 DECODE_HEAD;
1508
1509 READ_BUF(8);
1510 COPYMEM(&dc->clientid, 8);
1511
1512 DECODE_TAIL;
1513}
1514
4dc6ec00
BF
1515static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, struct nfsd4_reclaim_complete *rc)
1516{
1517 DECODE_HEAD;
1518
1519 READ_BUF(4);
06553991 1520 rc->rca_one_fs = be32_to_cpup(p++);
4dc6ec00
BF
1521
1522 DECODE_TAIL;
1523}
1524
95d871f0
AS
1525static __be32
1526nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp,
1527 struct nfsd4_fallocate *fallocate)
1528{
1529 DECODE_HEAD;
1530
1531 status = nfsd4_decode_stateid(argp, &fallocate->falloc_stateid);
1532 if (status)
1533 return status;
1534
1535 READ_BUF(16);
1536 p = xdr_decode_hyper(p, &fallocate->falloc_offset);
1537 xdr_decode_hyper(p, &fallocate->falloc_length);
1538
1539 DECODE_TAIL;
1540}
1541
24bab491
AS
1542static __be32
1543nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek)
1544{
1545 DECODE_HEAD;
1546
1547 status = nfsd4_decode_stateid(argp, &seek->seek_stateid);
1548 if (status)
1549 return status;
1550
1551 READ_BUF(8 + 4);
1552 p = xdr_decode_hyper(p, &seek->seek_offset);
1553 seek->seek_whence = be32_to_cpup(p);
1554
1555 DECODE_TAIL;
1556}
1557
347e0ad9
BH
1558static __be32
1559nfsd4_decode_noop(struct nfsd4_compoundargs *argp, void *p)
1560{
1561 return nfs_ok;
1562}
1563
3c375c6f
BH
1564static __be32
1565nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, void *p)
1566{
1e685ec2 1567 return nfserr_notsupp;
3c375c6f
BH
1568}
1569
347e0ad9
BH
1570typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, void *);
1571
1572static nfsd4_dec nfsd4_dec_ops[] = {
ad1060c8
BF
1573 [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access,
1574 [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close,
1575 [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit,
1576 [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create,
1577 [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp,
1578 [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn,
1579 [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr,
1580 [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop,
1581 [OP_LINK] = (nfsd4_dec)nfsd4_decode_link,
1582 [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock,
1583 [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt,
1584 [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku,
1585 [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup,
1586 [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop,
1587 [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify,
1588 [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open,
1589 [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp,
1590 [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm,
1591 [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade,
1592 [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh,
e1a90ebd 1593 [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_putpubfh,
ad1060c8
BF
1594 [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop,
1595 [OP_READ] = (nfsd4_dec)nfsd4_decode_read,
1596 [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir,
1597 [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop,
1598 [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove,
1599 [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename,
1600 [OP_RENEW] = (nfsd4_dec)nfsd4_decode_renew,
1601 [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop,
1602 [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop,
1603 [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo,
1604 [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr,
1605 [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_setclientid,
1606 [OP_SETCLIENTID_CONFIRM] = (nfsd4_dec)nfsd4_decode_setclientid_confirm,
1607 [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify,
1608 [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write,
1609 [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner,
2db134eb
AA
1610
1611 /* new operations for NFSv4.1 */
cb73a9f4 1612 [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_backchannel_ctl,
1d1bc8f2 1613 [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session,
9064caae
RD
1614 [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id,
1615 [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session,
1616 [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session,
e1ca12df 1617 [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_free_stateid,
9064caae
RD
1618 [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp,
1619 [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp,
1620 [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp,
1621 [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp,
1622 [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp,
1623 [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp,
04f4ad16 1624 [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name,
9064caae
RD
1625 [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence,
1626 [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp,
17456804 1627 [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_test_stateid,
9064caae 1628 [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp,
345c2842 1629 [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_destroy_clientid,
4dc6ec00 1630 [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete,
87a15a80
AS
1631
1632 /* new operations for NFSv4.2 */
95d871f0 1633 [OP_ALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate,
87a15a80
AS
1634 [OP_COPY] = (nfsd4_dec)nfsd4_decode_notsupp,
1635 [OP_COPY_NOTIFY] = (nfsd4_dec)nfsd4_decode_notsupp,
b0cb9085 1636 [OP_DEALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate,
87a15a80
AS
1637 [OP_IO_ADVISE] = (nfsd4_dec)nfsd4_decode_notsupp,
1638 [OP_LAYOUTERROR] = (nfsd4_dec)nfsd4_decode_notsupp,
1639 [OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp,
1640 [OP_OFFLOAD_CANCEL] = (nfsd4_dec)nfsd4_decode_notsupp,
1641 [OP_OFFLOAD_STATUS] = (nfsd4_dec)nfsd4_decode_notsupp,
1642 [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_notsupp,
24bab491 1643 [OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek,
87a15a80 1644 [OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp,
2db134eb
AA
1645};
1646
e1a90ebd
AS
1647static inline bool
1648nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op)
1649{
8217d146 1650 if (op->opnum < FIRST_NFS4_OP)
e1a90ebd 1651 return false;
8217d146 1652 else if (argp->minorversion == 0 && op->opnum > LAST_NFS40_OP)
e1a90ebd 1653 return false;
8217d146
AS
1654 else if (argp->minorversion == 1 && op->opnum > LAST_NFS41_OP)
1655 return false;
1656 else if (argp->minorversion == 2 && op->opnum > LAST_NFS42_OP)
e1a90ebd
AS
1657 return false;
1658 return true;
1659}
f2feb96b 1660
b37ad28b 1661static __be32
1da177e4
LT
1662nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1663{
1664 DECODE_HEAD;
1665 struct nfsd4_op *op;
1091006c 1666 bool cachethis = false;
a5cddc88
BF
1667 int auth_slack= argp->rqstp->rq_auth_slack;
1668 int max_reply = auth_slack + 8; /* opcnt, status */
b0e35fda
BF
1669 int readcount = 0;
1670 int readbytes = 0;
1da177e4
LT
1671 int i;
1672
1da177e4 1673 READ_BUF(4);
06553991 1674 argp->taglen = be32_to_cpup(p++);
1da177e4
LT
1675 READ_BUF(argp->taglen + 8);
1676 SAVEMEM(argp->tag, argp->taglen);
06553991
BF
1677 argp->minorversion = be32_to_cpup(p++);
1678 argp->opcnt = be32_to_cpup(p++);
4f0cefbf 1679 max_reply += 4 + (XDR_QUADLEN(argp->taglen) << 2);
1da177e4
LT
1680
1681 if (argp->taglen > NFSD4_MAX_TAGLEN)
1682 goto xdr_error;
1683 if (argp->opcnt > 100)
1684 goto xdr_error;
1685
e8c96f8c 1686 if (argp->opcnt > ARRAY_SIZE(argp->iops)) {
5d6031ca 1687 argp->ops = kzalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL);
1da177e4
LT
1688 if (!argp->ops) {
1689 argp->ops = argp->iops;
817cb9d4 1690 dprintk("nfsd: couldn't allocate room for COMPOUND\n");
1da177e4
LT
1691 goto xdr_error;
1692 }
1693 }
1694
e1a90ebd 1695 if (argp->minorversion > NFSD_SUPPORTED_MINOR_VERSION)
30cff1ff
BH
1696 argp->opcnt = 0;
1697
1da177e4
LT
1698 for (i = 0; i < argp->opcnt; i++) {
1699 op = &argp->ops[i];
1700 op->replay = NULL;
1701
8a61b18c 1702 READ_BUF(4);
06553991 1703 op->opnum = be32_to_cpup(p++);
1da177e4 1704
e1a90ebd
AS
1705 if (nfsd4_opnum_in_range(argp, op))
1706 op->status = nfsd4_dec_ops[op->opnum](argp, &op->u);
347e0ad9 1707 else {
1da177e4
LT
1708 op->opnum = OP_ILLEGAL;
1709 op->status = nfserr_op_illegal;
1da177e4 1710 }
1091006c
BF
1711 /*
1712 * We'll try to cache the result in the DRC if any one
1713 * op in the compound wants to be cached:
1714 */
1715 cachethis |= nfsd4_cache_this_op(op);
6ff40dec 1716
b0e35fda
BF
1717 if (op->opnum == OP_READ) {
1718 readcount++;
1719 readbytes += nfsd4_max_reply(argp->rqstp, op);
1720 } else
1721 max_reply += nfsd4_max_reply(argp->rqstp, op);
f7b43d0c
BF
1722 /*
1723 * OP_LOCK may return a conflicting lock. (Special case
1724 * because it will just skip encoding this if it runs
1725 * out of xdr buffer space, and it is the only operation
1726 * that behaves this way.)
1727 */
1728 if (op->opnum == OP_LOCK)
1729 max_reply += NFS4_OPAQUE_LIMIT;
e372ba60
BF
1730
1731 if (op->status) {
1732 argp->opcnt = i+1;
1733 break;
1734 }
1da177e4 1735 }
1091006c
BF
1736 /* Sessions make the DRC unnecessary: */
1737 if (argp->minorversion)
1738 cachethis = false;
b0e35fda 1739 svc_reserve(argp->rqstp, max_reply + readbytes);
1091006c 1740 argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
1da177e4 1741
a5cddc88 1742 if (readcount > 1 || max_reply > PAGE_SIZE - auth_slack)
779fb0f3 1743 clear_bit(RQ_SPLICE_OK, &argp->rqstp->rq_flags);
b0e35fda 1744
1da177e4
LT
1745 DECODE_TAIL;
1746}
1da177e4 1747
d05d5744 1748static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode)
c654b8a9
BF
1749{
1750 if (IS_I_VERSION(inode)) {
d05d5744 1751 p = xdr_encode_hyper(p, inode->i_version);
c654b8a9 1752 } else {
d05d5744
BF
1753 *p++ = cpu_to_be32(stat->ctime.tv_sec);
1754 *p++ = cpu_to_be32(stat->ctime.tv_nsec);
c654b8a9 1755 }
d05d5744 1756 return p;
c654b8a9
BF
1757}
1758
d05d5744 1759static __be32 *encode_cinfo(__be32 *p, struct nfsd4_change_info *c)
c654b8a9 1760{
d05d5744 1761 *p++ = cpu_to_be32(c->atomic);
c654b8a9 1762 if (c->change_supported) {
d05d5744
BF
1763 p = xdr_encode_hyper(p, c->before_change);
1764 p = xdr_encode_hyper(p, c->after_change);
c654b8a9 1765 } else {
d05d5744
BF
1766 *p++ = cpu_to_be32(c->before_ctime_sec);
1767 *p++ = cpu_to_be32(c->before_ctime_nsec);
1768 *p++ = cpu_to_be32(c->after_ctime_sec);
1769 *p++ = cpu_to_be32(c->after_ctime_nsec);
c654b8a9 1770 }
d05d5744 1771 return p;
c654b8a9 1772}
1da177e4 1773
81c3f413 1774/* Encode as an array of strings the string given with components
e7a0444a 1775 * separated @sep, escaped with esc_enter and esc_exit.
81c3f413 1776 */
ddd1ea56
BF
1777static __be32 nfsd4_encode_components_esc(struct xdr_stream *xdr, char sep,
1778 char *components, char esc_enter,
1779 char esc_exit)
81c3f413 1780{
ddd1ea56 1781 __be32 *p;
082d4bd7
BF
1782 __be32 pathlen;
1783 int pathlen_offset;
81c3f413 1784 int strlen, count=0;
e7a0444a 1785 char *str, *end, *next;
81c3f413
BF
1786
1787 dprintk("nfsd4_encode_components(%s)\n", components);
082d4bd7
BF
1788
1789 pathlen_offset = xdr->buf->len;
ddd1ea56
BF
1790 p = xdr_reserve_space(xdr, 4);
1791 if (!p)
81c3f413 1792 return nfserr_resource;
082d4bd7
BF
1793 p++; /* We will fill this in with @count later */
1794
81c3f413
BF
1795 end = str = components;
1796 while (*end) {
e7a0444a
WAA
1797 bool found_esc = false;
1798
1799 /* try to parse as esc_start, ..., esc_end, sep */
1800 if (*str == esc_enter) {
1801 for (; *end && (*end != esc_exit); end++)
1802 /* find esc_exit or end of string */;
1803 next = end + 1;
1804 if (*end && (!*next || *next == sep)) {
1805 str++;
1806 found_esc = true;
1807 }
1808 }
1809
1810 if (!found_esc)
1811 for (; *end && (*end != sep); end++)
1812 /* find sep or end of string */;
1813
81c3f413
BF
1814 strlen = end - str;
1815 if (strlen) {
ddd1ea56
BF
1816 p = xdr_reserve_space(xdr, strlen + 4);
1817 if (!p)
81c3f413 1818 return nfserr_resource;
0c0c267b 1819 p = xdr_encode_opaque(p, str, strlen);
81c3f413
BF
1820 count++;
1821 }
1822 else
1823 end++;
5a64e569
BC
1824 if (found_esc)
1825 end = next;
1826
81c3f413
BF
1827 str = end;
1828 }
bf7491f1 1829 pathlen = htonl(count);
082d4bd7 1830 write_bytes_to_xdr_buf(xdr->buf, pathlen_offset, &pathlen, 4);
81c3f413
BF
1831 return 0;
1832}
1833
e7a0444a
WAA
1834/* Encode as an array of strings the string given with components
1835 * separated @sep.
1836 */
ddd1ea56
BF
1837static __be32 nfsd4_encode_components(struct xdr_stream *xdr, char sep,
1838 char *components)
e7a0444a 1839{
ddd1ea56 1840 return nfsd4_encode_components_esc(xdr, sep, components, 0, 0);
e7a0444a
WAA
1841}
1842
81c3f413
BF
1843/*
1844 * encode a location element of a fs_locations structure
1845 */
ddd1ea56
BF
1846static __be32 nfsd4_encode_fs_location4(struct xdr_stream *xdr,
1847 struct nfsd4_fs_location *location)
81c3f413 1848{
b37ad28b 1849 __be32 status;
81c3f413 1850
ddd1ea56 1851 status = nfsd4_encode_components_esc(xdr, ':', location->hosts,
e7a0444a 1852 '[', ']');
81c3f413
BF
1853 if (status)
1854 return status;
ddd1ea56 1855 status = nfsd4_encode_components(xdr, '/', location->path);
81c3f413
BF
1856 if (status)
1857 return status;
81c3f413
BF
1858 return 0;
1859}
1860
1861/*
ed748aac 1862 * Encode a path in RFC3530 'pathname4' format
81c3f413 1863 */
ddd1ea56
BF
1864static __be32 nfsd4_encode_path(struct xdr_stream *xdr,
1865 const struct path *root,
1866 const struct path *path)
81c3f413 1867{
301f0268 1868 struct path cur = *path;
ddd1ea56 1869 __be32 *p;
ed748aac
TM
1870 struct dentry **components = NULL;
1871 unsigned int ncomponents = 0;
1872 __be32 err = nfserr_jukebox;
81c3f413 1873
ed748aac 1874 dprintk("nfsd4_encode_components(");
81c3f413 1875
ed748aac
TM
1876 path_get(&cur);
1877 /* First walk the path up to the nfsd root, and store the
1878 * dentries/path components in an array.
1879 */
1880 for (;;) {
1881 if (cur.dentry == root->dentry && cur.mnt == root->mnt)
1882 break;
1883 if (cur.dentry == cur.mnt->mnt_root) {
1884 if (follow_up(&cur))
1885 continue;
1886 goto out_free;
1887 }
1888 if ((ncomponents & 15) == 0) {
1889 struct dentry **new;
1890 new = krealloc(components,
1891 sizeof(*new) * (ncomponents + 16),
1892 GFP_KERNEL);
1893 if (!new)
1894 goto out_free;
1895 components = new;
1896 }
1897 components[ncomponents++] = cur.dentry;
1898 cur.dentry = dget_parent(cur.dentry);
1899 }
ddd1ea56
BF
1900 err = nfserr_resource;
1901 p = xdr_reserve_space(xdr, 4);
1902 if (!p)
ed748aac 1903 goto out_free;
c373b0a4 1904 *p++ = cpu_to_be32(ncomponents);
ed748aac
TM
1905
1906 while (ncomponents) {
1907 struct dentry *dentry = components[ncomponents - 1];
301f0268 1908 unsigned int len;
ed748aac 1909
301f0268
AV
1910 spin_lock(&dentry->d_lock);
1911 len = dentry->d_name.len;
ddd1ea56
BF
1912 p = xdr_reserve_space(xdr, len + 4);
1913 if (!p) {
301f0268 1914 spin_unlock(&dentry->d_lock);
ed748aac 1915 goto out_free;
301f0268 1916 }
0c0c267b 1917 p = xdr_encode_opaque(p, dentry->d_name.name, len);
a455589f 1918 dprintk("/%pd", dentry);
301f0268 1919 spin_unlock(&dentry->d_lock);
ed748aac
TM
1920 dput(dentry);
1921 ncomponents--;
81c3f413 1922 }
ed748aac 1923
ed748aac
TM
1924 err = 0;
1925out_free:
1926 dprintk(")\n");
1927 while (ncomponents)
1928 dput(components[--ncomponents]);
1929 kfree(components);
1930 path_put(&cur);
1931 return err;
1932}
1933
ddd1ea56
BF
1934static __be32 nfsd4_encode_fsloc_fsroot(struct xdr_stream *xdr,
1935 struct svc_rqst *rqstp, const struct path *path)
ed748aac
TM
1936{
1937 struct svc_export *exp_ps;
1938 __be32 res;
1939
1940 exp_ps = rqst_find_fsidzero_export(rqstp);
1941 if (IS_ERR(exp_ps))
1942 return nfserrno(PTR_ERR(exp_ps));
ddd1ea56 1943 res = nfsd4_encode_path(xdr, &exp_ps->ex_path, path);
ed748aac
TM
1944 exp_put(exp_ps);
1945 return res;
81c3f413
BF
1946}
1947
1948/*
1949 * encode a fs_locations structure
1950 */
ddd1ea56
BF
1951static __be32 nfsd4_encode_fs_locations(struct xdr_stream *xdr,
1952 struct svc_rqst *rqstp, struct svc_export *exp)
81c3f413 1953{
b37ad28b 1954 __be32 status;
cc45f017 1955 int i;
ddd1ea56 1956 __be32 *p;
81c3f413 1957 struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs;
81c3f413 1958
ddd1ea56 1959 status = nfsd4_encode_fsloc_fsroot(xdr, rqstp, &exp->ex_path);
81c3f413
BF
1960 if (status)
1961 return status;
ddd1ea56
BF
1962 p = xdr_reserve_space(xdr, 4);
1963 if (!p)
81c3f413 1964 return nfserr_resource;
c373b0a4 1965 *p++ = cpu_to_be32(fslocs->locations_count);
81c3f413 1966 for (i=0; i<fslocs->locations_count; i++) {
ddd1ea56 1967 status = nfsd4_encode_fs_location4(xdr, &fslocs->locations[i]);
81c3f413
BF
1968 if (status)
1969 return status;
1970 }
81c3f413
BF
1971 return 0;
1972}
1da177e4 1973
3d2544b1
BF
1974static u32 nfs4_file_type(umode_t mode)
1975{
1976 switch (mode & S_IFMT) {
1977 case S_IFIFO: return NF4FIFO;
1978 case S_IFCHR: return NF4CHR;
1979 case S_IFDIR: return NF4DIR;
1980 case S_IFBLK: return NF4BLK;
1981 case S_IFLNK: return NF4LNK;
1982 case S_IFREG: return NF4REG;
1983 case S_IFSOCK: return NF4SOCK;
1984 default: return NF4BAD;
1985 };
1986}
1da177e4 1987
b37ad28b 1988static inline __be32
ddd1ea56
BF
1989nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp,
1990 struct nfs4_ace *ace)
1da177e4 1991{
3554116d 1992 if (ace->whotype != NFS4_ACL_WHO_NAMED)
ddd1ea56 1993 return nfs4_acl_write_who(xdr, ace->whotype);
3554116d 1994 else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
ddd1ea56 1995 return nfsd4_encode_group(xdr, rqstp, ace->who_gid);
3554116d 1996 else
ddd1ea56 1997 return nfsd4_encode_user(xdr, rqstp, ace->who_uid);
1da177e4
LT
1998}
1999
42ca0993
BF
2000#define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
2001 FATTR4_WORD0_RDATTR_ERROR)
2002#define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
2003
18032ca0
DQ
2004#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
2005static inline __be32
ddd1ea56
BF
2006nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
2007 void *context, int len)
18032ca0 2008{
ddd1ea56 2009 __be32 *p;
18032ca0 2010
ddd1ea56
BF
2011 p = xdr_reserve_space(xdr, len + 4 + 4 + 4);
2012 if (!p)
18032ca0
DQ
2013 return nfserr_resource;
2014
2015 /*
2016 * For now we use a 0 here to indicate the null translation; in
2017 * the future we may place a call to translation code here.
2018 */
c373b0a4
BF
2019 *p++ = cpu_to_be32(0); /* lfs */
2020 *p++ = cpu_to_be32(0); /* pi */
18032ca0 2021 p = xdr_encode_opaque(p, context, len);
18032ca0
DQ
2022 return 0;
2023}
2024#else
2025static inline __be32
ddd1ea56
BF
2026nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
2027 void *context, int len)
18032ca0
DQ
2028{ return 0; }
2029#endif
2030
b37ad28b 2031static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
42ca0993
BF
2032{
2033 /* As per referral draft: */
2034 if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS ||
2035 *bmval1 & ~WORD1_ABSENT_FS_ATTRS) {
2036 if (*bmval0 & FATTR4_WORD0_RDATTR_ERROR ||
2037 *bmval0 & FATTR4_WORD0_FS_LOCATIONS)
2038 *rdattr_err = NFSERR_MOVED;
2039 else
2040 return nfserr_moved;
2041 }
2042 *bmval0 &= WORD0_ABSENT_FS_ATTRS;
2043 *bmval1 &= WORD1_ABSENT_FS_ATTRS;
2044 return 0;
2045}
1da177e4 2046
ae7095a7
BF
2047
2048static int get_parent_attributes(struct svc_export *exp, struct kstat *stat)
2049{
2050 struct path path = exp->ex_path;
2051 int err;
2052
2053 path_get(&path);
2054 while (follow_up(&path)) {
2055 if (path.dentry != path.mnt->mnt_root)
2056 break;
2057 }
3dadecce 2058 err = vfs_getattr(&path, stat);
ae7095a7
BF
2059 path_put(&path);
2060 return err;
2061}
2062
1da177e4
LT
2063/*
2064 * Note: @fhp can be NULL; in this case, we might have to compose the filehandle
2065 * ourselves.
1da177e4 2066 */
da2ebce6 2067static __be32
d5184658
BF
2068nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
2069 struct svc_export *exp,
2070 struct dentry *dentry, u32 *bmval,
406a7ea9 2071 struct svc_rqst *rqstp, int ignore_crossmnt)
1da177e4
LT
2072{
2073 u32 bmval0 = bmval[0];
2074 u32 bmval1 = bmval[1];
7e705706 2075 u32 bmval2 = bmval[2];
1da177e4 2076 struct kstat stat;
d50e6136 2077 struct svc_fh *tempfh = NULL;
1da177e4 2078 struct kstatfs statfs;
ddd1ea56 2079 __be32 *p;
1fcea5b2 2080 int starting_len = xdr->buf->len;
082d4bd7
BF
2081 int attrlen_offset;
2082 __be32 attrlen;
1da177e4
LT
2083 u32 dummy;
2084 u64 dummy64;
42ca0993 2085 u32 rdattr_err = 0;
b37ad28b 2086 __be32 status;
b8dd7b9a 2087 int err;
1da177e4
LT
2088 int aclsupport = 0;
2089 struct nfs4_acl *acl = NULL;
18032ca0
DQ
2090 void *context = NULL;
2091 int contextlen;
2092 bool contextsupport = false;
7e705706
AA
2093 struct nfsd4_compoundres *resp = rqstp->rq_resp;
2094 u32 minorversion = resp->cstate.minorversion;
ebabe9a9
CH
2095 struct path path = {
2096 .mnt = exp->ex_path.mnt,
2097 .dentry = dentry,
2098 };
3d733711 2099 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1da177e4
LT
2100
2101 BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
7e705706
AA
2102 BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion));
2103 BUG_ON(bmval1 & ~nfsd_suppattrs1(minorversion));
2104 BUG_ON(bmval2 & ~nfsd_suppattrs2(minorversion));
1da177e4 2105
42ca0993 2106 if (exp->ex_fslocs.migrated) {
7e705706 2107 BUG_ON(bmval[2]);
42ca0993
BF
2108 status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err);
2109 if (status)
2110 goto out;
2111 }
2112
3dadecce 2113 err = vfs_getattr(&path, &stat);
b8dd7b9a 2114 if (err)
1da177e4 2115 goto out_nfserr;
12337901
CH
2116 if ((bmval0 & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE |
2117 FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_MAXNAME)) ||
1da177e4
LT
2118 (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
2119 FATTR4_WORD1_SPACE_TOTAL))) {
ebabe9a9 2120 err = vfs_statfs(&path, &statfs);
b8dd7b9a 2121 if (err)
1da177e4
LT
2122 goto out_nfserr;
2123 }
2124 if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) {
d50e6136
BF
2125 tempfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
2126 status = nfserr_jukebox;
2127 if (!tempfh)
2128 goto out;
2129 fh_init(tempfh, NFS4_FHSIZE);
2130 status = fh_compose(tempfh, exp, dentry, NULL);
1da177e4
LT
2131 if (status)
2132 goto out;
d50e6136 2133 fhp = tempfh;
1da177e4
LT
2134 }
2135 if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT
2136 | FATTR4_WORD0_SUPPORTED_ATTRS)) {
b8dd7b9a
AV
2137 err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
2138 aclsupport = (err == 0);
1da177e4 2139 if (bmval0 & FATTR4_WORD0_ACL) {
b8dd7b9a 2140 if (err == -EOPNOTSUPP)
1da177e4 2141 bmval0 &= ~FATTR4_WORD0_ACL;
b8dd7b9a 2142 else if (err == -EINVAL) {
1da177e4
LT
2143 status = nfserr_attrnotsupp;
2144 goto out;
b8dd7b9a 2145 } else if (err != 0)
1da177e4
LT
2146 goto out_nfserr;
2147 }
2148 }
1da177e4 2149
18032ca0
DQ
2150#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
2151 if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) ||
2152 bmval[0] & FATTR4_WORD0_SUPPORTED_ATTRS) {
2153 err = security_inode_getsecctx(dentry->d_inode,
2154 &context, &contextlen);
2155 contextsupport = (err == 0);
2156 if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
2157 if (err == -EOPNOTSUPP)
2158 bmval2 &= ~FATTR4_WORD2_SECURITY_LABEL;
2159 else if (err)
2160 goto out_nfserr;
2161 }
2162 }
2163#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
2164
2b44f1ba 2165 if (bmval2) {
ddd1ea56
BF
2166 p = xdr_reserve_space(xdr, 16);
2167 if (!p)
2b44f1ba 2168 goto out_resource;
c373b0a4
BF
2169 *p++ = cpu_to_be32(3);
2170 *p++ = cpu_to_be32(bmval0);
2171 *p++ = cpu_to_be32(bmval1);
2172 *p++ = cpu_to_be32(bmval2);
2b44f1ba 2173 } else if (bmval1) {
ddd1ea56
BF
2174 p = xdr_reserve_space(xdr, 12);
2175 if (!p)
2b44f1ba 2176 goto out_resource;
c373b0a4
BF
2177 *p++ = cpu_to_be32(2);
2178 *p++ = cpu_to_be32(bmval0);
2179 *p++ = cpu_to_be32(bmval1);
7e705706 2180 } else {
ddd1ea56
BF
2181 p = xdr_reserve_space(xdr, 8);
2182 if (!p)
2b44f1ba 2183 goto out_resource;
c373b0a4
BF
2184 *p++ = cpu_to_be32(1);
2185 *p++ = cpu_to_be32(bmval0);
7e705706 2186 }
082d4bd7
BF
2187
2188 attrlen_offset = xdr->buf->len;
ddd1ea56
BF
2189 p = xdr_reserve_space(xdr, 4);
2190 if (!p)
2191 goto out_resource;
082d4bd7 2192 p++; /* to be backfilled later */
1da177e4
LT
2193
2194 if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
7e705706
AA
2195 u32 word0 = nfsd_suppattrs0(minorversion);
2196 u32 word1 = nfsd_suppattrs1(minorversion);
2197 u32 word2 = nfsd_suppattrs2(minorversion);
2198
42ca0993
BF
2199 if (!aclsupport)
2200 word0 &= ~FATTR4_WORD0_ACL;
18032ca0
DQ
2201 if (!contextsupport)
2202 word2 &= ~FATTR4_WORD2_SECURITY_LABEL;
7e705706 2203 if (!word2) {
ddd1ea56
BF
2204 p = xdr_reserve_space(xdr, 12);
2205 if (!p)
2b44f1ba 2206 goto out_resource;
c373b0a4
BF
2207 *p++ = cpu_to_be32(2);
2208 *p++ = cpu_to_be32(word0);
2209 *p++ = cpu_to_be32(word1);
7e705706 2210 } else {
ddd1ea56
BF
2211 p = xdr_reserve_space(xdr, 16);
2212 if (!p)
2b44f1ba 2213 goto out_resource;
c373b0a4
BF
2214 *p++ = cpu_to_be32(3);
2215 *p++ = cpu_to_be32(word0);
2216 *p++ = cpu_to_be32(word1);
2217 *p++ = cpu_to_be32(word2);
7e705706 2218 }
1da177e4
LT
2219 }
2220 if (bmval0 & FATTR4_WORD0_TYPE) {
ddd1ea56
BF
2221 p = xdr_reserve_space(xdr, 4);
2222 if (!p)
1da177e4 2223 goto out_resource;
3d2544b1 2224 dummy = nfs4_file_type(stat.mode);
6b6d8137
BF
2225 if (dummy == NF4BAD) {
2226 status = nfserr_serverfault;
2227 goto out;
2228 }
c373b0a4 2229 *p++ = cpu_to_be32(dummy);
1da177e4
LT
2230 }
2231 if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) {
ddd1ea56
BF
2232 p = xdr_reserve_space(xdr, 4);
2233 if (!p)
1da177e4 2234 goto out_resource;
49640001 2235 if (exp->ex_flags & NFSEXP_NOSUBTREECHECK)
c373b0a4 2236 *p++ = cpu_to_be32(NFS4_FH_PERSISTENT);
49640001 2237 else
c373b0a4
BF
2238 *p++ = cpu_to_be32(NFS4_FH_PERSISTENT|
2239 NFS4_FH_VOL_RENAME);
1da177e4
LT
2240 }
2241 if (bmval0 & FATTR4_WORD0_CHANGE) {
ddd1ea56
BF
2242 p = xdr_reserve_space(xdr, 8);
2243 if (!p)
1da177e4 2244 goto out_resource;
d05d5744 2245 p = encode_change(p, &stat, dentry->d_inode);
1da177e4
LT
2246 }
2247 if (bmval0 & FATTR4_WORD0_SIZE) {
ddd1ea56
BF
2248 p = xdr_reserve_space(xdr, 8);
2249 if (!p)
1da177e4 2250 goto out_resource;
b64c7f3b 2251 p = xdr_encode_hyper(p, stat.size);
1da177e4
LT
2252 }
2253 if (bmval0 & FATTR4_WORD0_LINK_SUPPORT) {
ddd1ea56
BF
2254 p = xdr_reserve_space(xdr, 4);
2255 if (!p)
1da177e4 2256 goto out_resource;
c373b0a4 2257 *p++ = cpu_to_be32(1);
1da177e4
LT
2258 }
2259 if (bmval0 & FATTR4_WORD0_SYMLINK_SUPPORT) {
ddd1ea56
BF
2260 p = xdr_reserve_space(xdr, 4);
2261 if (!p)
1da177e4 2262 goto out_resource;
c373b0a4 2263 *p++ = cpu_to_be32(1);
1da177e4
LT
2264 }
2265 if (bmval0 & FATTR4_WORD0_NAMED_ATTR) {
ddd1ea56
BF
2266 p = xdr_reserve_space(xdr, 4);
2267 if (!p)
1da177e4 2268 goto out_resource;
c373b0a4 2269 *p++ = cpu_to_be32(0);
1da177e4
LT
2270 }
2271 if (bmval0 & FATTR4_WORD0_FSID) {
ddd1ea56
BF
2272 p = xdr_reserve_space(xdr, 16);
2273 if (!p)
1da177e4 2274 goto out_resource;
42ca0993 2275 if (exp->ex_fslocs.migrated) {
b64c7f3b
BF
2276 p = xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MAJOR);
2277 p = xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MINOR);
af6a4e28
N
2278 } else switch(fsid_source(fhp)) {
2279 case FSIDSOURCE_FSID:
b64c7f3b
BF
2280 p = xdr_encode_hyper(p, (u64)exp->ex_fsid);
2281 p = xdr_encode_hyper(p, (u64)0);
af6a4e28
N
2282 break;
2283 case FSIDSOURCE_DEV:
c373b0a4
BF
2284 *p++ = cpu_to_be32(0);
2285 *p++ = cpu_to_be32(MAJOR(stat.dev));
2286 *p++ = cpu_to_be32(0);
2287 *p++ = cpu_to_be32(MINOR(stat.dev));
af6a4e28
N
2288 break;
2289 case FSIDSOURCE_UUID:
94eb3689
KM
2290 p = xdr_encode_opaque_fixed(p, exp->ex_uuid,
2291 EX_UUID_LEN);
af6a4e28 2292 break;
1da177e4
LT
2293 }
2294 }
2295 if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) {
ddd1ea56
BF
2296 p = xdr_reserve_space(xdr, 4);
2297 if (!p)
1da177e4 2298 goto out_resource;
c373b0a4 2299 *p++ = cpu_to_be32(0);
1da177e4
LT
2300 }
2301 if (bmval0 & FATTR4_WORD0_LEASE_TIME) {
ddd1ea56
BF
2302 p = xdr_reserve_space(xdr, 4);
2303 if (!p)
1da177e4 2304 goto out_resource;
c373b0a4 2305 *p++ = cpu_to_be32(nn->nfsd4_lease);
1da177e4
LT
2306 }
2307 if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) {
ddd1ea56
BF
2308 p = xdr_reserve_space(xdr, 4);
2309 if (!p)
1da177e4 2310 goto out_resource;
c373b0a4 2311 *p++ = cpu_to_be32(rdattr_err);
1da177e4
LT
2312 }
2313 if (bmval0 & FATTR4_WORD0_ACL) {
2314 struct nfs4_ace *ace;
1da177e4
LT
2315
2316 if (acl == NULL) {
ddd1ea56
BF
2317 p = xdr_reserve_space(xdr, 4);
2318 if (!p)
1da177e4
LT
2319 goto out_resource;
2320
c373b0a4 2321 *p++ = cpu_to_be32(0);
1da177e4
LT
2322 goto out_acl;
2323 }
ddd1ea56
BF
2324 p = xdr_reserve_space(xdr, 4);
2325 if (!p)
1da177e4 2326 goto out_resource;
c373b0a4 2327 *p++ = cpu_to_be32(acl->naces);
1da177e4 2328
28e05dd8 2329 for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) {
ddd1ea56
BF
2330 p = xdr_reserve_space(xdr, 4*3);
2331 if (!p)
1da177e4 2332 goto out_resource;
c373b0a4
BF
2333 *p++ = cpu_to_be32(ace->type);
2334 *p++ = cpu_to_be32(ace->flag);
2335 *p++ = cpu_to_be32(ace->access_mask &
2336 NFS4_ACE_MASK_ALL);
ddd1ea56 2337 status = nfsd4_encode_aclname(xdr, rqstp, ace);
1da177e4
LT
2338 if (status)
2339 goto out;
2340 }
2341 }
2342out_acl:
2343 if (bmval0 & FATTR4_WORD0_ACLSUPPORT) {
ddd1ea56
BF
2344 p = xdr_reserve_space(xdr, 4);
2345 if (!p)
1da177e4 2346 goto out_resource;
c373b0a4 2347 *p++ = cpu_to_be32(aclsupport ?
1da177e4
LT
2348 ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL : 0);
2349 }
2350 if (bmval0 & FATTR4_WORD0_CANSETTIME) {
ddd1ea56
BF
2351 p = xdr_reserve_space(xdr, 4);
2352 if (!p)
1da177e4 2353 goto out_resource;
c373b0a4 2354 *p++ = cpu_to_be32(1);
1da177e4
LT
2355 }
2356 if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) {
ddd1ea56
BF
2357 p = xdr_reserve_space(xdr, 4);
2358 if (!p)
1da177e4 2359 goto out_resource;
c373b0a4 2360 *p++ = cpu_to_be32(0);
1da177e4
LT
2361 }
2362 if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) {
ddd1ea56
BF
2363 p = xdr_reserve_space(xdr, 4);
2364 if (!p)
1da177e4 2365 goto out_resource;
c373b0a4 2366 *p++ = cpu_to_be32(1);
1da177e4
LT
2367 }
2368 if (bmval0 & FATTR4_WORD0_CHOWN_RESTRICTED) {
ddd1ea56
BF
2369 p = xdr_reserve_space(xdr, 4);
2370 if (!p)
1da177e4 2371 goto out_resource;
c373b0a4 2372 *p++ = cpu_to_be32(1);
1da177e4
LT
2373 }
2374 if (bmval0 & FATTR4_WORD0_FILEHANDLE) {
ddd1ea56
BF
2375 p = xdr_reserve_space(xdr, fhp->fh_handle.fh_size + 4);
2376 if (!p)
1da177e4 2377 goto out_resource;
0c0c267b
BF
2378 p = xdr_encode_opaque(p, &fhp->fh_handle.fh_base,
2379 fhp->fh_handle.fh_size);
1da177e4
LT
2380 }
2381 if (bmval0 & FATTR4_WORD0_FILEID) {
ddd1ea56
BF
2382 p = xdr_reserve_space(xdr, 8);
2383 if (!p)
1da177e4 2384 goto out_resource;
b64c7f3b 2385 p = xdr_encode_hyper(p, stat.ino);
1da177e4
LT
2386 }
2387 if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
ddd1ea56
BF
2388 p = xdr_reserve_space(xdr, 8);
2389 if (!p)
1da177e4 2390 goto out_resource;
b64c7f3b 2391 p = xdr_encode_hyper(p, (u64) statfs.f_ffree);
1da177e4
LT
2392 }
2393 if (bmval0 & FATTR4_WORD0_FILES_FREE) {
ddd1ea56
BF
2394 p = xdr_reserve_space(xdr, 8);
2395 if (!p)
1da177e4 2396 goto out_resource;
b64c7f3b 2397 p = xdr_encode_hyper(p, (u64) statfs.f_ffree);
1da177e4
LT
2398 }
2399 if (bmval0 & FATTR4_WORD0_FILES_TOTAL) {
ddd1ea56
BF
2400 p = xdr_reserve_space(xdr, 8);
2401 if (!p)
1da177e4 2402 goto out_resource;
b64c7f3b 2403 p = xdr_encode_hyper(p, (u64) statfs.f_files);
1da177e4 2404 }
81c3f413 2405 if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
ddd1ea56 2406 status = nfsd4_encode_fs_locations(xdr, rqstp, exp);
81c3f413
BF
2407 if (status)
2408 goto out;
2409 }
1da177e4 2410 if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) {
ddd1ea56
BF
2411 p = xdr_reserve_space(xdr, 4);
2412 if (!p)
1da177e4 2413 goto out_resource;
c373b0a4 2414 *p++ = cpu_to_be32(1);
1da177e4
LT
2415 }
2416 if (bmval0 & FATTR4_WORD0_MAXFILESIZE) {
ddd1ea56
BF
2417 p = xdr_reserve_space(xdr, 8);
2418 if (!p)
1da177e4 2419 goto out_resource;
b64c7f3b 2420 p = xdr_encode_hyper(p, exp->ex_path.mnt->mnt_sb->s_maxbytes);
1da177e4
LT
2421 }
2422 if (bmval0 & FATTR4_WORD0_MAXLINK) {
ddd1ea56
BF
2423 p = xdr_reserve_space(xdr, 4);
2424 if (!p)
1da177e4 2425 goto out_resource;
c373b0a4 2426 *p++ = cpu_to_be32(255);
1da177e4
LT
2427 }
2428 if (bmval0 & FATTR4_WORD0_MAXNAME) {
ddd1ea56
BF
2429 p = xdr_reserve_space(xdr, 4);
2430 if (!p)
1da177e4 2431 goto out_resource;
c373b0a4 2432 *p++ = cpu_to_be32(statfs.f_namelen);
1da177e4
LT
2433 }
2434 if (bmval0 & FATTR4_WORD0_MAXREAD) {
ddd1ea56
BF
2435 p = xdr_reserve_space(xdr, 8);
2436 if (!p)
1da177e4 2437 goto out_resource;
b64c7f3b 2438 p = xdr_encode_hyper(p, (u64) svc_max_payload(rqstp));
1da177e4
LT
2439 }
2440 if (bmval0 & FATTR4_WORD0_MAXWRITE) {
ddd1ea56
BF
2441 p = xdr_reserve_space(xdr, 8);
2442 if (!p)
1da177e4 2443 goto out_resource;
b64c7f3b 2444 p = xdr_encode_hyper(p, (u64) svc_max_payload(rqstp));
1da177e4
LT
2445 }
2446 if (bmval1 & FATTR4_WORD1_MODE) {
ddd1ea56
BF
2447 p = xdr_reserve_space(xdr, 4);
2448 if (!p)
1da177e4 2449 goto out_resource;
c373b0a4 2450 *p++ = cpu_to_be32(stat.mode & S_IALLUGO);
1da177e4
LT
2451 }
2452 if (bmval1 & FATTR4_WORD1_NO_TRUNC) {
ddd1ea56
BF
2453 p = xdr_reserve_space(xdr, 4);
2454 if (!p)
1da177e4 2455 goto out_resource;
c373b0a4 2456 *p++ = cpu_to_be32(1);
1da177e4
LT
2457 }
2458 if (bmval1 & FATTR4_WORD1_NUMLINKS) {
ddd1ea56
BF
2459 p = xdr_reserve_space(xdr, 4);
2460 if (!p)
1da177e4 2461 goto out_resource;
c373b0a4 2462 *p++ = cpu_to_be32(stat.nlink);
1da177e4
LT
2463 }
2464 if (bmval1 & FATTR4_WORD1_OWNER) {
ddd1ea56 2465 status = nfsd4_encode_user(xdr, rqstp, stat.uid);
1da177e4
LT
2466 if (status)
2467 goto out;
2468 }
2469 if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
ddd1ea56 2470 status = nfsd4_encode_group(xdr, rqstp, stat.gid);
1da177e4
LT
2471 if (status)
2472 goto out;
2473 }
2474 if (bmval1 & FATTR4_WORD1_RAWDEV) {
ddd1ea56
BF
2475 p = xdr_reserve_space(xdr, 8);
2476 if (!p)
1da177e4 2477 goto out_resource;
c373b0a4
BF
2478 *p++ = cpu_to_be32((u32) MAJOR(stat.rdev));
2479 *p++ = cpu_to_be32((u32) MINOR(stat.rdev));
1da177e4
LT
2480 }
2481 if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
ddd1ea56
BF
2482 p = xdr_reserve_space(xdr, 8);
2483 if (!p)
1da177e4
LT
2484 goto out_resource;
2485 dummy64 = (u64)statfs.f_bavail * (u64)statfs.f_bsize;
b64c7f3b 2486 p = xdr_encode_hyper(p, dummy64);
1da177e4
LT
2487 }
2488 if (bmval1 & FATTR4_WORD1_SPACE_FREE) {
ddd1ea56
BF
2489 p = xdr_reserve_space(xdr, 8);
2490 if (!p)
1da177e4
LT
2491 goto out_resource;
2492 dummy64 = (u64)statfs.f_bfree * (u64)statfs.f_bsize;
b64c7f3b 2493 p = xdr_encode_hyper(p, dummy64);
1da177e4
LT
2494 }
2495 if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) {
ddd1ea56
BF
2496 p = xdr_reserve_space(xdr, 8);
2497 if (!p)
1da177e4
LT
2498 goto out_resource;
2499 dummy64 = (u64)statfs.f_blocks * (u64)statfs.f_bsize;
b64c7f3b 2500 p = xdr_encode_hyper(p, dummy64);
1da177e4
LT
2501 }
2502 if (bmval1 & FATTR4_WORD1_SPACE_USED) {
ddd1ea56
BF
2503 p = xdr_reserve_space(xdr, 8);
2504 if (!p)
1da177e4
LT
2505 goto out_resource;
2506 dummy64 = (u64)stat.blocks << 9;
b64c7f3b 2507 p = xdr_encode_hyper(p, dummy64);
1da177e4
LT
2508 }
2509 if (bmval1 & FATTR4_WORD1_TIME_ACCESS) {
ddd1ea56
BF
2510 p = xdr_reserve_space(xdr, 12);
2511 if (!p)
1da177e4 2512 goto out_resource;
b64c7f3b 2513 p = xdr_encode_hyper(p, (s64)stat.atime.tv_sec);
c373b0a4 2514 *p++ = cpu_to_be32(stat.atime.tv_nsec);
1da177e4
LT
2515 }
2516 if (bmval1 & FATTR4_WORD1_TIME_DELTA) {
ddd1ea56
BF
2517 p = xdr_reserve_space(xdr, 12);
2518 if (!p)
1da177e4 2519 goto out_resource;
c373b0a4
BF
2520 *p++ = cpu_to_be32(0);
2521 *p++ = cpu_to_be32(1);
2522 *p++ = cpu_to_be32(0);
1da177e4
LT
2523 }
2524 if (bmval1 & FATTR4_WORD1_TIME_METADATA) {
ddd1ea56
BF
2525 p = xdr_reserve_space(xdr, 12);
2526 if (!p)
1da177e4 2527 goto out_resource;
b64c7f3b 2528 p = xdr_encode_hyper(p, (s64)stat.ctime.tv_sec);
c373b0a4 2529 *p++ = cpu_to_be32(stat.ctime.tv_nsec);
1da177e4
LT
2530 }
2531 if (bmval1 & FATTR4_WORD1_TIME_MODIFY) {
ddd1ea56
BF
2532 p = xdr_reserve_space(xdr, 12);
2533 if (!p)
1da177e4 2534 goto out_resource;
b64c7f3b 2535 p = xdr_encode_hyper(p, (s64)stat.mtime.tv_sec);
c373b0a4 2536 *p++ = cpu_to_be32(stat.mtime.tv_nsec);
1da177e4
LT
2537 }
2538 if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
ddd1ea56
BF
2539 p = xdr_reserve_space(xdr, 8);
2540 if (!p)
1da177e4 2541 goto out_resource;
406a7ea9
FF
2542 /*
2543 * Get parent's attributes if not ignoring crossmount
2544 * and this is the root of a cross-mounted filesystem.
2545 */
2546 if (ignore_crossmnt == 0 &&
ae7095a7
BF
2547 dentry == exp->ex_path.mnt->mnt_root)
2548 get_parent_attributes(exp, &stat);
b64c7f3b 2549 p = xdr_encode_hyper(p, stat.ino);
1da177e4 2550 }
18032ca0 2551 if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
ddd1ea56
BF
2552 status = nfsd4_encode_security_label(xdr, rqstp, context,
2553 contextlen);
18032ca0
DQ
2554 if (status)
2555 goto out;
2556 }
8c18f205 2557 if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
ddd1ea56
BF
2558 p = xdr_reserve_space(xdr, 16);
2559 if (!p)
de3997a7 2560 goto out_resource;
c373b0a4
BF
2561 *p++ = cpu_to_be32(3);
2562 *p++ = cpu_to_be32(NFSD_SUPPATTR_EXCLCREAT_WORD0);
2563 *p++ = cpu_to_be32(NFSD_SUPPATTR_EXCLCREAT_WORD1);
2564 *p++ = cpu_to_be32(NFSD_SUPPATTR_EXCLCREAT_WORD2);
8c18f205 2565 }
7e705706 2566
082d4bd7
BF
2567 attrlen = htonl(xdr->buf->len - attrlen_offset - 4);
2568 write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, 4);
1da177e4
LT
2569 status = nfs_ok;
2570
2571out:
ba4e55bb 2572#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
18032ca0
DQ
2573 if (context)
2574 security_release_secctx(context, contextlen);
ba4e55bb 2575#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
28e05dd8 2576 kfree(acl);
18df11d0 2577 if (tempfh) {
d50e6136 2578 fh_put(tempfh);
18df11d0
YZ
2579 kfree(tempfh);
2580 }
1fcea5b2
BF
2581 if (status)
2582 xdr_truncate_encode(xdr, starting_len);
1da177e4
LT
2583 return status;
2584out_nfserr:
b8dd7b9a 2585 status = nfserrno(err);
1da177e4
LT
2586 goto out;
2587out_resource:
1da177e4
LT
2588 status = nfserr_resource;
2589 goto out;
1da177e4
LT
2590}
2591
2825a7f9
BF
2592static void svcxdr_init_encode_from_buffer(struct xdr_stream *xdr,
2593 struct xdr_buf *buf, __be32 *p, int bytes)
2594{
2595 xdr->scratch.iov_len = 0;
2596 memset(buf, 0, sizeof(struct xdr_buf));
2597 buf->head[0].iov_base = p;
2598 buf->head[0].iov_len = 0;
2599 buf->len = 0;
2600 xdr->buf = buf;
2601 xdr->iov = buf->head;
2602 xdr->p = p;
2603 xdr->end = (void *)p + bytes;
2604 buf->buflen = bytes;
2605}
2606
d5184658
BF
2607__be32 nfsd4_encode_fattr_to_buf(__be32 **p, int words,
2608 struct svc_fh *fhp, struct svc_export *exp,
2609 struct dentry *dentry, u32 *bmval,
2610 struct svc_rqst *rqstp, int ignore_crossmnt)
2611{
2825a7f9 2612 struct xdr_buf dummy;
d5184658
BF
2613 struct xdr_stream xdr;
2614 __be32 ret;
2615
2825a7f9 2616 svcxdr_init_encode_from_buffer(&xdr, &dummy, *p, words << 2);
d5184658
BF
2617 ret = nfsd4_encode_fattr(&xdr, fhp, exp, dentry, bmval, rqstp,
2618 ignore_crossmnt);
2619 *p = xdr.p;
2620 return ret;
2621}
2622
c0ce6ec8
BF
2623static inline int attributes_need_mount(u32 *bmval)
2624{
2625 if (bmval[0] & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_LEASE_TIME))
2626 return 1;
2627 if (bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID)
2628 return 1;
2629 return 0;
2630}
2631
b37ad28b 2632static __be32
561f0ed4
BF
2633nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd,
2634 const char *name, int namlen)
1da177e4
LT
2635{
2636 struct svc_export *exp = cd->rd_fhp->fh_export;
2637 struct dentry *dentry;
b37ad28b 2638 __be32 nfserr;
406a7ea9 2639 int ignore_crossmnt = 0;
1da177e4
LT
2640
2641 dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
2642 if (IS_ERR(dentry))
2643 return nfserrno(PTR_ERR(dentry));
b2c0cea6
BF
2644 if (!dentry->d_inode) {
2645 /*
2646 * nfsd_buffered_readdir drops the i_mutex between
2647 * readdir and calling this callback, leaving a window
2648 * where this directory entry could have gone away.
2649 */
2650 dput(dentry);
2651 return nfserr_noent;
2652 }
1da177e4
LT
2653
2654 exp_get(exp);
406a7ea9
FF
2655 /*
2656 * In the case of a mountpoint, the client may be asking for
2657 * attributes that are only properties of the underlying filesystem
2658 * as opposed to the cross-mounted file system. In such a case,
2659 * we will not follow the cross mount and will fill the attribtutes
2660 * directly from the mountpoint dentry.
2661 */
3227fa41 2662 if (nfsd_mountpoint(dentry, exp)) {
021d3a72
BF
2663 int err;
2664
3227fa41
BF
2665 if (!(exp->ex_flags & NFSEXP_V4ROOT)
2666 && !attributes_need_mount(cd->rd_bmval)) {
2667 ignore_crossmnt = 1;
2668 goto out_encode;
2669 }
dcb488a3
AA
2670 /*
2671 * Why the heck aren't we just using nfsd_lookup??
2672 * Different "."/".." handling? Something else?
2673 * At least, add a comment here to explain....
2674 */
021d3a72
BF
2675 err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp);
2676 if (err) {
2677 nfserr = nfserrno(err);
1da177e4
LT
2678 goto out_put;
2679 }
dcb488a3
AA
2680 nfserr = check_nfsd_access(exp, cd->rd_rqstp);
2681 if (nfserr)
2682 goto out_put;
1da177e4
LT
2683
2684 }
3227fa41 2685out_encode:
561f0ed4 2686 nfserr = nfsd4_encode_fattr(xdr, NULL, exp, dentry, cd->rd_bmval,
406a7ea9 2687 cd->rd_rqstp, ignore_crossmnt);
1da177e4
LT
2688out_put:
2689 dput(dentry);
2690 exp_put(exp);
2691 return nfserr;
2692}
2693
2ebbc012 2694static __be32 *
561f0ed4 2695nfsd4_encode_rdattr_error(struct xdr_stream *xdr, __be32 nfserr)
1da177e4 2696{
561f0ed4
BF
2697 __be32 *p;
2698
c3a45617 2699 p = xdr_reserve_space(xdr, 20);
561f0ed4 2700 if (!p)
1da177e4
LT
2701 return NULL;
2702 *p++ = htonl(2);
2703 *p++ = htonl(FATTR4_WORD0_RDATTR_ERROR); /* bmval0 */
2704 *p++ = htonl(0); /* bmval1 */
2705
87915c64 2706 *p++ = htonl(4); /* attribute length */
1da177e4 2707 *p++ = nfserr; /* no htonl */
1da177e4
LT
2708 return p;
2709}
2710
2711static int
a0ad13ef
N
2712nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
2713 loff_t offset, u64 ino, unsigned int d_type)
1da177e4 2714{
a0ad13ef 2715 struct readdir_cd *ccd = ccdv;
1da177e4 2716 struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common);
561f0ed4
BF
2717 struct xdr_stream *xdr = cd->xdr;
2718 int start_offset = xdr->buf->len;
2719 int cookie_offset;
aee37764 2720 u32 name_and_cookie;
561f0ed4 2721 int entry_bytes;
b37ad28b 2722 __be32 nfserr = nfserr_toosmall;
561f0ed4
BF
2723 __be64 wire_offset;
2724 __be32 *p;
1da177e4
LT
2725
2726 /* In nfsv4, "." and ".." never make it onto the wire.. */
2727 if (name && isdotent(name, namlen)) {
2728 cd->common.err = nfs_ok;
2729 return 0;
2730 }
2731
561f0ed4
BF
2732 if (cd->cookie_offset) {
2733 wire_offset = cpu_to_be64(offset);
2734 write_bytes_to_xdr_buf(xdr->buf, cd->cookie_offset,
2735 &wire_offset, 8);
2736 }
1da177e4 2737
561f0ed4
BF
2738 p = xdr_reserve_space(xdr, 4);
2739 if (!p)
1da177e4 2740 goto fail;
1da177e4 2741 *p++ = xdr_one; /* mark entry present */
561f0ed4
BF
2742 cookie_offset = xdr->buf->len;
2743 p = xdr_reserve_space(xdr, 3*4 + namlen);
2744 if (!p)
2745 goto fail;
1da177e4
LT
2746 p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */
2747 p = xdr_encode_array(p, name, namlen); /* name length & name */
2748
561f0ed4 2749 nfserr = nfsd4_encode_dirent_fattr(xdr, cd, name, namlen);
1da177e4
LT
2750 switch (nfserr) {
2751 case nfs_ok:
1da177e4
LT
2752 break;
2753 case nfserr_resource:
2754 nfserr = nfserr_toosmall;
2755 goto fail;
b2c0cea6 2756 case nfserr_noent:
f41c5ad2 2757 xdr_truncate_encode(xdr, start_offset);
b2c0cea6 2758 goto skip_entry;
1da177e4
LT
2759 default:
2760 /*
2761 * If the client requested the RDATTR_ERROR attribute,
2762 * we stuff the error code into this attribute
2763 * and continue. If this attribute was not requested,
2764 * then in accordance with the spec, we fail the
2765 * entire READDIR operation(!)
2766 */
2767 if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR))
2768 goto fail;
561f0ed4 2769 p = nfsd4_encode_rdattr_error(xdr, nfserr);
34081efc
FI
2770 if (p == NULL) {
2771 nfserr = nfserr_toosmall;
1da177e4 2772 goto fail;
34081efc 2773 }
1da177e4 2774 }
561f0ed4
BF
2775 nfserr = nfserr_toosmall;
2776 entry_bytes = xdr->buf->len - start_offset;
2777 if (entry_bytes > cd->rd_maxcount)
2778 goto fail;
2779 cd->rd_maxcount -= entry_bytes;
aee37764
BF
2780 /*
2781 * RFC 3530 14.2.24 describes rd_dircount as only a "hint", so
2782 * let's always let through the first entry, at least:
2783 */
0ec016e3
BF
2784 if (!cd->rd_dircount)
2785 goto fail;
2786 name_and_cookie = 4 + 4 * XDR_QUADLEN(namlen) + 8;
aee37764
BF
2787 if (name_and_cookie > cd->rd_dircount && cd->cookie_offset)
2788 goto fail;
2789 cd->rd_dircount -= min(cd->rd_dircount, name_and_cookie);
0ec016e3 2790
561f0ed4 2791 cd->cookie_offset = cookie_offset;
b2c0cea6 2792skip_entry:
1da177e4
LT
2793 cd->common.err = nfs_ok;
2794 return 0;
2795fail:
561f0ed4 2796 xdr_truncate_encode(xdr, start_offset);
1da177e4
LT
2797 cd->common.err = nfserr;
2798 return -EINVAL;
2799}
2800
d0a381dd
BF
2801static __be32
2802nfsd4_encode_stateid(struct xdr_stream *xdr, stateid_t *sid)
e2f282b9 2803{
bc749ca4 2804 __be32 *p;
e2f282b9 2805
d0a381dd
BF
2806 p = xdr_reserve_space(xdr, sizeof(stateid_t));
2807 if (!p)
2808 return nfserr_resource;
c373b0a4 2809 *p++ = cpu_to_be32(sid->si_generation);
0c0c267b
BF
2810 p = xdr_encode_opaque_fixed(p, &sid->si_opaque,
2811 sizeof(stateid_opaque_t));
d0a381dd 2812 return 0;
e2f282b9
BH
2813}
2814
695e12f8 2815static __be32
b37ad28b 2816nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
1da177e4 2817{
d0a381dd 2818 struct xdr_stream *xdr = &resp->xdr;
bc749ca4 2819 __be32 *p;
1da177e4
LT
2820
2821 if (!nfserr) {
d0a381dd
BF
2822 p = xdr_reserve_space(xdr, 8);
2823 if (!p)
2824 return nfserr_resource;
c373b0a4
BF
2825 *p++ = cpu_to_be32(access->ac_supported);
2826 *p++ = cpu_to_be32(access->ac_resp_access);
1da177e4 2827 }
695e12f8 2828 return nfserr;
1da177e4
LT
2829}
2830
1d1bc8f2
BF
2831static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts)
2832{
d0a381dd 2833 struct xdr_stream *xdr = &resp->xdr;
1d1bc8f2
BF
2834 __be32 *p;
2835
2836 if (!nfserr) {
d0a381dd
BF
2837 p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 8);
2838 if (!p)
2839 return nfserr_resource;
0c0c267b
BF
2840 p = xdr_encode_opaque_fixed(p, bcts->sessionid.data,
2841 NFS4_MAX_SESSIONID_LEN);
c373b0a4 2842 *p++ = cpu_to_be32(bcts->dir);
6e67b5d1 2843 /* Sorry, we do not yet support RDMA over 4.1: */
c373b0a4 2844 *p++ = cpu_to_be32(0);
1d1bc8f2
BF
2845 }
2846 return nfserr;
2847}
2848
695e12f8 2849static __be32
b37ad28b 2850nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
1da177e4 2851{
d0a381dd
BF
2852 struct xdr_stream *xdr = &resp->xdr;
2853
e2f282b9 2854 if (!nfserr)
d0a381dd 2855 nfserr = nfsd4_encode_stateid(xdr, &close->cl_stateid);
e2f282b9 2856
695e12f8 2857 return nfserr;
1da177e4
LT
2858}
2859
2860
695e12f8 2861static __be32
b37ad28b 2862nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit)
1da177e4 2863{
d0a381dd 2864 struct xdr_stream *xdr = &resp->xdr;
bc749ca4 2865 __be32 *p;
1da177e4
LT
2866
2867 if (!nfserr) {
d0a381dd
BF
2868 p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
2869 if (!p)
2870 return nfserr_resource;
0c0c267b
BF
2871 p = xdr_encode_opaque_fixed(p, commit->co_verf.data,
2872 NFS4_VERIFIER_SIZE);
1da177e4 2873 }
695e12f8 2874 return nfserr;
1da177e4
LT
2875}
2876
695e12f8 2877static __be32
b37ad28b 2878nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create)
1da177e4 2879{
d0a381dd 2880 struct xdr_stream *xdr = &resp->xdr;
bc749ca4 2881 __be32 *p;
1da177e4
LT
2882
2883 if (!nfserr) {
d0a381dd
BF
2884 p = xdr_reserve_space(xdr, 32);
2885 if (!p)
2886 return nfserr_resource;
d05d5744 2887 p = encode_cinfo(p, &create->cr_cinfo);
c373b0a4
BF
2888 *p++ = cpu_to_be32(2);
2889 *p++ = cpu_to_be32(create->cr_bmval[0]);
2890 *p++ = cpu_to_be32(create->cr_bmval[1]);
1da177e4 2891 }
695e12f8 2892 return nfserr;
1da177e4
LT
2893}
2894
b37ad28b
AV
2895static __be32
2896nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr)
1da177e4
LT
2897{
2898 struct svc_fh *fhp = getattr->ga_fhp;
d5184658 2899 struct xdr_stream *xdr = &resp->xdr;
1da177e4
LT
2900
2901 if (nfserr)
2902 return nfserr;
2903
d5184658
BF
2904 nfserr = nfsd4_encode_fattr(xdr, fhp, fhp->fh_export, fhp->fh_dentry,
2905 getattr->ga_bmval,
406a7ea9 2906 resp->rqstp, 0);
1da177e4
LT
2907 return nfserr;
2908}
2909
695e12f8
BH
2910static __be32
2911nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp)
1da177e4 2912{
d0a381dd 2913 struct xdr_stream *xdr = &resp->xdr;
695e12f8 2914 struct svc_fh *fhp = *fhpp;
1da177e4 2915 unsigned int len;
bc749ca4 2916 __be32 *p;
1da177e4
LT
2917
2918 if (!nfserr) {
2919 len = fhp->fh_handle.fh_size;
d0a381dd
BF
2920 p = xdr_reserve_space(xdr, len + 4);
2921 if (!p)
2922 return nfserr_resource;
0c0c267b 2923 p = xdr_encode_opaque(p, &fhp->fh_handle.fh_base, len);
1da177e4 2924 }
695e12f8 2925 return nfserr;
1da177e4
LT
2926}
2927
2928/*
2929* Including all fields other than the name, a LOCK4denied structure requires
2930* 8(clientid) + 4(namelen) + 8(offset) + 8(length) + 4(type) = 32 bytes.
2931*/
d0a381dd
BF
2932static __be32
2933nfsd4_encode_lock_denied(struct xdr_stream *xdr, struct nfsd4_lock_denied *ld)
1da177e4 2934{
7c13f344 2935 struct xdr_netobj *conf = &ld->ld_owner;
bc749ca4 2936 __be32 *p;
1da177e4 2937
8c7424cf 2938again:
d0a381dd 2939 p = xdr_reserve_space(xdr, 32 + XDR_LEN(conf->len));
8c7424cf
BF
2940 if (!p) {
2941 /*
2942 * Don't fail to return the result just because we can't
2943 * return the conflicting open:
2944 */
2945 if (conf->len) {
f98bac5a 2946 kfree(conf->data);
8c7424cf
BF
2947 conf->len = 0;
2948 conf->data = NULL;
2949 goto again;
2950 }
d0a381dd 2951 return nfserr_resource;
8c7424cf 2952 }
b64c7f3b
BF
2953 p = xdr_encode_hyper(p, ld->ld_start);
2954 p = xdr_encode_hyper(p, ld->ld_length);
c373b0a4 2955 *p++ = cpu_to_be32(ld->ld_type);
7c13f344 2956 if (conf->len) {
0c0c267b
BF
2957 p = xdr_encode_opaque_fixed(p, &ld->ld_clientid, 8);
2958 p = xdr_encode_opaque(p, conf->data, conf->len);
f98bac5a 2959 kfree(conf->data);
1da177e4 2960 } else { /* non - nfsv4 lock in conflict, no clientid nor owner */
b64c7f3b 2961 p = xdr_encode_hyper(p, (u64)0); /* clientid */
c373b0a4 2962 *p++ = cpu_to_be32(0); /* length of owner name */
1da177e4 2963 }
d0a381dd 2964 return nfserr_denied;
1da177e4
LT
2965}
2966
695e12f8 2967static __be32
b37ad28b 2968nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock)
1da177e4 2969{
d0a381dd
BF
2970 struct xdr_stream *xdr = &resp->xdr;
2971
e2f282b9 2972 if (!nfserr)
d0a381dd 2973 nfserr = nfsd4_encode_stateid(xdr, &lock->lk_resp_stateid);
e2f282b9 2974 else if (nfserr == nfserr_denied)
d0a381dd 2975 nfserr = nfsd4_encode_lock_denied(xdr, &lock->lk_denied);
f98bac5a 2976
695e12f8 2977 return nfserr;
1da177e4
LT
2978}
2979
695e12f8 2980static __be32
b37ad28b 2981nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt)
1da177e4 2982{
d0a381dd
BF
2983 struct xdr_stream *xdr = &resp->xdr;
2984
1da177e4 2985 if (nfserr == nfserr_denied)
d0a381dd 2986 nfsd4_encode_lock_denied(xdr, &lockt->lt_denied);
695e12f8 2987 return nfserr;
1da177e4
LT
2988}
2989
695e12f8 2990static __be32
b37ad28b 2991nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku)
1da177e4 2992{
d0a381dd
BF
2993 struct xdr_stream *xdr = &resp->xdr;
2994
e2f282b9 2995 if (!nfserr)
d0a381dd 2996 nfserr = nfsd4_encode_stateid(xdr, &locku->lu_stateid);
e2f282b9 2997
695e12f8 2998 return nfserr;
1da177e4
LT
2999}
3000
3001
695e12f8 3002static __be32
b37ad28b 3003nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link)
1da177e4 3004{
d0a381dd 3005 struct xdr_stream *xdr = &resp->xdr;
bc749ca4 3006 __be32 *p;
1da177e4
LT
3007
3008 if (!nfserr) {
d0a381dd
BF
3009 p = xdr_reserve_space(xdr, 20);
3010 if (!p)
3011 return nfserr_resource;
d05d5744 3012 p = encode_cinfo(p, &link->li_cinfo);
1da177e4 3013 }
695e12f8 3014 return nfserr;
1da177e4
LT
3015}
3016
3017
695e12f8 3018static __be32
b37ad28b 3019nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
1da177e4 3020{
d0a381dd 3021 struct xdr_stream *xdr = &resp->xdr;
bc749ca4 3022 __be32 *p;
1da177e4
LT
3023
3024 if (nfserr)
3025 goto out;
3026
d0a381dd
BF
3027 nfserr = nfsd4_encode_stateid(xdr, &open->op_stateid);
3028 if (nfserr)
3029 goto out;
3030 p = xdr_reserve_space(xdr, 40);
3031 if (!p)
3032 return nfserr_resource;
d05d5744 3033 p = encode_cinfo(p, &open->op_cinfo);
c373b0a4
BF
3034 *p++ = cpu_to_be32(open->op_rflags);
3035 *p++ = cpu_to_be32(2);
3036 *p++ = cpu_to_be32(open->op_bmval[0]);
3037 *p++ = cpu_to_be32(open->op_bmval[1]);
3038 *p++ = cpu_to_be32(open->op_delegate_type);
1da177e4
LT
3039
3040 switch (open->op_delegate_type) {
3041 case NFS4_OPEN_DELEGATE_NONE:
3042 break;
3043 case NFS4_OPEN_DELEGATE_READ:
d0a381dd
BF
3044 nfserr = nfsd4_encode_stateid(xdr, &open->op_delegate_stateid);
3045 if (nfserr)
3046 return nfserr;
3047 p = xdr_reserve_space(xdr, 20);
3048 if (!p)
3049 return nfserr_resource;
c373b0a4 3050 *p++ = cpu_to_be32(open->op_recall);
1da177e4
LT
3051
3052 /*
3053 * TODO: ACE's in delegations
3054 */
c373b0a4
BF
3055 *p++ = cpu_to_be32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE);
3056 *p++ = cpu_to_be32(0);
3057 *p++ = cpu_to_be32(0);
3058 *p++ = cpu_to_be32(0); /* XXX: is NULL principal ok? */
1da177e4
LT
3059 break;
3060 case NFS4_OPEN_DELEGATE_WRITE:
d0a381dd
BF
3061 nfserr = nfsd4_encode_stateid(xdr, &open->op_delegate_stateid);
3062 if (nfserr)
3063 return nfserr;
3064 p = xdr_reserve_space(xdr, 32);
3065 if (!p)
3066 return nfserr_resource;
c373b0a4 3067 *p++ = cpu_to_be32(0);
1da177e4
LT
3068
3069 /*
3070 * TODO: space_limit's in delegations
3071 */
c373b0a4
BF
3072 *p++ = cpu_to_be32(NFS4_LIMIT_SIZE);
3073 *p++ = cpu_to_be32(~(u32)0);
3074 *p++ = cpu_to_be32(~(u32)0);
1da177e4
LT
3075
3076 /*
3077 * TODO: ACE's in delegations
3078 */
c373b0a4
BF
3079 *p++ = cpu_to_be32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE);
3080 *p++ = cpu_to_be32(0);
3081 *p++ = cpu_to_be32(0);
3082 *p++ = cpu_to_be32(0); /* XXX: is NULL principal ok? */
1da177e4 3083 break;
d24433cd
BH
3084 case NFS4_OPEN_DELEGATE_NONE_EXT: /* 4.1 */
3085 switch (open->op_why_no_deleg) {
3086 case WND4_CONTENTION:
3087 case WND4_RESOURCE:
d0a381dd
BF
3088 p = xdr_reserve_space(xdr, 8);
3089 if (!p)
3090 return nfserr_resource;
c373b0a4
BF
3091 *p++ = cpu_to_be32(open->op_why_no_deleg);
3092 /* deleg signaling not supported yet: */
3093 *p++ = cpu_to_be32(0);
d24433cd
BH
3094 break;
3095 default:
d0a381dd
BF
3096 p = xdr_reserve_space(xdr, 4);
3097 if (!p)
3098 return nfserr_resource;
c373b0a4 3099 *p++ = cpu_to_be32(open->op_why_no_deleg);
d24433cd 3100 }
d24433cd 3101 break;
1da177e4
LT
3102 default:
3103 BUG();
3104 }
3105 /* XXX save filehandle here */
3106out:
695e12f8 3107 return nfserr;
1da177e4
LT
3108}
3109
695e12f8 3110static __be32
b37ad28b 3111nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc)
1da177e4 3112{
d0a381dd
BF
3113 struct xdr_stream *xdr = &resp->xdr;
3114
e2f282b9 3115 if (!nfserr)
d0a381dd 3116 nfserr = nfsd4_encode_stateid(xdr, &oc->oc_resp_stateid);
1da177e4 3117
695e12f8 3118 return nfserr;
1da177e4
LT
3119}
3120
695e12f8 3121static __be32
b37ad28b 3122nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od)
1da177e4 3123{
d0a381dd
BF
3124 struct xdr_stream *xdr = &resp->xdr;
3125
e2f282b9 3126 if (!nfserr)
d0a381dd 3127 nfserr = nfsd4_encode_stateid(xdr, &od->od_stateid);
1da177e4 3128
695e12f8 3129 return nfserr;
1da177e4
LT
3130}
3131
dc97618d
BF
3132static __be32 nfsd4_encode_splice_read(
3133 struct nfsd4_compoundres *resp,
3134 struct nfsd4_read *read,
3135 struct file *file, unsigned long maxcount)
1da177e4 3136{
ddd1ea56 3137 struct xdr_stream *xdr = &resp->xdr;
34a78b48 3138 struct xdr_buf *buf = xdr->buf;
dc97618d 3139 u32 eof;
30596768 3140 int space_left;
dc97618d 3141 __be32 nfserr;
fec25fa4 3142 __be32 *p = xdr->p - 2;
1da177e4 3143
d5d5c304
KM
3144 /* Make sure there will be room for padding if needed */
3145 if (xdr->end - xdr->p < 1)
d0a381dd 3146 return nfserr_resource;
dc97618d
BF
3147
3148 nfserr = nfsd_splice_read(read->rd_rqstp, file,
3149 read->rd_offset, &maxcount);
3150 if (nfserr) {
3151 /*
3152 * nfsd_splice_actor may have already messed with the
3153 * page length; reset it so as not to confuse
3154 * xdr_truncate_encode:
3155 */
34a78b48 3156 buf->page_len = 0;
dc97618d 3157 return nfserr;
b0e35fda 3158 }
1da177e4 3159
dc97618d
BF
3160 eof = (read->rd_offset + maxcount >=
3161 read->rd_fhp->fh_dentry->d_inode->i_size);
4e21ac4b 3162
fec25fa4
BF
3163 *(p++) = htonl(eof);
3164 *(p++) = htonl(maxcount);
dc97618d 3165
34a78b48
BF
3166 buf->page_len = maxcount;
3167 buf->len += maxcount;
15b23ef5
BF
3168 xdr->page_ptr += (buf->page_base + maxcount + PAGE_SIZE - 1)
3169 / PAGE_SIZE;
dc97618d
BF
3170
3171 /* Use rest of head for padding and remaining ops: */
34a78b48
BF
3172 buf->tail[0].iov_base = xdr->p;
3173 buf->tail[0].iov_len = 0;
fec25fa4 3174 xdr->iov = buf->tail;
dc97618d 3175 if (maxcount&3) {
fec25fa4
BF
3176 int pad = 4 - (maxcount&3);
3177
3178 *(xdr->p++) = 0;
3179
34a78b48 3180 buf->tail[0].iov_base += maxcount&3;
fec25fa4
BF
3181 buf->tail[0].iov_len = pad;
3182 buf->len += pad;
b0e35fda 3183 }
2825a7f9 3184
dc97618d 3185 space_left = min_t(int, (void *)xdr->end - (void *)xdr->p,
34a78b48
BF
3186 buf->buflen - buf->len);
3187 buf->buflen = buf->len + space_left;
dc97618d
BF
3188 xdr->end = (__be32 *)((void *)xdr->end + space_left);
3189
3190 return 0;
3191}
3192
3193static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
3194 struct nfsd4_read *read,
3195 struct file *file, unsigned long maxcount)
3196{
3197 struct xdr_stream *xdr = &resp->xdr;
3198 u32 eof;
3199 int v;
dc97618d 3200 int starting_len = xdr->buf->len - 8;
dc97618d 3201 long len;
b0420980 3202 int thislen;
dc97618d
BF
3203 __be32 nfserr;
3204 __be32 tmp;
3205 __be32 *p;
b0420980
BF
3206 u32 zzz = 0;
3207 int pad;
1da177e4
LT
3208
3209 len = maxcount;
3210 v = 0;
6ff9897d 3211
1055414f 3212 thislen = min_t(long, len, ((void *)xdr->end - (void *)xdr->p));
b0420980
BF
3213 p = xdr_reserve_space(xdr, (thislen+3)&~3);
3214 WARN_ON_ONCE(!p);
3215 resp->rqstp->rq_vec[v].iov_base = p;
3216 resp->rqstp->rq_vec[v].iov_len = thislen;
3217 v++;
3218 len -= thislen;
3219
3220 while (len) {
6ff9897d 3221 thislen = min_t(long, len, PAGE_SIZE);
b0420980
BF
3222 p = xdr_reserve_space(xdr, (thislen+3)&~3);
3223 WARN_ON_ONCE(!p);
3224 resp->rqstp->rq_vec[v].iov_base = p;
6ff9897d 3225 resp->rqstp->rq_vec[v].iov_len = thislen;
1da177e4 3226 v++;
6ff9897d 3227 len -= thislen;
1da177e4
LT
3228 }
3229 read->rd_vlen = v;
3230
dc97618d
BF
3231 nfserr = nfsd_readv(file, read->rd_offset, resp->rqstp->rq_vec,
3232 read->rd_vlen, &maxcount);
3233 if (nfserr)
1da177e4 3234 return nfserr;
b0420980 3235 xdr_truncate_encode(xdr, starting_len + 8 + ((maxcount+3)&~3));
dc97618d 3236
44524359
N
3237 eof = (read->rd_offset + maxcount >=
3238 read->rd_fhp->fh_dentry->d_inode->i_size);
1da177e4 3239
dc97618d
BF
3240 tmp = htonl(eof);
3241 write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4);
3242 tmp = htonl(maxcount);
3243 write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
3244
b0420980
BF
3245 pad = (maxcount&3) ? 4 - (maxcount&3) : 0;
3246 write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + maxcount,
3247 &zzz, pad);
1da177e4 3248 return 0;
dc97618d
BF
3249
3250}
3251
3252static __be32
3253nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
3254 struct nfsd4_read *read)
3255{
3256 unsigned long maxcount;
3257 struct xdr_stream *xdr = &resp->xdr;
3258 struct file *file = read->rd_filp;
3259 int starting_len = xdr->buf->len;
3260 struct raparms *ra;
3261 __be32 *p;
3262 __be32 err;
3263
3264 if (nfserr)
3265 return nfserr;
3266
3267 p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */
3268 if (!p) {
779fb0f3 3269 WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags));
dc97618d
BF
3270 return nfserr_resource;
3271 }
779fb0f3 3272 if (resp->xdr.buf->page_len && test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) {
b0420980 3273 WARN_ON_ONCE(1);
dc97618d
BF
3274 return nfserr_resource;
3275 }
dc97618d
BF
3276 xdr_commit_encode(xdr);
3277
3278 maxcount = svc_max_payload(resp->rqstp);
3c7aa15d
KM
3279 maxcount = min_t(unsigned long, maxcount, (xdr->buf->buflen - xdr->buf->len));
3280 maxcount = min_t(unsigned long, maxcount, read->rd_length);
dc97618d
BF
3281
3282 if (!read->rd_filp) {
3283 err = nfsd_get_tmp_read_open(resp->rqstp, read->rd_fhp,
3284 &file, &ra);
3285 if (err)
3286 goto err_truncate;
3287 }
3288
779fb0f3 3289 if (file->f_op->splice_read && test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags))
dc97618d
BF
3290 err = nfsd4_encode_splice_read(resp, read, file, maxcount);
3291 else
3292 err = nfsd4_encode_readv(resp, read, file, maxcount);
3293
3294 if (!read->rd_filp)
3295 nfsd_put_tmp_read_open(file, ra);
3296
3297err_truncate:
3298 if (err)
3299 xdr_truncate_encode(xdr, starting_len);
3300 return err;
1da177e4
LT
3301}
3302
b37ad28b
AV
3303static __be32
3304nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink)
1da177e4
LT
3305{
3306 int maxcount;
476a7b1f
BF
3307 __be32 wire_count;
3308 int zero = 0;
ddd1ea56 3309 struct xdr_stream *xdr = &resp->xdr;
1fcea5b2 3310 int length_offset = xdr->buf->len;
bc749ca4 3311 __be32 *p;
1da177e4
LT
3312
3313 if (nfserr)
3314 return nfserr;
2825a7f9
BF
3315
3316 p = xdr_reserve_space(xdr, 4);
3317 if (!p)
3318 return nfserr_resource;
1da177e4 3319 maxcount = PAGE_SIZE;
d0a381dd 3320
476a7b1f
BF
3321 p = xdr_reserve_space(xdr, maxcount);
3322 if (!p)
4e21ac4b 3323 return nfserr_resource;
1da177e4
LT
3324 /*
3325 * XXX: By default, the ->readlink() VFS op will truncate symlinks
3326 * if they would overflow the buffer. Is this kosher in NFSv4? If
3327 * not, one easy fix is: if ->readlink() precisely fills the buffer,
3328 * assume that truncation occurred, and return NFS4ERR_RESOURCE.
3329 */
476a7b1f
BF
3330 nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp,
3331 (char *)p, &maxcount);
1da177e4 3332 if (nfserr == nfserr_isdir)
d3f627c8
BF
3333 nfserr = nfserr_inval;
3334 if (nfserr) {
1fcea5b2 3335 xdr_truncate_encode(xdr, length_offset);
1da177e4 3336 return nfserr;
d3f627c8 3337 }
1da177e4 3338
476a7b1f
BF
3339 wire_count = htonl(maxcount);
3340 write_bytes_to_xdr_buf(xdr->buf, length_offset, &wire_count, 4);
69bbd9c7 3341 xdr_truncate_encode(xdr, length_offset + 4 + ALIGN(maxcount, 4));
476a7b1f
BF
3342 if (maxcount & 3)
3343 write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount,
3344 &zero, 4 - (maxcount&3));
1da177e4
LT
3345 return 0;
3346}
3347
b37ad28b
AV
3348static __be32
3349nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readdir *readdir)
1da177e4
LT
3350{
3351 int maxcount;
561f0ed4 3352 int bytes_left;
1da177e4 3353 loff_t offset;
561f0ed4 3354 __be64 wire_offset;
ddd1ea56 3355 struct xdr_stream *xdr = &resp->xdr;
1fcea5b2 3356 int starting_len = xdr->buf->len;
bc749ca4 3357 __be32 *p;
1da177e4
LT
3358
3359 if (nfserr)
3360 return nfserr;
1da177e4 3361
d0a381dd
BF
3362 p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
3363 if (!p)
3364 return nfserr_resource;
1da177e4
LT
3365
3366 /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */
c373b0a4
BF
3367 *p++ = cpu_to_be32(0);
3368 *p++ = cpu_to_be32(0);
4aea24b2
BF
3369 resp->xdr.buf->head[0].iov_len = ((char *)resp->xdr.p)
3370 - (char *)resp->xdr.buf->head[0].iov_base;
1da177e4
LT
3371
3372 /*
561f0ed4
BF
3373 * Number of bytes left for directory entries allowing for the
3374 * final 8 bytes of the readdir and a following failed op:
3375 */
3376 bytes_left = xdr->buf->buflen - xdr->buf->len
3377 - COMPOUND_ERR_SLACK_SPACE - 8;
3378 if (bytes_left < 0) {
3379 nfserr = nfserr_resource;
3380 goto err_no_verf;
3381 }
3382 maxcount = min_t(u32, readdir->rd_maxcount, INT_MAX);
3383 /*
3384 * Note the rfc defines rd_maxcount as the size of the
3385 * READDIR4resok structure, which includes the verifier above
3386 * and the 8 bytes encoded at the end of this function:
1da177e4 3387 */
561f0ed4
BF
3388 if (maxcount < 16) {
3389 nfserr = nfserr_toosmall;
1da177e4
LT
3390 goto err_no_verf;
3391 }
561f0ed4 3392 maxcount = min_t(int, maxcount-16, bytes_left);
1da177e4 3393
aee37764
BF
3394 /* RFC 3530 14.2.24 allows us to ignore dircount when it's 0: */
3395 if (!readdir->rd_dircount)
3396 readdir->rd_dircount = INT_MAX;
3397
561f0ed4
BF
3398 readdir->xdr = xdr;
3399 readdir->rd_maxcount = maxcount;
1da177e4 3400 readdir->common.err = 0;
561f0ed4 3401 readdir->cookie_offset = 0;
1da177e4
LT
3402
3403 offset = readdir->rd_cookie;
3404 nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp,
3405 &offset,
3406 &readdir->common, nfsd4_encode_dirent);
3407 if (nfserr == nfs_ok &&
3408 readdir->common.err == nfserr_toosmall &&
561f0ed4
BF
3409 xdr->buf->len == starting_len + 8) {
3410 /* nothing encoded; which limit did we hit?: */
3411 if (maxcount - 16 < bytes_left)
3412 /* It was the fault of rd_maxcount: */
3413 nfserr = nfserr_toosmall;
3414 else
3415 /* We ran out of buffer space: */
3416 nfserr = nfserr_resource;
3417 }
1da177e4
LT
3418 if (nfserr)
3419 goto err_no_verf;
3420
561f0ed4
BF
3421 if (readdir->cookie_offset) {
3422 wire_offset = cpu_to_be64(offset);
3423 write_bytes_to_xdr_buf(xdr->buf, readdir->cookie_offset,
3424 &wire_offset, 8);
3425 }
1da177e4 3426
561f0ed4
BF
3427 p = xdr_reserve_space(xdr, 8);
3428 if (!p) {
3429 WARN_ON_ONCE(1);
3430 goto err_no_verf;
3431 }
1da177e4
LT
3432 *p++ = 0; /* no more entries */
3433 *p++ = htonl(readdir->common.err == nfserr_eof);
1da177e4
LT
3434
3435 return 0;
3436err_no_verf:
1fcea5b2 3437 xdr_truncate_encode(xdr, starting_len);
1da177e4
LT
3438 return nfserr;
3439}
3440
695e12f8 3441static __be32
b37ad28b 3442nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove)
1da177e4 3443{
d0a381dd 3444 struct xdr_stream *xdr = &resp->xdr;
bc749ca4 3445 __be32 *p;
1da177e4
LT
3446
3447 if (!nfserr) {
d0a381dd
BF
3448 p = xdr_reserve_space(xdr, 20);
3449 if (!p)
3450 return nfserr_resource;
d05d5744 3451 p = encode_cinfo(p, &remove->rm_cinfo);
1da177e4 3452 }
695e12f8 3453 return nfserr;
1da177e4
LT
3454}
3455
695e12f8 3456static __be32
b37ad28b 3457nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename)
1da177e4 3458{
d0a381dd 3459 struct xdr_stream *xdr = &resp->xdr;
bc749ca4 3460 __be32 *p;
1da177e4
LT
3461
3462 if (!nfserr) {
d0a381dd
BF
3463 p = xdr_reserve_space(xdr, 40);
3464 if (!p)
3465 return nfserr_resource;
d05d5744
BF
3466 p = encode_cinfo(p, &rename->rn_sinfo);
3467 p = encode_cinfo(p, &rename->rn_tinfo);
1da177e4 3468 }
695e12f8 3469 return nfserr;
1da177e4
LT
3470}
3471
695e12f8 3472static __be32
d0a381dd 3473nfsd4_do_encode_secinfo(struct xdr_stream *xdr,
a77c806f 3474 __be32 nfserr, struct svc_export *exp)
dcb488a3 3475{
676e4ebd 3476 u32 i, nflavs, supported;
4796f457
BF
3477 struct exp_flavor_info *flavs;
3478 struct exp_flavor_info def_flavs[2];
676e4ebd
CL
3479 __be32 *p, *flavorsp;
3480 static bool report = true;
dcb488a3
AA
3481
3482 if (nfserr)
3483 goto out;
d0a381dd 3484 nfserr = nfserr_resource;
4796f457
BF
3485 if (exp->ex_nflavors) {
3486 flavs = exp->ex_flavors;
3487 nflavs = exp->ex_nflavors;
3488 } else { /* Handling of some defaults in absence of real secinfo: */
3489 flavs = def_flavs;
3490 if (exp->ex_client->flavour->flavour == RPC_AUTH_UNIX) {
3491 nflavs = 2;
3492 flavs[0].pseudoflavor = RPC_AUTH_UNIX;
3493 flavs[1].pseudoflavor = RPC_AUTH_NULL;
3494 } else if (exp->ex_client->flavour->flavour == RPC_AUTH_GSS) {
3495 nflavs = 1;
3496 flavs[0].pseudoflavor
3497 = svcauth_gss_flavor(exp->ex_client);
3498 } else {
3499 nflavs = 1;
3500 flavs[0].pseudoflavor
3501 = exp->ex_client->flavour->flavour;
3502 }
3503 }
3504
676e4ebd 3505 supported = 0;
d0a381dd
BF
3506 p = xdr_reserve_space(xdr, 4);
3507 if (!p)
3508 goto out;
676e4ebd 3509 flavorsp = p++; /* to be backfilled later */
676e4ebd 3510
4796f457 3511 for (i = 0; i < nflavs; i++) {
676e4ebd 3512 rpc_authflavor_t pf = flavs[i].pseudoflavor;
a77c806f 3513 struct rpcsec_gss_info info;
dcb488a3 3514
676e4ebd
CL
3515 if (rpcauth_get_gssinfo(pf, &info) == 0) {
3516 supported++;
d0a381dd
BF
3517 p = xdr_reserve_space(xdr, 4 + 4 +
3518 XDR_LEN(info.oid.len) + 4 + 4);
3519 if (!p)
3520 goto out;
c373b0a4 3521 *p++ = cpu_to_be32(RPC_AUTH_GSS);
0c0c267b 3522 p = xdr_encode_opaque(p, info.oid.data, info.oid.len);
c373b0a4
BF
3523 *p++ = cpu_to_be32(info.qop);
3524 *p++ = cpu_to_be32(info.service);
676e4ebd
CL
3525 } else if (pf < RPC_AUTH_MAXFLAVOR) {
3526 supported++;
d0a381dd
BF
3527 p = xdr_reserve_space(xdr, 4);
3528 if (!p)
3529 goto out;
c373b0a4 3530 *p++ = cpu_to_be32(pf);
676e4ebd
CL
3531 } else {
3532 if (report)
3533 pr_warn("NFS: SECINFO: security flavor %u "
3534 "is not supported\n", pf);
dcb488a3
AA
3535 }
3536 }
a77c806f 3537
676e4ebd
CL
3538 if (nflavs != supported)
3539 report = false;
3540 *flavorsp = htonl(supported);
d0a381dd 3541 nfserr = 0;
dcb488a3
AA
3542out:
3543 if (exp)
3544 exp_put(exp);
695e12f8 3545 return nfserr;
dcb488a3
AA
3546}
3547
22b6dee8
MJ
3548static __be32
3549nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
3550 struct nfsd4_secinfo *secinfo)
3551{
d0a381dd
BF
3552 struct xdr_stream *xdr = &resp->xdr;
3553
3554 return nfsd4_do_encode_secinfo(xdr, nfserr, secinfo->si_exp);
22b6dee8
MJ
3555}
3556
3557static __be32
3558nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr,
3559 struct nfsd4_secinfo_no_name *secinfo)
3560{
d0a381dd
BF
3561 struct xdr_stream *xdr = &resp->xdr;
3562
3563 return nfsd4_do_encode_secinfo(xdr, nfserr, secinfo->sin_exp);
22b6dee8
MJ
3564}
3565
1da177e4
LT
3566/*
3567 * The SETATTR encode routine is special -- it always encodes a bitmap,
3568 * regardless of the error status.
3569 */
695e12f8 3570static __be32
b37ad28b 3571nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr)
1da177e4 3572{
d0a381dd 3573 struct xdr_stream *xdr = &resp->xdr;
bc749ca4 3574 __be32 *p;
1da177e4 3575
d0a381dd
BF
3576 p = xdr_reserve_space(xdr, 16);
3577 if (!p)
3578 return nfserr_resource;
1da177e4 3579 if (nfserr) {
c373b0a4
BF
3580 *p++ = cpu_to_be32(3);
3581 *p++ = cpu_to_be32(0);
3582 *p++ = cpu_to_be32(0);
3583 *p++ = cpu_to_be32(0);
1da177e4
LT
3584 }
3585 else {
c373b0a4
BF
3586 *p++ = cpu_to_be32(3);
3587 *p++ = cpu_to_be32(setattr->sa_bmval[0]);
3588 *p++ = cpu_to_be32(setattr->sa_bmval[1]);
3589 *p++ = cpu_to_be32(setattr->sa_bmval[2]);
1da177e4 3590 }
695e12f8 3591 return nfserr;
1da177e4
LT
3592}
3593
695e12f8 3594static __be32
b37ad28b 3595nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd)
1da177e4 3596{
d0a381dd 3597 struct xdr_stream *xdr = &resp->xdr;
bc749ca4 3598 __be32 *p;
1da177e4
LT
3599
3600 if (!nfserr) {
d0a381dd
BF
3601 p = xdr_reserve_space(xdr, 8 + NFS4_VERIFIER_SIZE);
3602 if (!p)
3603 return nfserr_resource;
0c0c267b
BF
3604 p = xdr_encode_opaque_fixed(p, &scd->se_clientid, 8);
3605 p = xdr_encode_opaque_fixed(p, &scd->se_confirm,
3606 NFS4_VERIFIER_SIZE);
1da177e4
LT
3607 }
3608 else if (nfserr == nfserr_clid_inuse) {
d0a381dd
BF
3609 p = xdr_reserve_space(xdr, 8);
3610 if (!p)
3611 return nfserr_resource;
c373b0a4
BF
3612 *p++ = cpu_to_be32(0);
3613 *p++ = cpu_to_be32(0);
1da177e4 3614 }
695e12f8 3615 return nfserr;
1da177e4
LT
3616}
3617
695e12f8 3618static __be32
b37ad28b 3619nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write)
1da177e4 3620{
d0a381dd 3621 struct xdr_stream *xdr = &resp->xdr;
bc749ca4 3622 __be32 *p;
1da177e4
LT
3623
3624 if (!nfserr) {
d0a381dd
BF
3625 p = xdr_reserve_space(xdr, 16);
3626 if (!p)
3627 return nfserr_resource;
c373b0a4
BF
3628 *p++ = cpu_to_be32(write->wr_bytes_written);
3629 *p++ = cpu_to_be32(write->wr_how_written);
0c0c267b
BF
3630 p = xdr_encode_opaque_fixed(p, write->wr_verifier.data,
3631 NFS4_VERIFIER_SIZE);
1da177e4 3632 }
695e12f8 3633 return nfserr;
1da177e4
LT
3634}
3635
57266a6e
BF
3636static const u32 nfs4_minimal_spo_must_enforce[2] = {
3637 [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
3638 1 << (OP_EXCHANGE_ID - 32) |
3639 1 << (OP_CREATE_SESSION - 32) |
3640 1 << (OP_DESTROY_SESSION - 32) |
3641 1 << (OP_DESTROY_CLIENTID - 32)
3642};
3643
2db134eb 3644static __be32
57b7b43b 3645nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
2db134eb
AA
3646 struct nfsd4_exchange_id *exid)
3647{
d0a381dd 3648 struct xdr_stream *xdr = &resp->xdr;
bc749ca4 3649 __be32 *p;
0733d213
AA
3650 char *major_id;
3651 char *server_scope;
3652 int major_id_sz;
3653 int server_scope_sz;
3654 uint64_t minor_id = 0;
3655
3656 if (nfserr)
3657 return nfserr;
3658
3659 major_id = utsname()->nodename;
3660 major_id_sz = strlen(major_id);
3661 server_scope = utsname()->nodename;
3662 server_scope_sz = strlen(server_scope);
3663
d0a381dd 3664 p = xdr_reserve_space(xdr,
0733d213
AA
3665 8 /* eir_clientid */ +
3666 4 /* eir_sequenceid */ +
3667 4 /* eir_flags */ +
a8bb84bc 3668 4 /* spr_how */);
d0a381dd
BF
3669 if (!p)
3670 return nfserr_resource;
0733d213 3671
0c0c267b 3672 p = xdr_encode_opaque_fixed(p, &exid->clientid, 8);
c373b0a4
BF
3673 *p++ = cpu_to_be32(exid->seqid);
3674 *p++ = cpu_to_be32(exid->flags);
0733d213 3675
c373b0a4 3676 *p++ = cpu_to_be32(exid->spa_how);
a8bb84bc 3677
57266a6e
BF
3678 switch (exid->spa_how) {
3679 case SP4_NONE:
3680 break;
3681 case SP4_MACH_CRED:
a8bb84bc 3682 /* spo_must_enforce, spo_must_allow */
d0a381dd
BF
3683 p = xdr_reserve_space(xdr, 16);
3684 if (!p)
3685 return nfserr_resource;
a8bb84bc 3686
57266a6e 3687 /* spo_must_enforce bitmap: */
c373b0a4
BF
3688 *p++ = cpu_to_be32(2);
3689 *p++ = cpu_to_be32(nfs4_minimal_spo_must_enforce[0]);
3690 *p++ = cpu_to_be32(nfs4_minimal_spo_must_enforce[1]);
57266a6e 3691 /* empty spo_must_allow bitmap: */
c373b0a4 3692 *p++ = cpu_to_be32(0);
a8bb84bc 3693
57266a6e
BF
3694 break;
3695 default:
3696 WARN_ON_ONCE(1);
3697 }
0733d213 3698
d0a381dd 3699 p = xdr_reserve_space(xdr,
a8bb84bc
KM
3700 8 /* so_minor_id */ +
3701 4 /* so_major_id.len */ +
3702 (XDR_QUADLEN(major_id_sz) * 4) +
3703 4 /* eir_server_scope.len */ +
3704 (XDR_QUADLEN(server_scope_sz) * 4) +
3705 4 /* eir_server_impl_id.count (0) */);
d0a381dd
BF
3706 if (!p)
3707 return nfserr_resource;
a8bb84bc 3708
0733d213 3709 /* The server_owner struct */
b64c7f3b 3710 p = xdr_encode_hyper(p, minor_id); /* Minor id */
0733d213 3711 /* major id */
0c0c267b 3712 p = xdr_encode_opaque(p, major_id, major_id_sz);
0733d213
AA
3713
3714 /* Server scope */
0c0c267b 3715 p = xdr_encode_opaque(p, server_scope, server_scope_sz);
0733d213
AA
3716
3717 /* Implementation id */
c373b0a4 3718 *p++ = cpu_to_be32(0); /* zero length nfs_impl_id4 array */
0733d213 3719 return 0;
2db134eb
AA
3720}
3721
3722static __be32
57b7b43b 3723nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr,
2db134eb
AA
3724 struct nfsd4_create_session *sess)
3725{
d0a381dd 3726 struct xdr_stream *xdr = &resp->xdr;
bc749ca4 3727 __be32 *p;
ec6b5d7b
AA
3728
3729 if (nfserr)
3730 return nfserr;
3731
d0a381dd
BF
3732 p = xdr_reserve_space(xdr, 24);
3733 if (!p)
3734 return nfserr_resource;
0c0c267b
BF
3735 p = xdr_encode_opaque_fixed(p, sess->sessionid.data,
3736 NFS4_MAX_SESSIONID_LEN);
c373b0a4
BF
3737 *p++ = cpu_to_be32(sess->seqid);
3738 *p++ = cpu_to_be32(sess->flags);
ec6b5d7b 3739
d0a381dd
BF
3740 p = xdr_reserve_space(xdr, 28);
3741 if (!p)
3742 return nfserr_resource;
c373b0a4
BF
3743 *p++ = cpu_to_be32(0); /* headerpadsz */
3744 *p++ = cpu_to_be32(sess->fore_channel.maxreq_sz);
3745 *p++ = cpu_to_be32(sess->fore_channel.maxresp_sz);
3746 *p++ = cpu_to_be32(sess->fore_channel.maxresp_cached);
3747 *p++ = cpu_to_be32(sess->fore_channel.maxops);
3748 *p++ = cpu_to_be32(sess->fore_channel.maxreqs);
3749 *p++ = cpu_to_be32(sess->fore_channel.nr_rdma_attrs);
ec6b5d7b
AA
3750
3751 if (sess->fore_channel.nr_rdma_attrs) {
d0a381dd
BF
3752 p = xdr_reserve_space(xdr, 4);
3753 if (!p)
3754 return nfserr_resource;
c373b0a4 3755 *p++ = cpu_to_be32(sess->fore_channel.rdma_attrs);
ec6b5d7b
AA
3756 }
3757
d0a381dd
BF
3758 p = xdr_reserve_space(xdr, 28);
3759 if (!p)
3760 return nfserr_resource;
c373b0a4
BF
3761 *p++ = cpu_to_be32(0); /* headerpadsz */
3762 *p++ = cpu_to_be32(sess->back_channel.maxreq_sz);
3763 *p++ = cpu_to_be32(sess->back_channel.maxresp_sz);
3764 *p++ = cpu_to_be32(sess->back_channel.maxresp_cached);
3765 *p++ = cpu_to_be32(sess->back_channel.maxops);
3766 *p++ = cpu_to_be32(sess->back_channel.maxreqs);
3767 *p++ = cpu_to_be32(sess->back_channel.nr_rdma_attrs);
ec6b5d7b
AA
3768
3769 if (sess->back_channel.nr_rdma_attrs) {
d0a381dd
BF
3770 p = xdr_reserve_space(xdr, 4);
3771 if (!p)
3772 return nfserr_resource;
c373b0a4 3773 *p++ = cpu_to_be32(sess->back_channel.rdma_attrs);
ec6b5d7b
AA
3774 }
3775 return 0;
2db134eb
AA
3776}
3777
c47d832b 3778static __be32
57b7b43b 3779nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr,
2db134eb
AA
3780 struct nfsd4_sequence *seq)
3781{
d0a381dd 3782 struct xdr_stream *xdr = &resp->xdr;
bc749ca4 3783 __be32 *p;
b85d4c01
BH
3784
3785 if (nfserr)
3786 return nfserr;
3787
d0a381dd
BF
3788 p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 20);
3789 if (!p)
3790 return nfserr_resource;
0c0c267b
BF
3791 p = xdr_encode_opaque_fixed(p, seq->sessionid.data,
3792 NFS4_MAX_SESSIONID_LEN);
c373b0a4
BF
3793 *p++ = cpu_to_be32(seq->seqid);
3794 *p++ = cpu_to_be32(seq->slotid);
b7d7ca35 3795 /* Note slotid's are numbered from zero: */
c373b0a4
BF
3796 *p++ = cpu_to_be32(seq->maxslots - 1); /* sr_highest_slotid */
3797 *p++ = cpu_to_be32(seq->maxslots - 1); /* sr_target_highest_slotid */
3798 *p++ = cpu_to_be32(seq->status_flags);
b85d4c01 3799
f5236013 3800 resp->cstate.data_offset = xdr->buf->len; /* DRC cache data pointer */
b85d4c01 3801 return 0;
2db134eb
AA
3802}
3803
2355c596 3804static __be32
57b7b43b 3805nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
17456804
BS
3806 struct nfsd4_test_stateid *test_stateid)
3807{
d0a381dd 3808 struct xdr_stream *xdr = &resp->xdr;
03cfb420 3809 struct nfsd4_test_stateid_id *stateid, *next;
17456804 3810 __be32 *p;
17456804 3811
a11fcce1
BF
3812 if (nfserr)
3813 return nfserr;
3814
d0a381dd
BF
3815 p = xdr_reserve_space(xdr, 4 + (4 * test_stateid->ts_num_ids));
3816 if (!p)
3817 return nfserr_resource;
17456804 3818 *p++ = htonl(test_stateid->ts_num_ids);
17456804 3819
03cfb420 3820 list_for_each_entry_safe(stateid, next, &test_stateid->ts_stateid_list, ts_id_list) {
02f5fde5 3821 *p++ = stateid->ts_id_status;
17456804 3822 }
17456804
BS
3823
3824 return nfserr;
3825}
3826
24bab491
AS
3827static __be32
3828nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr,
3829 struct nfsd4_seek *seek)
3830{
3831 __be32 *p;
3832
3833 if (nfserr)
3834 return nfserr;
3835
3836 p = xdr_reserve_space(&resp->xdr, 4 + 8);
3837 *p++ = cpu_to_be32(seek->seek_eof);
3838 p = xdr_encode_hyper(p, seek->seek_pos);
3839
3840 return nfserr;
3841}
3842
695e12f8
BH
3843static __be32
3844nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p)
3845{
3846 return nfserr;
3847}
3848
3849typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *);
3850
2db134eb
AA
3851/*
3852 * Note: nfsd4_enc_ops vector is shared for v4.0 and v4.1
3853 * since we don't need to filter out obsolete ops as this is
3854 * done in the decoding phase.
3855 */
695e12f8 3856static nfsd4_enc nfsd4_enc_ops[] = {
ad1060c8
BF
3857 [OP_ACCESS] = (nfsd4_enc)nfsd4_encode_access,
3858 [OP_CLOSE] = (nfsd4_enc)nfsd4_encode_close,
3859 [OP_COMMIT] = (nfsd4_enc)nfsd4_encode_commit,
3860 [OP_CREATE] = (nfsd4_enc)nfsd4_encode_create,
3861 [OP_DELEGPURGE] = (nfsd4_enc)nfsd4_encode_noop,
3862 [OP_DELEGRETURN] = (nfsd4_enc)nfsd4_encode_noop,
3863 [OP_GETATTR] = (nfsd4_enc)nfsd4_encode_getattr,
3864 [OP_GETFH] = (nfsd4_enc)nfsd4_encode_getfh,
3865 [OP_LINK] = (nfsd4_enc)nfsd4_encode_link,
3866 [OP_LOCK] = (nfsd4_enc)nfsd4_encode_lock,
3867 [OP_LOCKT] = (nfsd4_enc)nfsd4_encode_lockt,
3868 [OP_LOCKU] = (nfsd4_enc)nfsd4_encode_locku,
3869 [OP_LOOKUP] = (nfsd4_enc)nfsd4_encode_noop,
3870 [OP_LOOKUPP] = (nfsd4_enc)nfsd4_encode_noop,
3871 [OP_NVERIFY] = (nfsd4_enc)nfsd4_encode_noop,
3872 [OP_OPEN] = (nfsd4_enc)nfsd4_encode_open,
84f09f46 3873 [OP_OPENATTR] = (nfsd4_enc)nfsd4_encode_noop,
ad1060c8
BF
3874 [OP_OPEN_CONFIRM] = (nfsd4_enc)nfsd4_encode_open_confirm,
3875 [OP_OPEN_DOWNGRADE] = (nfsd4_enc)nfsd4_encode_open_downgrade,
3876 [OP_PUTFH] = (nfsd4_enc)nfsd4_encode_noop,
3877 [OP_PUTPUBFH] = (nfsd4_enc)nfsd4_encode_noop,
3878 [OP_PUTROOTFH] = (nfsd4_enc)nfsd4_encode_noop,
3879 [OP_READ] = (nfsd4_enc)nfsd4_encode_read,
3880 [OP_READDIR] = (nfsd4_enc)nfsd4_encode_readdir,
3881 [OP_READLINK] = (nfsd4_enc)nfsd4_encode_readlink,
3882 [OP_REMOVE] = (nfsd4_enc)nfsd4_encode_remove,
3883 [OP_RENAME] = (nfsd4_enc)nfsd4_encode_rename,
3884 [OP_RENEW] = (nfsd4_enc)nfsd4_encode_noop,
3885 [OP_RESTOREFH] = (nfsd4_enc)nfsd4_encode_noop,
3886 [OP_SAVEFH] = (nfsd4_enc)nfsd4_encode_noop,
3887 [OP_SECINFO] = (nfsd4_enc)nfsd4_encode_secinfo,
3888 [OP_SETATTR] = (nfsd4_enc)nfsd4_encode_setattr,
3889 [OP_SETCLIENTID] = (nfsd4_enc)nfsd4_encode_setclientid,
3890 [OP_SETCLIENTID_CONFIRM] = (nfsd4_enc)nfsd4_encode_noop,
3891 [OP_VERIFY] = (nfsd4_enc)nfsd4_encode_noop,
3892 [OP_WRITE] = (nfsd4_enc)nfsd4_encode_write,
3893 [OP_RELEASE_LOCKOWNER] = (nfsd4_enc)nfsd4_encode_noop,
2db134eb
AA
3894
3895 /* NFSv4.1 operations */
3896 [OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop,
1d1bc8f2 3897 [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session,
2db134eb
AA
3898 [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id,
3899 [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session,
43212cc7
KM
3900 [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_noop,
3901 [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_noop,
2db134eb
AA
3902 [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop,
3903 [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop,
3904 [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop,
3905 [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop,
3906 [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop,
3907 [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop,
22b6dee8 3908 [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name,
2db134eb
AA
3909 [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence,
3910 [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop,
17456804 3911 [OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_test_stateid,
2db134eb
AA
3912 [OP_WANT_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop,
3913 [OP_DESTROY_CLIENTID] = (nfsd4_enc)nfsd4_encode_noop,
3914 [OP_RECLAIM_COMPLETE] = (nfsd4_enc)nfsd4_encode_noop,
87a15a80
AS
3915
3916 /* NFSv4.2 operations */
3917 [OP_ALLOCATE] = (nfsd4_enc)nfsd4_encode_noop,
3918 [OP_COPY] = (nfsd4_enc)nfsd4_encode_noop,
3919 [OP_COPY_NOTIFY] = (nfsd4_enc)nfsd4_encode_noop,
3920 [OP_DEALLOCATE] = (nfsd4_enc)nfsd4_encode_noop,
3921 [OP_IO_ADVISE] = (nfsd4_enc)nfsd4_encode_noop,
3922 [OP_LAYOUTERROR] = (nfsd4_enc)nfsd4_encode_noop,
3923 [OP_LAYOUTSTATS] = (nfsd4_enc)nfsd4_encode_noop,
3924 [OP_OFFLOAD_CANCEL] = (nfsd4_enc)nfsd4_encode_noop,
3925 [OP_OFFLOAD_STATUS] = (nfsd4_enc)nfsd4_encode_noop,
3926 [OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_noop,
24bab491 3927 [OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek,
87a15a80 3928 [OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop,
695e12f8
BH
3929};
3930
496c262c 3931/*
a8095f7e
BF
3932 * Calculate whether we still have space to encode repsize bytes.
3933 * There are two considerations:
3934 * - For NFS versions >=4.1, the size of the reply must stay within
3935 * session limits
3936 * - For all NFS versions, we must stay within limited preallocated
3937 * buffer space.
496c262c 3938 *
a8095f7e
BF
3939 * This is called before the operation is processed, so can only provide
3940 * an upper estimate. For some nonidempotent operations (such as
3941 * getattr), it's not necessarily a problem if that estimate is wrong,
3942 * as we can fail it after processing without significant side effects.
496c262c 3943 */
a8095f7e 3944__be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 respsize)
496c262c 3945{
67492c99 3946 struct xdr_buf *buf = &resp->rqstp->rq_res;
47ee5298 3947 struct nfsd4_slot *slot = resp->cstate.slot;
496c262c 3948
47ee5298
BF
3949 if (buf->len + respsize <= buf->buflen)
3950 return nfs_ok;
3951 if (!nfsd4_has_session(&resp->cstate))
ea8d7720 3952 return nfserr_resource;
47ee5298
BF
3953 if (slot->sl_flags & NFSD4_SLOT_CACHETHIS) {
3954 WARN_ON_ONCE(1);
3955 return nfserr_rep_too_big_to_cache;
ea8d7720 3956 }
47ee5298 3957 return nfserr_rep_too_big;
496c262c
AA
3958}
3959
1da177e4
LT
3960void
3961nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
3962{
082d4bd7 3963 struct xdr_stream *xdr = &resp->xdr;
9411b1d4 3964 struct nfs4_stateowner *so = resp->cstate.replay_owner;
5f4ab945 3965 struct svc_rqst *rqstp = resp->rqstp;
082d4bd7 3966 int post_err_offset;
07d1f802 3967 nfsd4_enc encoder;
bc749ca4 3968 __be32 *p;
1da177e4 3969
d0a381dd
BF
3970 p = xdr_reserve_space(xdr, 8);
3971 if (!p) {
3972 WARN_ON_ONCE(1);
3973 return;
3974 }
c373b0a4 3975 *p++ = cpu_to_be32(op->opnum);
082d4bd7 3976 post_err_offset = xdr->buf->len;
1da177e4 3977
695e12f8
BH
3978 if (op->opnum == OP_ILLEGAL)
3979 goto status;
3980 BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) ||
3981 !nfsd4_enc_ops[op->opnum]);
07d1f802
BF
3982 encoder = nfsd4_enc_ops[op->opnum];
3983 op->status = encoder(resp, op->status, &op->u);
2825a7f9
BF
3984 xdr_commit_encode(xdr);
3985
067e1ace 3986 /* nfsd4_check_resp_size guarantees enough room for error status */
5f4ab945
BF
3987 if (!op->status) {
3988 int space_needed = 0;
3989 if (!nfsd4_last_compound_op(rqstp))
3990 space_needed = COMPOUND_ERR_SLACK_SPACE;
3991 op->status = nfsd4_check_resp_size(resp, space_needed);
3992 }
c8f13d97
BF
3993 if (op->status == nfserr_resource && nfsd4_has_session(&resp->cstate)) {
3994 struct nfsd4_slot *slot = resp->cstate.slot;
3995
3996 if (slot->sl_flags & NFSD4_SLOT_CACHETHIS)
3997 op->status = nfserr_rep_too_big_to_cache;
3998 else
3999 op->status = nfserr_rep_too_big;
4000 }
07d1f802
BF
4001 if (op->status == nfserr_resource ||
4002 op->status == nfserr_rep_too_big ||
4003 op->status == nfserr_rep_too_big_to_cache) {
4004 /*
4005 * The operation may have already been encoded or
4006 * partially encoded. No op returns anything additional
4007 * in the case of one of these three errors, so we can
4008 * just truncate back to after the status. But it's a
4009 * bug if we had to do this on a non-idempotent op:
4010 */
4011 warn_on_nonidempotent_op(op);
082d4bd7 4012 xdr_truncate_encode(xdr, post_err_offset);
07d1f802 4013 }
9411b1d4 4014 if (so) {
082d4bd7
BF
4015 int len = xdr->buf->len - post_err_offset;
4016
9411b1d4 4017 so->so_replay.rp_status = op->status;
082d4bd7
BF
4018 so->so_replay.rp_buflen = len;
4019 read_bytes_from_xdr_buf(xdr->buf, post_err_offset,
4020 so->so_replay.rp_buf, len);
9411b1d4 4021 }
695e12f8 4022status:
082d4bd7
BF
4023 /* Note that op->status is already in network byte order: */
4024 write_bytes_to_xdr_buf(xdr->buf, post_err_offset - 4, &op->status, 4);
1da177e4
LT
4025}
4026
4027/*
4028 * Encode the reply stored in the stateowner reply cache
4029 *
4030 * XDR note: do not encode rp->rp_buflen: the buffer contains the
4031 * previously sent already encoded operation.
1da177e4
LT
4032 */
4033void
d0a381dd 4034nfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op)
1da177e4 4035{
bc749ca4 4036 __be32 *p;
1da177e4
LT
4037 struct nfs4_replay *rp = op->replay;
4038
4039 BUG_ON(!rp);
4040
d0a381dd
BF
4041 p = xdr_reserve_space(xdr, 8 + rp->rp_buflen);
4042 if (!p) {
4043 WARN_ON_ONCE(1);
4044 return;
4045 }
c373b0a4 4046 *p++ = cpu_to_be32(op->opnum);
1da177e4 4047 *p++ = rp->rp_status; /* already xdr'ed */
1da177e4 4048
0c0c267b 4049 p = xdr_encode_opaque_fixed(p, rp->rp_buf, rp->rp_buflen);
1da177e4
LT
4050}
4051
1da177e4 4052int
2ebbc012 4053nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
1da177e4
LT
4054{
4055 return xdr_ressize_check(rqstp, p);
4056}
4057
3e98abff 4058int nfsd4_release_compoundargs(void *rq, __be32 *p, void *resp)
1da177e4 4059{
3e98abff
BF
4060 struct svc_rqst *rqstp = rq;
4061 struct nfsd4_compoundargs *args = rqstp->rq_argp;
4062
1da177e4
LT
4063 if (args->ops != args->iops) {
4064 kfree(args->ops);
4065 args->ops = args->iops;
4066 }
f99d49ad
JJ
4067 kfree(args->tmpp);
4068 args->tmpp = NULL;
1da177e4 4069 while (args->to_free) {
d5e23383 4070 struct svcxdr_tmpbuf *tb = args->to_free;
1da177e4 4071 args->to_free = tb->next;
1da177e4
LT
4072 kfree(tb);
4073 }
3e98abff 4074 return 1;
1da177e4
LT
4075}
4076
4077int
2ebbc012 4078nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args)
1da177e4 4079{
e874f9f8
JL
4080 if (rqstp->rq_arg.head[0].iov_len % 4) {
4081 /* client is nuts */
4082 dprintk("%s: compound not properly padded! (peeraddr=%pISc xid=0x%x)",
4083 __func__, svc_addr(rqstp), be32_to_cpu(rqstp->rq_xid));
4084 return 0;
4085 }
1da177e4
LT
4086 args->p = p;
4087 args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len;
4088 args->pagelist = rqstp->rq_arg.pages;
4089 args->pagelen = rqstp->rq_arg.page_len;
4090 args->tmpp = NULL;
4091 args->to_free = NULL;
4092 args->ops = args->iops;
4093 args->rqstp = rqstp;
4094
3e98abff 4095 return !nfsd4_decode_compound(args);
1da177e4
LT
4096}
4097
4098int
2ebbc012 4099nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundres *resp)
1da177e4
LT
4100{
4101 /*
4102 * All that remains is to write the tag and operation count...
4103 */
6ac90391
BF
4104 struct xdr_buf *buf = resp->xdr.buf;
4105
4106 WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len +
4107 buf->tail[0].iov_len);
dd97fdde 4108
2825a7f9
BF
4109 rqstp->rq_next_page = resp->xdr.page_ptr + 1;
4110
1da177e4
LT
4111 p = resp->tagp;
4112 *p++ = htonl(resp->taglen);
4113 memcpy(p, resp->tag, resp->taglen);
4114 p += XDR_QUADLEN(resp->taglen);
4115 *p++ = htonl(resp->opcnt);
4116
b607664e 4117 nfsd4_sequence_done(resp);
1da177e4
LT
4118 return 1;
4119}
4120
4121/*
4122 * Local variables:
4123 * c-basic-offset: 8
4124 * End:
4125 */