blob: a7ee5c79ff944b3ced62ef4be80e28a4c5ca545a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * 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.
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 */
35
Christoph Hellwig96bcad52015-06-18 16:45:01 +020036#include <linux/file.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090037#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/namei.h>
Boaz Harrosh341eb182009-12-03 20:29:12 +020039#include <linux/statfs.h>
Andy Adamson0733d212009-04-03 08:28:01 +030040#include <linux/utsname.h>
Bryan Schumaker17456802011-07-13 10:50:48 -040041#include <linux/pagemap.h>
J. Bruce Fields4796f452007-07-17 04:04:51 -070042#include <linux/sunrpc/svcauth_gss.h>
Olga Kornievskaia84e1b212019-09-13 14:00:57 -040043#include <linux/sunrpc/addr.h>
Frank van der Linden23e50fe2020-06-23 22:39:26 +000044#include <linux/xattr.h>
45#include <uapi/linux/xattr.h>
Boaz Harrosh9a74af22009-12-03 20:30:56 +020046
J. Bruce Fields2ca72e12011-01-04 17:37:15 -050047#include "idmap.h"
48#include "acl.h"
Boaz Harrosh9a74af22009-12-03 20:30:56 +020049#include "xdr4.h"
J. Bruce Fields0a3adad2009-11-04 18:12:35 -050050#include "vfs.h"
Bryan Schumaker17456802011-07-13 10:50:48 -040051#include "state.h"
J. Bruce Fields10910062011-01-24 12:11:02 -050052#include "cache.h"
Stanislav Kinsbursky3d733712012-11-27 14:11:44 +030053#include "netns.h"
Christoph Hellwig9cf514c2014-05-05 13:11:59 +020054#include "pnfs.h"
Jeff Layton5c4583b2019-08-18 14:18:54 -040055#include "filecache.h"
J. Bruce Fields2ca72e12011-01-04 17:37:15 -050056
Chuck Lever08281342020-11-21 11:36:42 -050057#include "trace.h"
58
David Quigley18032ca2013-05-02 13:19:10 -040059#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
60#include <linux/security.h>
61#endif
62
63
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#define NFSDDBG_FACILITY NFSDDBG_XDR
65
J. Bruce Fields5cf23db2017-01-11 20:40:36 -050066const u32 nfsd_suppattrs[3][3] = {
J. Bruce Fields916d2d82016-10-18 14:18:40 -040067 {NFSD4_SUPPORTED_ATTRS_WORD0,
68 NFSD4_SUPPORTED_ATTRS_WORD1,
69 NFSD4_SUPPORTED_ATTRS_WORD2},
70
71 {NFSD4_1_SUPPORTED_ATTRS_WORD0,
72 NFSD4_1_SUPPORTED_ATTRS_WORD1,
73 NFSD4_1_SUPPORTED_ATTRS_WORD2},
74
75 {NFSD4_1_SUPPORTED_ATTRS_WORD0,
76 NFSD4_1_SUPPORTED_ATTRS_WORD1,
77 NFSD4_2_SUPPORTED_ATTRS_WORD2},
78};
79
J.Bruce Fields42ca0992006-10-04 02:16:20 -070080/*
81 * As per referral draft, the fsid for a referral MUST be different from the fsid of the containing
82 * directory in order to indicate to the client that a filesystem boundary is present
83 * We use a fixed fsid for a referral
84 */
85#define NFS4_REFERRAL_FSID_MAJOR 0x8000000ULL
86#define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL
87
Al Virob37ad282006-10-19 23:28:59 -070088static __be32
J. Bruce Fieldsa36b1722012-11-25 16:31:00 -050089check_filename(char *str, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -070090{
91 int i;
92
93 if (len == 0)
94 return nfserr_inval;
Chuck Lever000dfa12020-11-03 13:24:10 -050095 if (len > NFS4_MAXNAMLEN)
96 return nfserr_nametoolong;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 if (isdotent(str, len))
J. Bruce Fieldsa36b1722012-11-25 16:31:00 -050098 return nfserr_badname;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 for (i = 0; i < len; i++)
100 if (str[i] == '/')
J. Bruce Fieldsa36b1722012-11-25 16:31:00 -0500101 return nfserr_badname;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 return 0;
103}
104
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105#define DECODE_HEAD \
Al Viro2ebbc012006-10-19 23:28:58 -0700106 __be32 *p; \
Al Virob37ad282006-10-19 23:28:59 -0700107 __be32 status
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108#define DECODE_TAIL \
109 status = 0; \
110out: \
111 return status; \
112xdr_error: \
Chuck Lever817cb9d2007-09-11 18:01:20 -0400113 dprintk("NFSD: xdr error (%s:%d)\n", \
114 __FILE__, __LINE__); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 status = nfserr_bad_xdr; \
116 goto out
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118#define READMEM(x,nbytes) do { \
119 x = (char *)p; \
120 p += XDR_QUADLEN(nbytes); \
121} while (0)
122#define SAVEMEM(x,nbytes) do { \
123 if (!(x = (p==argp->tmp || p == argp->tmpp) ? \
124 savemem(argp, p, nbytes) : \
125 (char *)p)) { \
Chuck Lever817cb9d2007-09-11 18:01:20 -0400126 dprintk("NFSD: xdr error (%s:%d)\n", \
127 __FILE__, __LINE__); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 goto xdr_error; \
129 } \
130 p += XDR_QUADLEN(nbytes); \
131} while (0)
132#define COPYMEM(x,nbytes) do { \
133 memcpy((x), p, nbytes); \
134 p += XDR_QUADLEN(nbytes); \
135} while (0)
Chuck Leverc1346a122020-11-03 11:54:23 -0500136#define READ_BUF(nbytes) \
137 do { \
138 p = xdr_inline_decode(argp->xdr,\
139 nbytes); \
140 if (!p) \
141 goto xdr_error; \
142 } while (0)
J. Bruce Fields2b86e3a2019-08-28 21:13:45 -0400143
Andy Adamson60adfc52009-04-03 08:28:50 +0300144static int zero_clientid(clientid_t *clid)
145{
146 return (clid->cl_boot == 0) && (clid->cl_id == 0);
147}
148
Christoph Hellwig2d8498d2013-11-20 00:24:11 -0800149/**
J. Bruce Fieldsd5e23382014-06-24 17:43:45 -0400150 * svcxdr_tmpalloc - allocate memory to be freed after compound processing
J. Bruce Fieldsce043ac2014-06-24 16:51:12 -0400151 * @argp: NFSv4 compound argument structure
Trond Myklebusted992752019-08-18 14:18:59 -0400152 * @len: length of buffer to allocate
Christoph Hellwig2d8498d2013-11-20 00:24:11 -0800153 *
Trond Myklebusted992752019-08-18 14:18:59 -0400154 * Allocates a buffer of size @len to be freed when processing the compound
155 * operation described in @argp finishes.
Christoph Hellwig2d8498d2013-11-20 00:24:11 -0800156 */
J. Bruce Fieldsd5e23382014-06-24 17:43:45 -0400157static void *
158svcxdr_tmpalloc(struct nfsd4_compoundargs *argp, u32 len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159{
J. Bruce Fieldsd5e23382014-06-24 17:43:45 -0400160 struct svcxdr_tmpbuf *tb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161
J. Bruce Fieldsd5e23382014-06-24 17:43:45 -0400162 tb = kmalloc(sizeof(*tb) + len, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 if (!tb)
J. Bruce Fieldsd5e23382014-06-24 17:43:45 -0400164 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 tb->next = argp->to_free;
166 argp->to_free = tb;
J. Bruce Fieldsd5e23382014-06-24 17:43:45 -0400167 return tb->buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168}
169
J. Bruce Fields29c353b2014-06-24 17:06:51 -0400170/*
171 * For xdr strings that need to be passed to other kernel api's
172 * as null-terminated strings.
173 *
174 * Note null-terminating in place usually isn't safe since the
175 * buffer might end on a page boundary.
176 */
177static char *
178svcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, u32 len)
179{
J. Bruce Fieldsd5e23382014-06-24 17:43:45 -0400180 char *p = svcxdr_tmpalloc(argp, len + 1);
J. Bruce Fields29c353b2014-06-24 17:06:51 -0400181
182 if (!p)
183 return NULL;
184 memcpy(p, buf, len);
185 p[len] = '\0';
J. Bruce Fields29c353b2014-06-24 17:06:51 -0400186 return p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187}
188
Christoph Hellwig2d8498d2013-11-20 00:24:11 -0800189/**
190 * savemem - duplicate a chunk of memory for later processing
191 * @argp: NFSv4 compound argument structure to be freed with
192 * @p: pointer to be duplicated
193 * @nbytes: length to be duplicated
194 *
195 * Returns a pointer to a copy of @nbytes bytes of memory at @p
196 * that are preserved until processing of the NFSv4 compound
197 * operation described by @argp finishes.
198 */
Al Viro2ebbc012006-10-19 23:28:58 -0700199static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200{
J. Bruce Fieldsd5e23382014-06-24 17:43:45 -0400201 void *ret;
202
203 ret = svcxdr_tmpalloc(argp, nbytes);
204 if (!ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 return NULL;
J. Bruce Fieldsd5e23382014-06-24 17:43:45 -0400206 memcpy(ret, p, nbytes);
207 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208}
209
Chuck Lever5dcbfab2020-11-04 11:41:55 -0500210
211/*
212 * NFSv4 basic data type decoders
213 */
214
215static __be32
216nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o)
217{
218 __be32 *p;
219 u32 len;
220
221 if (xdr_stream_decode_u32(argp->xdr, &len) < 0)
222 return nfserr_bad_xdr;
223 if (len == 0 || len > NFS4_OPAQUE_LIMIT)
224 return nfserr_bad_xdr;
225 p = xdr_inline_decode(argp->xdr, len);
226 if (!p)
227 return nfserr_bad_xdr;
228 o->data = svcxdr_tmpalloc(argp, len);
229 if (!o->data)
230 return nfserr_jukebox;
231 o->len = len;
232 memcpy(o->data, p, len);
233
234 return nfs_ok;
235}
236
Christoph Hellwig4c94e132015-01-22 12:09:50 +0100237static __be32
Chuck Lever000dfa12020-11-03 13:24:10 -0500238nfsd4_decode_component4(struct nfsd4_compoundargs *argp, char **namp, u32 *lenp)
239{
240 __be32 *p, status;
241
242 if (xdr_stream_decode_u32(argp->xdr, lenp) < 0)
243 return nfserr_bad_xdr;
244 p = xdr_inline_decode(argp->xdr, *lenp);
245 if (!p)
246 return nfserr_bad_xdr;
247 status = check_filename((char *)p, *lenp);
248 if (status)
249 return status;
250 *namp = svcxdr_tmpalloc(argp, *lenp);
251 if (!*namp)
252 return nfserr_jukebox;
253 memcpy(*namp, p, *lenp);
254
255 return nfs_ok;
256}
257
258static __be32
J. Bruce Fieldsbdba5362019-06-05 14:17:42 -0400259nfsd4_decode_time(struct nfsd4_compoundargs *argp, struct timespec64 *tv)
Christoph Hellwig4c94e132015-01-22 12:09:50 +0100260{
261 DECODE_HEAD;
Christoph Hellwig4c94e132015-01-22 12:09:50 +0100262
263 READ_BUF(12);
J. Bruce Fieldsbdba5362019-06-05 14:17:42 -0400264 p = xdr_decode_hyper(p, &tv->tv_sec);
Christoph Hellwig4c94e132015-01-22 12:09:50 +0100265 tv->tv_nsec = be32_to_cpup(p++);
266 if (tv->tv_nsec >= (u32)1000000000)
267 return nfserr_inval;
268
269 DECODE_TAIL;
270}
271
Al Virob37ad282006-10-19 23:28:59 -0700272static __be32
Chuck Lever1c3eff72020-11-19 14:01:08 -0500273nfsd4_decode_nfstime4(struct nfsd4_compoundargs *argp, struct timespec64 *tv)
274{
275 __be32 *p;
276
277 p = xdr_inline_decode(argp->xdr, XDR_UNIT * 3);
278 if (!p)
279 return nfserr_bad_xdr;
280 p = xdr_decode_hyper(p, &tv->tv_sec);
281 tv->tv_nsec = be32_to_cpup(p++);
282 if (tv->tv_nsec >= (u32)1000000000)
283 return nfserr_inval;
284 return nfs_ok;
285}
286
287static __be32
Chuck Lever796dd1c2020-11-16 17:34:01 -0500288nfsd4_decode_verifier4(struct nfsd4_compoundargs *argp, nfs4_verifier *verf)
289{
290 __be32 *p;
291
292 p = xdr_inline_decode(argp->xdr, NFS4_VERIFIER_SIZE);
293 if (!p)
294 return nfserr_bad_xdr;
295 memcpy(verf->data, p, sizeof(verf->data));
296 return nfs_ok;
297}
298
299static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
301{
302 u32 bmlen;
303 DECODE_HEAD;
304
305 bmval[0] = 0;
306 bmval[1] = 0;
Andy Adamson7e705702009-04-03 08:29:11 +0300307 bmval[2] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
309 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -0400310 bmlen = be32_to_cpup(p++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 if (bmlen > 1000)
312 goto xdr_error;
313
314 READ_BUF(bmlen << 2);
315 if (bmlen > 0)
J. Bruce Fields06553992014-06-02 12:32:51 -0400316 bmval[0] = be32_to_cpup(p++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 if (bmlen > 1)
J. Bruce Fields06553992014-06-02 12:32:51 -0400318 bmval[1] = be32_to_cpup(p++);
Andy Adamson7e705702009-04-03 08:29:11 +0300319 if (bmlen > 2)
J. Bruce Fields06553992014-06-02 12:32:51 -0400320 bmval[2] = be32_to_cpup(p++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322 DECODE_TAIL;
323}
324
Chuck Leverd1c263a2020-11-03 12:56:05 -0500325/**
326 * nfsd4_decode_bitmap4 - Decode an NFSv4 bitmap4
327 * @argp: NFSv4 compound argument structure
328 * @bmval: pointer to an array of u32's to decode into
329 * @bmlen: size of the @bmval array
330 *
331 * The server needs to return nfs_ok rather than nfserr_bad_xdr when
332 * encountering bitmaps containing bits it does not recognize. This
333 * includes bits in bitmap words past WORDn, where WORDn is the last
334 * bitmap WORD the implementation currently supports. Thus we are
335 * careful here to simply ignore bits in bitmap words that this
336 * implementation has yet to support explicitly.
337 *
338 * Return values:
339 * %nfs_ok: @bmval populated successfully
340 * %nfserr_bad_xdr: the encoded bitmap was invalid
341 */
342static __be32
343nfsd4_decode_bitmap4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen)
344{
345 u32 i, count;
346 __be32 *p;
347
348 if (xdr_stream_decode_u32(argp->xdr, &count) < 0)
349 return nfserr_bad_xdr;
350 /* request sanity */
351 if (count > 1000)
352 return nfserr_bad_xdr;
353 p = xdr_inline_decode(argp->xdr, count << 2);
354 if (!p)
355 return nfserr_bad_xdr;
356 i = 0;
357 while (i < count)
358 bmval[i++] = be32_to_cpup(p++);
359 while (i < bmlen)
360 bmval[i++] = 0;
361
362 return nfs_ok;
363}
364
Al Virob37ad282006-10-19 23:28:59 -0700365static __be32
Chuck Leverc941a962020-11-19 13:02:54 -0500366nfsd4_decode_nfsace4(struct nfsd4_compoundargs *argp, struct nfs4_ace *ace)
367{
368 __be32 *p, status;
369 u32 length;
370
371 if (xdr_stream_decode_u32(argp->xdr, &ace->type) < 0)
372 return nfserr_bad_xdr;
373 if (xdr_stream_decode_u32(argp->xdr, &ace->flag) < 0)
374 return nfserr_bad_xdr;
375 if (xdr_stream_decode_u32(argp->xdr, &ace->access_mask) < 0)
376 return nfserr_bad_xdr;
377
378 if (xdr_stream_decode_u32(argp->xdr, &length) < 0)
379 return nfserr_bad_xdr;
380 p = xdr_inline_decode(argp->xdr, length);
381 if (!p)
382 return nfserr_bad_xdr;
383 ace->whotype = nfs4_acl_get_whotype((char *)p, length);
384 if (ace->whotype != NFS4_ACL_WHO_NAMED)
385 status = nfs_ok;
386 else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
387 status = nfsd_map_name_to_gid(argp->rqstp,
388 (char *)p, length, &ace->who_gid);
389 else
390 status = nfsd_map_name_to_uid(argp->rqstp,
391 (char *)p, length, &ace->who_uid);
392
393 return status;
394}
395
396/* A counted array of nfsace4's */
397static noinline __be32
398nfsd4_decode_acl(struct nfsd4_compoundargs *argp, struct nfs4_acl **acl)
399{
400 struct nfs4_ace *ace;
401 __be32 status;
402 u32 count;
403
404 if (xdr_stream_decode_u32(argp->xdr, &count) < 0)
405 return nfserr_bad_xdr;
406
407 if (count > xdr_stream_remaining(argp->xdr) / 20)
408 /*
409 * Even with 4-byte names there wouldn't be
410 * space for that many aces; something fishy is
411 * going on:
412 */
413 return nfserr_fbig;
414
415 *acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(count));
416 if (*acl == NULL)
417 return nfserr_jukebox;
418
419 (*acl)->naces = count;
420 for (ace = (*acl)->aces; ace < (*acl)->aces + count; ace++) {
421 status = nfsd4_decode_nfsace4(argp, ace);
422 if (status)
423 return status;
424 }
425
426 return nfs_ok;
427}
428
Chuck Leverdabe9182020-11-19 14:05:51 -0500429static noinline __be32
430nfsd4_decode_security_label(struct nfsd4_compoundargs *argp,
431 struct xdr_netobj *label)
432{
433 u32 lfs, pi, length;
434 __be32 *p;
435
436 if (xdr_stream_decode_u32(argp->xdr, &lfs) < 0)
437 return nfserr_bad_xdr;
438 if (xdr_stream_decode_u32(argp->xdr, &pi) < 0)
439 return nfserr_bad_xdr;
440
441 if (xdr_stream_decode_u32(argp->xdr, &length) < 0)
442 return nfserr_bad_xdr;
443 if (length > NFS4_MAXLABELLEN)
444 return nfserr_badlabel;
445 p = xdr_inline_decode(argp->xdr, length);
446 if (!p)
447 return nfserr_bad_xdr;
448 label->len = length;
449 label->data = svcxdr_dupstr(argp, p, length);
450 if (!label->data)
451 return nfserr_jukebox;
452
453 return nfs_ok;
454}
455
Chuck Leverc941a962020-11-19 13:02:54 -0500456static __be32
Chuck Leverd1c263a2020-11-03 12:56:05 -0500457nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen,
458 struct iattr *iattr, struct nfs4_acl **acl,
459 struct xdr_netobj *label, int *umask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460{
Chuck Lever081d53f2020-11-19 13:09:13 -0500461 unsigned int starting_pos;
462 u32 attrlist4_count;
Chuck Leverd1c263a2020-11-03 12:56:05 -0500463 __be32 *p, status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 iattr->ia_valid = 0;
Chuck Leverd1c263a2020-11-03 12:56:05 -0500466 status = nfsd4_decode_bitmap4(argp, bmval, bmlen);
467 if (status)
468 return nfserr_bad_xdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
J. Bruce Fieldse864c182016-06-10 16:56:05 -0400470 if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0
471 || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1
472 || bmval[2] & ~NFSD_WRITEABLE_ATTRS_WORD2) {
473 if (nfsd_attrs_supported(argp->minorversion, bmval))
474 return nfserr_inval;
475 return nfserr_attrnotsupp;
476 }
477
Chuck Lever081d53f2020-11-19 13:09:13 -0500478 if (xdr_stream_decode_u32(argp->xdr, &attrlist4_count) < 0)
479 return nfserr_bad_xdr;
480 starting_pos = xdr_stream_pos(argp->xdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
482 if (bmval[0] & FATTR4_WORD0_SIZE) {
Chuck Lever2ac1b9b2020-11-19 13:47:16 -0500483 u64 size;
484
485 if (xdr_stream_decode_u64(argp->xdr, &size) < 0)
486 return nfserr_bad_xdr;
487 iattr->ia_size = size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 iattr->ia_valid |= ATTR_SIZE;
489 }
490 if (bmval[0] & FATTR4_WORD0_ACL) {
Chuck Leverc941a962020-11-19 13:02:54 -0500491 status = nfsd4_decode_acl(argp, acl);
492 if (status)
493 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 } else
495 *acl = NULL;
496 if (bmval[1] & FATTR4_WORD1_MODE) {
Chuck Lever1c8f0ad2020-11-19 13:54:26 -0500497 u32 mode;
498
499 if (xdr_stream_decode_u32(argp->xdr, &mode) < 0)
500 return nfserr_bad_xdr;
501 iattr->ia_mode = mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 iattr->ia_mode &= (S_IFMT | S_IALLUGO);
503 iattr->ia_valid |= ATTR_MODE;
504 }
505 if (bmval[1] & FATTR4_WORD1_OWNER) {
Chuck Lever9853a5a2020-11-19 13:56:42 -0500506 u32 length;
507
508 if (xdr_stream_decode_u32(argp->xdr, &length) < 0)
509 return nfserr_bad_xdr;
510 p = xdr_inline_decode(argp->xdr, length);
511 if (!p)
512 return nfserr_bad_xdr;
513 status = nfsd_map_name_to_uid(argp->rqstp, (char *)p, length,
514 &iattr->ia_uid);
515 if (status)
NeilBrown47c85292011-02-16 13:08:35 +1100516 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 iattr->ia_valid |= ATTR_UID;
518 }
519 if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) {
Chuck Lever393c31d2020-11-19 13:58:18 -0500520 u32 length;
521
522 if (xdr_stream_decode_u32(argp->xdr, &length) < 0)
523 return nfserr_bad_xdr;
524 p = xdr_inline_decode(argp->xdr, length);
525 if (!p)
526 return nfserr_bad_xdr;
527 status = nfsd_map_name_to_gid(argp->rqstp, (char *)p, length,
528 &iattr->ia_gid);
529 if (status)
NeilBrown47c85292011-02-16 13:08:35 +1100530 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 iattr->ia_valid |= ATTR_GID;
532 }
533 if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
Chuck Lever1c3eff72020-11-19 14:01:08 -0500534 u32 set_it;
535
536 if (xdr_stream_decode_u32(argp->xdr, &set_it) < 0)
537 return nfserr_bad_xdr;
538 switch (set_it) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 case NFS4_SET_TO_CLIENT_TIME:
Chuck Lever1c3eff72020-11-19 14:01:08 -0500540 status = nfsd4_decode_nfstime4(argp, &iattr->ia_atime);
Christoph Hellwig4c94e132015-01-22 12:09:50 +0100541 if (status)
542 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 iattr->ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET);
544 break;
545 case NFS4_SET_TO_SERVER_TIME:
546 iattr->ia_valid |= ATTR_ATIME;
547 break;
548 default:
Chuck Lever1c3eff72020-11-19 14:01:08 -0500549 return nfserr_bad_xdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 }
551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
Chuck Lever1c3eff72020-11-19 14:01:08 -0500553 u32 set_it;
554
555 if (xdr_stream_decode_u32(argp->xdr, &set_it) < 0)
556 return nfserr_bad_xdr;
557 switch (set_it) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 case NFS4_SET_TO_CLIENT_TIME:
Chuck Lever1c3eff72020-11-19 14:01:08 -0500559 status = nfsd4_decode_nfstime4(argp, &iattr->ia_mtime);
Christoph Hellwig4c94e132015-01-22 12:09:50 +0100560 if (status)
561 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 iattr->ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET);
563 break;
564 case NFS4_SET_TO_SERVER_TIME:
565 iattr->ia_valid |= ATTR_MTIME;
566 break;
567 default:
Chuck Lever1c3eff72020-11-19 14:01:08 -0500568 return nfserr_bad_xdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 }
570 }
David Quigley18032ca2013-05-02 13:19:10 -0400571 label->len = 0;
Arnd Bergmann2285ae72018-01-22 22:09:12 +0100572 if (IS_ENABLED(CONFIG_NFSD_V4_SECURITY_LABEL) &&
573 bmval[2] & FATTR4_WORD2_SECURITY_LABEL) {
Chuck Leverdabe9182020-11-19 14:05:51 -0500574 status = nfsd4_decode_security_label(argp, label);
575 if (status)
576 return status;
David Quigley18032ca2013-05-02 13:19:10 -0400577 }
Andreas Gruenbacher47057ab2016-01-12 20:24:14 +0100578 if (bmval[2] & FATTR4_WORD2_MODE_UMASK) {
Chuck Lever66f04762020-11-19 14:07:43 -0500579 u32 mode, mask;
580
Andreas Gruenbacher47057ab2016-01-12 20:24:14 +0100581 if (!umask)
Chuck Lever66f04762020-11-19 14:07:43 -0500582 return nfserr_bad_xdr;
583 if (xdr_stream_decode_u32(argp->xdr, &mode) < 0)
584 return nfserr_bad_xdr;
585 iattr->ia_mode = mode & (S_IFMT | S_IALLUGO);
586 if (xdr_stream_decode_u32(argp->xdr, &mask) < 0)
587 return nfserr_bad_xdr;
588 *umask = mask & S_IRWXUGO;
Andreas Gruenbacher47057ab2016-01-12 20:24:14 +0100589 iattr->ia_valid |= ATTR_MODE;
590 }
Chuck Lever081d53f2020-11-19 13:09:13 -0500591
592 /* request sanity: did attrlist4 contain the expected number of words? */
593 if (attrlist4_count != xdr_stream_pos(argp->xdr) - starting_pos)
594 return nfserr_bad_xdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
Chuck Leverd1c263a2020-11-03 12:56:05 -0500596 return nfs_ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597}
598
Al Virob37ad282006-10-19 23:28:59 -0700599static __be32
Benny Halevye31a1b62008-08-12 20:46:18 +0300600nfsd4_decode_stateid(struct nfsd4_compoundargs *argp, stateid_t *sid)
601{
602 DECODE_HEAD;
603
604 READ_BUF(sizeof(stateid_t));
J. Bruce Fields06553992014-06-02 12:32:51 -0400605 sid->si_generation = be32_to_cpup(p++);
Benny Halevye31a1b62008-08-12 20:46:18 +0300606 COPYMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
607
608 DECODE_TAIL;
609}
610
Chuck Leverd3d2f382020-11-03 13:18:23 -0500611static __be32
612nfsd4_decode_stateid4(struct nfsd4_compoundargs *argp, stateid_t *sid)
613{
614 __be32 *p;
615
616 p = xdr_inline_decode(argp->xdr, NFS4_STATEID_SIZE);
617 if (!p)
618 return nfserr_bad_xdr;
619 sid->si_generation = be32_to_cpup(p++);
620 memcpy(&sid->si_opaque, p, sizeof(sid->si_opaque));
621 return nfs_ok;
622}
623
Chuck Lever144e8262020-11-16 17:25:02 -0500624static __be32
625nfsd4_decode_clientid4(struct nfsd4_compoundargs *argp, clientid_t *clientid)
626{
627 __be32 *p;
628
629 p = xdr_inline_decode(argp->xdr, sizeof(__be64));
630 if (!p)
631 return nfserr_bad_xdr;
632 memcpy(clientid, p, sizeof(*clientid));
633 return nfs_ok;
634}
635
636static __be32
637nfsd4_decode_state_owner4(struct nfsd4_compoundargs *argp,
638 clientid_t *clientid, struct xdr_netobj *owner)
639{
640 __be32 status;
641
642 status = nfsd4_decode_clientid4(argp, clientid);
643 if (status)
644 return status;
645 return nfsd4_decode_opaque(argp, owner);
646}
647
J. Bruce Fieldsacb28872012-03-27 14:50:26 -0400648static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs)
649{
650 DECODE_HEAD;
Trond Myklebuste45d1a12019-04-09 12:13:42 -0400651 struct user_namespace *userns = nfsd_user_namespace(argp->rqstp);
J. Bruce Fields12fc3e92012-11-05 16:01:48 -0500652 u32 dummy, uid, gid;
J. Bruce Fieldsacb28872012-03-27 14:50:26 -0400653 char *machine_name;
654 int i;
655 int nr_secflavs;
656
657 /* callback_sec_params4 */
658 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -0400659 nr_secflavs = be32_to_cpup(p++);
J. Bruce Fields57569a72013-05-17 16:25:32 -0400660 if (nr_secflavs)
661 cbs->flavor = (u32)(-1);
662 else
663 /* Is this legal? Be generous, take it to mean AUTH_NONE: */
664 cbs->flavor = 0;
J. Bruce Fieldsacb28872012-03-27 14:50:26 -0400665 for (i = 0; i < nr_secflavs; ++i) {
666 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -0400667 dummy = be32_to_cpup(p++);
J. Bruce Fieldsacb28872012-03-27 14:50:26 -0400668 switch (dummy) {
669 case RPC_AUTH_NULL:
670 /* Nothing to read */
J. Bruce Fields12fc3e92012-11-05 16:01:48 -0500671 if (cbs->flavor == (u32)(-1))
672 cbs->flavor = RPC_AUTH_NULL;
J. Bruce Fieldsacb28872012-03-27 14:50:26 -0400673 break;
674 case RPC_AUTH_UNIX:
675 READ_BUF(8);
676 /* stamp */
J. Bruce Fields06553992014-06-02 12:32:51 -0400677 dummy = be32_to_cpup(p++);
J. Bruce Fieldsacb28872012-03-27 14:50:26 -0400678
679 /* machine name */
J. Bruce Fields06553992014-06-02 12:32:51 -0400680 dummy = be32_to_cpup(p++);
J. Bruce Fieldsacb28872012-03-27 14:50:26 -0400681 READ_BUF(dummy);
682 SAVEMEM(machine_name, dummy);
683
684 /* uid, gid */
685 READ_BUF(8);
J. Bruce Fields06553992014-06-02 12:32:51 -0400686 uid = be32_to_cpup(p++);
687 gid = be32_to_cpup(p++);
J. Bruce Fieldsacb28872012-03-27 14:50:26 -0400688
689 /* more gids */
690 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -0400691 dummy = be32_to_cpup(p++);
J. Bruce Fieldsacb28872012-03-27 14:50:26 -0400692 READ_BUF(dummy * 4);
J. Bruce Fields12fc3e92012-11-05 16:01:48 -0500693 if (cbs->flavor == (u32)(-1)) {
Trond Myklebuste45d1a12019-04-09 12:13:42 -0400694 kuid_t kuid = make_kuid(userns, uid);
695 kgid_t kgid = make_kgid(userns, gid);
Eric W. Biederman03bc6d12013-02-02 06:24:49 -0800696 if (uid_valid(kuid) && gid_valid(kgid)) {
697 cbs->uid = kuid;
698 cbs->gid = kgid;
699 cbs->flavor = RPC_AUTH_UNIX;
700 } else {
701 dprintk("RPC_AUTH_UNIX with invalid"
702 "uid or gid ignoring!\n");
703 }
J. Bruce Fields12fc3e92012-11-05 16:01:48 -0500704 }
J. Bruce Fieldsacb28872012-03-27 14:50:26 -0400705 break;
706 case RPC_AUTH_GSS:
707 dprintk("RPC_AUTH_GSS callback secflavor "
708 "not supported!\n");
709 READ_BUF(8);
710 /* gcbp_service */
J. Bruce Fields06553992014-06-02 12:32:51 -0400711 dummy = be32_to_cpup(p++);
J. Bruce Fieldsacb28872012-03-27 14:50:26 -0400712 /* gcbp_handle_from_server */
J. Bruce Fields06553992014-06-02 12:32:51 -0400713 dummy = be32_to_cpup(p++);
J. Bruce Fieldsacb28872012-03-27 14:50:26 -0400714 READ_BUF(dummy);
715 p += XDR_QUADLEN(dummy);
716 /* gcbp_handle_from_client */
717 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -0400718 dummy = be32_to_cpup(p++);
J. Bruce Fieldsacb28872012-03-27 14:50:26 -0400719 READ_BUF(dummy);
720 break;
721 default:
722 dprintk("Illegal callback secflavor\n");
723 return nfserr_inval;
724 }
725 }
726 DECODE_TAIL;
727}
728
Chuck Leverd169a6a2020-11-03 13:12:27 -0500729/*
730 * NFSv4 operation argument decoders
731 */
732
733static __be32
734nfsd4_decode_access(struct nfsd4_compoundargs *argp,
735 struct nfsd4_access *access)
736{
737 if (xdr_stream_decode_u32(argp->xdr, &access->ac_req_access) < 0)
738 return nfserr_bad_xdr;
739 return nfs_ok;
740}
741
J. Bruce Fieldscb73a9f2012-11-01 18:09:48 -0400742static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, struct nfsd4_backchannel_ctl *bc)
743{
744 DECODE_HEAD;
745
746 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -0400747 bc->bc_cb_program = be32_to_cpup(p++);
J. Bruce Fieldscb73a9f2012-11-01 18:09:48 -0400748 nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec);
749
750 DECODE_TAIL;
751}
752
J. Bruce Fields1d1bc8f2010-10-04 23:12:59 -0400753static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts)
754{
755 DECODE_HEAD;
J. Bruce Fields1d1bc8f2010-10-04 23:12:59 -0400756
757 READ_BUF(NFS4_MAX_SESSIONID_LEN + 8);
758 COPYMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN);
J. Bruce Fields06553992014-06-02 12:32:51 -0400759 bcts->dir = be32_to_cpup(p++);
Bryan Schumaker6ce23572011-04-27 15:47:16 -0400760 /* XXX: skipping ctsa_use_conn_in_rdma_mode. Perhaps Tom Tucker
761 * could help us figure out we should be using it. */
J. Bruce Fields1d1bc8f2010-10-04 23:12:59 -0400762 DECODE_TAIL;
763}
764
Al Virob37ad282006-10-19 23:28:59 -0700765static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
767{
Chuck Leverd3d2f382020-11-03 13:18:23 -0500768 if (xdr_stream_decode_u32(argp->xdr, &close->cl_seqid) < 0)
769 return nfserr_bad_xdr;
770 return nfsd4_decode_stateid4(argp, &close->cl_stateid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771}
772
773
Al Virob37ad282006-10-19 23:28:59 -0700774static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit)
776{
Chuck Levercbd9abb2020-11-03 13:19:51 -0500777 if (xdr_stream_decode_u64(argp->xdr, &commit->co_offset) < 0)
778 return nfserr_bad_xdr;
779 if (xdr_stream_decode_u32(argp->xdr, &commit->co_count) < 0)
780 return nfserr_bad_xdr;
781 return nfs_ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782}
783
Al Virob37ad282006-10-19 23:28:59 -0700784static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create)
786{
Chuck Lever000dfa12020-11-03 13:24:10 -0500787 __be32 *p, status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
Chuck Lever000dfa12020-11-03 13:24:10 -0500789 if (xdr_stream_decode_u32(argp->xdr, &create->cr_type) < 0)
790 return nfserr_bad_xdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 switch (create->cr_type) {
792 case NF4LNK:
Chuck Lever000dfa12020-11-03 13:24:10 -0500793 if (xdr_stream_decode_u32(argp->xdr, &create->cr_datalen) < 0)
794 return nfserr_bad_xdr;
795 p = xdr_inline_decode(argp->xdr, create->cr_datalen);
796 if (!p)
797 return nfserr_bad_xdr;
J. Bruce Fields29c353b2014-06-24 17:06:51 -0400798 create->cr_data = svcxdr_dupstr(argp, p, create->cr_datalen);
J. Bruce Fields7fb84302014-06-24 15:06:41 -0400799 if (!create->cr_data)
J. Bruce Fields76f471282014-06-19 16:44:48 -0400800 return nfserr_jukebox;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 break;
802 case NF4BLK:
803 case NF4CHR:
Chuck Lever000dfa12020-11-03 13:24:10 -0500804 if (xdr_stream_decode_u32(argp->xdr, &create->cr_specdata1) < 0)
805 return nfserr_bad_xdr;
806 if (xdr_stream_decode_u32(argp->xdr, &create->cr_specdata2) < 0)
807 return nfserr_bad_xdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 break;
809 case NF4SOCK:
810 case NF4FIFO:
811 case NF4DIR:
812 default:
813 break;
814 }
Chuck Lever000dfa12020-11-03 13:24:10 -0500815 status = nfsd4_decode_component4(argp, &create->cr_name,
816 &create->cr_namelen);
817 if (status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 return status;
Chuck Leverd1c263a2020-11-03 12:56:05 -0500819 status = nfsd4_decode_fattr4(argp, create->cr_bmval,
820 ARRAY_SIZE(create->cr_bmval),
821 &create->cr_iattr, &create->cr_acl,
822 &create->cr_label, &create->cr_umask);
Benny Halevyc0d6fc82009-04-03 08:29:05 +0300823 if (status)
Chuck Lever000dfa12020-11-03 13:24:10 -0500824 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
Chuck Lever000dfa12020-11-03 13:24:10 -0500826 return nfs_ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827}
828
Al Virob37ad282006-10-19 23:28:59 -0700829static inline __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr)
831{
Chuck Lever95e64822020-11-21 14:11:58 -0500832 return nfsd4_decode_stateid4(argp, &dr->dr_stateid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833}
834
Al Virob37ad282006-10-19 23:28:59 -0700835static inline __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr)
837{
Chuck Leverf759eff2020-11-19 14:40:20 -0500838 return nfsd4_decode_bitmap4(argp, getattr->ga_bmval,
839 ARRAY_SIZE(getattr->ga_bmval));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840}
841
Al Virob37ad282006-10-19 23:28:59 -0700842static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link)
844{
Chuck Lever5c505d12020-11-04 15:01:24 -0500845 return nfsd4_decode_component4(argp, &link->li_name, &link->li_namelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846}
847
Al Virob37ad282006-10-19 23:28:59 -0700848static __be32
Chuck Lever8918cc02020-11-16 17:16:52 -0500849nfsd4_decode_open_to_lock_owner4(struct nfsd4_compoundargs *argp,
850 struct nfsd4_lock *lock)
851{
852 __be32 status;
853
854 if (xdr_stream_decode_u32(argp->xdr, &lock->lk_new_open_seqid) < 0)
855 return nfserr_bad_xdr;
856 status = nfsd4_decode_stateid4(argp, &lock->lk_new_open_stateid);
857 if (status)
858 return status;
859 if (xdr_stream_decode_u32(argp->xdr, &lock->lk_new_lock_seqid) < 0)
860 return nfserr_bad_xdr;
861 return nfsd4_decode_state_owner4(argp, &lock->lk_new_clientid,
862 &lock->lk_new_owner);
863}
864
865static __be32
866nfsd4_decode_exist_lock_owner4(struct nfsd4_compoundargs *argp,
867 struct nfsd4_lock *lock)
868{
869 __be32 status;
870
871 status = nfsd4_decode_stateid4(argp, &lock->lk_old_lock_stateid);
872 if (status)
873 return status;
874 if (xdr_stream_decode_u32(argp->xdr, &lock->lk_old_lock_seqid) < 0)
875 return nfserr_bad_xdr;
876
877 return nfs_ok;
878}
879
880static __be32
881nfsd4_decode_locker4(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
882{
883 if (xdr_stream_decode_bool(argp->xdr, &lock->lk_is_new) < 0)
884 return nfserr_bad_xdr;
885 if (lock->lk_is_new)
886 return nfsd4_decode_open_to_lock_owner4(argp, lock);
887 return nfsd4_decode_exist_lock_owner4(argp, lock);
888}
889
890static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
892{
Chuck Lever7c59dee2020-11-03 13:29:27 -0500893 if (xdr_stream_decode_u32(argp->xdr, &lock->lk_type) < 0)
894 return nfserr_bad_xdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 if ((lock->lk_type < NFS4_READ_LT) || (lock->lk_type > NFS4_WRITEW_LT))
Chuck Lever7c59dee2020-11-03 13:29:27 -0500896 return nfserr_bad_xdr;
897 if (xdr_stream_decode_bool(argp->xdr, &lock->lk_reclaim) < 0)
898 return nfserr_bad_xdr;
899 if (xdr_stream_decode_u64(argp->xdr, &lock->lk_offset) < 0)
900 return nfserr_bad_xdr;
901 if (xdr_stream_decode_u64(argp->xdr, &lock->lk_length) < 0)
902 return nfserr_bad_xdr;
903 return nfsd4_decode_locker4(argp, lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904}
905
Al Virob37ad282006-10-19 23:28:59 -0700906static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt)
908{
Chuck Lever0a146f02020-11-03 13:31:44 -0500909 if (xdr_stream_decode_u32(argp->xdr, &lockt->lt_type) < 0)
910 return nfserr_bad_xdr;
911 if ((lockt->lt_type < NFS4_READ_LT) || (lockt->lt_type > NFS4_WRITEW_LT))
912 return nfserr_bad_xdr;
913 if (xdr_stream_decode_u64(argp->xdr, &lockt->lt_offset) < 0)
914 return nfserr_bad_xdr;
915 if (xdr_stream_decode_u64(argp->xdr, &lockt->lt_length) < 0)
916 return nfserr_bad_xdr;
917 return nfsd4_decode_state_owner4(argp, &lockt->lt_clientid,
918 &lockt->lt_owner);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919}
920
Al Virob37ad282006-10-19 23:28:59 -0700921static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
923{
Chuck Leverca9cf9f2020-11-03 13:33:28 -0500924 __be32 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925
Chuck Leverca9cf9f2020-11-03 13:33:28 -0500926 if (xdr_stream_decode_u32(argp->xdr, &locku->lu_type) < 0)
927 return nfserr_bad_xdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT))
Chuck Leverca9cf9f2020-11-03 13:33:28 -0500929 return nfserr_bad_xdr;
930 if (xdr_stream_decode_u32(argp->xdr, &locku->lu_seqid) < 0)
931 return nfserr_bad_xdr;
932 status = nfsd4_decode_stateid4(argp, &locku->lu_stateid);
Benny Halevye31a1b62008-08-12 20:46:18 +0300933 if (status)
934 return status;
Chuck Leverca9cf9f2020-11-03 13:33:28 -0500935 if (xdr_stream_decode_u64(argp->xdr, &locku->lu_offset) < 0)
936 return nfserr_bad_xdr;
937 if (xdr_stream_decode_u64(argp->xdr, &locku->lu_length) < 0)
938 return nfserr_bad_xdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
Chuck Leverca9cf9f2020-11-03 13:33:28 -0500940 return nfs_ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941}
942
Al Virob37ad282006-10-19 23:28:59 -0700943static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup)
945{
Chuck Lever3d5877e2020-11-04 15:02:40 -0500946 return nfsd4_decode_component4(argp, &lookup->lo_name, &lookup->lo_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947}
948
Chuck Leverbf33bab2020-11-16 17:37:42 -0500949static __be32
950nfsd4_decode_createhow4(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
951{
952 __be32 status;
953
954 if (xdr_stream_decode_u32(argp->xdr, &open->op_createmode) < 0)
955 return nfserr_bad_xdr;
956 switch (open->op_createmode) {
957 case NFS4_CREATE_UNCHECKED:
958 case NFS4_CREATE_GUARDED:
959 status = nfsd4_decode_fattr4(argp, open->op_bmval,
960 ARRAY_SIZE(open->op_bmval),
961 &open->op_iattr, &open->op_acl,
962 &open->op_label, &open->op_umask);
963 if (status)
964 return status;
965 break;
966 case NFS4_CREATE_EXCLUSIVE:
967 status = nfsd4_decode_verifier4(argp, &open->op_verf);
968 if (status)
969 return status;
970 break;
971 case NFS4_CREATE_EXCLUSIVE4_1:
972 if (argp->minorversion < 1)
973 return nfserr_bad_xdr;
974 status = nfsd4_decode_verifier4(argp, &open->op_verf);
975 if (status)
976 return status;
977 status = nfsd4_decode_fattr4(argp, open->op_bmval,
978 ARRAY_SIZE(open->op_bmval),
979 &open->op_iattr, &open->op_acl,
980 &open->op_label, &open->op_umask);
981 if (status)
982 return status;
983 break;
984 default:
985 return nfserr_bad_xdr;
986 }
987
988 return nfs_ok;
989}
990
Chuck Levere6ec04b2020-11-16 17:41:21 -0500991static __be32
992nfsd4_decode_openflag4(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
993{
994 __be32 status;
995
996 if (xdr_stream_decode_u32(argp->xdr, &open->op_create) < 0)
997 return nfserr_bad_xdr;
998 switch (open->op_create) {
999 case NFS4_OPEN_NOCREATE:
1000 break;
1001 case NFS4_OPEN_CREATE:
1002 status = nfsd4_decode_createhow4(argp, open);
1003 if (status)
1004 return status;
1005 break;
1006 default:
1007 return nfserr_bad_xdr;
1008 }
1009
1010 return nfs_ok;
1011}
1012
Benny Halevy2c8bd7e2012-02-16 20:57:09 +02001013static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *share_access, u32 *deleg_want, u32 *deleg_when)
J. Bruce Fields04f9e662011-10-10 14:37:13 -04001014{
J. Bruce Fields04f9e662011-10-10 14:37:13 -04001015 u32 w;
1016
Chuck Lever9aa62f52020-11-16 17:54:48 -05001017 if (xdr_stream_decode_u32(argp->xdr, &w) < 0)
1018 return nfserr_bad_xdr;
Benny Halevy2c8bd7e2012-02-16 20:57:09 +02001019 *share_access = w & NFS4_SHARE_ACCESS_MASK;
1020 *deleg_want = w & NFS4_SHARE_WANT_MASK;
1021 if (deleg_when)
1022 *deleg_when = w & NFS4_SHARE_WHEN_MASK;
1023
J. Bruce Fields04f9e662011-10-10 14:37:13 -04001024 switch (w & NFS4_SHARE_ACCESS_MASK) {
1025 case NFS4_SHARE_ACCESS_READ:
1026 case NFS4_SHARE_ACCESS_WRITE:
1027 case NFS4_SHARE_ACCESS_BOTH:
1028 break;
1029 default:
1030 return nfserr_bad_xdr;
1031 }
Benny Halevyfc0d14f2011-10-27 20:43:01 +02001032 w &= ~NFS4_SHARE_ACCESS_MASK;
J. Bruce Fields04f9e662011-10-10 14:37:13 -04001033 if (!w)
1034 return nfs_ok;
1035 if (!argp->minorversion)
1036 return nfserr_bad_xdr;
1037 switch (w & NFS4_SHARE_WANT_MASK) {
1038 case NFS4_SHARE_WANT_NO_PREFERENCE:
1039 case NFS4_SHARE_WANT_READ_DELEG:
1040 case NFS4_SHARE_WANT_WRITE_DELEG:
1041 case NFS4_SHARE_WANT_ANY_DELEG:
1042 case NFS4_SHARE_WANT_NO_DELEG:
1043 case NFS4_SHARE_WANT_CANCEL:
1044 break;
1045 default:
1046 return nfserr_bad_xdr;
1047 }
Benny Halevy92bac8c2011-10-19 19:13:29 -07001048 w &= ~NFS4_SHARE_WANT_MASK;
J. Bruce Fields04f9e662011-10-10 14:37:13 -04001049 if (!w)
1050 return nfs_ok;
Benny Halevy2c8bd7e2012-02-16 20:57:09 +02001051
1052 if (!deleg_when) /* open_downgrade */
1053 return nfserr_inval;
J. Bruce Fields04f9e662011-10-10 14:37:13 -04001054 switch (w) {
1055 case NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL:
1056 case NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED:
Benny Halevyc668fc62011-10-19 19:13:13 -07001057 case (NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL |
1058 NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED):
J. Bruce Fields04f9e662011-10-10 14:37:13 -04001059 return nfs_ok;
1060 }
J. Bruce Fields04f9e662011-10-10 14:37:13 -04001061 return nfserr_bad_xdr;
1062}
1063
1064static __be32 nfsd4_decode_share_deny(struct nfsd4_compoundargs *argp, u32 *x)
1065{
Chuck Leverb07bebd2020-11-16 17:56:17 -05001066 if (xdr_stream_decode_u32(argp->xdr, x) < 0)
1067 return nfserr_bad_xdr;
1068 /* Note: unlike access bits, deny bits may be zero. */
Dan Carpenter01cd4af2011-10-17 10:41:17 +03001069 if (*x & ~NFS4_SHARE_DENY_BOTH)
J. Bruce Fields04f9e662011-10-10 14:37:13 -04001070 return nfserr_bad_xdr;
Chuck Leverb07bebd2020-11-16 17:56:17 -05001071
J. Bruce Fields04f9e662011-10-10 14:37:13 -04001072 return nfs_ok;
J. Bruce Fields04f9e662011-10-10 14:37:13 -04001073}
1074
Al Virob37ad282006-10-19 23:28:59 -07001075static __be32
Chuck Lever1708e502020-11-16 17:45:04 -05001076nfsd4_decode_open_claim4(struct nfsd4_compoundargs *argp,
1077 struct nfsd4_open *open)
1078{
1079 __be32 status;
1080
1081 if (xdr_stream_decode_u32(argp->xdr, &open->op_claim_type) < 0)
1082 return nfserr_bad_xdr;
1083 switch (open->op_claim_type) {
1084 case NFS4_OPEN_CLAIM_NULL:
1085 case NFS4_OPEN_CLAIM_DELEGATE_PREV:
1086 status = nfsd4_decode_component4(argp, &open->op_fname,
1087 &open->op_fnamelen);
1088 if (status)
1089 return status;
1090 break;
1091 case NFS4_OPEN_CLAIM_PREVIOUS:
1092 if (xdr_stream_decode_u32(argp->xdr, &open->op_delegate_type) < 0)
1093 return nfserr_bad_xdr;
1094 break;
1095 case NFS4_OPEN_CLAIM_DELEGATE_CUR:
1096 status = nfsd4_decode_stateid4(argp, &open->op_delegate_stateid);
1097 if (status)
1098 return status;
1099 status = nfsd4_decode_component4(argp, &open->op_fname,
1100 &open->op_fnamelen);
1101 if (status)
1102 return status;
1103 break;
1104 case NFS4_OPEN_CLAIM_FH:
1105 case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
1106 if (argp->minorversion < 1)
1107 return nfserr_bad_xdr;
1108 /* void */
1109 break;
1110 case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
1111 if (argp->minorversion < 1)
1112 return nfserr_bad_xdr;
1113 status = nfsd4_decode_stateid4(argp, &open->op_delegate_stateid);
1114 if (status)
1115 return status;
1116 break;
1117 default:
1118 return nfserr_bad_xdr;
1119 }
1120
1121 return nfs_ok;
1122}
1123
1124static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
1126{
Chuck Lever61e5e0b2020-11-01 12:04:06 -05001127 __be32 status;
Benny Halevy2c8bd7e2012-02-16 20:57:09 +02001128 u32 dummy;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
1130 memset(open->op_bmval, 0, sizeof(open->op_bmval));
1131 open->op_iattr.ia_valid = 0;
J. Bruce Fieldsfe0750e2011-07-30 23:33:59 -04001132 open->op_openowner = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
J. Bruce Fields9d313b12013-02-28 12:51:49 -08001134 open->op_xdr_error = 0;
Chuck Lever61e5e0b2020-11-01 12:04:06 -05001135 if (xdr_stream_decode_u32(argp->xdr, &open->op_seqid) < 0)
1136 return nfserr_bad_xdr;
1137 /* deleg_want is ignored */
Benny Halevy2c8bd7e2012-02-16 20:57:09 +02001138 status = nfsd4_decode_share_access(argp, &open->op_share_access,
1139 &open->op_deleg_want, &dummy);
J. Bruce Fields04f9e662011-10-10 14:37:13 -04001140 if (status)
Chuck Lever61e5e0b2020-11-01 12:04:06 -05001141 return status;
J. Bruce Fields04f9e662011-10-10 14:37:13 -04001142 status = nfsd4_decode_share_deny(argp, &open->op_share_deny);
1143 if (status)
Chuck Lever61e5e0b2020-11-01 12:04:06 -05001144 return status;
1145 status = nfsd4_decode_state_owner4(argp, &open->op_clientid,
1146 &open->op_owner);
J. Bruce Fieldsa084daf2011-10-10 15:07:40 -04001147 if (status)
Chuck Lever61e5e0b2020-11-01 12:04:06 -05001148 return status;
Chuck Levere6ec04b2020-11-16 17:41:21 -05001149 status = nfsd4_decode_openflag4(argp, open);
1150 if (status)
1151 return status;
Chuck Lever61e5e0b2020-11-01 12:04:06 -05001152 return nfsd4_decode_open_claim4(argp, open);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153}
1154
Al Virob37ad282006-10-19 23:28:59 -07001155static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf)
1157{
Chuck Lever06bee692020-11-03 14:18:57 -05001158 __be32 status;
Anna Schumakere1a90eb2013-10-30 10:00:20 -04001159
1160 if (argp->minorversion >= 1)
1161 return nfserr_notsupp;
1162
Chuck Lever06bee692020-11-03 14:18:57 -05001163 status = nfsd4_decode_stateid4(argp, &open_conf->oc_req_stateid);
Benny Halevye31a1b62008-08-12 20:46:18 +03001164 if (status)
1165 return status;
Chuck Lever06bee692020-11-03 14:18:57 -05001166 if (xdr_stream_decode_u32(argp->xdr, &open_conf->oc_seqid) < 0)
1167 return nfserr_bad_xdr;
Anna Schumakere1a90eb2013-10-30 10:00:20 -04001168
Chuck Lever06bee692020-11-03 14:18:57 -05001169 return nfs_ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170}
1171
Al Virob37ad282006-10-19 23:28:59 -07001172static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down)
1174{
Chuck Leverdca716512020-11-03 14:21:01 -05001175 __be32 status;
1176
1177 status = nfsd4_decode_stateid4(argp, &open_down->od_stateid);
Benny Halevye31a1b62008-08-12 20:46:18 +03001178 if (status)
1179 return status;
Chuck Leverdca716512020-11-03 14:21:01 -05001180 if (xdr_stream_decode_u32(argp->xdr, &open_down->od_seqid) < 0)
1181 return nfserr_bad_xdr;
1182 /* deleg_want is ignored */
Benny Halevy2c8bd7e2012-02-16 20:57:09 +02001183 status = nfsd4_decode_share_access(argp, &open_down->od_share_access,
1184 &open_down->od_deleg_want, NULL);
J. Bruce Fields04f9e662011-10-10 14:37:13 -04001185 if (status)
1186 return status;
Chuck Leverdca716512020-11-03 14:21:01 -05001187 return nfsd4_decode_share_deny(argp, &open_down->od_share_deny);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188}
1189
Al Virob37ad282006-10-19 23:28:59 -07001190static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
1192{
Chuck Levera73bed92020-11-03 14:23:02 -05001193 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194
Chuck Levera73bed92020-11-03 14:23:02 -05001195 if (xdr_stream_decode_u32(argp->xdr, &putfh->pf_fhlen) < 0)
1196 return nfserr_bad_xdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 if (putfh->pf_fhlen > NFS4_FHSIZE)
Chuck Levera73bed92020-11-03 14:23:02 -05001198 return nfserr_bad_xdr;
1199 p = xdr_inline_decode(argp->xdr, putfh->pf_fhlen);
1200 if (!p)
1201 return nfserr_bad_xdr;
1202 putfh->pf_fhval = svcxdr_tmpalloc(argp, putfh->pf_fhlen);
1203 if (!putfh->pf_fhval)
1204 return nfserr_jukebox;
1205 memcpy(putfh->pf_fhval, p, putfh->pf_fhlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206
Chuck Levera73bed92020-11-03 14:23:02 -05001207 return nfs_ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208}
1209
Al Virob37ad282006-10-19 23:28:59 -07001210static __be32
Anna Schumakere1a90eb2013-10-30 10:00:20 -04001211nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, void *p)
1212{
1213 if (argp->minorversion == 0)
1214 return nfs_ok;
1215 return nfserr_notsupp;
1216}
1217
1218static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
1220{
Chuck Lever3909c3b2020-11-03 14:28:24 -05001221 __be32 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222
Chuck Lever3909c3b2020-11-03 14:28:24 -05001223 status = nfsd4_decode_stateid4(argp, &read->rd_stateid);
Benny Halevye31a1b62008-08-12 20:46:18 +03001224 if (status)
1225 return status;
Chuck Lever3909c3b2020-11-03 14:28:24 -05001226 if (xdr_stream_decode_u64(argp->xdr, &read->rd_offset) < 0)
1227 return nfserr_bad_xdr;
1228 if (xdr_stream_decode_u32(argp->xdr, &read->rd_length) < 0)
1229 return nfserr_bad_xdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
Chuck Lever3909c3b2020-11-03 14:28:24 -05001231 return nfs_ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232}
1233
Al Virob37ad282006-10-19 23:28:59 -07001234static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir)
1236{
Chuck Lever0dfaf2a2020-11-03 14:30:59 -05001237 __be32 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
Chuck Lever0dfaf2a2020-11-03 14:30:59 -05001239 if (xdr_stream_decode_u64(argp->xdr, &readdir->rd_cookie) < 0)
1240 return nfserr_bad_xdr;
1241 status = nfsd4_decode_verifier4(argp, &readdir->rd_verf);
1242 if (status)
1243 return status;
1244 if (xdr_stream_decode_u32(argp->xdr, &readdir->rd_dircount) < 0)
1245 return nfserr_bad_xdr;
1246 if (xdr_stream_decode_u32(argp->xdr, &readdir->rd_maxcount) < 0)
1247 return nfserr_bad_xdr;
1248 if (xdr_stream_decode_uint32_array(argp->xdr, readdir->rd_bmval,
1249 ARRAY_SIZE(readdir->rd_bmval)) < 0)
1250 return nfserr_bad_xdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
Chuck Lever0dfaf2a2020-11-03 14:30:59 -05001252 return nfs_ok;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253}
1254
Al Virob37ad282006-10-19 23:28:59 -07001255static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove)
1257{
Chuck Leverb7f5fbf2020-11-04 15:04:36 -05001258 return nfsd4_decode_component4(argp, &remove->rm_name, &remove->rm_namelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259}
1260
Al Virob37ad282006-10-19 23:28:59 -07001261static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename)
1263{
Chuck Leverba881a02020-11-04 15:05:58 -05001264 __be32 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265
Chuck Leverba881a02020-11-04 15:05:58 -05001266 status = nfsd4_decode_component4(argp, &rename->rn_sname, &rename->rn_snamelen);
1267 if (status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 return status;
Chuck Leverba881a02020-11-04 15:05:58 -05001269 return nfsd4_decode_component4(argp, &rename->rn_tname, &rename->rn_tnamelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270}
1271
Al Virob37ad282006-10-19 23:28:59 -07001272static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
1274{
Chuck Leverd12f9042020-11-04 15:08:50 -05001275 return nfsd4_decode_clientid4(argp, clientid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276}
1277
Al Virob37ad282006-10-19 23:28:59 -07001278static __be32
Andy Adamsondcb488a32007-07-17 04:04:51 -07001279nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
1280 struct nfsd4_secinfo *secinfo)
1281{
Chuck Leverd0abdae2020-11-04 15:09:42 -05001282 return nfsd4_decode_component4(argp, &secinfo->si_name, &secinfo->si_namelen);
Andy Adamsondcb488a32007-07-17 04:04:51 -07001283}
1284
1285static __be32
J. Bruce Fields04f4ad12010-12-16 09:51:13 -05001286nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp,
1287 struct nfsd4_secinfo_no_name *sin)
1288{
1289 DECODE_HEAD;
1290
1291 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04001292 sin->sin_style = be32_to_cpup(p++);
J. Bruce Fields04f4ad12010-12-16 09:51:13 -05001293 DECODE_TAIL;
1294}
1295
1296static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
1298{
Benny Halevye31a1b62008-08-12 20:46:18 +03001299 __be32 status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
Chuck Lever44592fe2020-11-21 14:14:59 -05001301 status = nfsd4_decode_stateid4(argp, &setattr->sa_stateid);
Benny Halevye31a1b62008-08-12 20:46:18 +03001302 if (status)
1303 return status;
Chuck Leverd1c263a2020-11-03 12:56:05 -05001304 return nfsd4_decode_fattr4(argp, setattr->sa_bmval,
1305 ARRAY_SIZE(setattr->sa_bmval),
1306 &setattr->sa_iattr, &setattr->sa_acl,
1307 &setattr->sa_label, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308}
1309
Al Virob37ad282006-10-19 23:28:59 -07001310static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid)
1312{
1313 DECODE_HEAD;
1314
Anna Schumakere1a90eb2013-10-30 10:00:20 -04001315 if (argp->minorversion >= 1)
1316 return nfserr_notsupp;
1317
Chuck Leverab4684d2012-03-02 17:13:50 -05001318 READ_BUF(NFS4_VERIFIER_SIZE);
1319 COPYMEM(setclientid->se_verf.data, NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320
J. Bruce Fieldsa084daf2011-10-10 15:07:40 -04001321 status = nfsd4_decode_opaque(argp, &setclientid->se_name);
1322 if (status)
1323 return nfserr_bad_xdr;
1324 READ_BUF(8);
J. Bruce Fields06553992014-06-02 12:32:51 -04001325 setclientid->se_callback_prog = be32_to_cpup(p++);
1326 setclientid->se_callback_netid_len = be32_to_cpup(p++);
J. Bruce Fields4aed9c42016-02-29 20:21:21 -05001327 READ_BUF(setclientid->se_callback_netid_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 SAVEMEM(setclientid->se_callback_netid_val, setclientid->se_callback_netid_len);
J. Bruce Fields4aed9c42016-02-29 20:21:21 -05001329 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04001330 setclientid->se_callback_addr_len = be32_to_cpup(p++);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331
J. Bruce Fields4aed9c42016-02-29 20:21:21 -05001332 READ_BUF(setclientid->se_callback_addr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 SAVEMEM(setclientid->se_callback_addr_val, setclientid->se_callback_addr_len);
J. Bruce Fields4aed9c42016-02-29 20:21:21 -05001334 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04001335 setclientid->se_callback_ident = be32_to_cpup(p++);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336
1337 DECODE_TAIL;
1338}
1339
Al Virob37ad282006-10-19 23:28:59 -07001340static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c)
1342{
1343 DECODE_HEAD;
1344
Anna Schumakere1a90eb2013-10-30 10:00:20 -04001345 if (argp->minorversion >= 1)
1346 return nfserr_notsupp;
1347
Chuck Leverab4684d2012-03-02 17:13:50 -05001348 READ_BUF(8 + NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 COPYMEM(&scd_c->sc_clientid, 8);
Chuck Leverab4684d2012-03-02 17:13:50 -05001350 COPYMEM(&scd_c->sc_confirm, NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351
1352 DECODE_TAIL;
1353}
1354
1355/* Also used for NVERIFY */
Al Virob37ad282006-10-19 23:28:59 -07001356static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify)
1358{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 DECODE_HEAD;
1360
1361 if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval)))
1362 goto out;
1363
1364 /* For convenience's sake, we compare raw xdr'd attributes in
J. Bruce Fieldse5f95702012-11-30 17:24:18 -05001365 * nfsd4_proc_verify */
1366
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04001368 verify->ve_attrlen = be32_to_cpup(p++);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 READ_BUF(verify->ve_attrlen);
1370 SAVEMEM(verify->ve_attrval, verify->ve_attrlen);
1371
1372 DECODE_TAIL;
1373}
1374
Al Virob37ad282006-10-19 23:28:59 -07001375static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
1377{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 DECODE_HEAD;
1379
Benny Halevye31a1b62008-08-12 20:46:18 +03001380 status = nfsd4_decode_stateid(argp, &write->wr_stateid);
1381 if (status)
1382 return status;
1383 READ_BUF(16);
J. Bruce Fields542d1ab2014-06-02 12:45:31 -04001384 p = xdr_decode_hyper(p, &write->wr_offset);
J. Bruce Fields06553992014-06-02 12:32:51 -04001385 write->wr_stable_how = be32_to_cpup(p++);
Kinglong Mee54bbb7d2016-12-31 20:59:53 +08001386 if (write->wr_stable_how > NFS_FILE_SYNC)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 goto xdr_error;
J. Bruce Fields06553992014-06-02 12:32:51 -04001388 write->wr_buflen = be32_to_cpup(p++);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389
Chuck Leverc1346a122020-11-03 11:54:23 -05001390 if (!xdr_stream_subsegment(argp->xdr, &write->wr_payload, write->wr_buflen))
1391 goto xdr_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392
1393 DECODE_TAIL;
1394}
1395
Al Virob37ad282006-10-19 23:28:59 -07001396static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner)
1398{
1399 DECODE_HEAD;
1400
Anna Schumakere1a90eb2013-10-30 10:00:20 -04001401 if (argp->minorversion >= 1)
1402 return nfserr_notsupp;
1403
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404 READ_BUF(12);
1405 COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t));
J. Bruce Fields06553992014-06-02 12:32:51 -04001406 rlockowner->rl_owner.len = be32_to_cpup(p++);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 READ_BUF(rlockowner->rl_owner.len);
1408 READMEM(rlockowner->rl_owner.data, rlockowner->rl_owner.len);
1409
Andy Adamson60adfc52009-04-03 08:28:50 +03001410 if (argp->minorversion && !zero_clientid(&rlockowner->rl_clientid))
1411 return nfserr_inval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 DECODE_TAIL;
1413}
1414
Al Virob37ad282006-10-19 23:28:59 -07001415static __be32
Andy Adamson2db134e2009-04-03 08:27:55 +03001416nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
Andy Adamson0733d212009-04-03 08:28:01 +03001417 struct nfsd4_exchange_id *exid)
Andy Adamson2db134e2009-04-03 08:27:55 +03001418{
Mi Jinlong5afa0402010-11-09 09:39:23 +08001419 int dummy, tmp;
Andy Adamson0733d212009-04-03 08:28:01 +03001420 DECODE_HEAD;
1421
1422 READ_BUF(NFS4_VERIFIER_SIZE);
1423 COPYMEM(exid->verifier.data, NFS4_VERIFIER_SIZE);
1424
J. Bruce Fieldsa084daf2011-10-10 15:07:40 -04001425 status = nfsd4_decode_opaque(argp, &exid->clname);
1426 if (status)
1427 return nfserr_bad_xdr;
Andy Adamson0733d212009-04-03 08:28:01 +03001428
1429 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04001430 exid->flags = be32_to_cpup(p++);
Andy Adamson0733d212009-04-03 08:28:01 +03001431
1432 /* Ignore state_protect4_a */
1433 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04001434 exid->spa_how = be32_to_cpup(p++);
Andy Adamson0733d212009-04-03 08:28:01 +03001435 switch (exid->spa_how) {
1436 case SP4_NONE:
1437 break;
1438 case SP4_MACH_CRED:
1439 /* spo_must_enforce */
Andrew Elbleed941642016-06-15 12:52:09 -04001440 status = nfsd4_decode_bitmap(argp,
1441 exid->spo_must_enforce);
1442 if (status)
1443 goto out;
Andy Adamson0733d212009-04-03 08:28:01 +03001444 /* spo_must_allow */
Andrew Elbleed941642016-06-15 12:52:09 -04001445 status = nfsd4_decode_bitmap(argp, exid->spo_must_allow);
1446 if (status)
1447 goto out;
Andy Adamson0733d212009-04-03 08:28:01 +03001448 break;
1449 case SP4_SSV:
1450 /* ssp_ops */
1451 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04001452 dummy = be32_to_cpup(p++);
Andy Adamson0733d212009-04-03 08:28:01 +03001453 READ_BUF(dummy * 4);
1454 p += dummy;
1455
1456 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04001457 dummy = be32_to_cpup(p++);
Andy Adamson0733d212009-04-03 08:28:01 +03001458 READ_BUF(dummy * 4);
1459 p += dummy;
1460
1461 /* ssp_hash_algs<> */
1462 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04001463 tmp = be32_to_cpup(p++);
Mi Jinlong5afa0402010-11-09 09:39:23 +08001464 while (tmp--) {
1465 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04001466 dummy = be32_to_cpup(p++);
Mi Jinlong5afa0402010-11-09 09:39:23 +08001467 READ_BUF(dummy);
1468 p += XDR_QUADLEN(dummy);
1469 }
Andy Adamson0733d212009-04-03 08:28:01 +03001470
1471 /* ssp_encr_algs<> */
1472 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04001473 tmp = be32_to_cpup(p++);
Mi Jinlong5afa0402010-11-09 09:39:23 +08001474 while (tmp--) {
1475 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04001476 dummy = be32_to_cpup(p++);
Mi Jinlong5afa0402010-11-09 09:39:23 +08001477 READ_BUF(dummy);
1478 p += XDR_QUADLEN(dummy);
1479 }
Andy Adamson0733d212009-04-03 08:28:01 +03001480
nixiaoming5ed96bc2018-07-23 09:57:11 +08001481 /* ignore ssp_window and ssp_num_gss_handles: */
Andy Adamson0733d212009-04-03 08:28:01 +03001482 READ_BUF(8);
Andy Adamson0733d212009-04-03 08:28:01 +03001483 break;
1484 default:
1485 goto xdr_error;
1486 }
1487
Andy Adamson0733d212009-04-03 08:28:01 +03001488 READ_BUF(4); /* nfs_impl_id4 array length */
J. Bruce Fields06553992014-06-02 12:32:51 -04001489 dummy = be32_to_cpup(p++);
Andy Adamson0733d212009-04-03 08:28:01 +03001490
1491 if (dummy > 1)
1492 goto xdr_error;
1493
1494 if (dummy == 1) {
J. Bruce Fields79123442019-06-05 12:42:05 -04001495 status = nfsd4_decode_opaque(argp, &exid->nii_domain);
1496 if (status)
1497 goto xdr_error;
Andy Adamson0733d212009-04-03 08:28:01 +03001498
1499 /* nii_name */
J. Bruce Fields79123442019-06-05 12:42:05 -04001500 status = nfsd4_decode_opaque(argp, &exid->nii_name);
1501 if (status)
1502 goto xdr_error;
Andy Adamson0733d212009-04-03 08:28:01 +03001503
1504 /* nii_date */
J. Bruce Fields79123442019-06-05 12:42:05 -04001505 status = nfsd4_decode_time(argp, &exid->nii_time);
1506 if (status)
1507 goto xdr_error;
Andy Adamson0733d212009-04-03 08:28:01 +03001508 }
1509 DECODE_TAIL;
Andy Adamson2db134e2009-04-03 08:27:55 +03001510}
1511
1512static __be32
1513nfsd4_decode_create_session(struct nfsd4_compoundargs *argp,
1514 struct nfsd4_create_session *sess)
1515{
Andy Adamsonec6b5d72009-04-03 08:28:28 +03001516 DECODE_HEAD;
Andy Adamsonec6b5d72009-04-03 08:28:28 +03001517
1518 READ_BUF(16);
1519 COPYMEM(&sess->clientid, 8);
J. Bruce Fields06553992014-06-02 12:32:51 -04001520 sess->seqid = be32_to_cpup(p++);
1521 sess->flags = be32_to_cpup(p++);
Andy Adamsonec6b5d72009-04-03 08:28:28 +03001522
1523 /* Fore channel attrs */
1524 READ_BUF(28);
Trond Myklebustb96811c2019-08-18 14:18:58 -04001525 p++; /* headerpadsz is always 0 */
J. Bruce Fields06553992014-06-02 12:32:51 -04001526 sess->fore_channel.maxreq_sz = be32_to_cpup(p++);
1527 sess->fore_channel.maxresp_sz = be32_to_cpup(p++);
1528 sess->fore_channel.maxresp_cached = be32_to_cpup(p++);
1529 sess->fore_channel.maxops = be32_to_cpup(p++);
1530 sess->fore_channel.maxreqs = be32_to_cpup(p++);
1531 sess->fore_channel.nr_rdma_attrs = be32_to_cpup(p++);
Andy Adamsonec6b5d72009-04-03 08:28:28 +03001532 if (sess->fore_channel.nr_rdma_attrs == 1) {
1533 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04001534 sess->fore_channel.rdma_attrs = be32_to_cpup(p++);
Andy Adamsonec6b5d72009-04-03 08:28:28 +03001535 } else if (sess->fore_channel.nr_rdma_attrs > 1) {
1536 dprintk("Too many fore channel attr bitmaps!\n");
1537 goto xdr_error;
1538 }
1539
1540 /* Back channel attrs */
1541 READ_BUF(28);
Trond Myklebustb96811c2019-08-18 14:18:58 -04001542 p++; /* headerpadsz is always 0 */
J. Bruce Fields06553992014-06-02 12:32:51 -04001543 sess->back_channel.maxreq_sz = be32_to_cpup(p++);
1544 sess->back_channel.maxresp_sz = be32_to_cpup(p++);
1545 sess->back_channel.maxresp_cached = be32_to_cpup(p++);
1546 sess->back_channel.maxops = be32_to_cpup(p++);
1547 sess->back_channel.maxreqs = be32_to_cpup(p++);
1548 sess->back_channel.nr_rdma_attrs = be32_to_cpup(p++);
Andy Adamsonec6b5d72009-04-03 08:28:28 +03001549 if (sess->back_channel.nr_rdma_attrs == 1) {
1550 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04001551 sess->back_channel.rdma_attrs = be32_to_cpup(p++);
Andy Adamsonec6b5d72009-04-03 08:28:28 +03001552 } else if (sess->back_channel.nr_rdma_attrs > 1) {
1553 dprintk("Too many back channel attr bitmaps!\n");
1554 goto xdr_error;
1555 }
1556
J. Bruce Fieldsacb28872012-03-27 14:50:26 -04001557 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04001558 sess->callback_prog = be32_to_cpup(p++);
J. Bruce Fieldsacb28872012-03-27 14:50:26 -04001559 nfsd4_decode_cb_sec(argp, &sess->cb_sec);
Andy Adamsonec6b5d72009-04-03 08:28:28 +03001560 DECODE_TAIL;
Andy Adamson2db134e2009-04-03 08:27:55 +03001561}
1562
1563static __be32
1564nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp,
1565 struct nfsd4_destroy_session *destroy_session)
1566{
Benny Halevye10e0cf2009-04-03 08:28:38 +03001567 DECODE_HEAD;
1568 READ_BUF(NFS4_MAX_SESSIONID_LEN);
1569 COPYMEM(destroy_session->sessionid.data, NFS4_MAX_SESSIONID_LEN);
1570
1571 DECODE_TAIL;
Andy Adamson2db134e2009-04-03 08:27:55 +03001572}
1573
1574static __be32
Bryan Schumakere1ca12d2011-07-13 11:04:21 -04001575nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp,
1576 struct nfsd4_free_stateid *free_stateid)
1577{
1578 DECODE_HEAD;
1579
1580 READ_BUF(sizeof(stateid_t));
J. Bruce Fields06553992014-06-02 12:32:51 -04001581 free_stateid->fr_stateid.si_generation = be32_to_cpup(p++);
Bryan Schumakere1ca12d2011-07-13 11:04:21 -04001582 COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t));
1583
1584 DECODE_TAIL;
1585}
1586
1587static __be32
Andy Adamson2db134e2009-04-03 08:27:55 +03001588nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
1589 struct nfsd4_sequence *seq)
1590{
Benny Halevyb85d4c02009-04-03 08:28:08 +03001591 DECODE_HEAD;
1592
1593 READ_BUF(NFS4_MAX_SESSIONID_LEN + 16);
1594 COPYMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN);
J. Bruce Fields06553992014-06-02 12:32:51 -04001595 seq->seqid = be32_to_cpup(p++);
1596 seq->slotid = be32_to_cpup(p++);
1597 seq->maxslots = be32_to_cpup(p++);
1598 seq->cachethis = be32_to_cpup(p++);
Benny Halevyb85d4c02009-04-03 08:28:08 +03001599
1600 DECODE_TAIL;
Andy Adamson2db134e2009-04-03 08:27:55 +03001601}
1602
Bryan Schumaker17456802011-07-13 10:50:48 -04001603static __be32
1604nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid)
1605{
Bryan Schumaker17456802011-07-13 10:50:48 -04001606 int i;
Bryan Schumaker03cfb422012-01-27 10:22:49 -05001607 __be32 *p, status;
1608 struct nfsd4_test_stateid_id *stateid;
Bryan Schumaker17456802011-07-13 10:50:48 -04001609
1610 READ_BUF(4);
1611 test_stateid->ts_num_ids = ntohl(*p++);
1612
Bryan Schumaker03cfb422012-01-27 10:22:49 -05001613 INIT_LIST_HEAD(&test_stateid->ts_stateid_list);
Bryan Schumaker17456802011-07-13 10:50:48 -04001614
1615 for (i = 0; i < test_stateid->ts_num_ids; i++) {
J. Bruce Fieldsd5e23382014-06-24 17:43:45 -04001616 stateid = svcxdr_tmpalloc(argp, sizeof(*stateid));
Bryan Schumaker03cfb422012-01-27 10:22:49 -05001617 if (!stateid) {
Al Viroafcf6792012-04-13 00:15:37 -04001618 status = nfserrno(-ENOMEM);
Bryan Schumaker03cfb422012-01-27 10:22:49 -05001619 goto out;
1620 }
1621
Bryan Schumaker03cfb422012-01-27 10:22:49 -05001622 INIT_LIST_HEAD(&stateid->ts_id_list);
1623 list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list);
1624
1625 status = nfsd4_decode_stateid(argp, &stateid->ts_id_stateid);
Bryan Schumaker17456802011-07-13 10:50:48 -04001626 if (status)
Bryan Schumaker03cfb422012-01-27 10:22:49 -05001627 goto out;
Bryan Schumaker17456802011-07-13 10:50:48 -04001628 }
1629
1630 status = 0;
1631out:
1632 return status;
1633xdr_error:
1634 dprintk("NFSD: xdr error (%s:%d)\n", __FILE__, __LINE__);
1635 status = nfserr_bad_xdr;
1636 goto out;
1637}
1638
Mi Jinlong345c2842011-10-20 17:51:39 +08001639static __be32 nfsd4_decode_destroy_clientid(struct nfsd4_compoundargs *argp, struct nfsd4_destroy_clientid *dc)
1640{
1641 DECODE_HEAD;
1642
1643 READ_BUF(8);
1644 COPYMEM(&dc->clientid, 8);
1645
1646 DECODE_TAIL;
1647}
1648
J. Bruce Fields4dc6ec02010-04-19 15:11:28 -04001649static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, struct nfsd4_reclaim_complete *rc)
1650{
1651 DECODE_HEAD;
1652
1653 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04001654 rc->rca_one_fs = be32_to_cpup(p++);
J. Bruce Fields4dc6ec02010-04-19 15:11:28 -04001655
1656 DECODE_TAIL;
1657}
1658
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02001659#ifdef CONFIG_NFSD_PNFS
1660static __be32
1661nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp,
1662 struct nfsd4_getdeviceinfo *gdev)
1663{
1664 DECODE_HEAD;
1665 u32 num, i;
1666
1667 READ_BUF(sizeof(struct nfsd4_deviceid) + 3 * 4);
1668 COPYMEM(&gdev->gd_devid, sizeof(struct nfsd4_deviceid));
1669 gdev->gd_layout_type = be32_to_cpup(p++);
1670 gdev->gd_maxcount = be32_to_cpup(p++);
1671 num = be32_to_cpup(p++);
1672 if (num) {
Scott Mayhew3171822f2018-06-08 16:31:46 -04001673 if (num > 1000)
1674 goto xdr_error;
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02001675 READ_BUF(4 * num);
1676 gdev->gd_notify_types = be32_to_cpup(p++);
1677 for (i = 1; i < num; i++) {
1678 if (be32_to_cpup(p++)) {
1679 status = nfserr_inval;
1680 goto out;
1681 }
1682 }
1683 }
1684 DECODE_TAIL;
1685}
1686
1687static __be32
1688nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp,
1689 struct nfsd4_layoutget *lgp)
1690{
1691 DECODE_HEAD;
1692
1693 READ_BUF(36);
1694 lgp->lg_signal = be32_to_cpup(p++);
1695 lgp->lg_layout_type = be32_to_cpup(p++);
1696 lgp->lg_seg.iomode = be32_to_cpup(p++);
1697 p = xdr_decode_hyper(p, &lgp->lg_seg.offset);
1698 p = xdr_decode_hyper(p, &lgp->lg_seg.length);
1699 p = xdr_decode_hyper(p, &lgp->lg_minlength);
Kinglong Meedb59c0e2015-03-19 19:04:41 +08001700
1701 status = nfsd4_decode_stateid(argp, &lgp->lg_sid);
1702 if (status)
1703 return status;
1704
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02001705 READ_BUF(4);
1706 lgp->lg_maxcount = be32_to_cpup(p++);
1707
1708 DECODE_TAIL;
1709}
1710
1711static __be32
1712nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp,
1713 struct nfsd4_layoutcommit *lcp)
1714{
1715 DECODE_HEAD;
1716 u32 timechange;
1717
1718 READ_BUF(20);
1719 p = xdr_decode_hyper(p, &lcp->lc_seg.offset);
1720 p = xdr_decode_hyper(p, &lcp->lc_seg.length);
1721 lcp->lc_reclaim = be32_to_cpup(p++);
Kinglong Meedb59c0e2015-03-19 19:04:41 +08001722
1723 status = nfsd4_decode_stateid(argp, &lcp->lc_sid);
1724 if (status)
1725 return status;
1726
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02001727 READ_BUF(4);
1728 lcp->lc_newoffset = be32_to_cpup(p++);
1729 if (lcp->lc_newoffset) {
1730 READ_BUF(8);
1731 p = xdr_decode_hyper(p, &lcp->lc_last_wr);
1732 } else
1733 lcp->lc_last_wr = 0;
1734 READ_BUF(4);
1735 timechange = be32_to_cpup(p++);
1736 if (timechange) {
1737 status = nfsd4_decode_time(argp, &lcp->lc_mtime);
1738 if (status)
1739 return status;
1740 } else {
1741 lcp->lc_mtime.tv_nsec = UTIME_NOW;
1742 }
1743 READ_BUF(8);
1744 lcp->lc_layout_type = be32_to_cpup(p++);
1745
1746 /*
1747 * Save the layout update in XDR format and let the layout driver deal
1748 * with it later.
1749 */
1750 lcp->lc_up_len = be32_to_cpup(p++);
1751 if (lcp->lc_up_len > 0) {
1752 READ_BUF(lcp->lc_up_len);
1753 READMEM(lcp->lc_up_layout, lcp->lc_up_len);
1754 }
1755
1756 DECODE_TAIL;
1757}
1758
1759static __be32
1760nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp,
1761 struct nfsd4_layoutreturn *lrp)
1762{
1763 DECODE_HEAD;
1764
1765 READ_BUF(16);
1766 lrp->lr_reclaim = be32_to_cpup(p++);
1767 lrp->lr_layout_type = be32_to_cpup(p++);
1768 lrp->lr_seg.iomode = be32_to_cpup(p++);
1769 lrp->lr_return_type = be32_to_cpup(p++);
1770 if (lrp->lr_return_type == RETURN_FILE) {
1771 READ_BUF(16);
1772 p = xdr_decode_hyper(p, &lrp->lr_seg.offset);
1773 p = xdr_decode_hyper(p, &lrp->lr_seg.length);
Kinglong Meedb59c0e2015-03-19 19:04:41 +08001774
1775 status = nfsd4_decode_stateid(argp, &lrp->lr_sid);
1776 if (status)
1777 return status;
1778
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02001779 READ_BUF(4);
1780 lrp->lrf_body_len = be32_to_cpup(p++);
1781 if (lrp->lrf_body_len > 0) {
1782 READ_BUF(lrp->lrf_body_len);
1783 READMEM(lrp->lrf_body, lrp->lrf_body_len);
1784 }
1785 } else {
1786 lrp->lr_seg.offset = 0;
1787 lrp->lr_seg.length = NFS4_MAX_UINT64;
1788 }
1789
1790 DECODE_TAIL;
1791}
1792#endif /* CONFIG_NFSD_PNFS */
1793
Andy Adamson2db134e2009-04-03 08:27:55 +03001794static __be32
Anna Schumaker95d871f2014-11-07 14:44:26 -05001795nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp,
1796 struct nfsd4_fallocate *fallocate)
1797{
1798 DECODE_HEAD;
1799
1800 status = nfsd4_decode_stateid(argp, &fallocate->falloc_stateid);
1801 if (status)
1802 return status;
1803
1804 READ_BUF(16);
1805 p = xdr_decode_hyper(p, &fallocate->falloc_offset);
1806 xdr_decode_hyper(p, &fallocate->falloc_length);
1807
1808 DECODE_TAIL;
1809}
1810
1811static __be32
Christoph Hellwigffa01602015-12-03 12:59:52 +01001812nfsd4_decode_clone(struct nfsd4_compoundargs *argp, struct nfsd4_clone *clone)
1813{
1814 DECODE_HEAD;
1815
1816 status = nfsd4_decode_stateid(argp, &clone->cl_src_stateid);
1817 if (status)
1818 return status;
1819 status = nfsd4_decode_stateid(argp, &clone->cl_dst_stateid);
1820 if (status)
1821 return status;
1822
1823 READ_BUF(8 + 8 + 8);
1824 p = xdr_decode_hyper(p, &clone->cl_src_pos);
1825 p = xdr_decode_hyper(p, &clone->cl_dst_pos);
1826 p = xdr_decode_hyper(p, &clone->cl_count);
1827 DECODE_TAIL;
1828}
1829
Olga Kornievskaia84e1b212019-09-13 14:00:57 -04001830static __be32 nfsd4_decode_nl4_server(struct nfsd4_compoundargs *argp,
1831 struct nl4_server *ns)
1832{
1833 DECODE_HEAD;
1834 struct nfs42_netaddr *naddr;
1835
1836 READ_BUF(4);
1837 ns->nl4_type = be32_to_cpup(p++);
1838
1839 /* currently support for 1 inter-server source server */
1840 switch (ns->nl4_type) {
1841 case NL4_NETADDR:
1842 naddr = &ns->u.nl4_addr;
1843
1844 READ_BUF(4);
1845 naddr->netid_len = be32_to_cpup(p++);
1846 if (naddr->netid_len > RPCBIND_MAXNETIDLEN)
1847 goto xdr_error;
1848
1849 READ_BUF(naddr->netid_len + 4); /* 4 for uaddr len */
1850 COPYMEM(naddr->netid, naddr->netid_len);
1851
1852 naddr->addr_len = be32_to_cpup(p++);
1853 if (naddr->addr_len > RPCBIND_MAXUADDRLEN)
1854 goto xdr_error;
1855
1856 READ_BUF(naddr->addr_len);
1857 COPYMEM(naddr->addr, naddr->addr_len);
1858 break;
1859 default:
1860 goto xdr_error;
1861 }
1862 DECODE_TAIL;
1863}
1864
Christoph Hellwigffa01602015-12-03 12:59:52 +01001865static __be32
Anna Schumaker29ae7f92016-09-07 15:57:30 -04001866nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy)
1867{
1868 DECODE_HEAD;
Olga Kornievskaia84e1b212019-09-13 14:00:57 -04001869 struct nl4_server *ns_dummy;
1870 int i, count;
Anna Schumaker29ae7f92016-09-07 15:57:30 -04001871
1872 status = nfsd4_decode_stateid(argp, &copy->cp_src_stateid);
1873 if (status)
1874 return status;
1875 status = nfsd4_decode_stateid(argp, &copy->cp_dst_stateid);
1876 if (status)
1877 return status;
1878
1879 READ_BUF(8 + 8 + 8 + 4 + 4 + 4);
1880 p = xdr_decode_hyper(p, &copy->cp_src_pos);
1881 p = xdr_decode_hyper(p, &copy->cp_dst_pos);
1882 p = xdr_decode_hyper(p, &copy->cp_count);
J. Bruce Fieldsedcc8452018-03-07 15:37:35 -05001883 p++; /* ca_consecutive: we always do consecutive copies */
Anna Schumaker29ae7f92016-09-07 15:57:30 -04001884 copy->cp_synchronous = be32_to_cpup(p++);
Olga Kornievskaia84e1b212019-09-13 14:00:57 -04001885
1886 count = be32_to_cpup(p++);
1887
1888 copy->cp_intra = false;
1889 if (count == 0) { /* intra-server copy */
1890 copy->cp_intra = true;
1891 goto intra;
1892 }
1893
1894 /* decode all the supplied server addresses but use first */
1895 status = nfsd4_decode_nl4_server(argp, &copy->cp_src);
1896 if (status)
1897 return status;
1898
1899 ns_dummy = kmalloc(sizeof(struct nl4_server), GFP_KERNEL);
1900 if (ns_dummy == NULL)
1901 return nfserrno(-ENOMEM);
1902 for (i = 0; i < count - 1; i++) {
1903 status = nfsd4_decode_nl4_server(argp, ns_dummy);
1904 if (status) {
1905 kfree(ns_dummy);
1906 return status;
1907 }
1908 }
1909 kfree(ns_dummy);
1910intra:
Anna Schumaker29ae7f92016-09-07 15:57:30 -04001911
1912 DECODE_TAIL;
1913}
1914
1915static __be32
Olga Kornievskaia6308bc92018-07-20 18:19:18 -04001916nfsd4_decode_offload_status(struct nfsd4_compoundargs *argp,
1917 struct nfsd4_offload_status *os)
1918{
1919 return nfsd4_decode_stateid(argp, &os->stateid);
1920}
1921
1922static __be32
Olga Kornievskaia51911862019-08-08 11:14:59 -04001923nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp,
1924 struct nfsd4_copy_notify *cn)
1925{
Chuck Lever5aff7d02020-09-11 14:47:59 -04001926 __be32 status;
Olga Kornievskaia51911862019-08-08 11:14:59 -04001927
1928 status = nfsd4_decode_stateid(argp, &cn->cpn_src_stateid);
1929 if (status)
1930 return status;
1931 return nfsd4_decode_nl4_server(argp, &cn->cpn_dst);
1932}
1933
1934static __be32
Anna Schumaker24bab492014-09-26 13:58:27 -04001935nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek)
1936{
1937 DECODE_HEAD;
1938
1939 status = nfsd4_decode_stateid(argp, &seek->seek_stateid);
1940 if (status)
1941 return status;
1942
1943 READ_BUF(8 + 4);
1944 p = xdr_decode_hyper(p, &seek->seek_offset);
1945 seek->seek_whence = be32_to_cpup(p);
1946
1947 DECODE_TAIL;
1948}
1949
Frank van der Linden23e50fe2020-06-23 22:39:26 +00001950/*
1951 * XDR data that is more than PAGE_SIZE in size is normally part of a
1952 * read or write. However, the size of extended attributes is limited
1953 * by the maximum request size, and then further limited by the underlying
1954 * filesystem limits. This can exceed PAGE_SIZE (currently, XATTR_SIZE_MAX
1955 * is 64k). Since there is no kvec- or page-based interface to xattrs,
1956 * and we're not dealing with contiguous pages, we need to do some copying.
1957 */
1958
1959/*
Chuck Leverc1346a122020-11-03 11:54:23 -05001960 * Decode data into buffer.
Frank van der Linden23e50fe2020-06-23 22:39:26 +00001961 */
1962static __be32
Chuck Leverc1346a122020-11-03 11:54:23 -05001963nfsd4_vbuf_from_vector(struct nfsd4_compoundargs *argp, struct xdr_buf *xdr,
1964 char **bufp, u32 buflen)
Frank van der Linden23e50fe2020-06-23 22:39:26 +00001965{
Chuck Leverc1346a122020-11-03 11:54:23 -05001966 struct page **pages = xdr->pages;
1967 struct kvec *head = xdr->head;
Frank van der Linden23e50fe2020-06-23 22:39:26 +00001968 char *tmp, *dp;
1969 u32 len;
1970
1971 if (buflen <= head->iov_len) {
1972 /*
1973 * We're in luck, the head has enough space. Just return
1974 * the head, no need for copying.
1975 */
1976 *bufp = head->iov_base;
1977 return 0;
1978 }
1979
1980 tmp = svcxdr_tmpalloc(argp, buflen);
1981 if (tmp == NULL)
1982 return nfserr_jukebox;
1983
1984 dp = tmp;
1985 memcpy(dp, head->iov_base, head->iov_len);
1986 buflen -= head->iov_len;
1987 dp += head->iov_len;
1988
1989 while (buflen > 0) {
1990 len = min_t(u32, buflen, PAGE_SIZE);
1991 memcpy(dp, page_address(*pages), len);
1992
1993 buflen -= len;
1994 dp += len;
1995 pages++;
1996 }
1997
1998 *bufp = tmp;
1999 return 0;
2000}
2001
2002/*
2003 * Get a user extended attribute name from the XDR buffer.
2004 * It will not have the "user." prefix, so prepend it.
2005 * Lastly, check for nul characters in the name.
2006 */
2007static __be32
2008nfsd4_decode_xattr_name(struct nfsd4_compoundargs *argp, char **namep)
2009{
2010 DECODE_HEAD;
2011 char *name, *sp, *dp;
2012 u32 namelen, cnt;
2013
2014 READ_BUF(4);
2015 namelen = be32_to_cpup(p++);
2016
2017 if (namelen > (XATTR_NAME_MAX - XATTR_USER_PREFIX_LEN))
2018 return nfserr_nametoolong;
2019
2020 if (namelen == 0)
2021 goto xdr_error;
2022
2023 READ_BUF(namelen);
2024
2025 name = svcxdr_tmpalloc(argp, namelen + XATTR_USER_PREFIX_LEN + 1);
2026 if (!name)
2027 return nfserr_jukebox;
2028
2029 memcpy(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
2030
2031 /*
2032 * Copy the extended attribute name over while checking for 0
2033 * characters.
2034 */
2035 sp = (char *)p;
2036 dp = name + XATTR_USER_PREFIX_LEN;
2037 cnt = namelen;
2038
2039 while (cnt-- > 0) {
2040 if (*sp == '\0')
2041 goto xdr_error;
2042 *dp++ = *sp++;
2043 }
2044 *dp = '\0';
2045
2046 *namep = name;
2047
2048 DECODE_TAIL;
2049}
2050
2051/*
2052 * A GETXATTR op request comes without a length specifier. We just set the
2053 * maximum length for the reply based on XATTR_SIZE_MAX and the maximum
2054 * channel reply size. nfsd_getxattr will probe the length of the xattr,
2055 * check it against getxa_len, and allocate + return the value.
2056 */
2057static __be32
2058nfsd4_decode_getxattr(struct nfsd4_compoundargs *argp,
2059 struct nfsd4_getxattr *getxattr)
2060{
2061 __be32 status;
2062 u32 maxcount;
2063
2064 status = nfsd4_decode_xattr_name(argp, &getxattr->getxa_name);
2065 if (status)
2066 return status;
2067
2068 maxcount = svc_max_payload(argp->rqstp);
2069 maxcount = min_t(u32, XATTR_SIZE_MAX, maxcount);
2070
2071 getxattr->getxa_len = maxcount;
2072
2073 return status;
2074}
2075
2076static __be32
2077nfsd4_decode_setxattr(struct nfsd4_compoundargs *argp,
2078 struct nfsd4_setxattr *setxattr)
2079{
2080 DECODE_HEAD;
2081 u32 flags, maxcount, size;
Frank van der Linden23e50fe2020-06-23 22:39:26 +00002082
2083 READ_BUF(4);
2084 flags = be32_to_cpup(p++);
2085
2086 if (flags > SETXATTR4_REPLACE)
2087 return nfserr_inval;
2088 setxattr->setxa_flags = flags;
2089
2090 status = nfsd4_decode_xattr_name(argp, &setxattr->setxa_name);
2091 if (status)
2092 return status;
2093
2094 maxcount = svc_max_payload(argp->rqstp);
2095 maxcount = min_t(u32, XATTR_SIZE_MAX, maxcount);
2096
2097 READ_BUF(4);
2098 size = be32_to_cpup(p++);
2099 if (size > maxcount)
2100 return nfserr_xattr2big;
2101
2102 setxattr->setxa_len = size;
2103 if (size > 0) {
Chuck Leverc1346a122020-11-03 11:54:23 -05002104 struct xdr_buf payload;
Frank van der Linden23e50fe2020-06-23 22:39:26 +00002105
Chuck Leverc1346a122020-11-03 11:54:23 -05002106 if (!xdr_stream_subsegment(argp->xdr, &payload, size))
2107 goto xdr_error;
2108 status = nfsd4_vbuf_from_vector(argp, &payload,
2109 &setxattr->setxa_buf, size);
Frank van der Linden23e50fe2020-06-23 22:39:26 +00002110 }
2111
2112 DECODE_TAIL;
2113}
2114
2115static __be32
2116nfsd4_decode_listxattrs(struct nfsd4_compoundargs *argp,
2117 struct nfsd4_listxattrs *listxattrs)
2118{
2119 DECODE_HEAD;
2120 u32 maxcount;
2121
2122 READ_BUF(12);
2123 p = xdr_decode_hyper(p, &listxattrs->lsxa_cookie);
2124
2125 /*
2126 * If the cookie is too large to have even one user.x attribute
2127 * plus trailing '\0' left in a maximum size buffer, it's invalid.
2128 */
2129 if (listxattrs->lsxa_cookie >=
2130 (XATTR_LIST_MAX / (XATTR_USER_PREFIX_LEN + 2)))
2131 return nfserr_badcookie;
2132
2133 maxcount = be32_to_cpup(p++);
2134 if (maxcount < 8)
2135 /* Always need at least 2 words (length and one character) */
2136 return nfserr_inval;
2137
2138 maxcount = min(maxcount, svc_max_payload(argp->rqstp));
2139 listxattrs->lsxa_maxcount = maxcount;
2140
2141 DECODE_TAIL;
2142}
2143
2144static __be32
2145nfsd4_decode_removexattr(struct nfsd4_compoundargs *argp,
2146 struct nfsd4_removexattr *removexattr)
2147{
2148 return nfsd4_decode_xattr_name(argp, &removexattr->rmxa_name);
2149}
2150
Anna Schumaker24bab492014-09-26 13:58:27 -04002151static __be32
Benny Halevy347e0ad2008-07-02 11:13:41 +03002152nfsd4_decode_noop(struct nfsd4_compoundargs *argp, void *p)
2153{
2154 return nfs_ok;
2155}
2156
Benny Halevy3c375c62008-07-02 11:14:01 +03002157static __be32
2158nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, void *p)
2159{
Benny Halevy1e685ec2009-03-04 23:06:06 +02002160 return nfserr_notsupp;
Benny Halevy3c375c62008-07-02 11:14:01 +03002161}
2162
Benny Halevy347e0ad2008-07-02 11:13:41 +03002163typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, void *);
2164
Chuck Leverc1df6092017-08-01 11:59:58 -04002165static const nfsd4_dec nfsd4_dec_ops[] = {
J. Bruce Fieldsad1060c2008-07-18 15:04:16 -04002166 [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access,
2167 [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close,
2168 [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit,
2169 [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create,
2170 [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp,
2171 [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn,
2172 [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr,
2173 [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop,
2174 [OP_LINK] = (nfsd4_dec)nfsd4_decode_link,
2175 [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock,
2176 [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt,
2177 [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku,
2178 [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup,
2179 [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop,
2180 [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify,
2181 [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open,
2182 [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp,
2183 [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm,
2184 [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade,
2185 [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh,
Anna Schumakere1a90eb2013-10-30 10:00:20 -04002186 [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_putpubfh,
J. Bruce Fieldsad1060c2008-07-18 15:04:16 -04002187 [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop,
2188 [OP_READ] = (nfsd4_dec)nfsd4_decode_read,
2189 [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir,
2190 [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop,
2191 [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove,
2192 [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename,
2193 [OP_RENEW] = (nfsd4_dec)nfsd4_decode_renew,
2194 [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop,
2195 [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop,
2196 [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo,
2197 [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr,
2198 [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_setclientid,
2199 [OP_SETCLIENTID_CONFIRM] = (nfsd4_dec)nfsd4_decode_setclientid_confirm,
2200 [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify,
2201 [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write,
2202 [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner,
Andy Adamson2db134e2009-04-03 08:27:55 +03002203
2204 /* new operations for NFSv4.1 */
J. Bruce Fieldscb73a9f2012-11-01 18:09:48 -04002205 [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_backchannel_ctl,
J. Bruce Fields1d1bc8f2010-10-04 23:12:59 -04002206 [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session,
Randy Dunlap9064caa2009-04-28 16:48:25 -07002207 [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id,
2208 [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session,
2209 [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session,
Bryan Schumakere1ca12d2011-07-13 11:04:21 -04002210 [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_free_stateid,
Randy Dunlap9064caa2009-04-28 16:48:25 -07002211 [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp,
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02002212#ifdef CONFIG_NFSD_PNFS
2213 [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_getdeviceinfo,
2214 [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp,
2215 [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_layoutcommit,
2216 [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_layoutget,
2217 [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_layoutreturn,
2218#else
Randy Dunlap9064caa2009-04-28 16:48:25 -07002219 [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp,
2220 [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp,
2221 [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp,
2222 [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp,
2223 [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp,
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02002224#endif
J. Bruce Fields04f4ad12010-12-16 09:51:13 -05002225 [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name,
Randy Dunlap9064caa2009-04-28 16:48:25 -07002226 [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence,
2227 [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp,
Bryan Schumaker17456802011-07-13 10:50:48 -04002228 [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_test_stateid,
Randy Dunlap9064caa2009-04-28 16:48:25 -07002229 [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp,
Mi Jinlong345c2842011-10-20 17:51:39 +08002230 [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_destroy_clientid,
J. Bruce Fields4dc6ec02010-04-19 15:11:28 -04002231 [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete,
Anna Schumaker87a15a82014-09-26 13:58:26 -04002232
2233 /* new operations for NFSv4.2 */
Anna Schumaker95d871f2014-11-07 14:44:26 -05002234 [OP_ALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate,
Anna Schumaker29ae7f92016-09-07 15:57:30 -04002235 [OP_COPY] = (nfsd4_dec)nfsd4_decode_copy,
Olga Kornievskaia51911862019-08-08 11:14:59 -04002236 [OP_COPY_NOTIFY] = (nfsd4_dec)nfsd4_decode_copy_notify,
Anna Schumakerb0cb9082014-11-07 14:44:27 -05002237 [OP_DEALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate,
Anna Schumaker87a15a82014-09-26 13:58:26 -04002238 [OP_IO_ADVISE] = (nfsd4_dec)nfsd4_decode_notsupp,
2239 [OP_LAYOUTERROR] = (nfsd4_dec)nfsd4_decode_notsupp,
2240 [OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp,
Olga Kornievskaia885e2bf2018-07-20 18:19:19 -04002241 [OP_OFFLOAD_CANCEL] = (nfsd4_dec)nfsd4_decode_offload_status,
Olga Kornievskaia6308bc92018-07-20 18:19:18 -04002242 [OP_OFFLOAD_STATUS] = (nfsd4_dec)nfsd4_decode_offload_status,
Anna Schumaker528b8492020-09-28 13:08:58 -04002243 [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_read,
Anna Schumaker24bab492014-09-26 13:58:27 -04002244 [OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek,
Anna Schumaker87a15a82014-09-26 13:58:26 -04002245 [OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp,
Christoph Hellwigffa01602015-12-03 12:59:52 +01002246 [OP_CLONE] = (nfsd4_dec)nfsd4_decode_clone,
Frank van der Linden23e50fe2020-06-23 22:39:26 +00002247 /* RFC 8276 extended atributes operations */
2248 [OP_GETXATTR] = (nfsd4_dec)nfsd4_decode_getxattr,
2249 [OP_SETXATTR] = (nfsd4_dec)nfsd4_decode_setxattr,
2250 [OP_LISTXATTRS] = (nfsd4_dec)nfsd4_decode_listxattrs,
2251 [OP_REMOVEXATTR] = (nfsd4_dec)nfsd4_decode_removexattr,
Andy Adamson2db134e2009-04-03 08:27:55 +03002252};
2253
Anna Schumakere1a90eb2013-10-30 10:00:20 -04002254static inline bool
2255nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op)
2256{
Anna Schumaker8217d142013-10-30 13:38:13 -04002257 if (op->opnum < FIRST_NFS4_OP)
Anna Schumakere1a90eb2013-10-30 10:00:20 -04002258 return false;
Anna Schumaker8217d142013-10-30 13:38:13 -04002259 else if (argp->minorversion == 0 && op->opnum > LAST_NFS40_OP)
Anna Schumakere1a90eb2013-10-30 10:00:20 -04002260 return false;
Anna Schumaker8217d142013-10-30 13:38:13 -04002261 else if (argp->minorversion == 1 && op->opnum > LAST_NFS41_OP)
2262 return false;
2263 else if (argp->minorversion == 2 && op->opnum > LAST_NFS42_OP)
Anna Schumakere1a90eb2013-10-30 10:00:20 -04002264 return false;
2265 return true;
2266}
Benny Halevyf2feb962008-07-02 11:14:22 +03002267
Benny Halevy347e0ad2008-07-02 11:13:41 +03002268static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
2270{
2271 DECODE_HEAD;
2272 struct nfsd4_op *op;
J. Bruce Fields10910062011-01-24 12:11:02 -05002273 bool cachethis = false;
J. Bruce Fieldsa5cddc82014-05-12 18:10:58 -04002274 int auth_slack= argp->rqstp->rq_auth_slack;
2275 int max_reply = auth_slack + 8; /* opcnt, status */
J. Bruce Fieldsb0e35fd2014-02-04 10:36:59 -05002276 int readcount = 0;
2277 int readbytes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 int i;
2279
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04002281 argp->taglen = be32_to_cpup(p++);
J. Bruce Fields4aed9c42016-02-29 20:21:21 -05002282 READ_BUF(argp->taglen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 SAVEMEM(argp->tag, argp->taglen);
J. Bruce Fields4aed9c42016-02-29 20:21:21 -05002284 READ_BUF(8);
J. Bruce Fields06553992014-06-02 12:32:51 -04002285 argp->minorversion = be32_to_cpup(p++);
2286 argp->opcnt = be32_to_cpup(p++);
J. Bruce Fields4f0cefb2014-03-11 15:39:13 -04002287 max_reply += 4 + (XDR_QUADLEN(argp->taglen) << 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288
2289 if (argp->taglen > NFSD4_MAX_TAGLEN)
2290 goto xdr_error;
J. Bruce Fields00781172017-11-15 12:30:27 -05002291 /*
2292 * NFS4ERR_RESOURCE is a more helpful error than GARBAGE_ARGS
2293 * here, so we return success at the xdr level so that
2294 * nfsd4_proc can handle this is an NFS-level error.
2295 */
2296 if (argp->opcnt > NFSD_MAX_OPS_PER_COMPOUND)
2297 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298
Tobias Klausere8c96f82006-03-24 03:15:34 -08002299 if (argp->opcnt > ARRAY_SIZE(argp->iops)) {
J. Bruce Fields5d6031c2014-07-17 16:20:39 -04002300 argp->ops = kzalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 if (!argp->ops) {
2302 argp->ops = argp->iops;
Chuck Lever817cb9d2007-09-11 18:01:20 -04002303 dprintk("nfsd: couldn't allocate room for COMPOUND\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 goto xdr_error;
2305 }
2306 }
2307
Anna Schumakere1a90eb2013-10-30 10:00:20 -04002308 if (argp->minorversion > NFSD_SUPPORTED_MINOR_VERSION)
Benny Halevy30cff1f2008-07-02 11:13:18 +03002309 argp->opcnt = 0;
2310
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311 for (i = 0; i < argp->opcnt; i++) {
2312 op = &argp->ops[i];
2313 op->replay = NULL;
2314
J. Bruce Fields8a61b182012-11-16 22:28:38 -05002315 READ_BUF(4);
J. Bruce Fields06553992014-06-02 12:32:51 -04002316 op->opnum = be32_to_cpup(p++);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317
Chuck Lever08281342020-11-21 11:36:42 -05002318 if (nfsd4_opnum_in_range(argp, op)) {
Anna Schumakere1a90eb2013-10-30 10:00:20 -04002319 op->status = nfsd4_dec_ops[op->opnum](argp, &op->u);
Chuck Lever08281342020-11-21 11:36:42 -05002320 if (op->status != nfs_ok)
2321 trace_nfsd_compound_decode_err(argp->rqstp,
2322 argp->opcnt, i,
2323 op->opnum,
2324 op->status);
2325 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 op->opnum = OP_ILLEGAL;
2327 op->status = nfserr_op_illegal;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 }
J. Bruce Fieldsf4f9ef42017-07-06 17:51:29 -04002329 op->opdesc = OPDESC(op);
J. Bruce Fields10910062011-01-24 12:11:02 -05002330 /*
2331 * We'll try to cache the result in the DRC if any one
2332 * op in the compound wants to be cached:
2333 */
2334 cachethis |= nfsd4_cache_this_op(op);
J. Bruce Fields6ff40de2013-11-05 15:07:16 -05002335
Anna Schumaker528b8492020-09-28 13:08:58 -04002336 if (op->opnum == OP_READ || op->opnum == OP_READ_PLUS) {
J. Bruce Fieldsb0e35fd2014-02-04 10:36:59 -05002337 readcount++;
2338 readbytes += nfsd4_max_reply(argp->rqstp, op);
2339 } else
2340 max_reply += nfsd4_max_reply(argp->rqstp, op);
J. Bruce Fieldsf7b43d02014-08-12 11:41:40 -04002341 /*
Kinglong Mee7323f0d2017-02-03 22:51:46 +08002342 * OP_LOCK and OP_LOCKT may return a conflicting lock.
2343 * (Special case because it will just skip encoding this
2344 * if it runs out of xdr buffer space, and it is the only
2345 * operation that behaves this way.)
J. Bruce Fieldsf7b43d02014-08-12 11:41:40 -04002346 */
Kinglong Mee7323f0d2017-02-03 22:51:46 +08002347 if (op->opnum == OP_LOCK || op->opnum == OP_LOCKT)
J. Bruce Fieldsf7b43d02014-08-12 11:41:40 -04002348 max_reply += NFS4_OPAQUE_LIMIT;
J. Bruce Fieldse372ba62014-05-19 12:27:11 -04002349
2350 if (op->status) {
2351 argp->opcnt = i+1;
2352 break;
2353 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 }
J. Bruce Fields10910062011-01-24 12:11:02 -05002355 /* Sessions make the DRC unnecessary: */
2356 if (argp->minorversion)
2357 cachethis = false;
J. Bruce Fieldsb0e35fd2014-02-04 10:36:59 -05002358 svc_reserve(argp->rqstp, max_reply + readbytes);
J. Bruce Fields10910062011-01-24 12:11:02 -05002359 argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360
J. Bruce Fieldsa5cddc82014-05-12 18:10:58 -04002361 if (readcount > 1 || max_reply > PAGE_SIZE - auth_slack)
Jeff Layton779fb0f2014-11-19 07:51:18 -05002362 clear_bit(RQ_SPLICE_OK, &argp->rqstp->rq_flags);
J. Bruce Fieldsb0e35fd2014-02-04 10:36:59 -05002363
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 DECODE_TAIL;
2365}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366
NeilBrownb8800922017-01-30 17:17:00 +11002367static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode,
2368 struct svc_export *exp)
J. Bruce Fieldsc654b8a2009-04-16 17:33:25 -04002369{
NeilBrownb8800922017-01-30 17:17:00 +11002370 if (exp->ex_flags & NFSEXP_V4ROOT) {
2371 *p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time));
2372 *p++ = 0;
2373 } else if (IS_I_VERSION(inode)) {
Amir Goldstein39ca1bf2018-01-03 17:14:35 +02002374 p = xdr_encode_hyper(p, nfsd4_change_attribute(stat, inode));
J. Bruce Fieldsc654b8a2009-04-16 17:33:25 -04002375 } else {
J. Bruce Fieldsd05d5742014-03-22 18:48:39 -04002376 *p++ = cpu_to_be32(stat->ctime.tv_sec);
2377 *p++ = cpu_to_be32(stat->ctime.tv_nsec);
J. Bruce Fieldsc654b8a2009-04-16 17:33:25 -04002378 }
J. Bruce Fieldsd05d5742014-03-22 18:48:39 -04002379 return p;
J. Bruce Fieldsc654b8a2009-04-16 17:33:25 -04002380}
2381
J. Bruce Fields16945142018-04-25 14:34:11 -04002382/*
2383 * ctime (in NFSv4, time_metadata) is not writeable, and the client
2384 * doesn't really care what resolution could theoretically be stored by
2385 * the filesystem.
2386 *
2387 * The client cares how close together changes can be while still
2388 * guaranteeing ctime changes. For most filesystems (which have
2389 * timestamps with nanosecond fields) that is limited by the resolution
2390 * of the time returned from current_time() (which I'm assuming to be
2391 * 1/HZ).
2392 */
2393static __be32 *encode_time_delta(__be32 *p, struct inode *inode)
2394{
Arnd Bergmanne4598e32019-10-31 15:14:03 +01002395 struct timespec64 ts;
J. Bruce Fields16945142018-04-25 14:34:11 -04002396 u32 ns;
2397
2398 ns = max_t(u32, NSEC_PER_SEC/HZ, inode->i_sb->s_time_gran);
Arnd Bergmanne4598e32019-10-31 15:14:03 +01002399 ts = ns_to_timespec64(ns);
J. Bruce Fields16945142018-04-25 14:34:11 -04002400
2401 p = xdr_encode_hyper(p, ts.tv_sec);
2402 *p++ = cpu_to_be32(ts.tv_nsec);
2403
2404 return p;
2405}
2406
J. Bruce Fieldsd05d5742014-03-22 18:48:39 -04002407static __be32 *encode_cinfo(__be32 *p, struct nfsd4_change_info *c)
J. Bruce Fieldsc654b8a2009-04-16 17:33:25 -04002408{
J. Bruce Fieldsd05d5742014-03-22 18:48:39 -04002409 *p++ = cpu_to_be32(c->atomic);
J. Bruce Fieldsc654b8a2009-04-16 17:33:25 -04002410 if (c->change_supported) {
J. Bruce Fieldsd05d5742014-03-22 18:48:39 -04002411 p = xdr_encode_hyper(p, c->before_change);
2412 p = xdr_encode_hyper(p, c->after_change);
J. Bruce Fieldsc654b8a2009-04-16 17:33:25 -04002413 } else {
J. Bruce Fieldsd05d5742014-03-22 18:48:39 -04002414 *p++ = cpu_to_be32(c->before_ctime_sec);
2415 *p++ = cpu_to_be32(c->before_ctime_nsec);
2416 *p++ = cpu_to_be32(c->after_ctime_sec);
2417 *p++ = cpu_to_be32(c->after_ctime_nsec);
J. Bruce Fieldsc654b8a2009-04-16 17:33:25 -04002418 }
J. Bruce Fieldsd05d5742014-03-22 18:48:39 -04002419 return p;
J. Bruce Fieldsc654b8a2009-04-16 17:33:25 -04002420}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002422/* Encode as an array of strings the string given with components
Weston Andros Adamsone7a04442012-04-24 11:07:59 -04002423 * separated @sep, escaped with esc_enter and esc_exit.
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002424 */
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002425static __be32 nfsd4_encode_components_esc(struct xdr_stream *xdr, char sep,
2426 char *components, char esc_enter,
2427 char esc_exit)
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002428{
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002429 __be32 *p;
J. Bruce Fields082d4bd2013-08-29 15:42:52 -04002430 __be32 pathlen;
2431 int pathlen_offset;
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002432 int strlen, count=0;
Weston Andros Adamsone7a04442012-04-24 11:07:59 -04002433 char *str, *end, *next;
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002434
2435 dprintk("nfsd4_encode_components(%s)\n", components);
J. Bruce Fields082d4bd2013-08-29 15:42:52 -04002436
2437 pathlen_offset = xdr->buf->len;
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002438 p = xdr_reserve_space(xdr, 4);
2439 if (!p)
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002440 return nfserr_resource;
J. Bruce Fields082d4bd2013-08-29 15:42:52 -04002441 p++; /* We will fill this in with @count later */
2442
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002443 end = str = components;
2444 while (*end) {
Weston Andros Adamsone7a04442012-04-24 11:07:59 -04002445 bool found_esc = false;
2446
2447 /* try to parse as esc_start, ..., esc_end, sep */
2448 if (*str == esc_enter) {
2449 for (; *end && (*end != esc_exit); end++)
2450 /* find esc_exit or end of string */;
2451 next = end + 1;
2452 if (*end && (!*next || *next == sep)) {
2453 str++;
2454 found_esc = true;
2455 }
2456 }
2457
2458 if (!found_esc)
2459 for (; *end && (*end != sep); end++)
2460 /* find sep or end of string */;
2461
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002462 strlen = end - str;
2463 if (strlen) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002464 p = xdr_reserve_space(xdr, strlen + 4);
2465 if (!p)
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002466 return nfserr_resource;
J. Bruce Fields0c0c2672014-03-22 18:43:16 -04002467 p = xdr_encode_opaque(p, str, strlen);
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002468 count++;
2469 }
2470 else
2471 end++;
Benjamin Coddington5a64e562014-12-07 16:05:47 -05002472 if (found_esc)
2473 end = next;
2474
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002475 str = end;
2476 }
Benjamin Coddingtonbf7491f2014-12-07 16:05:48 -05002477 pathlen = htonl(count);
J. Bruce Fields082d4bd2013-08-29 15:42:52 -04002478 write_bytes_to_xdr_buf(xdr->buf, pathlen_offset, &pathlen, 4);
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002479 return 0;
2480}
2481
Weston Andros Adamsone7a04442012-04-24 11:07:59 -04002482/* Encode as an array of strings the string given with components
2483 * separated @sep.
2484 */
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002485static __be32 nfsd4_encode_components(struct xdr_stream *xdr, char sep,
2486 char *components)
Weston Andros Adamsone7a04442012-04-24 11:07:59 -04002487{
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002488 return nfsd4_encode_components_esc(xdr, sep, components, 0, 0);
Weston Andros Adamsone7a04442012-04-24 11:07:59 -04002489}
2490
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002491/*
2492 * encode a location element of a fs_locations structure
2493 */
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002494static __be32 nfsd4_encode_fs_location4(struct xdr_stream *xdr,
2495 struct nfsd4_fs_location *location)
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002496{
Al Virob37ad282006-10-19 23:28:59 -07002497 __be32 status;
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002498
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002499 status = nfsd4_encode_components_esc(xdr, ':', location->hosts,
Weston Andros Adamsone7a04442012-04-24 11:07:59 -04002500 '[', ']');
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002501 if (status)
2502 return status;
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002503 status = nfsd4_encode_components(xdr, '/', location->path);
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002504 if (status)
2505 return status;
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002506 return 0;
2507}
2508
2509/*
Trond Myklebusted748aa2011-09-12 19:37:06 -04002510 * Encode a path in RFC3530 'pathname4' format
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002511 */
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002512static __be32 nfsd4_encode_path(struct xdr_stream *xdr,
2513 const struct path *root,
2514 const struct path *path)
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002515{
Al Viro301f0262013-09-01 16:06:39 -04002516 struct path cur = *path;
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002517 __be32 *p;
Trond Myklebusted748aa2011-09-12 19:37:06 -04002518 struct dentry **components = NULL;
2519 unsigned int ncomponents = 0;
2520 __be32 err = nfserr_jukebox;
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002521
Trond Myklebusted748aa2011-09-12 19:37:06 -04002522 dprintk("nfsd4_encode_components(");
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002523
Trond Myklebusted748aa2011-09-12 19:37:06 -04002524 path_get(&cur);
2525 /* First walk the path up to the nfsd root, and store the
2526 * dentries/path components in an array.
2527 */
2528 for (;;) {
Kinglong Meeb77a4b22015-03-15 23:13:32 +08002529 if (path_equal(&cur, root))
Trond Myklebusted748aa2011-09-12 19:37:06 -04002530 break;
2531 if (cur.dentry == cur.mnt->mnt_root) {
2532 if (follow_up(&cur))
2533 continue;
2534 goto out_free;
2535 }
2536 if ((ncomponents & 15) == 0) {
2537 struct dentry **new;
2538 new = krealloc(components,
2539 sizeof(*new) * (ncomponents + 16),
2540 GFP_KERNEL);
2541 if (!new)
2542 goto out_free;
2543 components = new;
2544 }
2545 components[ncomponents++] = cur.dentry;
2546 cur.dentry = dget_parent(cur.dentry);
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002547 }
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002548 err = nfserr_resource;
2549 p = xdr_reserve_space(xdr, 4);
2550 if (!p)
Trond Myklebusted748aa2011-09-12 19:37:06 -04002551 goto out_free;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04002552 *p++ = cpu_to_be32(ncomponents);
Trond Myklebusted748aa2011-09-12 19:37:06 -04002553
2554 while (ncomponents) {
2555 struct dentry *dentry = components[ncomponents - 1];
Al Viro301f0262013-09-01 16:06:39 -04002556 unsigned int len;
Trond Myklebusted748aa2011-09-12 19:37:06 -04002557
Al Viro301f0262013-09-01 16:06:39 -04002558 spin_lock(&dentry->d_lock);
2559 len = dentry->d_name.len;
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002560 p = xdr_reserve_space(xdr, len + 4);
2561 if (!p) {
Al Viro301f0262013-09-01 16:06:39 -04002562 spin_unlock(&dentry->d_lock);
Trond Myklebusted748aa2011-09-12 19:37:06 -04002563 goto out_free;
Al Viro301f0262013-09-01 16:06:39 -04002564 }
J. Bruce Fields0c0c2672014-03-22 18:43:16 -04002565 p = xdr_encode_opaque(p, dentry->d_name.name, len);
Al Viroa4555892014-10-21 20:11:25 -04002566 dprintk("/%pd", dentry);
Al Viro301f0262013-09-01 16:06:39 -04002567 spin_unlock(&dentry->d_lock);
Trond Myklebusted748aa2011-09-12 19:37:06 -04002568 dput(dentry);
2569 ncomponents--;
2570 }
2571
Trond Myklebusted748aa2011-09-12 19:37:06 -04002572 err = 0;
2573out_free:
2574 dprintk(")\n");
2575 while (ncomponents)
2576 dput(components[--ncomponents]);
2577 kfree(components);
2578 path_put(&cur);
2579 return err;
2580}
2581
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002582static __be32 nfsd4_encode_fsloc_fsroot(struct xdr_stream *xdr,
2583 struct svc_rqst *rqstp, const struct path *path)
Trond Myklebusted748aa2011-09-12 19:37:06 -04002584{
2585 struct svc_export *exp_ps;
2586 __be32 res;
2587
2588 exp_ps = rqst_find_fsidzero_export(rqstp);
2589 if (IS_ERR(exp_ps))
2590 return nfserrno(PTR_ERR(exp_ps));
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002591 res = nfsd4_encode_path(xdr, &exp_ps->ex_path, path);
Trond Myklebusted748aa2011-09-12 19:37:06 -04002592 exp_put(exp_ps);
2593 return res;
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002594}
2595
2596/*
2597 * encode a fs_locations structure
2598 */
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002599static __be32 nfsd4_encode_fs_locations(struct xdr_stream *xdr,
2600 struct svc_rqst *rqstp, struct svc_export *exp)
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002601{
Al Virob37ad282006-10-19 23:28:59 -07002602 __be32 status;
Al Virocc45f012006-10-19 23:28:44 -07002603 int i;
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002604 __be32 *p;
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002605 struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs;
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002606
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002607 status = nfsd4_encode_fsloc_fsroot(xdr, rqstp, &exp->ex_path);
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002608 if (status)
2609 return status;
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002610 p = xdr_reserve_space(xdr, 4);
2611 if (!p)
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002612 return nfserr_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04002613 *p++ = cpu_to_be32(fslocs->locations_count);
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002614 for (i=0; i<fslocs->locations_count; i++) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002615 status = nfsd4_encode_fs_location4(xdr, &fslocs->locations[i]);
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002616 if (status)
2617 return status;
2618 }
J.Bruce Fields81c3f412006-10-04 02:16:19 -07002619 return 0;
2620}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621
J. Bruce Fields3d2544b2011-08-15 11:49:30 -04002622static u32 nfs4_file_type(umode_t mode)
2623{
2624 switch (mode & S_IFMT) {
2625 case S_IFIFO: return NF4FIFO;
2626 case S_IFCHR: return NF4CHR;
2627 case S_IFDIR: return NF4DIR;
2628 case S_IFBLK: return NF4BLK;
2629 case S_IFLNK: return NF4LNK;
2630 case S_IFREG: return NF4REG;
2631 case S_IFSOCK: return NF4SOCK;
2632 default: return NF4BAD;
Tom Rix25fef482020-11-01 07:32:34 -08002633 }
J. Bruce Fields3d2544b2011-08-15 11:49:30 -04002634}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635
Al Virob37ad282006-10-19 23:28:59 -07002636static inline __be32
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002637nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp,
2638 struct nfs4_ace *ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639{
J. Bruce Fields35541162014-01-08 09:49:01 -05002640 if (ace->whotype != NFS4_ACL_WHO_NAMED)
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002641 return nfs4_acl_write_who(xdr, ace->whotype);
J. Bruce Fields35541162014-01-08 09:49:01 -05002642 else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002643 return nfsd4_encode_group(xdr, rqstp, ace->who_gid);
J. Bruce Fields35541162014-01-08 09:49:01 -05002644 else
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002645 return nfsd4_encode_user(xdr, rqstp, ace->who_uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646}
2647
Kinglong Mee6896f152015-07-30 21:52:44 +08002648static inline __be32
Jeff Layton8a4c3922016-07-10 15:55:58 -04002649nfsd4_encode_layout_types(struct xdr_stream *xdr, u32 layout_types)
Kinglong Mee6896f152015-07-30 21:52:44 +08002650{
Jeff Layton8a4c3922016-07-10 15:55:58 -04002651 __be32 *p;
2652 unsigned long i = hweight_long(layout_types);
Kinglong Mee6896f152015-07-30 21:52:44 +08002653
Jeff Layton8a4c3922016-07-10 15:55:58 -04002654 p = xdr_reserve_space(xdr, 4 + 4 * i);
2655 if (!p)
2656 return nfserr_resource;
2657
2658 *p++ = cpu_to_be32(i);
2659
2660 for (i = LAYOUT_NFSV4_1_FILES; i < LAYOUT_TYPE_MAX; ++i)
2661 if (layout_types & (1 << i))
2662 *p++ = cpu_to_be32(i);
Kinglong Mee6896f152015-07-30 21:52:44 +08002663
2664 return 0;
2665}
2666
J.Bruce Fields42ca0992006-10-04 02:16:20 -07002667#define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
2668 FATTR4_WORD0_RDATTR_ERROR)
2669#define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
Kinglong Meec2227a32015-07-07 10:16:37 +08002670#define WORD2_ABSENT_FS_ATTRS 0
J.Bruce Fields42ca0992006-10-04 02:16:20 -07002671
David Quigley18032ca2013-05-02 13:19:10 -04002672#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
2673static inline __be32
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002674nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
2675 void *context, int len)
David Quigley18032ca2013-05-02 13:19:10 -04002676{
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002677 __be32 *p;
David Quigley18032ca2013-05-02 13:19:10 -04002678
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002679 p = xdr_reserve_space(xdr, len + 4 + 4 + 4);
2680 if (!p)
David Quigley18032ca2013-05-02 13:19:10 -04002681 return nfserr_resource;
2682
2683 /*
2684 * For now we use a 0 here to indicate the null translation; in
2685 * the future we may place a call to translation code here.
2686 */
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04002687 *p++ = cpu_to_be32(0); /* lfs */
2688 *p++ = cpu_to_be32(0); /* pi */
David Quigley18032ca2013-05-02 13:19:10 -04002689 p = xdr_encode_opaque(p, context, len);
David Quigley18032ca2013-05-02 13:19:10 -04002690 return 0;
2691}
2692#else
2693static inline __be32
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002694nfsd4_encode_security_label(struct xdr_stream *xdr, struct svc_rqst *rqstp,
2695 void *context, int len)
David Quigley18032ca2013-05-02 13:19:10 -04002696{ return 0; }
2697#endif
2698
Kinglong Meec2227a32015-07-07 10:16:37 +08002699static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *bmval2, u32 *rdattr_err)
J.Bruce Fields42ca0992006-10-04 02:16:20 -07002700{
2701 /* As per referral draft: */
2702 if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS ||
2703 *bmval1 & ~WORD1_ABSENT_FS_ATTRS) {
2704 if (*bmval0 & FATTR4_WORD0_RDATTR_ERROR ||
2705 *bmval0 & FATTR4_WORD0_FS_LOCATIONS)
2706 *rdattr_err = NFSERR_MOVED;
2707 else
2708 return nfserr_moved;
2709 }
2710 *bmval0 &= WORD0_ABSENT_FS_ATTRS;
2711 *bmval1 &= WORD1_ABSENT_FS_ATTRS;
Kinglong Meec2227a32015-07-07 10:16:37 +08002712 *bmval2 &= WORD2_ABSENT_FS_ATTRS;
J.Bruce Fields42ca0992006-10-04 02:16:20 -07002713 return 0;
2714}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715
J. Bruce Fieldsae7095a2012-10-01 17:50:56 -04002716
2717static int get_parent_attributes(struct svc_export *exp, struct kstat *stat)
2718{
2719 struct path path = exp->ex_path;
2720 int err;
2721
2722 path_get(&path);
2723 while (follow_up(&path)) {
2724 if (path.dentry != path.mnt->mnt_root)
2725 break;
2726 }
David Howellsa528d352017-01-31 16:46:22 +00002727 err = vfs_getattr(&path, stat, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT);
J. Bruce Fieldsae7095a2012-10-01 17:50:56 -04002728 path_put(&path);
2729 return err;
2730}
2731
Kinglong Mee75976de2015-07-30 21:55:30 +08002732static __be32
2733nfsd4_encode_bitmap(struct xdr_stream *xdr, u32 bmval0, u32 bmval1, u32 bmval2)
2734{
2735 __be32 *p;
2736
2737 if (bmval2) {
2738 p = xdr_reserve_space(xdr, 16);
2739 if (!p)
2740 goto out_resource;
2741 *p++ = cpu_to_be32(3);
2742 *p++ = cpu_to_be32(bmval0);
2743 *p++ = cpu_to_be32(bmval1);
2744 *p++ = cpu_to_be32(bmval2);
2745 } else if (bmval1) {
2746 p = xdr_reserve_space(xdr, 12);
2747 if (!p)
2748 goto out_resource;
2749 *p++ = cpu_to_be32(2);
2750 *p++ = cpu_to_be32(bmval0);
2751 *p++ = cpu_to_be32(bmval1);
2752 } else {
2753 p = xdr_reserve_space(xdr, 8);
2754 if (!p)
2755 goto out_resource;
2756 *p++ = cpu_to_be32(1);
2757 *p++ = cpu_to_be32(bmval0);
2758 }
2759
2760 return 0;
2761out_resource:
2762 return nfserr_resource;
2763}
2764
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765/*
2766 * Note: @fhp can be NULL; in this case, we might have to compose the filehandle
2767 * ourselves.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 */
Jeff Laytonda2ebce2014-05-30 09:09:25 -04002769static __be32
J. Bruce Fieldsd5184652013-08-26 16:04:46 -04002770nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp,
2771 struct svc_export *exp,
2772 struct dentry *dentry, u32 *bmval,
Frank Filz406a7ea2007-11-27 11:34:05 -08002773 struct svc_rqst *rqstp, int ignore_crossmnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774{
2775 u32 bmval0 = bmval[0];
2776 u32 bmval1 = bmval[1];
Andy Adamson7e705702009-04-03 08:29:11 +03002777 u32 bmval2 = bmval[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 struct kstat stat;
J. Bruce Fieldsd50e61362014-01-15 12:21:12 -05002779 struct svc_fh *tempfh = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 struct kstatfs statfs;
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002781 __be32 *p;
J. Bruce Fields1fcea5b2014-02-26 20:17:02 -05002782 int starting_len = xdr->buf->len;
J. Bruce Fields082d4bd2013-08-29 15:42:52 -04002783 int attrlen_offset;
2784 __be32 attrlen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 u32 dummy;
2786 u64 dummy64;
J.Bruce Fields42ca0992006-10-04 02:16:20 -07002787 u32 rdattr_err = 0;
Al Virob37ad282006-10-19 23:28:59 -07002788 __be32 status;
Al Virob8dd7b92006-10-19 23:29:01 -07002789 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 struct nfs4_acl *acl = NULL;
Arnd Bergmann0ab88ca2019-03-22 15:07:11 +01002791#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
David Quigley18032ca2013-05-02 13:19:10 -04002792 void *context = NULL;
2793 int contextlen;
Arnd Bergmann0ab88ca2019-03-22 15:07:11 +01002794#endif
David Quigley18032ca2013-05-02 13:19:10 -04002795 bool contextsupport = false;
Andy Adamson7e705702009-04-03 08:29:11 +03002796 struct nfsd4_compoundres *resp = rqstp->rq_resp;
2797 u32 minorversion = resp->cstate.minorversion;
Christoph Hellwigebabe9a2010-07-07 18:53:11 +02002798 struct path path = {
2799 .mnt = exp->ex_path.mnt,
2800 .dentry = dentry,
2801 };
Stanislav Kinsbursky3d733712012-11-27 14:11:44 +03002802 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803
2804 BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
J. Bruce Fields916d2d82016-10-18 14:18:40 -04002805 BUG_ON(!nfsd_attrs_supported(minorversion, bmval));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806
J.Bruce Fields42ca0992006-10-04 02:16:20 -07002807 if (exp->ex_fslocs.migrated) {
Kinglong Meec2227a32015-07-07 10:16:37 +08002808 status = fattr_handle_absent_fs(&bmval0, &bmval1, &bmval2, &rdattr_err);
J.Bruce Fields42ca0992006-10-04 02:16:20 -07002809 if (status)
2810 goto out;
2811 }
2812
David Howellsa528d352017-01-31 16:46:22 +00002813 err = vfs_getattr(&path, &stat, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT);
Al Virob8dd7b92006-10-19 23:29:01 -07002814 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 goto out_nfserr;
Christoph Hellwig12337902014-05-28 10:46:13 +02002816 if ((bmval0 & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE |
2817 FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_MAXNAME)) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
2819 FATTR4_WORD1_SPACE_TOTAL))) {
Christoph Hellwigebabe9a2010-07-07 18:53:11 +02002820 err = vfs_statfs(&path, &statfs);
Al Virob8dd7b92006-10-19 23:29:01 -07002821 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 goto out_nfserr;
2823 }
2824 if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) {
J. Bruce Fieldsd50e61362014-01-15 12:21:12 -05002825 tempfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
2826 status = nfserr_jukebox;
2827 if (!tempfh)
2828 goto out;
2829 fh_init(tempfh, NFS4_FHSIZE);
2830 status = fh_compose(tempfh, exp, dentry, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 if (status)
2832 goto out;
J. Bruce Fieldsd50e61362014-01-15 12:21:12 -05002833 fhp = tempfh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 }
Andreas Gruenbacher0c9d65e2015-04-24 13:04:00 +02002835 if (bmval0 & FATTR4_WORD0_ACL) {
Al Virob8dd7b92006-10-19 23:29:01 -07002836 err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
Andreas Gruenbacher0c9d65e2015-04-24 13:04:00 +02002837 if (err == -EOPNOTSUPP)
2838 bmval0 &= ~FATTR4_WORD0_ACL;
2839 else if (err == -EINVAL) {
2840 status = nfserr_attrnotsupp;
2841 goto out;
2842 } else if (err != 0)
2843 goto out_nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845
David Quigley18032ca2013-05-02 13:19:10 -04002846#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
Kinglong Meec2227a32015-07-07 10:16:37 +08002847 if ((bmval2 & FATTR4_WORD2_SECURITY_LABEL) ||
2848 bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
J. Bruce Fields32ddd942017-01-03 12:30:11 -05002849 if (exp->ex_flags & NFSEXP_SECURITY_LABEL)
2850 err = security_inode_getsecctx(d_inode(dentry),
David Quigley18032ca2013-05-02 13:19:10 -04002851 &context, &contextlen);
J. Bruce Fields32ddd942017-01-03 12:30:11 -05002852 else
2853 err = -EOPNOTSUPP;
David Quigley18032ca2013-05-02 13:19:10 -04002854 contextsupport = (err == 0);
2855 if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
2856 if (err == -EOPNOTSUPP)
2857 bmval2 &= ~FATTR4_WORD2_SECURITY_LABEL;
2858 else if (err)
2859 goto out_nfserr;
2860 }
2861 }
2862#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
2863
Kinglong Mee75976de2015-07-30 21:55:30 +08002864 status = nfsd4_encode_bitmap(xdr, bmval0, bmval1, bmval2);
2865 if (status)
2866 goto out;
J. Bruce Fields082d4bd2013-08-29 15:42:52 -04002867
2868 attrlen_offset = xdr->buf->len;
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002869 p = xdr_reserve_space(xdr, 4);
2870 if (!p)
2871 goto out_resource;
J. Bruce Fields082d4bd2013-08-29 15:42:52 -04002872 p++; /* to be backfilled later */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873
2874 if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
J. Bruce Fieldsdcd208692017-01-11 20:34:50 -05002875 u32 supp[3];
2876
2877 memcpy(supp, nfsd_suppattrs[minorversion], sizeof(supp));
Andy Adamson7e705702009-04-03 08:29:11 +03002878
Andreas Gruenbacher0c9d65e2015-04-24 13:04:00 +02002879 if (!IS_POSIXACL(dentry->d_inode))
J. Bruce Fields916d2d82016-10-18 14:18:40 -04002880 supp[0] &= ~FATTR4_WORD0_ACL;
David Quigley18032ca2013-05-02 13:19:10 -04002881 if (!contextsupport)
J. Bruce Fields916d2d82016-10-18 14:18:40 -04002882 supp[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
2883 if (!supp[2]) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002884 p = xdr_reserve_space(xdr, 12);
2885 if (!p)
Benny Halevy2b44f1b2010-09-30 20:47:46 +02002886 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04002887 *p++ = cpu_to_be32(2);
J. Bruce Fields916d2d82016-10-18 14:18:40 -04002888 *p++ = cpu_to_be32(supp[0]);
2889 *p++ = cpu_to_be32(supp[1]);
Andy Adamson7e705702009-04-03 08:29:11 +03002890 } else {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002891 p = xdr_reserve_space(xdr, 16);
2892 if (!p)
Benny Halevy2b44f1b2010-09-30 20:47:46 +02002893 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04002894 *p++ = cpu_to_be32(3);
J. Bruce Fields916d2d82016-10-18 14:18:40 -04002895 *p++ = cpu_to_be32(supp[0]);
2896 *p++ = cpu_to_be32(supp[1]);
2897 *p++ = cpu_to_be32(supp[2]);
Andy Adamson7e705702009-04-03 08:29:11 +03002898 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 }
2900 if (bmval0 & FATTR4_WORD0_TYPE) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002901 p = xdr_reserve_space(xdr, 4);
2902 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 goto out_resource;
J. Bruce Fields3d2544b2011-08-15 11:49:30 -04002904 dummy = nfs4_file_type(stat.mode);
J. Bruce Fields6b6d81372013-01-16 17:11:11 -05002905 if (dummy == NF4BAD) {
2906 status = nfserr_serverfault;
2907 goto out;
2908 }
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04002909 *p++ = cpu_to_be32(dummy);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 }
2911 if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002912 p = xdr_reserve_space(xdr, 4);
2913 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 goto out_resource;
NeilBrown49640002005-06-23 22:02:58 -07002915 if (exp->ex_flags & NFSEXP_NOSUBTREECHECK)
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04002916 *p++ = cpu_to_be32(NFS4_FH_PERSISTENT);
NeilBrown49640002005-06-23 22:02:58 -07002917 else
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04002918 *p++ = cpu_to_be32(NFS4_FH_PERSISTENT|
2919 NFS4_FH_VOL_RENAME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 }
2921 if (bmval0 & FATTR4_WORD0_CHANGE) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002922 p = xdr_reserve_space(xdr, 8);
2923 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 goto out_resource;
NeilBrownb8800922017-01-30 17:17:00 +11002925 p = encode_change(p, &stat, d_inode(dentry), exp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 }
2927 if (bmval0 & FATTR4_WORD0_SIZE) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002928 p = xdr_reserve_space(xdr, 8);
2929 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 goto out_resource;
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04002931 p = xdr_encode_hyper(p, stat.size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932 }
2933 if (bmval0 & FATTR4_WORD0_LINK_SUPPORT) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002934 p = xdr_reserve_space(xdr, 4);
2935 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04002937 *p++ = cpu_to_be32(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938 }
2939 if (bmval0 & FATTR4_WORD0_SYMLINK_SUPPORT) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002940 p = xdr_reserve_space(xdr, 4);
2941 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04002943 *p++ = cpu_to_be32(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 }
2945 if (bmval0 & FATTR4_WORD0_NAMED_ATTR) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002946 p = xdr_reserve_space(xdr, 4);
2947 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04002949 *p++ = cpu_to_be32(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 }
2951 if (bmval0 & FATTR4_WORD0_FSID) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002952 p = xdr_reserve_space(xdr, 16);
2953 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 goto out_resource;
J.Bruce Fields42ca0992006-10-04 02:16:20 -07002955 if (exp->ex_fslocs.migrated) {
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04002956 p = xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MAJOR);
2957 p = xdr_encode_hyper(p, NFS4_REFERRAL_FSID_MINOR);
NeilBrownaf6a4e22007-02-14 00:33:12 -08002958 } else switch(fsid_source(fhp)) {
2959 case FSIDSOURCE_FSID:
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04002960 p = xdr_encode_hyper(p, (u64)exp->ex_fsid);
2961 p = xdr_encode_hyper(p, (u64)0);
NeilBrownaf6a4e22007-02-14 00:33:12 -08002962 break;
2963 case FSIDSOURCE_DEV:
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04002964 *p++ = cpu_to_be32(0);
2965 *p++ = cpu_to_be32(MAJOR(stat.dev));
2966 *p++ = cpu_to_be32(0);
2967 *p++ = cpu_to_be32(MINOR(stat.dev));
NeilBrownaf6a4e22007-02-14 00:33:12 -08002968 break;
2969 case FSIDSOURCE_UUID:
Kinglong Mee94eb3682014-05-23 20:00:19 +08002970 p = xdr_encode_opaque_fixed(p, exp->ex_uuid,
2971 EX_UUID_LEN);
NeilBrownaf6a4e22007-02-14 00:33:12 -08002972 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 }
2974 }
2975 if (bmval0 & FATTR4_WORD0_UNIQUE_HANDLES) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002976 p = xdr_reserve_space(xdr, 4);
2977 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04002979 *p++ = cpu_to_be32(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 }
2981 if (bmval0 & FATTR4_WORD0_LEASE_TIME) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002982 p = xdr_reserve_space(xdr, 4);
2983 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04002985 *p++ = cpu_to_be32(nn->nfsd4_lease);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986 }
2987 if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002988 p = xdr_reserve_space(xdr, 4);
2989 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04002991 *p++ = cpu_to_be32(rdattr_err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 }
2993 if (bmval0 & FATTR4_WORD0_ACL) {
2994 struct nfs4_ace *ace;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995
2996 if (acl == NULL) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04002997 p = xdr_reserve_space(xdr, 4);
2998 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 goto out_resource;
3000
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003001 *p++ = cpu_to_be32(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 goto out_acl;
3003 }
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003004 p = xdr_reserve_space(xdr, 4);
3005 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003007 *p++ = cpu_to_be32(acl->naces);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008
J. Bruce Fields28e05dd2007-02-16 01:28:30 -08003009 for (ace = acl->aces; ace < acl->aces + acl->naces; ace++) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003010 p = xdr_reserve_space(xdr, 4*3);
3011 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003013 *p++ = cpu_to_be32(ace->type);
3014 *p++ = cpu_to_be32(ace->flag);
3015 *p++ = cpu_to_be32(ace->access_mask &
3016 NFS4_ACE_MASK_ALL);
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003017 status = nfsd4_encode_aclname(xdr, rqstp, ace);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 if (status)
3019 goto out;
3020 }
3021 }
3022out_acl:
3023 if (bmval0 & FATTR4_WORD0_ACLSUPPORT) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003024 p = xdr_reserve_space(xdr, 4);
3025 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 goto out_resource;
Andreas Gruenbacher0c9d65e2015-04-24 13:04:00 +02003027 *p++ = cpu_to_be32(IS_POSIXACL(dentry->d_inode) ?
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL : 0);
3029 }
3030 if (bmval0 & FATTR4_WORD0_CANSETTIME) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003031 p = xdr_reserve_space(xdr, 4);
3032 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003034 *p++ = cpu_to_be32(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 }
3036 if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003037 p = xdr_reserve_space(xdr, 4);
3038 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003040 *p++ = cpu_to_be32(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 }
3042 if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003043 p = xdr_reserve_space(xdr, 4);
3044 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003046 *p++ = cpu_to_be32(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 }
3048 if (bmval0 & FATTR4_WORD0_CHOWN_RESTRICTED) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003049 p = xdr_reserve_space(xdr, 4);
3050 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003051 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003052 *p++ = cpu_to_be32(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 }
3054 if (bmval0 & FATTR4_WORD0_FILEHANDLE) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003055 p = xdr_reserve_space(xdr, fhp->fh_handle.fh_size + 4);
3056 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 goto out_resource;
J. Bruce Fields0c0c2672014-03-22 18:43:16 -04003058 p = xdr_encode_opaque(p, &fhp->fh_handle.fh_base,
3059 fhp->fh_handle.fh_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 }
3061 if (bmval0 & FATTR4_WORD0_FILEID) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003062 p = xdr_reserve_space(xdr, 8);
3063 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 goto out_resource;
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04003065 p = xdr_encode_hyper(p, stat.ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 }
3067 if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003068 p = xdr_reserve_space(xdr, 8);
3069 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 goto out_resource;
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04003071 p = xdr_encode_hyper(p, (u64) statfs.f_ffree);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 }
3073 if (bmval0 & FATTR4_WORD0_FILES_FREE) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003074 p = xdr_reserve_space(xdr, 8);
3075 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 goto out_resource;
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04003077 p = xdr_encode_hyper(p, (u64) statfs.f_ffree);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 }
3079 if (bmval0 & FATTR4_WORD0_FILES_TOTAL) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003080 p = xdr_reserve_space(xdr, 8);
3081 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 goto out_resource;
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04003083 p = xdr_encode_hyper(p, (u64) statfs.f_files);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 }
J.Bruce Fields81c3f412006-10-04 02:16:19 -07003085 if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003086 status = nfsd4_encode_fs_locations(xdr, rqstp, exp);
J.Bruce Fields81c3f412006-10-04 02:16:19 -07003087 if (status)
3088 goto out;
3089 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003091 p = xdr_reserve_space(xdr, 4);
3092 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003094 *p++ = cpu_to_be32(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 }
3096 if (bmval0 & FATTR4_WORD0_MAXFILESIZE) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003097 p = xdr_reserve_space(xdr, 8);
3098 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099 goto out_resource;
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04003100 p = xdr_encode_hyper(p, exp->ex_path.mnt->mnt_sb->s_maxbytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 }
3102 if (bmval0 & FATTR4_WORD0_MAXLINK) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003103 p = xdr_reserve_space(xdr, 4);
3104 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003106 *p++ = cpu_to_be32(255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 }
3108 if (bmval0 & FATTR4_WORD0_MAXNAME) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003109 p = xdr_reserve_space(xdr, 4);
3110 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003112 *p++ = cpu_to_be32(statfs.f_namelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 }
3114 if (bmval0 & FATTR4_WORD0_MAXREAD) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003115 p = xdr_reserve_space(xdr, 8);
3116 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 goto out_resource;
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04003118 p = xdr_encode_hyper(p, (u64) svc_max_payload(rqstp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 }
3120 if (bmval0 & FATTR4_WORD0_MAXWRITE) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003121 p = xdr_reserve_space(xdr, 8);
3122 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 goto out_resource;
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04003124 p = xdr_encode_hyper(p, (u64) svc_max_payload(rqstp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125 }
3126 if (bmval1 & FATTR4_WORD1_MODE) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003127 p = xdr_reserve_space(xdr, 4);
3128 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003129 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003130 *p++ = cpu_to_be32(stat.mode & S_IALLUGO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 }
3132 if (bmval1 & FATTR4_WORD1_NO_TRUNC) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003133 p = xdr_reserve_space(xdr, 4);
3134 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003136 *p++ = cpu_to_be32(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 }
3138 if (bmval1 & FATTR4_WORD1_NUMLINKS) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003139 p = xdr_reserve_space(xdr, 4);
3140 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003142 *p++ = cpu_to_be32(stat.nlink);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 }
3144 if (bmval1 & FATTR4_WORD1_OWNER) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003145 status = nfsd4_encode_user(xdr, rqstp, stat.uid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146 if (status)
3147 goto out;
3148 }
3149 if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003150 status = nfsd4_encode_group(xdr, rqstp, stat.gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151 if (status)
3152 goto out;
3153 }
3154 if (bmval1 & FATTR4_WORD1_RAWDEV) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003155 p = xdr_reserve_space(xdr, 8);
3156 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157 goto out_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003158 *p++ = cpu_to_be32((u32) MAJOR(stat.rdev));
3159 *p++ = cpu_to_be32((u32) MINOR(stat.rdev));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160 }
3161 if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003162 p = xdr_reserve_space(xdr, 8);
3163 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003164 goto out_resource;
3165 dummy64 = (u64)statfs.f_bavail * (u64)statfs.f_bsize;
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04003166 p = xdr_encode_hyper(p, dummy64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 }
3168 if (bmval1 & FATTR4_WORD1_SPACE_FREE) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003169 p = xdr_reserve_space(xdr, 8);
3170 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 goto out_resource;
3172 dummy64 = (u64)statfs.f_bfree * (u64)statfs.f_bsize;
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04003173 p = xdr_encode_hyper(p, dummy64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 }
3175 if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003176 p = xdr_reserve_space(xdr, 8);
3177 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 goto out_resource;
3179 dummy64 = (u64)statfs.f_blocks * (u64)statfs.f_bsize;
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04003180 p = xdr_encode_hyper(p, dummy64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 }
3182 if (bmval1 & FATTR4_WORD1_SPACE_USED) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003183 p = xdr_reserve_space(xdr, 8);
3184 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185 goto out_resource;
3186 dummy64 = (u64)stat.blocks << 9;
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04003187 p = xdr_encode_hyper(p, dummy64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 }
3189 if (bmval1 & FATTR4_WORD1_TIME_ACCESS) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003190 p = xdr_reserve_space(xdr, 12);
3191 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 goto out_resource;
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04003193 p = xdr_encode_hyper(p, (s64)stat.atime.tv_sec);
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003194 *p++ = cpu_to_be32(stat.atime.tv_nsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 }
3196 if (bmval1 & FATTR4_WORD1_TIME_DELTA) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003197 p = xdr_reserve_space(xdr, 12);
3198 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003199 goto out_resource;
J. Bruce Fields16945142018-04-25 14:34:11 -04003200 p = encode_time_delta(p, d_inode(dentry));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003201 }
3202 if (bmval1 & FATTR4_WORD1_TIME_METADATA) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003203 p = xdr_reserve_space(xdr, 12);
3204 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003205 goto out_resource;
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04003206 p = xdr_encode_hyper(p, (s64)stat.ctime.tv_sec);
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003207 *p++ = cpu_to_be32(stat.ctime.tv_nsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208 }
3209 if (bmval1 & FATTR4_WORD1_TIME_MODIFY) {
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003210 p = xdr_reserve_space(xdr, 12);
3211 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 goto out_resource;
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04003213 p = xdr_encode_hyper(p, (s64)stat.mtime.tv_sec);
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003214 *p++ = cpu_to_be32(stat.mtime.tv_nsec);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 }
3216 if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
Kinglong Mee0a2050d2015-07-30 21:51:54 +08003217 struct kstat parent_stat;
3218 u64 ino = stat.ino;
3219
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003220 p = xdr_reserve_space(xdr, 8);
3221 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 goto out_resource;
Frank Filz406a7ea2007-11-27 11:34:05 -08003223 /*
3224 * Get parent's attributes if not ignoring crossmount
3225 * and this is the root of a cross-mounted filesystem.
3226 */
3227 if (ignore_crossmnt == 0 &&
Kinglong Mee0a2050d2015-07-30 21:51:54 +08003228 dentry == exp->ex_path.mnt->mnt_root) {
3229 err = get_parent_attributes(exp, &parent_stat);
3230 if (err)
3231 goto out_nfserr;
3232 ino = parent_stat.ino;
3233 }
3234 p = xdr_encode_hyper(p, ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 }
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02003236#ifdef CONFIG_NFSD_PNFS
Kinglong Mee6896f152015-07-30 21:52:44 +08003237 if (bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) {
Jeff Layton8a4c3922016-07-10 15:55:58 -04003238 status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types);
Kinglong Mee6896f152015-07-30 21:52:44 +08003239 if (status)
3240 goto out;
3241 }
3242
3243 if (bmval2 & FATTR4_WORD2_LAYOUT_TYPES) {
Jeff Layton8a4c3922016-07-10 15:55:58 -04003244 status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types);
Kinglong Mee6896f152015-07-30 21:52:44 +08003245 if (status)
3246 goto out;
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02003247 }
3248
3249 if (bmval2 & FATTR4_WORD2_LAYOUT_BLKSIZE) {
3250 p = xdr_reserve_space(xdr, 4);
3251 if (!p)
3252 goto out_resource;
3253 *p++ = cpu_to_be32(stat.blksize);
3254 }
3255#endif /* CONFIG_NFSD_PNFS */
Benny Halevy8c18f202009-04-03 08:29:14 +03003256 if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
Trond Myklebustb26b78c2017-05-09 16:24:59 -04003257 u32 supp[3];
3258
3259 memcpy(supp, nfsd_suppattrs[minorversion], sizeof(supp));
3260 supp[0] &= NFSD_SUPPATTR_EXCLCREAT_WORD0;
3261 supp[1] &= NFSD_SUPPATTR_EXCLCREAT_WORD1;
3262 supp[2] &= NFSD_SUPPATTR_EXCLCREAT_WORD2;
3263
3264 status = nfsd4_encode_bitmap(xdr, supp[0], supp[1], supp[2]);
Kinglong Mee75976de2015-07-30 21:55:30 +08003265 if (status)
3266 goto out;
Benny Halevy8c18f202009-04-03 08:29:14 +03003267 }
Andy Adamson7e705702009-04-03 08:29:11 +03003268
J. Bruce Fieldsa8585762018-04-25 13:26:23 -04003269 if (bmval2 & FATTR4_WORD2_CHANGE_ATTR_TYPE) {
3270 p = xdr_reserve_space(xdr, 4);
3271 if (!p)
3272 goto out_resource;
3273 if (IS_I_VERSION(d_inode(dentry)))
3274 *p++ = cpu_to_be32(NFS4_CHANGE_TYPE_IS_MONOTONIC_INCR);
3275 else
3276 *p++ = cpu_to_be32(NFS4_CHANGE_TYPE_IS_TIME_METADATA);
3277 }
3278
Arnd Bergmann0ab88ca2019-03-22 15:07:11 +01003279#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
Kinglong Mee7d580722015-07-30 21:54:26 +08003280 if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) {
3281 status = nfsd4_encode_security_label(xdr, rqstp, context,
3282 contextlen);
3283 if (status)
3284 goto out;
3285 }
Arnd Bergmann0ab88ca2019-03-22 15:07:11 +01003286#endif
Kinglong Mee7d580722015-07-30 21:54:26 +08003287
Frank van der Linden0e885e82020-06-23 22:39:27 +00003288 if (bmval2 & FATTR4_WORD2_XATTR_SUPPORT) {
3289 p = xdr_reserve_space(xdr, 4);
3290 if (!p)
3291 goto out_resource;
3292 err = xattr_supported_namespace(d_inode(dentry),
3293 XATTR_USER_PREFIX);
3294 *p++ = cpu_to_be32(err == 0);
3295 }
3296
J. Bruce Fields082d4bd2013-08-29 15:42:52 -04003297 attrlen = htonl(xdr->buf->len - attrlen_offset - 4);
3298 write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 status = nfs_ok;
3300
3301out:
J. Bruce Fieldsba4e55b2013-05-15 10:27:52 -04003302#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
David Quigley18032ca2013-05-02 13:19:10 -04003303 if (context)
3304 security_release_secctx(context, contextlen);
J. Bruce Fieldsba4e55b2013-05-15 10:27:52 -04003305#endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
J. Bruce Fields28e05dd2007-02-16 01:28:30 -08003306 kfree(acl);
Yan, Zheng18df11d02014-03-10 12:52:07 +08003307 if (tempfh) {
J. Bruce Fieldsd50e61362014-01-15 12:21:12 -05003308 fh_put(tempfh);
Yan, Zheng18df11d02014-03-10 12:52:07 +08003309 kfree(tempfh);
3310 }
J. Bruce Fields1fcea5b2014-02-26 20:17:02 -05003311 if (status)
3312 xdr_truncate_encode(xdr, starting_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 return status;
3314out_nfserr:
Al Virob8dd7b92006-10-19 23:29:01 -07003315 status = nfserrno(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 goto out;
3317out_resource:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 status = nfserr_resource;
3319 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003320}
3321
J. Bruce Fields2825a7f2013-08-26 16:04:46 -04003322static void svcxdr_init_encode_from_buffer(struct xdr_stream *xdr,
3323 struct xdr_buf *buf, __be32 *p, int bytes)
3324{
3325 xdr->scratch.iov_len = 0;
3326 memset(buf, 0, sizeof(struct xdr_buf));
3327 buf->head[0].iov_base = p;
3328 buf->head[0].iov_len = 0;
3329 buf->len = 0;
3330 xdr->buf = buf;
3331 xdr->iov = buf->head;
3332 xdr->p = p;
3333 xdr->end = (void *)p + bytes;
3334 buf->buflen = bytes;
3335}
3336
J. Bruce Fieldsd5184652013-08-26 16:04:46 -04003337__be32 nfsd4_encode_fattr_to_buf(__be32 **p, int words,
3338 struct svc_fh *fhp, struct svc_export *exp,
3339 struct dentry *dentry, u32 *bmval,
3340 struct svc_rqst *rqstp, int ignore_crossmnt)
3341{
J. Bruce Fields2825a7f2013-08-26 16:04:46 -04003342 struct xdr_buf dummy;
J. Bruce Fieldsd5184652013-08-26 16:04:46 -04003343 struct xdr_stream xdr;
3344 __be32 ret;
3345
J. Bruce Fields2825a7f2013-08-26 16:04:46 -04003346 svcxdr_init_encode_from_buffer(&xdr, &dummy, *p, words << 2);
J. Bruce Fieldsd5184652013-08-26 16:04:46 -04003347 ret = nfsd4_encode_fattr(&xdr, fhp, exp, dentry, bmval, rqstp,
3348 ignore_crossmnt);
3349 *p = xdr.p;
3350 return ret;
3351}
3352
J. Bruce Fieldsc0ce6ec2008-02-11 15:48:47 -05003353static inline int attributes_need_mount(u32 *bmval)
3354{
3355 if (bmval[0] & ~(FATTR4_WORD0_RDATTR_ERROR | FATTR4_WORD0_LEASE_TIME))
3356 return 1;
3357 if (bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID)
3358 return 1;
3359 return 0;
3360}
3361
Al Virob37ad282006-10-19 23:28:59 -07003362static __be32
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05003363nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd,
3364 const char *name, int namlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365{
3366 struct svc_export *exp = cd->rd_fhp->fh_export;
3367 struct dentry *dentry;
Al Virob37ad282006-10-19 23:28:59 -07003368 __be32 nfserr;
Frank Filz406a7ea2007-11-27 11:34:05 -08003369 int ignore_crossmnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370
Al Viro6c2d47982019-10-31 01:21:58 -04003371 dentry = lookup_positive_unlocked(name, cd->rd_fhp->fh_dentry, namlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 if (IS_ERR(dentry))
3373 return nfserrno(PTR_ERR(dentry));
3374
3375 exp_get(exp);
Frank Filz406a7ea2007-11-27 11:34:05 -08003376 /*
3377 * In the case of a mountpoint, the client may be asking for
3378 * attributes that are only properties of the underlying filesystem
3379 * as opposed to the cross-mounted file system. In such a case,
3380 * we will not follow the cross mount and will fill the attribtutes
3381 * directly from the mountpoint dentry.
3382 */
J. Bruce Fields3227fa42009-10-25 21:43:01 -04003383 if (nfsd_mountpoint(dentry, exp)) {
J.Bruce Fields021d3a72006-12-13 00:35:24 -08003384 int err;
3385
J. Bruce Fields3227fa42009-10-25 21:43:01 -04003386 if (!(exp->ex_flags & NFSEXP_V4ROOT)
3387 && !attributes_need_mount(cd->rd_bmval)) {
3388 ignore_crossmnt = 1;
3389 goto out_encode;
3390 }
Andy Adamsondcb488a32007-07-17 04:04:51 -07003391 /*
3392 * Why the heck aren't we just using nfsd_lookup??
3393 * Different "."/".." handling? Something else?
3394 * At least, add a comment here to explain....
3395 */
J.Bruce Fields021d3a72006-12-13 00:35:24 -08003396 err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp);
3397 if (err) {
3398 nfserr = nfserrno(err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399 goto out_put;
3400 }
Andy Adamsondcb488a32007-07-17 04:04:51 -07003401 nfserr = check_nfsd_access(exp, cd->rd_rqstp);
3402 if (nfserr)
3403 goto out_put;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404
3405 }
J. Bruce Fields3227fa42009-10-25 21:43:01 -04003406out_encode:
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05003407 nfserr = nfsd4_encode_fattr(xdr, NULL, exp, dentry, cd->rd_bmval,
Frank Filz406a7ea2007-11-27 11:34:05 -08003408 cd->rd_rqstp, ignore_crossmnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003409out_put:
3410 dput(dentry);
3411 exp_put(exp);
3412 return nfserr;
3413}
3414
Al Viro2ebbc012006-10-19 23:28:58 -07003415static __be32 *
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05003416nfsd4_encode_rdattr_error(struct xdr_stream *xdr, __be32 nfserr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003417{
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05003418 __be32 *p;
3419
Kinglong Meec3a45612014-07-06 11:34:43 +08003420 p = xdr_reserve_space(xdr, 20);
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05003421 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 return NULL;
3423 *p++ = htonl(2);
3424 *p++ = htonl(FATTR4_WORD0_RDATTR_ERROR); /* bmval0 */
3425 *p++ = htonl(0); /* bmval1 */
3426
J. Bruce Fields87915c62013-01-16 17:33:28 -05003427 *p++ = htonl(4); /* attribute length */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 *p++ = nfserr; /* no htonl */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 return p;
3430}
3431
3432static int
NeilBrowna0ad13e2007-01-26 00:57:10 -08003433nfsd4_encode_dirent(void *ccdv, const char *name, int namlen,
3434 loff_t offset, u64 ino, unsigned int d_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435{
NeilBrowna0ad13e2007-01-26 00:57:10 -08003436 struct readdir_cd *ccd = ccdv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common);
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05003438 struct xdr_stream *xdr = cd->xdr;
3439 int start_offset = xdr->buf->len;
3440 int cookie_offset;
J. Bruce Fieldsaee37762014-08-20 14:49:50 -04003441 u32 name_and_cookie;
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05003442 int entry_bytes;
Al Virob37ad282006-10-19 23:28:59 -07003443 __be32 nfserr = nfserr_toosmall;
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05003444 __be64 wire_offset;
3445 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446
3447 /* In nfsv4, "." and ".." never make it onto the wire.. */
3448 if (name && isdotent(name, namlen)) {
3449 cd->common.err = nfs_ok;
3450 return 0;
3451 }
3452
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05003453 if (cd->cookie_offset) {
3454 wire_offset = cpu_to_be64(offset);
3455 write_bytes_to_xdr_buf(xdr->buf, cd->cookie_offset,
3456 &wire_offset, 8);
3457 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05003459 p = xdr_reserve_space(xdr, 4);
3460 if (!p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003461 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 *p++ = xdr_one; /* mark entry present */
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05003463 cookie_offset = xdr->buf->len;
3464 p = xdr_reserve_space(xdr, 3*4 + namlen);
3465 if (!p)
3466 goto fail;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467 p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */
3468 p = xdr_encode_array(p, name, namlen); /* name length & name */
3469
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05003470 nfserr = nfsd4_encode_dirent_fattr(xdr, cd, name, namlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003471 switch (nfserr) {
3472 case nfs_ok:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 break;
3474 case nfserr_resource:
3475 nfserr = nfserr_toosmall;
3476 goto fail;
J. Bruce Fieldsb2c0cea2009-05-05 19:04:29 -04003477 case nfserr_noent:
Kinglong Meef41c5ad2014-06-13 17:32:42 +08003478 xdr_truncate_encode(xdr, start_offset);
J. Bruce Fieldsb2c0cea2009-05-05 19:04:29 -04003479 goto skip_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480 default:
3481 /*
3482 * If the client requested the RDATTR_ERROR attribute,
3483 * we stuff the error code into this attribute
3484 * and continue. If this attribute was not requested,
3485 * then in accordance with the spec, we fail the
3486 * entire READDIR operation(!)
3487 */
3488 if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR))
3489 goto fail;
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05003490 p = nfsd4_encode_rdattr_error(xdr, nfserr);
Fred Isaman34081ef2006-01-18 17:43:40 -08003491 if (p == NULL) {
3492 nfserr = nfserr_toosmall;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 goto fail;
Fred Isaman34081ef2006-01-18 17:43:40 -08003494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 }
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05003496 nfserr = nfserr_toosmall;
3497 entry_bytes = xdr->buf->len - start_offset;
3498 if (entry_bytes > cd->rd_maxcount)
3499 goto fail;
3500 cd->rd_maxcount -= entry_bytes;
J. Bruce Fieldsaee37762014-08-20 14:49:50 -04003501 /*
3502 * RFC 3530 14.2.24 describes rd_dircount as only a "hint", so
3503 * let's always let through the first entry, at least:
3504 */
J. Bruce Fields0ec016e2014-12-19 18:01:35 -05003505 if (!cd->rd_dircount)
3506 goto fail;
3507 name_and_cookie = 4 + 4 * XDR_QUADLEN(namlen) + 8;
J. Bruce Fieldsaee37762014-08-20 14:49:50 -04003508 if (name_and_cookie > cd->rd_dircount && cd->cookie_offset)
3509 goto fail;
3510 cd->rd_dircount -= min(cd->rd_dircount, name_and_cookie);
J. Bruce Fields0ec016e2014-12-19 18:01:35 -05003511
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05003512 cd->cookie_offset = cookie_offset;
J. Bruce Fieldsb2c0cea2009-05-05 19:04:29 -04003513skip_entry:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 cd->common.err = nfs_ok;
3515 return 0;
3516fail:
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05003517 xdr_truncate_encode(xdr, start_offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 cd->common.err = nfserr;
3519 return -EINVAL;
3520}
3521
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003522static __be32
3523nfsd4_encode_stateid(struct xdr_stream *xdr, stateid_t *sid)
Benny Halevye2f282b2008-08-12 20:45:07 +03003524{
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07003525 __be32 *p;
Benny Halevye2f282b2008-08-12 20:45:07 +03003526
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003527 p = xdr_reserve_space(xdr, sizeof(stateid_t));
3528 if (!p)
3529 return nfserr_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003530 *p++ = cpu_to_be32(sid->si_generation);
J. Bruce Fields0c0c2672014-03-22 18:43:16 -04003531 p = xdr_encode_opaque_fixed(p, &sid->si_opaque,
3532 sizeof(stateid_opaque_t));
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003533 return 0;
Benny Halevye2f282b2008-08-12 20:45:07 +03003534}
3535
Benny Halevy695e12f2008-07-04 14:38:33 +03003536static __be32
Al Virob37ad282006-10-19 23:28:59 -07003537nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003539 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07003540 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003542 p = xdr_reserve_space(xdr, 8);
3543 if (!p)
3544 return nfserr_resource;
3545 *p++ = cpu_to_be32(access->ac_supported);
3546 *p++ = cpu_to_be32(access->ac_resp_access);
3547 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548}
3549
J. Bruce Fields1d1bc8f2010-10-04 23:12:59 -04003550static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts)
3551{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003552 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fields1d1bc8f2010-10-04 23:12:59 -04003553 __be32 *p;
3554
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003555 p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 8);
3556 if (!p)
3557 return nfserr_resource;
3558 p = xdr_encode_opaque_fixed(p, bcts->sessionid.data,
3559 NFS4_MAX_SESSIONID_LEN);
3560 *p++ = cpu_to_be32(bcts->dir);
3561 /* Upshifting from TCP to RDMA is not supported */
3562 *p++ = cpu_to_be32(0);
3563 return 0;
J. Bruce Fields1d1bc8f2010-10-04 23:12:59 -04003564}
3565
Benny Halevy695e12f2008-07-04 14:38:33 +03003566static __be32
Al Virob37ad282006-10-19 23:28:59 -07003567nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003569 struct xdr_stream *xdr = &resp->xdr;
3570
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003571 return nfsd4_encode_stateid(xdr, &close->cl_stateid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572}
3573
3574
Benny Halevy695e12f2008-07-04 14:38:33 +03003575static __be32
Al Virob37ad282006-10-19 23:28:59 -07003576nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003578 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07003579 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003581 p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
3582 if (!p)
3583 return nfserr_resource;
3584 p = xdr_encode_opaque_fixed(p, commit->co_verf.data,
J. Bruce Fields0c0c2672014-03-22 18:43:16 -04003585 NFS4_VERIFIER_SIZE);
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003586 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587}
3588
Benny Halevy695e12f2008-07-04 14:38:33 +03003589static __be32
Al Virob37ad282006-10-19 23:28:59 -07003590nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003592 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07003593 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003595 p = xdr_reserve_space(xdr, 20);
3596 if (!p)
3597 return nfserr_resource;
3598 encode_cinfo(p, &create->cr_cinfo);
Trond Myklebustb96811c2019-08-18 14:18:58 -04003599 return nfsd4_encode_bitmap(xdr, create->cr_bmval[0],
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003600 create->cr_bmval[1], create->cr_bmval[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601}
3602
Al Virob37ad282006-10-19 23:28:59 -07003603static __be32
3604nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605{
3606 struct svc_fh *fhp = getattr->ga_fhp;
J. Bruce Fieldsd5184652013-08-26 16:04:46 -04003607 struct xdr_stream *xdr = &resp->xdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003609 return nfsd4_encode_fattr(xdr, fhp, fhp->fh_export, fhp->fh_dentry,
3610 getattr->ga_bmval, resp->rqstp, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611}
3612
Benny Halevy695e12f2008-07-04 14:38:33 +03003613static __be32
3614nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003616 struct xdr_stream *xdr = &resp->xdr;
Benny Halevy695e12f2008-07-04 14:38:33 +03003617 struct svc_fh *fhp = *fhpp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 unsigned int len;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07003619 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003621 len = fhp->fh_handle.fh_size;
3622 p = xdr_reserve_space(xdr, len + 4);
3623 if (!p)
3624 return nfserr_resource;
3625 p = xdr_encode_opaque(p, &fhp->fh_handle.fh_base, len);
3626 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627}
3628
3629/*
3630* Including all fields other than the name, a LOCK4denied structure requires
3631* 8(clientid) + 4(namelen) + 8(offset) + 8(length) + 4(type) = 32 bytes.
3632*/
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003633static __be32
3634nfsd4_encode_lock_denied(struct xdr_stream *xdr, struct nfsd4_lock_denied *ld)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003635{
J. Bruce Fields7c13f342011-08-30 22:15:47 -04003636 struct xdr_netobj *conf = &ld->ld_owner;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07003637 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638
J. Bruce Fields8c7424c2014-03-10 12:19:10 -04003639again:
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003640 p = xdr_reserve_space(xdr, 32 + XDR_LEN(conf->len));
J. Bruce Fields8c7424c2014-03-10 12:19:10 -04003641 if (!p) {
3642 /*
3643 * Don't fail to return the result just because we can't
3644 * return the conflicting open:
3645 */
3646 if (conf->len) {
Kinglong Meef98bac52014-07-07 22:10:56 +08003647 kfree(conf->data);
J. Bruce Fields8c7424c2014-03-10 12:19:10 -04003648 conf->len = 0;
3649 conf->data = NULL;
3650 goto again;
3651 }
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003652 return nfserr_resource;
J. Bruce Fields8c7424c2014-03-10 12:19:10 -04003653 }
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04003654 p = xdr_encode_hyper(p, ld->ld_start);
3655 p = xdr_encode_hyper(p, ld->ld_length);
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003656 *p++ = cpu_to_be32(ld->ld_type);
J. Bruce Fields7c13f342011-08-30 22:15:47 -04003657 if (conf->len) {
J. Bruce Fields0c0c2672014-03-22 18:43:16 -04003658 p = xdr_encode_opaque_fixed(p, &ld->ld_clientid, 8);
3659 p = xdr_encode_opaque(p, conf->data, conf->len);
Kinglong Meef98bac52014-07-07 22:10:56 +08003660 kfree(conf->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 } else { /* non - nfsv4 lock in conflict, no clientid nor owner */
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04003662 p = xdr_encode_hyper(p, (u64)0); /* clientid */
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003663 *p++ = cpu_to_be32(0); /* length of owner name */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 }
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003665 return nfserr_denied;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666}
3667
Benny Halevy695e12f2008-07-04 14:38:33 +03003668static __be32
Al Virob37ad282006-10-19 23:28:59 -07003669nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003671 struct xdr_stream *xdr = &resp->xdr;
3672
Benny Halevye2f282b2008-08-12 20:45:07 +03003673 if (!nfserr)
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003674 nfserr = nfsd4_encode_stateid(xdr, &lock->lk_resp_stateid);
Benny Halevye2f282b2008-08-12 20:45:07 +03003675 else if (nfserr == nfserr_denied)
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003676 nfserr = nfsd4_encode_lock_denied(xdr, &lock->lk_denied);
Kinglong Meef98bac52014-07-07 22:10:56 +08003677
Benny Halevy695e12f2008-07-04 14:38:33 +03003678 return nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679}
3680
Benny Halevy695e12f2008-07-04 14:38:33 +03003681static __be32
Al Virob37ad282006-10-19 23:28:59 -07003682nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003684 struct xdr_stream *xdr = &resp->xdr;
3685
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 if (nfserr == nfserr_denied)
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003687 nfsd4_encode_lock_denied(xdr, &lockt->lt_denied);
Benny Halevy695e12f2008-07-04 14:38:33 +03003688 return nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689}
3690
Benny Halevy695e12f2008-07-04 14:38:33 +03003691static __be32
Al Virob37ad282006-10-19 23:28:59 -07003692nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003693{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003694 struct xdr_stream *xdr = &resp->xdr;
3695
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003696 return nfsd4_encode_stateid(xdr, &locku->lu_stateid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697}
3698
3699
Benny Halevy695e12f2008-07-04 14:38:33 +03003700static __be32
Al Virob37ad282006-10-19 23:28:59 -07003701nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003703 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07003704 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003706 p = xdr_reserve_space(xdr, 20);
3707 if (!p)
3708 return nfserr_resource;
3709 p = encode_cinfo(p, &link->li_cinfo);
3710 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711}
3712
3713
Benny Halevy695e12f2008-07-04 14:38:33 +03003714static __be32
Al Virob37ad282006-10-19 23:28:59 -07003715nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003716{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003717 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07003718 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003720 nfserr = nfsd4_encode_stateid(xdr, &open->op_stateid);
3721 if (nfserr)
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003722 return nfserr;
Kinglong Mee75976de2015-07-30 21:55:30 +08003723 p = xdr_reserve_space(xdr, 24);
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003724 if (!p)
3725 return nfserr_resource;
J. Bruce Fieldsd05d5742014-03-22 18:48:39 -04003726 p = encode_cinfo(p, &open->op_cinfo);
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003727 *p++ = cpu_to_be32(open->op_rflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003728
Kinglong Mee75976de2015-07-30 21:55:30 +08003729 nfserr = nfsd4_encode_bitmap(xdr, open->op_bmval[0], open->op_bmval[1],
3730 open->op_bmval[2]);
3731 if (nfserr)
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003732 return nfserr;
Kinglong Mee75976de2015-07-30 21:55:30 +08003733
3734 p = xdr_reserve_space(xdr, 4);
3735 if (!p)
3736 return nfserr_resource;
3737
3738 *p++ = cpu_to_be32(open->op_delegate_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 switch (open->op_delegate_type) {
3740 case NFS4_OPEN_DELEGATE_NONE:
3741 break;
3742 case NFS4_OPEN_DELEGATE_READ:
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003743 nfserr = nfsd4_encode_stateid(xdr, &open->op_delegate_stateid);
3744 if (nfserr)
3745 return nfserr;
3746 p = xdr_reserve_space(xdr, 20);
3747 if (!p)
3748 return nfserr_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003749 *p++ = cpu_to_be32(open->op_recall);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750
3751 /*
3752 * TODO: ACE's in delegations
3753 */
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003754 *p++ = cpu_to_be32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE);
3755 *p++ = cpu_to_be32(0);
3756 *p++ = cpu_to_be32(0);
3757 *p++ = cpu_to_be32(0); /* XXX: is NULL principal ok? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758 break;
3759 case NFS4_OPEN_DELEGATE_WRITE:
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003760 nfserr = nfsd4_encode_stateid(xdr, &open->op_delegate_stateid);
3761 if (nfserr)
3762 return nfserr;
3763 p = xdr_reserve_space(xdr, 32);
3764 if (!p)
3765 return nfserr_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003766 *p++ = cpu_to_be32(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767
3768 /*
3769 * TODO: space_limit's in delegations
3770 */
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003771 *p++ = cpu_to_be32(NFS4_LIMIT_SIZE);
3772 *p++ = cpu_to_be32(~(u32)0);
3773 *p++ = cpu_to_be32(~(u32)0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774
3775 /*
3776 * TODO: ACE's in delegations
3777 */
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003778 *p++ = cpu_to_be32(NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE);
3779 *p++ = cpu_to_be32(0);
3780 *p++ = cpu_to_be32(0);
3781 *p++ = cpu_to_be32(0); /* XXX: is NULL principal ok? */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 break;
Benny Halevyd24433c2012-02-16 20:57:17 +02003783 case NFS4_OPEN_DELEGATE_NONE_EXT: /* 4.1 */
3784 switch (open->op_why_no_deleg) {
3785 case WND4_CONTENTION:
3786 case WND4_RESOURCE:
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003787 p = xdr_reserve_space(xdr, 8);
3788 if (!p)
3789 return nfserr_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003790 *p++ = cpu_to_be32(open->op_why_no_deleg);
3791 /* deleg signaling not supported yet: */
3792 *p++ = cpu_to_be32(0);
Benny Halevyd24433c2012-02-16 20:57:17 +02003793 break;
3794 default:
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003795 p = xdr_reserve_space(xdr, 4);
3796 if (!p)
3797 return nfserr_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04003798 *p++ = cpu_to_be32(open->op_why_no_deleg);
Benny Halevyd24433c2012-02-16 20:57:17 +02003799 }
Benny Halevyd24433c2012-02-16 20:57:17 +02003800 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003801 default:
3802 BUG();
3803 }
3804 /* XXX save filehandle here */
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003805 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003806}
3807
Benny Halevy695e12f2008-07-04 14:38:33 +03003808static __be32
Al Virob37ad282006-10-19 23:28:59 -07003809nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003810{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003811 struct xdr_stream *xdr = &resp->xdr;
3812
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003813 return nfsd4_encode_stateid(xdr, &oc->oc_resp_stateid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003814}
3815
Benny Halevy695e12f2008-07-04 14:38:33 +03003816static __be32
Al Virob37ad282006-10-19 23:28:59 -07003817nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003818{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003819 struct xdr_stream *xdr = &resp->xdr;
3820
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003821 return nfsd4_encode_stateid(xdr, &od->od_stateid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822}
3823
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003824static __be32 nfsd4_encode_splice_read(
3825 struct nfsd4_compoundres *resp,
3826 struct nfsd4_read *read,
3827 struct file *file, unsigned long maxcount)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828{
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003829 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fields34a78b482014-05-13 16:32:04 -04003830 struct xdr_buf *buf = xdr->buf;
Chuck Lever76e54922020-11-05 10:24:19 -05003831 int status, space_left;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003832 u32 eof;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003833 __be32 nfserr;
J. Bruce Fieldsfec25fa2014-05-13 17:27:03 -04003834 __be32 *p = xdr->p - 2;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003835
Kinglong Meed5d5c302014-07-09 21:51:27 +08003836 /* Make sure there will be room for padding if needed */
3837 if (xdr->end - xdr->p < 1)
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003838 return nfserr_resource;
3839
Chuck Lever87c59422018-03-28 13:29:11 -04003840 nfserr = nfsd_splice_read(read->rd_rqstp, read->rd_fhp,
Trond Myklebust83a63072019-08-26 13:03:11 -04003841 file, read->rd_offset, &maxcount, &eof);
Chuck Lever87c59422018-03-28 13:29:11 -04003842 read->rd_length = maxcount;
Chuck Lever76e54922020-11-05 10:24:19 -05003843 if (nfserr)
3844 goto out_err;
3845 status = svc_encode_result_payload(read->rd_rqstp,
3846 buf->head[0].iov_len, maxcount);
3847 if (status) {
3848 nfserr = nfserrno(status);
3849 goto out_err;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003850 }
3851
J. Bruce Fieldsfec25fa2014-05-13 17:27:03 -04003852 *(p++) = htonl(eof);
3853 *(p++) = htonl(maxcount);
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003854
J. Bruce Fields34a78b482014-05-13 16:32:04 -04003855 buf->page_len = maxcount;
3856 buf->len += maxcount;
J. Bruce Fields15b23ef2014-09-24 16:32:34 -04003857 xdr->page_ptr += (buf->page_base + maxcount + PAGE_SIZE - 1)
3858 / PAGE_SIZE;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003859
3860 /* Use rest of head for padding and remaining ops: */
J. Bruce Fields34a78b482014-05-13 16:32:04 -04003861 buf->tail[0].iov_base = xdr->p;
3862 buf->tail[0].iov_len = 0;
J. Bruce Fieldsfec25fa2014-05-13 17:27:03 -04003863 xdr->iov = buf->tail;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003864 if (maxcount&3) {
J. Bruce Fieldsfec25fa2014-05-13 17:27:03 -04003865 int pad = 4 - (maxcount&3);
3866
3867 *(xdr->p++) = 0;
3868
J. Bruce Fields34a78b482014-05-13 16:32:04 -04003869 buf->tail[0].iov_base += maxcount&3;
J. Bruce Fieldsfec25fa2014-05-13 17:27:03 -04003870 buf->tail[0].iov_len = pad;
3871 buf->len += pad;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003872 }
3873
3874 space_left = min_t(int, (void *)xdr->end - (void *)xdr->p,
J. Bruce Fields34a78b482014-05-13 16:32:04 -04003875 buf->buflen - buf->len);
3876 buf->buflen = buf->len + space_left;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003877 xdr->end = (__be32 *)((void *)xdr->end + space_left);
3878
3879 return 0;
Chuck Lever76e54922020-11-05 10:24:19 -05003880
3881out_err:
3882 /*
3883 * nfsd_splice_actor may have already messed with the
3884 * page length; reset it so as not to confuse
3885 * xdr_truncate_encode in our caller.
3886 */
3887 buf->page_len = 0;
3888 return nfserr;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003889}
3890
3891static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
3892 struct nfsd4_read *read,
3893 struct file *file, unsigned long maxcount)
3894{
3895 struct xdr_stream *xdr = &resp->xdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896 u32 eof;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003897 int starting_len = xdr->buf->len - 8;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003898 __be32 nfserr;
3899 __be32 tmp;
J. Bruce Fieldsb0420982014-03-18 17:44:10 -04003900 int pad;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901
Anna Schumaker403217f2020-08-17 12:53:06 -04003902 read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, maxcount);
3903 if (read->rd_vlen < 0)
3904 return nfserr_resource;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905
Chuck Lever87c59422018-03-28 13:29:11 -04003906 nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset,
Trond Myklebust83a63072019-08-26 13:03:11 -04003907 resp->rqstp->rq_vec, read->rd_vlen, &maxcount,
3908 &eof);
Chuck Lever87c59422018-03-28 13:29:11 -04003909 read->rd_length = maxcount;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003910 if (nfserr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 return nfserr;
Chuck Lever03493bc2020-06-10 10:36:42 -04003912 if (svc_encode_result_payload(resp->rqstp, starting_len + 8, maxcount))
Chuck Lever41205532020-03-02 14:45:53 -05003913 return nfserr_io;
Chuck Lever7dcf4ab2020-03-02 15:00:04 -05003914 xdr_truncate_encode(xdr, starting_len + 8 + xdr_align_size(maxcount));
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003915
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003916 tmp = htonl(eof);
3917 write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4);
3918 tmp = htonl(maxcount);
3919 write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
3920
Chuck Lever7dcf4ab2020-03-02 15:00:04 -05003921 tmp = xdr_zero;
J. Bruce Fieldsb0420982014-03-18 17:44:10 -04003922 pad = (maxcount&3) ? 4 - (maxcount&3) : 0;
3923 write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + maxcount,
Chuck Lever7dcf4ab2020-03-02 15:00:04 -05003924 &tmp, pad);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003925 return 0;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003926
3927}
3928
3929static __be32
3930nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
3931 struct nfsd4_read *read)
3932{
3933 unsigned long maxcount;
3934 struct xdr_stream *xdr = &resp->xdr;
Jeff Layton5c4583b2019-08-18 14:18:54 -04003935 struct file *file;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003936 int starting_len = xdr->buf->len;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003937 __be32 *p;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003938
Jeff Layton5c4583b2019-08-18 14:18:54 -04003939 if (nfserr)
3940 return nfserr;
3941 file = read->rd_nf->nf_file;
3942
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003943 p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */
3944 if (!p) {
Jeff Layton779fb0f2014-11-19 07:51:18 -05003945 WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags));
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003946 return nfserr_resource;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003947 }
Christoph Hellwig68e8bb02015-06-18 16:45:02 +02003948 if (resp->xdr.buf->page_len &&
3949 test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) {
J. Bruce Fieldsb0420982014-03-18 17:44:10 -04003950 WARN_ON_ONCE(1);
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04003951 return nfserr_resource;
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003952 }
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003953 xdr_commit_encode(xdr);
3954
3955 maxcount = svc_max_payload(resp->rqstp);
Christoph Hellwig68e8bb02015-06-18 16:45:02 +02003956 maxcount = min_t(unsigned long, maxcount,
3957 (xdr->buf->buflen - xdr->buf->len));
Kinglong Mee3c7aa152014-06-10 18:08:19 +08003958 maxcount = min_t(unsigned long, maxcount, read->rd_length);
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003959
Christoph Hellwig68e8bb02015-06-18 16:45:02 +02003960 if (file->f_op->splice_read &&
3961 test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags))
Christoph Hellwig96bcad52015-06-18 16:45:01 +02003962 nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount);
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003963 else
Christoph Hellwig96bcad52015-06-18 16:45:01 +02003964 nfserr = nfsd4_encode_readv(resp, read, file, maxcount);
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003965
Christoph Hellwig96bcad52015-06-18 16:45:01 +02003966 if (nfserr)
J. Bruce Fieldsdc976182014-03-18 17:01:51 -04003967 xdr_truncate_encode(xdr, starting_len);
Christoph Hellwig96bcad52015-06-18 16:45:01 +02003968
Christoph Hellwig96bcad52015-06-18 16:45:01 +02003969 return nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970}
3971
Al Virob37ad282006-10-19 23:28:59 -07003972static __be32
3973nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974{
3975 int maxcount;
J. Bruce Fields476a7b12014-01-20 17:08:27 -05003976 __be32 wire_count;
3977 int zero = 0;
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04003978 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fields1fcea5b2014-02-26 20:17:02 -05003979 int length_offset = xdr->buf->len;
Chuck Lever76e54922020-11-05 10:24:19 -05003980 int status;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07003981 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982
J. Bruce Fields2825a7f2013-08-26 16:04:46 -04003983 p = xdr_reserve_space(xdr, 4);
3984 if (!p)
3985 return nfserr_resource;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 maxcount = PAGE_SIZE;
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05003987
J. Bruce Fields476a7b12014-01-20 17:08:27 -05003988 p = xdr_reserve_space(xdr, maxcount);
3989 if (!p)
J. Bruce Fields4e21ac42014-03-22 15:15:11 -04003990 return nfserr_resource;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 /*
Miklos Szeredifd4a0edf2016-12-09 16:45:04 +01003992 * XXX: By default, vfs_readlink() will truncate symlinks if they
3993 * would overflow the buffer. Is this kosher in NFSv4? If not, one
3994 * easy fix is: if vfs_readlink() precisely fills the buffer, assume
3995 * that truncation occurred, and return NFS4ERR_RESOURCE.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003996 */
J. Bruce Fields476a7b12014-01-20 17:08:27 -05003997 nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp,
3998 (char *)p, &maxcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 if (nfserr == nfserr_isdir)
J. Bruce Fieldsd3f627c2014-02-26 17:00:38 -05004000 nfserr = nfserr_inval;
Chuck Lever76e54922020-11-05 10:24:19 -05004001 if (nfserr)
4002 goto out_err;
4003 status = svc_encode_result_payload(readlink->rl_rqstp, length_offset,
4004 maxcount);
4005 if (status) {
4006 nfserr = nfserrno(status);
4007 goto out_err;
J. Bruce Fieldsd3f627c2014-02-26 17:00:38 -05004008 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004009
J. Bruce Fields476a7b12014-01-20 17:08:27 -05004010 wire_count = htonl(maxcount);
4011 write_bytes_to_xdr_buf(xdr->buf, length_offset, &wire_count, 4);
Avi Kivity69bbd9c2014-06-26 17:23:12 +03004012 xdr_truncate_encode(xdr, length_offset + 4 + ALIGN(maxcount, 4));
J. Bruce Fields476a7b12014-01-20 17:08:27 -05004013 if (maxcount & 3)
4014 write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount,
4015 &zero, 4 - (maxcount&3));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 return 0;
Chuck Lever76e54922020-11-05 10:24:19 -05004017
4018out_err:
4019 xdr_truncate_encode(xdr, length_offset);
4020 return nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021}
4022
Al Virob37ad282006-10-19 23:28:59 -07004023static __be32
4024nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readdir *readdir)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025{
4026 int maxcount;
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05004027 int bytes_left;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 loff_t offset;
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05004029 __be64 wire_offset;
J. Bruce Fieldsddd1ea52013-08-27 21:32:25 -04004030 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fields1fcea5b2014-02-26 20:17:02 -05004031 int starting_len = xdr->buf->len;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07004032 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004034 p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
4035 if (!p)
4036 return nfserr_resource;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037
4038 /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004039 *p++ = cpu_to_be32(0);
4040 *p++ = cpu_to_be32(0);
J. Bruce Fields4aea24b2014-01-15 15:17:58 -05004041 resp->xdr.buf->head[0].iov_len = ((char *)resp->xdr.p)
4042 - (char *)resp->xdr.buf->head[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043
4044 /*
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05004045 * Number of bytes left for directory entries allowing for the
4046 * final 8 bytes of the readdir and a following failed op:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 */
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05004048 bytes_left = xdr->buf->buflen - xdr->buf->len
4049 - COMPOUND_ERR_SLACK_SPACE - 8;
4050 if (bytes_left < 0) {
4051 nfserr = nfserr_resource;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 goto err_no_verf;
4053 }
Scott Mayhew9c2ece62018-05-07 09:01:08 -04004054 maxcount = svc_max_payload(resp->rqstp);
4055 maxcount = min_t(u32, readdir->rd_maxcount, maxcount);
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05004056 /*
4057 * Note the rfc defines rd_maxcount as the size of the
4058 * READDIR4resok structure, which includes the verifier above
4059 * and the 8 bytes encoded at the end of this function:
4060 */
4061 if (maxcount < 16) {
4062 nfserr = nfserr_toosmall;
4063 goto err_no_verf;
4064 }
4065 maxcount = min_t(int, maxcount-16, bytes_left);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066
J. Bruce Fieldsaee37762014-08-20 14:49:50 -04004067 /* RFC 3530 14.2.24 allows us to ignore dircount when it's 0: */
4068 if (!readdir->rd_dircount)
Scott Mayhew9c2ece62018-05-07 09:01:08 -04004069 readdir->rd_dircount = svc_max_payload(resp->rqstp);
J. Bruce Fieldsaee37762014-08-20 14:49:50 -04004070
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05004071 readdir->xdr = xdr;
4072 readdir->rd_maxcount = maxcount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073 readdir->common.err = 0;
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05004074 readdir->cookie_offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075
4076 offset = readdir->rd_cookie;
4077 nfserr = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp,
4078 &offset,
4079 &readdir->common, nfsd4_encode_dirent);
4080 if (nfserr == nfs_ok &&
4081 readdir->common.err == nfserr_toosmall &&
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05004082 xdr->buf->len == starting_len + 8) {
4083 /* nothing encoded; which limit did we hit?: */
4084 if (maxcount - 16 < bytes_left)
4085 /* It was the fault of rd_maxcount: */
4086 nfserr = nfserr_toosmall;
4087 else
4088 /* We ran out of buffer space: */
4089 nfserr = nfserr_resource;
4090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 if (nfserr)
4092 goto err_no_verf;
4093
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05004094 if (readdir->cookie_offset) {
4095 wire_offset = cpu_to_be64(offset);
4096 write_bytes_to_xdr_buf(xdr->buf, readdir->cookie_offset,
4097 &wire_offset, 8);
4098 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099
J. Bruce Fields561f0ed2014-01-20 16:37:11 -05004100 p = xdr_reserve_space(xdr, 8);
4101 if (!p) {
4102 WARN_ON_ONCE(1);
4103 goto err_no_verf;
4104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105 *p++ = 0; /* no more entries */
4106 *p++ = htonl(readdir->common.err == nfserr_eof);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107
4108 return 0;
4109err_no_verf:
J. Bruce Fields1fcea5b2014-02-26 20:17:02 -05004110 xdr_truncate_encode(xdr, starting_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111 return nfserr;
4112}
4113
Benny Halevy695e12f2008-07-04 14:38:33 +03004114static __be32
Al Virob37ad282006-10-19 23:28:59 -07004115nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004117 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07004118 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004120 p = xdr_reserve_space(xdr, 20);
4121 if (!p)
4122 return nfserr_resource;
4123 p = encode_cinfo(p, &remove->rm_cinfo);
4124 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125}
4126
Benny Halevy695e12f2008-07-04 14:38:33 +03004127static __be32
Al Virob37ad282006-10-19 23:28:59 -07004128nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004130 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07004131 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004133 p = xdr_reserve_space(xdr, 40);
4134 if (!p)
4135 return nfserr_resource;
4136 p = encode_cinfo(p, &rename->rn_sinfo);
4137 p = encode_cinfo(p, &rename->rn_tinfo);
4138 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139}
4140
Benny Halevy695e12f2008-07-04 14:38:33 +03004141static __be32
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004142nfsd4_do_encode_secinfo(struct xdr_stream *xdr, struct svc_export *exp)
Andy Adamsondcb488a32007-07-17 04:04:51 -07004143{
Chuck Lever676e4eb2013-04-30 18:48:54 -04004144 u32 i, nflavs, supported;
J. Bruce Fields4796f452007-07-17 04:04:51 -07004145 struct exp_flavor_info *flavs;
4146 struct exp_flavor_info def_flavs[2];
Chuck Lever676e4eb2013-04-30 18:48:54 -04004147 __be32 *p, *flavorsp;
4148 static bool report = true;
Andy Adamsondcb488a32007-07-17 04:04:51 -07004149
J. Bruce Fields4796f452007-07-17 04:04:51 -07004150 if (exp->ex_nflavors) {
4151 flavs = exp->ex_flavors;
4152 nflavs = exp->ex_nflavors;
4153 } else { /* Handling of some defaults in absence of real secinfo: */
4154 flavs = def_flavs;
4155 if (exp->ex_client->flavour->flavour == RPC_AUTH_UNIX) {
4156 nflavs = 2;
4157 flavs[0].pseudoflavor = RPC_AUTH_UNIX;
4158 flavs[1].pseudoflavor = RPC_AUTH_NULL;
4159 } else if (exp->ex_client->flavour->flavour == RPC_AUTH_GSS) {
4160 nflavs = 1;
4161 flavs[0].pseudoflavor
4162 = svcauth_gss_flavor(exp->ex_client);
4163 } else {
4164 nflavs = 1;
4165 flavs[0].pseudoflavor
4166 = exp->ex_client->flavour->flavour;
4167 }
4168 }
4169
Chuck Lever676e4eb2013-04-30 18:48:54 -04004170 supported = 0;
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004171 p = xdr_reserve_space(xdr, 4);
4172 if (!p)
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004173 return nfserr_resource;
Chuck Lever676e4eb2013-04-30 18:48:54 -04004174 flavorsp = p++; /* to be backfilled later */
Chuck Lever676e4eb2013-04-30 18:48:54 -04004175
J. Bruce Fields4796f452007-07-17 04:04:51 -07004176 for (i = 0; i < nflavs; i++) {
Chuck Lever676e4eb2013-04-30 18:48:54 -04004177 rpc_authflavor_t pf = flavs[i].pseudoflavor;
Chuck Levera77c8062013-03-16 15:55:10 -04004178 struct rpcsec_gss_info info;
Andy Adamsondcb488a32007-07-17 04:04:51 -07004179
Chuck Lever676e4eb2013-04-30 18:48:54 -04004180 if (rpcauth_get_gssinfo(pf, &info) == 0) {
4181 supported++;
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004182 p = xdr_reserve_space(xdr, 4 + 4 +
4183 XDR_LEN(info.oid.len) + 4 + 4);
4184 if (!p)
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004185 return nfserr_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004186 *p++ = cpu_to_be32(RPC_AUTH_GSS);
J. Bruce Fields0c0c2672014-03-22 18:43:16 -04004187 p = xdr_encode_opaque(p, info.oid.data, info.oid.len);
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004188 *p++ = cpu_to_be32(info.qop);
4189 *p++ = cpu_to_be32(info.service);
Chuck Lever676e4eb2013-04-30 18:48:54 -04004190 } else if (pf < RPC_AUTH_MAXFLAVOR) {
4191 supported++;
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004192 p = xdr_reserve_space(xdr, 4);
4193 if (!p)
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004194 return nfserr_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004195 *p++ = cpu_to_be32(pf);
Chuck Lever676e4eb2013-04-30 18:48:54 -04004196 } else {
4197 if (report)
4198 pr_warn("NFS: SECINFO: security flavor %u "
4199 "is not supported\n", pf);
Andy Adamsondcb488a32007-07-17 04:04:51 -07004200 }
4201 }
Chuck Levera77c8062013-03-16 15:55:10 -04004202
Chuck Lever676e4eb2013-04-30 18:48:54 -04004203 if (nflavs != supported)
4204 report = false;
4205 *flavorsp = htonl(supported);
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004206 return 0;
Andy Adamsondcb488a32007-07-17 04:04:51 -07004207}
4208
Mi Jinlong22b6dee2010-12-27 14:29:57 +08004209static __be32
4210nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
4211 struct nfsd4_secinfo *secinfo)
4212{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004213 struct xdr_stream *xdr = &resp->xdr;
4214
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004215 return nfsd4_do_encode_secinfo(xdr, secinfo->si_exp);
Mi Jinlong22b6dee2010-12-27 14:29:57 +08004216}
4217
4218static __be32
4219nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr,
4220 struct nfsd4_secinfo_no_name *secinfo)
4221{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004222 struct xdr_stream *xdr = &resp->xdr;
4223
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004224 return nfsd4_do_encode_secinfo(xdr, secinfo->sin_exp);
Mi Jinlong22b6dee2010-12-27 14:29:57 +08004225}
4226
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227/*
4228 * The SETATTR encode routine is special -- it always encodes a bitmap,
4229 * regardless of the error status.
4230 */
Benny Halevy695e12f2008-07-04 14:38:33 +03004231static __be32
Al Virob37ad282006-10-19 23:28:59 -07004232nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004234 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07004235 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004237 p = xdr_reserve_space(xdr, 16);
4238 if (!p)
4239 return nfserr_resource;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 if (nfserr) {
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004241 *p++ = cpu_to_be32(3);
4242 *p++ = cpu_to_be32(0);
4243 *p++ = cpu_to_be32(0);
4244 *p++ = cpu_to_be32(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 }
4246 else {
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004247 *p++ = cpu_to_be32(3);
4248 *p++ = cpu_to_be32(setattr->sa_bmval[0]);
4249 *p++ = cpu_to_be32(setattr->sa_bmval[1]);
4250 *p++ = cpu_to_be32(setattr->sa_bmval[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 }
Benny Halevy695e12f2008-07-04 14:38:33 +03004252 return nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004253}
4254
Benny Halevy695e12f2008-07-04 14:38:33 +03004255static __be32
Al Virob37ad282006-10-19 23:28:59 -07004256nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004258 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07004259 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260
4261 if (!nfserr) {
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004262 p = xdr_reserve_space(xdr, 8 + NFS4_VERIFIER_SIZE);
4263 if (!p)
4264 return nfserr_resource;
J. Bruce Fields0c0c2672014-03-22 18:43:16 -04004265 p = xdr_encode_opaque_fixed(p, &scd->se_clientid, 8);
4266 p = xdr_encode_opaque_fixed(p, &scd->se_confirm,
4267 NFS4_VERIFIER_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 }
4269 else if (nfserr == nfserr_clid_inuse) {
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004270 p = xdr_reserve_space(xdr, 8);
4271 if (!p)
4272 return nfserr_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004273 *p++ = cpu_to_be32(0);
4274 *p++ = cpu_to_be32(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 }
Benny Halevy695e12f2008-07-04 14:38:33 +03004276 return nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277}
4278
Benny Halevy695e12f2008-07-04 14:38:33 +03004279static __be32
Al Virob37ad282006-10-19 23:28:59 -07004280nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004282 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07004283 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004285 p = xdr_reserve_space(xdr, 16);
4286 if (!p)
4287 return nfserr_resource;
4288 *p++ = cpu_to_be32(write->wr_bytes_written);
4289 *p++ = cpu_to_be32(write->wr_how_written);
4290 p = xdr_encode_opaque_fixed(p, write->wr_verifier.data,
4291 NFS4_VERIFIER_SIZE);
4292 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293}
4294
Benny Halevy695e12f2008-07-04 14:38:33 +03004295static __be32
J. Bruce Fields57b7b432012-04-25 17:58:50 -04004296nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
Andy Adamson2db134e2009-04-03 08:27:55 +03004297 struct nfsd4_exchange_id *exid)
4298{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004299 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07004300 __be32 *p;
Andy Adamson0733d212009-04-03 08:28:01 +03004301 char *major_id;
4302 char *server_scope;
4303 int major_id_sz;
4304 int server_scope_sz;
4305 uint64_t minor_id = 0;
Scott Mayhew7627d7d2020-02-19 15:52:15 -05004306 struct nfsd_net *nn = net_generic(SVC_NET(resp->rqstp), nfsd_net_id);
Andy Adamson0733d212009-04-03 08:28:01 +03004307
Scott Mayhew7627d7d2020-02-19 15:52:15 -05004308 major_id = nn->nfsd_name;
4309 major_id_sz = strlen(nn->nfsd_name);
4310 server_scope = nn->nfsd_name;
4311 server_scope_sz = strlen(nn->nfsd_name);
Andy Adamson0733d212009-04-03 08:28:01 +03004312
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004313 p = xdr_reserve_space(xdr,
Andy Adamson0733d212009-04-03 08:28:01 +03004314 8 /* eir_clientid */ +
4315 4 /* eir_sequenceid */ +
4316 4 /* eir_flags */ +
Kinglong Meea8bb84b2013-12-10 15:24:36 +08004317 4 /* spr_how */);
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004318 if (!p)
4319 return nfserr_resource;
Andy Adamson0733d212009-04-03 08:28:01 +03004320
J. Bruce Fields0c0c2672014-03-22 18:43:16 -04004321 p = xdr_encode_opaque_fixed(p, &exid->clientid, 8);
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004322 *p++ = cpu_to_be32(exid->seqid);
4323 *p++ = cpu_to_be32(exid->flags);
Andy Adamson0733d212009-04-03 08:28:01 +03004324
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004325 *p++ = cpu_to_be32(exid->spa_how);
Kinglong Meea8bb84b2013-12-10 15:24:36 +08004326
J. Bruce Fields57266a62013-04-13 14:27:29 -04004327 switch (exid->spa_how) {
4328 case SP4_NONE:
4329 break;
4330 case SP4_MACH_CRED:
4331 /* spo_must_enforce bitmap: */
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004332 nfserr = nfsd4_encode_bitmap(xdr,
Andrew Elbleed941642016-06-15 12:52:09 -04004333 exid->spo_must_enforce[0],
4334 exid->spo_must_enforce[1],
4335 exid->spo_must_enforce[2]);
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004336 if (nfserr)
4337 return nfserr;
Andrew Elbleed941642016-06-15 12:52:09 -04004338 /* spo_must_allow bitmap: */
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004339 nfserr = nfsd4_encode_bitmap(xdr,
Andrew Elbleed941642016-06-15 12:52:09 -04004340 exid->spo_must_allow[0],
4341 exid->spo_must_allow[1],
4342 exid->spo_must_allow[2]);
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004343 if (nfserr)
4344 return nfserr;
J. Bruce Fields57266a62013-04-13 14:27:29 -04004345 break;
4346 default:
4347 WARN_ON_ONCE(1);
4348 }
Andy Adamson0733d212009-04-03 08:28:01 +03004349
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004350 p = xdr_reserve_space(xdr,
Kinglong Meea8bb84b2013-12-10 15:24:36 +08004351 8 /* so_minor_id */ +
4352 4 /* so_major_id.len */ +
4353 (XDR_QUADLEN(major_id_sz) * 4) +
4354 4 /* eir_server_scope.len */ +
4355 (XDR_QUADLEN(server_scope_sz) * 4) +
4356 4 /* eir_server_impl_id.count (0) */);
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004357 if (!p)
4358 return nfserr_resource;
Kinglong Meea8bb84b2013-12-10 15:24:36 +08004359
Andy Adamson0733d212009-04-03 08:28:01 +03004360 /* The server_owner struct */
J. Bruce Fieldsb64c7f32014-03-22 17:11:35 -04004361 p = xdr_encode_hyper(p, minor_id); /* Minor id */
Andy Adamson0733d212009-04-03 08:28:01 +03004362 /* major id */
J. Bruce Fields0c0c2672014-03-22 18:43:16 -04004363 p = xdr_encode_opaque(p, major_id, major_id_sz);
Andy Adamson0733d212009-04-03 08:28:01 +03004364
4365 /* Server scope */
J. Bruce Fields0c0c2672014-03-22 18:43:16 -04004366 p = xdr_encode_opaque(p, server_scope, server_scope_sz);
Andy Adamson0733d212009-04-03 08:28:01 +03004367
4368 /* Implementation id */
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004369 *p++ = cpu_to_be32(0); /* zero length nfs_impl_id4 array */
Andy Adamson0733d212009-04-03 08:28:01 +03004370 return 0;
Andy Adamson2db134e2009-04-03 08:27:55 +03004371}
4372
4373static __be32
J. Bruce Fields57b7b432012-04-25 17:58:50 -04004374nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr,
Andy Adamson2db134e2009-04-03 08:27:55 +03004375 struct nfsd4_create_session *sess)
4376{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004377 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07004378 __be32 *p;
Andy Adamsonec6b5d72009-04-03 08:28:28 +03004379
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004380 p = xdr_reserve_space(xdr, 24);
4381 if (!p)
4382 return nfserr_resource;
J. Bruce Fields0c0c2672014-03-22 18:43:16 -04004383 p = xdr_encode_opaque_fixed(p, sess->sessionid.data,
4384 NFS4_MAX_SESSIONID_LEN);
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004385 *p++ = cpu_to_be32(sess->seqid);
4386 *p++ = cpu_to_be32(sess->flags);
Andy Adamsonec6b5d72009-04-03 08:28:28 +03004387
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004388 p = xdr_reserve_space(xdr, 28);
4389 if (!p)
4390 return nfserr_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004391 *p++ = cpu_to_be32(0); /* headerpadsz */
4392 *p++ = cpu_to_be32(sess->fore_channel.maxreq_sz);
4393 *p++ = cpu_to_be32(sess->fore_channel.maxresp_sz);
4394 *p++ = cpu_to_be32(sess->fore_channel.maxresp_cached);
4395 *p++ = cpu_to_be32(sess->fore_channel.maxops);
4396 *p++ = cpu_to_be32(sess->fore_channel.maxreqs);
4397 *p++ = cpu_to_be32(sess->fore_channel.nr_rdma_attrs);
Andy Adamsonec6b5d72009-04-03 08:28:28 +03004398
4399 if (sess->fore_channel.nr_rdma_attrs) {
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004400 p = xdr_reserve_space(xdr, 4);
4401 if (!p)
4402 return nfserr_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004403 *p++ = cpu_to_be32(sess->fore_channel.rdma_attrs);
Andy Adamsonec6b5d72009-04-03 08:28:28 +03004404 }
4405
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004406 p = xdr_reserve_space(xdr, 28);
4407 if (!p)
4408 return nfserr_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004409 *p++ = cpu_to_be32(0); /* headerpadsz */
4410 *p++ = cpu_to_be32(sess->back_channel.maxreq_sz);
4411 *p++ = cpu_to_be32(sess->back_channel.maxresp_sz);
4412 *p++ = cpu_to_be32(sess->back_channel.maxresp_cached);
4413 *p++ = cpu_to_be32(sess->back_channel.maxops);
4414 *p++ = cpu_to_be32(sess->back_channel.maxreqs);
4415 *p++ = cpu_to_be32(sess->back_channel.nr_rdma_attrs);
Andy Adamsonec6b5d72009-04-03 08:28:28 +03004416
4417 if (sess->back_channel.nr_rdma_attrs) {
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004418 p = xdr_reserve_space(xdr, 4);
4419 if (!p)
4420 return nfserr_resource;
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004421 *p++ = cpu_to_be32(sess->back_channel.rdma_attrs);
Andy Adamsonec6b5d72009-04-03 08:28:28 +03004422 }
4423 return 0;
Andy Adamson2db134e2009-04-03 08:27:55 +03004424}
4425
4426static __be32
J. Bruce Fields57b7b432012-04-25 17:58:50 -04004427nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr,
Andy Adamson2db134e2009-04-03 08:27:55 +03004428 struct nfsd4_sequence *seq)
4429{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004430 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07004431 __be32 *p;
Benny Halevyb85d4c02009-04-03 08:28:08 +03004432
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004433 p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 20);
4434 if (!p)
4435 return nfserr_resource;
J. Bruce Fields0c0c2672014-03-22 18:43:16 -04004436 p = xdr_encode_opaque_fixed(p, seq->sessionid.data,
4437 NFS4_MAX_SESSIONID_LEN);
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004438 *p++ = cpu_to_be32(seq->seqid);
4439 *p++ = cpu_to_be32(seq->slotid);
J. Bruce Fieldsb7d7ca32011-08-31 15:39:30 -04004440 /* Note slotid's are numbered from zero: */
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04004441 *p++ = cpu_to_be32(seq->maxslots - 1); /* sr_highest_slotid */
4442 *p++ = cpu_to_be32(seq->maxslots - 1); /* sr_target_highest_slotid */
4443 *p++ = cpu_to_be32(seq->status_flags);
Benny Halevyb85d4c02009-04-03 08:28:08 +03004444
J. Bruce Fieldsf5236012014-03-21 17:57:57 -04004445 resp->cstate.data_offset = xdr->buf->len; /* DRC cache data pointer */
Benny Halevyb85d4c02009-04-03 08:28:08 +03004446 return 0;
Andy Adamson2db134e2009-04-03 08:27:55 +03004447}
4448
J. Bruce Fields2355c592012-04-25 16:56:22 -04004449static __be32
J. Bruce Fields57b7b432012-04-25 17:58:50 -04004450nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
Bryan Schumaker17456802011-07-13 10:50:48 -04004451 struct nfsd4_test_stateid *test_stateid)
4452{
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004453 struct xdr_stream *xdr = &resp->xdr;
Bryan Schumaker03cfb422012-01-27 10:22:49 -05004454 struct nfsd4_test_stateid_id *stateid, *next;
Bryan Schumaker17456802011-07-13 10:50:48 -04004455 __be32 *p;
Bryan Schumaker17456802011-07-13 10:50:48 -04004456
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05004457 p = xdr_reserve_space(xdr, 4 + (4 * test_stateid->ts_num_ids));
4458 if (!p)
4459 return nfserr_resource;
Bryan Schumaker17456802011-07-13 10:50:48 -04004460 *p++ = htonl(test_stateid->ts_num_ids);
Bryan Schumaker17456802011-07-13 10:50:48 -04004461
Bryan Schumaker03cfb422012-01-27 10:22:49 -05004462 list_for_each_entry_safe(stateid, next, &test_stateid->ts_stateid_list, ts_id_list) {
Al Viro02f5fde2012-04-13 00:10:34 -04004463 *p++ = stateid->ts_id_status;
Bryan Schumaker17456802011-07-13 10:50:48 -04004464 }
Bryan Schumaker17456802011-07-13 10:50:48 -04004465
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004466 return 0;
Bryan Schumaker17456802011-07-13 10:50:48 -04004467}
4468
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004469#ifdef CONFIG_NFSD_PNFS
4470static __be32
4471nfsd4_encode_getdeviceinfo(struct nfsd4_compoundres *resp, __be32 nfserr,
4472 struct nfsd4_getdeviceinfo *gdev)
4473{
4474 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fieldsf961e3f2017-05-05 16:17:57 -04004475 const struct nfsd4_layout_ops *ops;
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004476 u32 starting_len = xdr->buf->len, needed_len;
4477 __be32 *p;
4478
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004479 p = xdr_reserve_space(xdr, 4);
4480 if (!p)
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004481 return nfserr_resource;
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004482
4483 *p++ = cpu_to_be32(gdev->gd_layout_type);
4484
4485 /* If maxcount is 0 then just update notifications */
4486 if (gdev->gd_maxcount != 0) {
J. Bruce Fieldsf961e3f2017-05-05 16:17:57 -04004487 ops = nfsd4_layout_ops[gdev->gd_layout_type];
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004488 nfserr = ops->encode_getdeviceinfo(xdr, gdev);
4489 if (nfserr) {
4490 /*
4491 * We don't bother to burden the layout drivers with
4492 * enforcing gd_maxcount, just tell the client to
4493 * come back with a bigger buffer if it's not enough.
4494 */
4495 if (xdr->buf->len + 4 > gdev->gd_maxcount)
4496 goto toosmall;
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004497 return nfserr;
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004498 }
4499 }
4500
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004501 if (gdev->gd_notify_types) {
4502 p = xdr_reserve_space(xdr, 4 + 4);
4503 if (!p)
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004504 return nfserr_resource;
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004505 *p++ = cpu_to_be32(1); /* bitmap length */
4506 *p++ = cpu_to_be32(gdev->gd_notify_types);
4507 } else {
4508 p = xdr_reserve_space(xdr, 4);
4509 if (!p)
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004510 return nfserr_resource;
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004511 *p++ = 0;
4512 }
4513
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004514 return 0;
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004515toosmall:
4516 dprintk("%s: maxcount too small\n", __func__);
4517 needed_len = xdr->buf->len + 4 /* notifications */;
4518 xdr_truncate_encode(xdr, starting_len);
4519 p = xdr_reserve_space(xdr, 4);
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004520 if (!p)
4521 return nfserr_resource;
4522 *p++ = cpu_to_be32(needed_len);
4523 return nfserr_toosmall;
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004524}
4525
4526static __be32
4527nfsd4_encode_layoutget(struct nfsd4_compoundres *resp, __be32 nfserr,
4528 struct nfsd4_layoutget *lgp)
4529{
4530 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fieldsf961e3f2017-05-05 16:17:57 -04004531 const struct nfsd4_layout_ops *ops;
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004532 __be32 *p;
4533
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004534 p = xdr_reserve_space(xdr, 36 + sizeof(stateid_opaque_t));
4535 if (!p)
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004536 return nfserr_resource;
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004537
4538 *p++ = cpu_to_be32(1); /* we always set return-on-close */
4539 *p++ = cpu_to_be32(lgp->lg_sid.si_generation);
4540 p = xdr_encode_opaque_fixed(p, &lgp->lg_sid.si_opaque,
4541 sizeof(stateid_opaque_t));
4542
4543 *p++ = cpu_to_be32(1); /* we always return a single layout */
4544 p = xdr_encode_hyper(p, lgp->lg_seg.offset);
4545 p = xdr_encode_hyper(p, lgp->lg_seg.length);
4546 *p++ = cpu_to_be32(lgp->lg_seg.iomode);
4547 *p++ = cpu_to_be32(lgp->lg_layout_type);
4548
J. Bruce Fieldsf961e3f2017-05-05 16:17:57 -04004549 ops = nfsd4_layout_ops[lgp->lg_layout_type];
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004550 return ops->encode_layoutget(xdr, lgp);
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004551}
4552
4553static __be32
4554nfsd4_encode_layoutcommit(struct nfsd4_compoundres *resp, __be32 nfserr,
4555 struct nfsd4_layoutcommit *lcp)
4556{
4557 struct xdr_stream *xdr = &resp->xdr;
4558 __be32 *p;
4559
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004560 p = xdr_reserve_space(xdr, 4);
4561 if (!p)
4562 return nfserr_resource;
4563 *p++ = cpu_to_be32(lcp->lc_size_chg);
4564 if (lcp->lc_size_chg) {
4565 p = xdr_reserve_space(xdr, 8);
4566 if (!p)
4567 return nfserr_resource;
4568 p = xdr_encode_hyper(p, lcp->lc_newsize);
4569 }
4570
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004571 return 0;
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004572}
4573
4574static __be32
4575nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr,
4576 struct nfsd4_layoutreturn *lrp)
4577{
4578 struct xdr_stream *xdr = &resp->xdr;
4579 __be32 *p;
4580
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004581 p = xdr_reserve_space(xdr, 4);
4582 if (!p)
4583 return nfserr_resource;
4584 *p++ = cpu_to_be32(lrp->lrs_present);
4585 if (lrp->lrs_present)
Kinglong Mee376675d2015-03-22 22:17:10 +08004586 return nfsd4_encode_stateid(xdr, &lrp->lr_sid);
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004587 return 0;
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02004588}
4589#endif /* CONFIG_NFSD_PNFS */
4590
Andy Adamson2db134e2009-04-03 08:27:55 +03004591static __be32
Olga Kornievskaiae0639dc2018-07-20 18:19:20 -04004592nfsd42_encode_write_res(struct nfsd4_compoundres *resp,
4593 struct nfsd42_write_res *write, bool sync)
Anna Schumaker29ae7f92016-09-07 15:57:30 -04004594{
4595 __be32 *p;
Olga Kornievskaiae0639dc2018-07-20 18:19:20 -04004596 p = xdr_reserve_space(&resp->xdr, 4);
Anna Schumaker29ae7f92016-09-07 15:57:30 -04004597 if (!p)
4598 return nfserr_resource;
4599
Olga Kornievskaiae0639dc2018-07-20 18:19:20 -04004600 if (sync)
4601 *p++ = cpu_to_be32(0);
4602 else {
4603 __be32 nfserr;
4604 *p++ = cpu_to_be32(1);
4605 nfserr = nfsd4_encode_stateid(&resp->xdr, &write->cb_stateid);
4606 if (nfserr)
4607 return nfserr;
4608 }
4609 p = xdr_reserve_space(&resp->xdr, 8 + 4 + NFS4_VERIFIER_SIZE);
4610 if (!p)
4611 return nfserr_resource;
4612
Anna Schumaker29ae7f92016-09-07 15:57:30 -04004613 p = xdr_encode_hyper(p, write->wr_bytes_written);
4614 *p++ = cpu_to_be32(write->wr_stable_how);
4615 p = xdr_encode_opaque_fixed(p, write->wr_verifier.data,
4616 NFS4_VERIFIER_SIZE);
4617 return nfs_ok;
4618}
4619
4620static __be32
Olga Kornievskaia51911862019-08-08 11:14:59 -04004621nfsd42_encode_nl4_server(struct nfsd4_compoundres *resp, struct nl4_server *ns)
4622{
4623 struct xdr_stream *xdr = &resp->xdr;
4624 struct nfs42_netaddr *addr;
4625 __be32 *p;
4626
4627 p = xdr_reserve_space(xdr, 4);
4628 *p++ = cpu_to_be32(ns->nl4_type);
4629
4630 switch (ns->nl4_type) {
4631 case NL4_NETADDR:
4632 addr = &ns->u.nl4_addr;
4633
4634 /* netid_len, netid, uaddr_len, uaddr (port included
4635 * in RPCBIND_MAXUADDRLEN)
4636 */
4637 p = xdr_reserve_space(xdr,
4638 4 /* netid len */ +
4639 (XDR_QUADLEN(addr->netid_len) * 4) +
4640 4 /* uaddr len */ +
4641 (XDR_QUADLEN(addr->addr_len) * 4));
4642 if (!p)
4643 return nfserr_resource;
4644
4645 *p++ = cpu_to_be32(addr->netid_len);
4646 p = xdr_encode_opaque_fixed(p, addr->netid,
4647 addr->netid_len);
4648 *p++ = cpu_to_be32(addr->addr_len);
4649 p = xdr_encode_opaque_fixed(p, addr->addr,
4650 addr->addr_len);
4651 break;
4652 default:
4653 WARN_ON_ONCE(ns->nl4_type != NL4_NETADDR);
4654 return nfserr_inval;
4655 }
4656
4657 return 0;
4658}
4659
4660static __be32
Anna Schumaker29ae7f92016-09-07 15:57:30 -04004661nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr,
4662 struct nfsd4_copy *copy)
4663{
4664 __be32 *p;
4665
Olga Kornievskaiae0639dc2018-07-20 18:19:20 -04004666 nfserr = nfsd42_encode_write_res(resp, &copy->cp_res,
4667 copy->cp_synchronous);
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004668 if (nfserr)
4669 return nfserr;
Anna Schumaker29ae7f92016-09-07 15:57:30 -04004670
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004671 p = xdr_reserve_space(&resp->xdr, 4 + 4);
J. Bruce Fieldsedcc8452018-03-07 15:37:35 -05004672 *p++ = xdr_one; /* cr_consecutive */
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004673 *p++ = cpu_to_be32(copy->cp_synchronous);
4674 return 0;
Anna Schumaker29ae7f92016-09-07 15:57:30 -04004675}
4676
4677static __be32
Olga Kornievskaia6308bc92018-07-20 18:19:18 -04004678nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr,
4679 struct nfsd4_offload_status *os)
4680{
4681 struct xdr_stream *xdr = &resp->xdr;
4682 __be32 *p;
4683
4684 p = xdr_reserve_space(xdr, 8 + 4);
4685 if (!p)
4686 return nfserr_resource;
4687 p = xdr_encode_hyper(p, os->count);
4688 *p++ = cpu_to_be32(0);
Anna Schumaker528b8492020-09-28 13:08:58 -04004689 return nfserr;
4690}
4691
4692static __be32
4693nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
4694 struct nfsd4_read *read,
Anna Schumaker9f0b5792020-09-28 13:09:01 -04004695 unsigned long *maxcount, u32 *eof,
4696 loff_t *pos)
Anna Schumaker528b8492020-09-28 13:08:58 -04004697{
4698 struct xdr_stream *xdr = &resp->xdr;
4699 struct file *file = read->rd_nf->nf_file;
4700 int starting_len = xdr->buf->len;
Anna Schumaker9f0b5792020-09-28 13:09:01 -04004701 loff_t hole_pos;
Anna Schumaker528b8492020-09-28 13:08:58 -04004702 __be32 nfserr;
4703 __be32 *p, tmp;
4704 __be64 tmp64;
4705
Anna Schumaker9f0b5792020-09-28 13:09:01 -04004706 hole_pos = pos ? *pos : vfs_llseek(file, read->rd_offset, SEEK_HOLE);
Anna Schumaker2db27992020-09-28 13:08:59 -04004707 if (hole_pos > read->rd_offset)
Anna Schumaker278765e2020-09-28 13:09:00 -04004708 *maxcount = min_t(unsigned long, *maxcount, hole_pos - read->rd_offset);
4709 *maxcount = min_t(unsigned long, *maxcount, (xdr->buf->buflen - xdr->buf->len));
Anna Schumaker528b8492020-09-28 13:08:58 -04004710
4711 /* Content type, offset, byte count */
4712 p = xdr_reserve_space(xdr, 4 + 8 + 4);
4713 if (!p)
4714 return nfserr_resource;
4715
Anna Schumaker278765e2020-09-28 13:09:00 -04004716 read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, *maxcount);
Anna Schumaker528b8492020-09-28 13:08:58 -04004717 if (read->rd_vlen < 0)
4718 return nfserr_resource;
4719
4720 nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset,
Anna Schumaker278765e2020-09-28 13:09:00 -04004721 resp->rqstp->rq_vec, read->rd_vlen, maxcount, eof);
Anna Schumaker528b8492020-09-28 13:08:58 -04004722 if (nfserr)
4723 return nfserr;
4724
4725 tmp = htonl(NFS4_CONTENT_DATA);
4726 write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4);
4727 tmp64 = cpu_to_be64(read->rd_offset);
4728 write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp64, 8);
Anna Schumaker278765e2020-09-28 13:09:00 -04004729 tmp = htonl(*maxcount);
Anna Schumaker528b8492020-09-28 13:08:58 -04004730 write_bytes_to_xdr_buf(xdr->buf, starting_len + 12, &tmp, 4);
4731 return nfs_ok;
4732}
4733
4734static __be32
Anna Schumaker2db27992020-09-28 13:08:59 -04004735nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp,
4736 struct nfsd4_read *read,
Anna Schumaker278765e2020-09-28 13:09:00 -04004737 unsigned long *maxcount, u32 *eof)
Anna Schumaker2db27992020-09-28 13:08:59 -04004738{
4739 struct file *file = read->rd_nf->nf_file;
Anna Schumaker278765e2020-09-28 13:09:00 -04004740 loff_t data_pos = vfs_llseek(file, read->rd_offset, SEEK_DATA);
Anna Schumaker9f0b5792020-09-28 13:09:01 -04004741 loff_t f_size = i_size_read(file_inode(file));
Anna Schumaker278765e2020-09-28 13:09:00 -04004742 unsigned long count;
Anna Schumaker2db27992020-09-28 13:08:59 -04004743 __be32 *p;
4744
Anna Schumaker278765e2020-09-28 13:09:00 -04004745 if (data_pos == -ENXIO)
Anna Schumaker9f0b5792020-09-28 13:09:01 -04004746 data_pos = f_size;
4747 else if (data_pos <= read->rd_offset || (data_pos < f_size && data_pos % PAGE_SIZE))
4748 return nfsd4_encode_read_plus_data(resp, read, maxcount, eof, &f_size);
Anna Schumaker278765e2020-09-28 13:09:00 -04004749 count = data_pos - read->rd_offset;
4750
Anna Schumaker2db27992020-09-28 13:08:59 -04004751 /* Content type, offset, byte count */
4752 p = xdr_reserve_space(&resp->xdr, 4 + 8 + 8);
4753 if (!p)
4754 return nfserr_resource;
4755
4756 *p++ = htonl(NFS4_CONTENT_HOLE);
4757 p = xdr_encode_hyper(p, read->rd_offset);
Anna Schumaker278765e2020-09-28 13:09:00 -04004758 p = xdr_encode_hyper(p, count);
Anna Schumaker2db27992020-09-28 13:08:59 -04004759
Anna Schumaker9f0b5792020-09-28 13:09:01 -04004760 *eof = (read->rd_offset + count) >= f_size;
Anna Schumaker278765e2020-09-28 13:09:00 -04004761 *maxcount = min_t(unsigned long, count, *maxcount);
Anna Schumaker2db27992020-09-28 13:08:59 -04004762 return nfs_ok;
4763}
4764
4765static __be32
Anna Schumaker528b8492020-09-28 13:08:58 -04004766nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
4767 struct nfsd4_read *read)
4768{
Anna Schumaker278765e2020-09-28 13:09:00 -04004769 unsigned long maxcount, count;
Anna Schumaker528b8492020-09-28 13:08:58 -04004770 struct xdr_stream *xdr = &resp->xdr;
4771 struct file *file;
4772 int starting_len = xdr->buf->len;
Anna Schumaker9f0b5792020-09-28 13:09:01 -04004773 int last_segment = xdr->buf->len;
Anna Schumaker528b8492020-09-28 13:08:58 -04004774 int segments = 0;
4775 __be32 *p, tmp;
Anna Schumaker9f0b5792020-09-28 13:09:01 -04004776 bool is_data;
Anna Schumaker2db27992020-09-28 13:08:59 -04004777 loff_t pos;
Anna Schumaker528b8492020-09-28 13:08:58 -04004778 u32 eof;
4779
4780 if (nfserr)
4781 return nfserr;
4782 file = read->rd_nf->nf_file;
4783
4784 /* eof flag, segment count */
4785 p = xdr_reserve_space(xdr, 4 + 4);
4786 if (!p)
4787 return nfserr_resource;
4788 xdr_commit_encode(xdr);
4789
4790 maxcount = svc_max_payload(resp->rqstp);
4791 maxcount = min_t(unsigned long, maxcount,
4792 (xdr->buf->buflen - xdr->buf->len));
4793 maxcount = min_t(unsigned long, maxcount, read->rd_length);
Anna Schumaker278765e2020-09-28 13:09:00 -04004794 count = maxcount;
Anna Schumaker528b8492020-09-28 13:08:58 -04004795
4796 eof = read->rd_offset >= i_size_read(file_inode(file));
Anna Schumaker2db27992020-09-28 13:08:59 -04004797 if (eof)
4798 goto out;
4799
Anna Schumaker9f0b5792020-09-28 13:09:01 -04004800 pos = vfs_llseek(file, read->rd_offset, SEEK_HOLE);
4801 is_data = pos > read->rd_offset;
Anna Schumaker2db27992020-09-28 13:08:59 -04004802
Anna Schumaker9f0b5792020-09-28 13:09:01 -04004803 while (count > 0 && !eof) {
Anna Schumaker278765e2020-09-28 13:09:00 -04004804 maxcount = count;
Anna Schumaker9f0b5792020-09-28 13:09:01 -04004805 if (is_data)
4806 nfserr = nfsd4_encode_read_plus_data(resp, read, &maxcount, &eof,
4807 segments == 0 ? &pos : NULL);
4808 else
4809 nfserr = nfsd4_encode_read_plus_hole(resp, read, &maxcount, &eof);
Anna Schumaker278765e2020-09-28 13:09:00 -04004810 if (nfserr)
4811 goto out;
4812 count -= maxcount;
4813 read->rd_offset += maxcount;
Anna Schumaker9f0b5792020-09-28 13:09:01 -04004814 is_data = !is_data;
4815 last_segment = xdr->buf->len;
Anna Schumaker528b8492020-09-28 13:08:58 -04004816 segments++;
4817 }
4818
Anna Schumaker2db27992020-09-28 13:08:59 -04004819out:
Anna Schumaker278765e2020-09-28 13:09:00 -04004820 if (nfserr && segments == 0)
Anna Schumaker528b8492020-09-28 13:08:58 -04004821 xdr_truncate_encode(xdr, starting_len);
4822 else {
4823 tmp = htonl(eof);
4824 write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4);
4825 tmp = htonl(segments);
4826 write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
Anna Schumaker9f0b5792020-09-28 13:09:01 -04004827 if (nfserr) {
4828 xdr_truncate_encode(xdr, last_segment);
4829 nfserr = nfs_ok;
4830 }
Anna Schumaker528b8492020-09-28 13:08:58 -04004831 }
Olga Kornievskaia6308bc92018-07-20 18:19:18 -04004832
4833 return nfserr;
4834}
4835
4836static __be32
Olga Kornievskaia51911862019-08-08 11:14:59 -04004837nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr,
4838 struct nfsd4_copy_notify *cn)
4839{
4840 struct xdr_stream *xdr = &resp->xdr;
4841 __be32 *p;
4842
4843 if (nfserr)
4844 return nfserr;
4845
4846 /* 8 sec, 4 nsec */
4847 p = xdr_reserve_space(xdr, 12);
4848 if (!p)
4849 return nfserr_resource;
4850
4851 /* cnr_lease_time */
4852 p = xdr_encode_hyper(p, cn->cpn_sec);
4853 *p++ = cpu_to_be32(cn->cpn_nsec);
4854
4855 /* cnr_stateid */
4856 nfserr = nfsd4_encode_stateid(xdr, &cn->cpn_cnr_stateid);
4857 if (nfserr)
4858 return nfserr;
4859
4860 /* cnr_src.nl_nsvr */
4861 p = xdr_reserve_space(xdr, 4);
4862 if (!p)
4863 return nfserr_resource;
4864
4865 *p++ = cpu_to_be32(1);
4866
4867 return nfsd42_encode_nl4_server(resp, &cn->cpn_src);
4868}
4869
4870static __be32
Anna Schumaker24bab492014-09-26 13:58:27 -04004871nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr,
4872 struct nfsd4_seek *seek)
4873{
4874 __be32 *p;
4875
Anna Schumaker24bab492014-09-26 13:58:27 -04004876 p = xdr_reserve_space(&resp->xdr, 4 + 8);
4877 *p++ = cpu_to_be32(seek->seek_eof);
4878 p = xdr_encode_hyper(p, seek->seek_pos);
4879
J. Bruce Fieldsbac966d2017-05-06 11:12:04 -04004880 return 0;
Anna Schumaker24bab492014-09-26 13:58:27 -04004881}
4882
4883static __be32
Benny Halevy695e12f2008-07-04 14:38:33 +03004884nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p)
4885{
4886 return nfserr;
4887}
4888
Frank van der Linden23e50fe2020-06-23 22:39:26 +00004889/*
4890 * Encode kmalloc-ed buffer in to XDR stream.
4891 */
Chuck Leverb9a49232020-09-11 14:47:53 -04004892static __be32
Frank van der Linden23e50fe2020-06-23 22:39:26 +00004893nfsd4_vbuf_to_stream(struct xdr_stream *xdr, char *buf, u32 buflen)
4894{
4895 u32 cplen;
4896 __be32 *p;
4897
4898 cplen = min_t(unsigned long, buflen,
4899 ((void *)xdr->end - (void *)xdr->p));
4900 p = xdr_reserve_space(xdr, cplen);
4901 if (!p)
4902 return nfserr_resource;
4903
4904 memcpy(p, buf, cplen);
4905 buf += cplen;
4906 buflen -= cplen;
4907
4908 while (buflen) {
4909 cplen = min_t(u32, buflen, PAGE_SIZE);
4910 p = xdr_reserve_space(xdr, cplen);
4911 if (!p)
4912 return nfserr_resource;
4913
4914 memcpy(p, buf, cplen);
4915
4916 if (cplen < PAGE_SIZE) {
4917 /*
4918 * We're done, with a length that wasn't page
4919 * aligned, so possibly not word aligned. Pad
4920 * any trailing bytes with 0.
4921 */
4922 xdr_encode_opaque_fixed(p, NULL, cplen);
4923 break;
4924 }
4925
4926 buflen -= PAGE_SIZE;
4927 buf += PAGE_SIZE;
4928 }
4929
4930 return 0;
4931}
4932
4933static __be32
4934nfsd4_encode_getxattr(struct nfsd4_compoundres *resp, __be32 nfserr,
4935 struct nfsd4_getxattr *getxattr)
4936{
4937 struct xdr_stream *xdr = &resp->xdr;
4938 __be32 *p, err;
4939
4940 p = xdr_reserve_space(xdr, 4);
4941 if (!p)
4942 return nfserr_resource;
4943
4944 *p = cpu_to_be32(getxattr->getxa_len);
4945
4946 if (getxattr->getxa_len == 0)
4947 return 0;
4948
4949 err = nfsd4_vbuf_to_stream(xdr, getxattr->getxa_buf,
4950 getxattr->getxa_len);
4951
4952 kvfree(getxattr->getxa_buf);
4953
4954 return err;
4955}
4956
4957static __be32
4958nfsd4_encode_setxattr(struct nfsd4_compoundres *resp, __be32 nfserr,
4959 struct nfsd4_setxattr *setxattr)
4960{
4961 struct xdr_stream *xdr = &resp->xdr;
4962 __be32 *p;
4963
4964 p = xdr_reserve_space(xdr, 20);
4965 if (!p)
4966 return nfserr_resource;
4967
4968 encode_cinfo(p, &setxattr->setxa_cinfo);
4969
4970 return 0;
4971}
4972
4973/*
4974 * See if there are cookie values that can be rejected outright.
4975 */
4976static __be32
4977nfsd4_listxattr_validate_cookie(struct nfsd4_listxattrs *listxattrs,
4978 u32 *offsetp)
4979{
4980 u64 cookie = listxattrs->lsxa_cookie;
4981
4982 /*
4983 * If the cookie is larger than the maximum number we can fit
4984 * in either the buffer we just got back from vfs_listxattr, or,
4985 * XDR-encoded, in the return buffer, it's invalid.
4986 */
4987 if (cookie > (listxattrs->lsxa_len) / (XATTR_USER_PREFIX_LEN + 2))
4988 return nfserr_badcookie;
4989
4990 if (cookie > (listxattrs->lsxa_maxcount /
4991 (XDR_QUADLEN(XATTR_USER_PREFIX_LEN + 2) + 4)))
4992 return nfserr_badcookie;
4993
4994 *offsetp = (u32)cookie;
4995 return 0;
4996}
4997
4998static __be32
4999nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr,
5000 struct nfsd4_listxattrs *listxattrs)
5001{
5002 struct xdr_stream *xdr = &resp->xdr;
5003 u32 cookie_offset, count_offset, eof;
5004 u32 left, xdrleft, slen, count;
5005 u32 xdrlen, offset;
5006 u64 cookie;
5007 char *sp;
Chuck Leverb9a49232020-09-11 14:47:53 -04005008 __be32 status, tmp;
Frank van der Linden23e50fe2020-06-23 22:39:26 +00005009 __be32 *p;
5010 u32 nuser;
5011
5012 eof = 1;
5013
5014 status = nfsd4_listxattr_validate_cookie(listxattrs, &offset);
5015 if (status)
5016 goto out;
5017
5018 /*
5019 * Reserve space for the cookie and the name array count. Record
5020 * the offsets to save them later.
5021 */
5022 cookie_offset = xdr->buf->len;
5023 count_offset = cookie_offset + 8;
5024 p = xdr_reserve_space(xdr, 12);
5025 if (!p) {
5026 status = nfserr_resource;
5027 goto out;
5028 }
5029
5030 count = 0;
5031 left = listxattrs->lsxa_len;
5032 sp = listxattrs->lsxa_buf;
5033 nuser = 0;
5034
5035 xdrleft = listxattrs->lsxa_maxcount;
5036
5037 while (left > 0 && xdrleft > 0) {
5038 slen = strlen(sp);
5039
5040 /*
Alex Dewar4cce11fa2020-08-17 18:51:26 +01005041 * Check if this is a "user." attribute, skip it if not.
Frank van der Linden23e50fe2020-06-23 22:39:26 +00005042 */
5043 if (strncmp(sp, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
5044 goto contloop;
5045
5046 slen -= XATTR_USER_PREFIX_LEN;
5047 xdrlen = 4 + ((slen + 3) & ~3);
5048 if (xdrlen > xdrleft) {
5049 if (count == 0) {
5050 /*
5051 * Can't even fit the first attribute name.
5052 */
5053 status = nfserr_toosmall;
5054 goto out;
5055 }
5056 eof = 0;
5057 goto wreof;
5058 }
5059
5060 left -= XATTR_USER_PREFIX_LEN;
5061 sp += XATTR_USER_PREFIX_LEN;
5062 if (nuser++ < offset)
5063 goto contloop;
5064
5065
5066 p = xdr_reserve_space(xdr, xdrlen);
5067 if (!p) {
5068 status = nfserr_resource;
5069 goto out;
5070 }
5071
Alex Deware2a18402020-08-12 15:12:51 +01005072 xdr_encode_opaque(p, sp, slen);
Frank van der Linden23e50fe2020-06-23 22:39:26 +00005073
5074 xdrleft -= xdrlen;
5075 count++;
5076contloop:
5077 sp += slen + 1;
5078 left -= slen + 1;
5079 }
5080
5081 /*
5082 * If there were user attributes to copy, but we didn't copy
5083 * any, the offset was too large (e.g. the cookie was invalid).
5084 */
5085 if (nuser > 0 && count == 0) {
5086 status = nfserr_badcookie;
5087 goto out;
5088 }
5089
5090wreof:
5091 p = xdr_reserve_space(xdr, 4);
5092 if (!p) {
5093 status = nfserr_resource;
5094 goto out;
5095 }
5096 *p = cpu_to_be32(eof);
5097
5098 cookie = offset + count;
5099
5100 write_bytes_to_xdr_buf(xdr->buf, cookie_offset, &cookie, 8);
Chuck Leverb9a49232020-09-11 14:47:53 -04005101 tmp = cpu_to_be32(count);
5102 write_bytes_to_xdr_buf(xdr->buf, count_offset, &tmp, 4);
Frank van der Linden23e50fe2020-06-23 22:39:26 +00005103out:
5104 if (listxattrs->lsxa_len)
5105 kvfree(listxattrs->lsxa_buf);
5106 return status;
5107}
5108
5109static __be32
5110nfsd4_encode_removexattr(struct nfsd4_compoundres *resp, __be32 nfserr,
5111 struct nfsd4_removexattr *removexattr)
5112{
5113 struct xdr_stream *xdr = &resp->xdr;
5114 __be32 *p;
5115
5116 p = xdr_reserve_space(xdr, 20);
5117 if (!p)
5118 return nfserr_resource;
5119
5120 p = encode_cinfo(p, &removexattr->rmxa_cinfo);
5121 return 0;
5122}
5123
Benny Halevy695e12f2008-07-04 14:38:33 +03005124typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *);
5125
Andy Adamson2db134e2009-04-03 08:27:55 +03005126/*
5127 * Note: nfsd4_enc_ops vector is shared for v4.0 and v4.1
5128 * since we don't need to filter out obsolete ops as this is
5129 * done in the decoding phase.
5130 */
Chuck Leverc1df6092017-08-01 11:59:58 -04005131static const nfsd4_enc nfsd4_enc_ops[] = {
J. Bruce Fieldsad1060c2008-07-18 15:04:16 -04005132 [OP_ACCESS] = (nfsd4_enc)nfsd4_encode_access,
5133 [OP_CLOSE] = (nfsd4_enc)nfsd4_encode_close,
5134 [OP_COMMIT] = (nfsd4_enc)nfsd4_encode_commit,
5135 [OP_CREATE] = (nfsd4_enc)nfsd4_encode_create,
5136 [OP_DELEGPURGE] = (nfsd4_enc)nfsd4_encode_noop,
5137 [OP_DELEGRETURN] = (nfsd4_enc)nfsd4_encode_noop,
5138 [OP_GETATTR] = (nfsd4_enc)nfsd4_encode_getattr,
5139 [OP_GETFH] = (nfsd4_enc)nfsd4_encode_getfh,
5140 [OP_LINK] = (nfsd4_enc)nfsd4_encode_link,
5141 [OP_LOCK] = (nfsd4_enc)nfsd4_encode_lock,
5142 [OP_LOCKT] = (nfsd4_enc)nfsd4_encode_lockt,
5143 [OP_LOCKU] = (nfsd4_enc)nfsd4_encode_locku,
5144 [OP_LOOKUP] = (nfsd4_enc)nfsd4_encode_noop,
5145 [OP_LOOKUPP] = (nfsd4_enc)nfsd4_encode_noop,
5146 [OP_NVERIFY] = (nfsd4_enc)nfsd4_encode_noop,
5147 [OP_OPEN] = (nfsd4_enc)nfsd4_encode_open,
Benny Halevy84f09f42009-03-04 23:05:35 +02005148 [OP_OPENATTR] = (nfsd4_enc)nfsd4_encode_noop,
J. Bruce Fieldsad1060c2008-07-18 15:04:16 -04005149 [OP_OPEN_CONFIRM] = (nfsd4_enc)nfsd4_encode_open_confirm,
5150 [OP_OPEN_DOWNGRADE] = (nfsd4_enc)nfsd4_encode_open_downgrade,
5151 [OP_PUTFH] = (nfsd4_enc)nfsd4_encode_noop,
5152 [OP_PUTPUBFH] = (nfsd4_enc)nfsd4_encode_noop,
5153 [OP_PUTROOTFH] = (nfsd4_enc)nfsd4_encode_noop,
5154 [OP_READ] = (nfsd4_enc)nfsd4_encode_read,
5155 [OP_READDIR] = (nfsd4_enc)nfsd4_encode_readdir,
5156 [OP_READLINK] = (nfsd4_enc)nfsd4_encode_readlink,
5157 [OP_REMOVE] = (nfsd4_enc)nfsd4_encode_remove,
5158 [OP_RENAME] = (nfsd4_enc)nfsd4_encode_rename,
5159 [OP_RENEW] = (nfsd4_enc)nfsd4_encode_noop,
5160 [OP_RESTOREFH] = (nfsd4_enc)nfsd4_encode_noop,
5161 [OP_SAVEFH] = (nfsd4_enc)nfsd4_encode_noop,
5162 [OP_SECINFO] = (nfsd4_enc)nfsd4_encode_secinfo,
5163 [OP_SETATTR] = (nfsd4_enc)nfsd4_encode_setattr,
5164 [OP_SETCLIENTID] = (nfsd4_enc)nfsd4_encode_setclientid,
5165 [OP_SETCLIENTID_CONFIRM] = (nfsd4_enc)nfsd4_encode_noop,
5166 [OP_VERIFY] = (nfsd4_enc)nfsd4_encode_noop,
5167 [OP_WRITE] = (nfsd4_enc)nfsd4_encode_write,
5168 [OP_RELEASE_LOCKOWNER] = (nfsd4_enc)nfsd4_encode_noop,
Andy Adamson2db134e2009-04-03 08:27:55 +03005169
5170 /* NFSv4.1 operations */
5171 [OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop,
J. Bruce Fields1d1bc8f2010-10-04 23:12:59 -04005172 [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session,
Andy Adamson2db134e2009-04-03 08:27:55 +03005173 [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id,
5174 [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session,
Kinglong Mee43212cc2013-12-09 19:04:23 +08005175 [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_noop,
5176 [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_noop,
Andy Adamson2db134e2009-04-03 08:27:55 +03005177 [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop,
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02005178#ifdef CONFIG_NFSD_PNFS
5179 [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_getdeviceinfo,
5180 [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop,
5181 [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_layoutcommit,
5182 [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_layoutget,
5183 [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_layoutreturn,
5184#else
Andy Adamson2db134e2009-04-03 08:27:55 +03005185 [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop,
5186 [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop,
5187 [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop,
5188 [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop,
5189 [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop,
Christoph Hellwig9cf514c2014-05-05 13:11:59 +02005190#endif
Mi Jinlong22b6dee2010-12-27 14:29:57 +08005191 [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name,
Andy Adamson2db134e2009-04-03 08:27:55 +03005192 [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence,
5193 [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop,
Bryan Schumaker17456802011-07-13 10:50:48 -04005194 [OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_test_stateid,
Andy Adamson2db134e2009-04-03 08:27:55 +03005195 [OP_WANT_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop,
5196 [OP_DESTROY_CLIENTID] = (nfsd4_enc)nfsd4_encode_noop,
5197 [OP_RECLAIM_COMPLETE] = (nfsd4_enc)nfsd4_encode_noop,
Anna Schumaker87a15a82014-09-26 13:58:26 -04005198
5199 /* NFSv4.2 operations */
5200 [OP_ALLOCATE] = (nfsd4_enc)nfsd4_encode_noop,
Anna Schumaker29ae7f92016-09-07 15:57:30 -04005201 [OP_COPY] = (nfsd4_enc)nfsd4_encode_copy,
Olga Kornievskaia51911862019-08-08 11:14:59 -04005202 [OP_COPY_NOTIFY] = (nfsd4_enc)nfsd4_encode_copy_notify,
Anna Schumaker87a15a82014-09-26 13:58:26 -04005203 [OP_DEALLOCATE] = (nfsd4_enc)nfsd4_encode_noop,
5204 [OP_IO_ADVISE] = (nfsd4_enc)nfsd4_encode_noop,
5205 [OP_LAYOUTERROR] = (nfsd4_enc)nfsd4_encode_noop,
5206 [OP_LAYOUTSTATS] = (nfsd4_enc)nfsd4_encode_noop,
5207 [OP_OFFLOAD_CANCEL] = (nfsd4_enc)nfsd4_encode_noop,
Olga Kornievskaia6308bc92018-07-20 18:19:18 -04005208 [OP_OFFLOAD_STATUS] = (nfsd4_enc)nfsd4_encode_offload_status,
Anna Schumaker528b8492020-09-28 13:08:58 -04005209 [OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_read_plus,
Anna Schumaker24bab492014-09-26 13:58:27 -04005210 [OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek,
Anna Schumaker87a15a82014-09-26 13:58:26 -04005211 [OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop,
Christoph Hellwigffa01602015-12-03 12:59:52 +01005212 [OP_CLONE] = (nfsd4_enc)nfsd4_encode_noop,
Frank van der Linden23e50fe2020-06-23 22:39:26 +00005213
5214 /* RFC 8276 extended atributes operations */
5215 [OP_GETXATTR] = (nfsd4_enc)nfsd4_encode_getxattr,
5216 [OP_SETXATTR] = (nfsd4_enc)nfsd4_encode_setxattr,
5217 [OP_LISTXATTRS] = (nfsd4_enc)nfsd4_encode_listxattrs,
5218 [OP_REMOVEXATTR] = (nfsd4_enc)nfsd4_encode_removexattr,
Benny Halevy695e12f2008-07-04 14:38:33 +03005219};
5220
Andy Adamson496c2622009-04-03 08:28:48 +03005221/*
J. Bruce Fieldsa8095f72014-03-11 17:54:34 -04005222 * Calculate whether we still have space to encode repsize bytes.
5223 * There are two considerations:
5224 * - For NFS versions >=4.1, the size of the reply must stay within
5225 * session limits
5226 * - For all NFS versions, we must stay within limited preallocated
5227 * buffer space.
Andy Adamson496c2622009-04-03 08:28:48 +03005228 *
J. Bruce Fieldsa8095f72014-03-11 17:54:34 -04005229 * This is called before the operation is processed, so can only provide
5230 * an upper estimate. For some nonidempotent operations (such as
5231 * getattr), it's not necessarily a problem if that estimate is wrong,
5232 * as we can fail it after processing without significant side effects.
Andy Adamson496c2622009-04-03 08:28:48 +03005233 */
J. Bruce Fieldsa8095f72014-03-11 17:54:34 -04005234__be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 respsize)
Andy Adamson496c2622009-04-03 08:28:48 +03005235{
J. Bruce Fields67492c92014-03-08 16:42:05 -05005236 struct xdr_buf *buf = &resp->rqstp->rq_res;
J. Bruce Fields47ee5292014-03-12 21:39:35 -04005237 struct nfsd4_slot *slot = resp->cstate.slot;
Andy Adamson496c2622009-04-03 08:28:48 +03005238
J. Bruce Fields47ee5292014-03-12 21:39:35 -04005239 if (buf->len + respsize <= buf->buflen)
5240 return nfs_ok;
5241 if (!nfsd4_has_session(&resp->cstate))
J. Bruce Fieldsea8d7722014-03-08 17:19:55 -05005242 return nfserr_resource;
J. Bruce Fields47ee5292014-03-12 21:39:35 -04005243 if (slot->sl_flags & NFSD4_SLOT_CACHETHIS) {
5244 WARN_ON_ONCE(1);
5245 return nfserr_rep_too_big_to_cache;
J. Bruce Fieldsea8d7722014-03-08 17:19:55 -05005246 }
J. Bruce Fields47ee5292014-03-12 21:39:35 -04005247 return nfserr_rep_too_big;
Andy Adamson496c2622009-04-03 08:28:48 +03005248}
5249
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250void
5251nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
5252{
J. Bruce Fields082d4bd2013-08-29 15:42:52 -04005253 struct xdr_stream *xdr = &resp->xdr;
J. Bruce Fields9411b1d2013-04-01 16:37:12 -04005254 struct nfs4_stateowner *so = resp->cstate.replay_owner;
J. Bruce Fields5f4ab942014-03-07 11:01:37 -05005255 struct svc_rqst *rqstp = resp->rqstp;
J. Bruce Fields34b1744c2017-05-05 17:09:37 -04005256 const struct nfsd4_operation *opdesc = op->opdesc;
J. Bruce Fields082d4bd2013-08-29 15:42:52 -04005257 int post_err_offset;
J. Bruce Fields07d1f802014-03-06 20:39:29 -05005258 nfsd4_enc encoder;
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07005259 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005260
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05005261 p = xdr_reserve_space(xdr, 8);
5262 if (!p) {
5263 WARN_ON_ONCE(1);
5264 return;
5265 }
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04005266 *p++ = cpu_to_be32(op->opnum);
J. Bruce Fields082d4bd2013-08-29 15:42:52 -04005267 post_err_offset = xdr->buf->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005268
Benny Halevy695e12f2008-07-04 14:38:33 +03005269 if (op->opnum == OP_ILLEGAL)
5270 goto status;
J. Bruce Fieldsb7571e42017-05-06 10:49:21 -04005271 if (op->status && opdesc &&
5272 !(opdesc->op_flags & OP_NONTRIVIAL_ERROR_ENCODE))
5273 goto status;
Benny Halevy695e12f2008-07-04 14:38:33 +03005274 BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) ||
5275 !nfsd4_enc_ops[op->opnum]);
J. Bruce Fields07d1f802014-03-06 20:39:29 -05005276 encoder = nfsd4_enc_ops[op->opnum];
5277 op->status = encoder(resp, op->status, &op->u);
Chuck Lever08281342020-11-21 11:36:42 -05005278 if (op->status)
5279 trace_nfsd_compound_encode_err(rqstp, op->opnum, op->status);
J. Bruce Fields34b1744c2017-05-05 17:09:37 -04005280 if (opdesc && opdesc->op_release)
5281 opdesc->op_release(&op->u);
J. Bruce Fields2825a7f2013-08-26 16:04:46 -04005282 xdr_commit_encode(xdr);
5283
J. Bruce Fields067e1ac2014-03-21 17:26:44 -04005284 /* nfsd4_check_resp_size guarantees enough room for error status */
J. Bruce Fields5f4ab942014-03-07 11:01:37 -05005285 if (!op->status) {
5286 int space_needed = 0;
5287 if (!nfsd4_last_compound_op(rqstp))
5288 space_needed = COMPOUND_ERR_SLACK_SPACE;
5289 op->status = nfsd4_check_resp_size(resp, space_needed);
5290 }
J. Bruce Fieldsc8f13d92014-05-08 17:38:18 -04005291 if (op->status == nfserr_resource && nfsd4_has_session(&resp->cstate)) {
5292 struct nfsd4_slot *slot = resp->cstate.slot;
5293
5294 if (slot->sl_flags & NFSD4_SLOT_CACHETHIS)
5295 op->status = nfserr_rep_too_big_to_cache;
5296 else
5297 op->status = nfserr_rep_too_big;
5298 }
J. Bruce Fields07d1f802014-03-06 20:39:29 -05005299 if (op->status == nfserr_resource ||
5300 op->status == nfserr_rep_too_big ||
5301 op->status == nfserr_rep_too_big_to_cache) {
5302 /*
5303 * The operation may have already been encoded or
5304 * partially encoded. No op returns anything additional
5305 * in the case of one of these three errors, so we can
5306 * just truncate back to after the status. But it's a
5307 * bug if we had to do this on a non-idempotent op:
5308 */
5309 warn_on_nonidempotent_op(op);
J. Bruce Fields082d4bd2013-08-29 15:42:52 -04005310 xdr_truncate_encode(xdr, post_err_offset);
J. Bruce Fields07d1f802014-03-06 20:39:29 -05005311 }
J. Bruce Fields9411b1d2013-04-01 16:37:12 -04005312 if (so) {
J. Bruce Fields082d4bd2013-08-29 15:42:52 -04005313 int len = xdr->buf->len - post_err_offset;
5314
J. Bruce Fields9411b1d2013-04-01 16:37:12 -04005315 so->so_replay.rp_status = op->status;
J. Bruce Fields082d4bd2013-08-29 15:42:52 -04005316 so->so_replay.rp_buflen = len;
5317 read_bytes_from_xdr_buf(xdr->buf, post_err_offset,
5318 so->so_replay.rp_buf, len);
J. Bruce Fields9411b1d2013-04-01 16:37:12 -04005319 }
Benny Halevy695e12f2008-07-04 14:38:33 +03005320status:
J. Bruce Fields082d4bd2013-08-29 15:42:52 -04005321 /* Note that op->status is already in network byte order: */
5322 write_bytes_to_xdr_buf(xdr->buf, post_err_offset - 4, &op->status, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323}
5324
5325/*
5326 * Encode the reply stored in the stateowner reply cache
5327 *
5328 * XDR note: do not encode rp->rp_buflen: the buffer contains the
5329 * previously sent already encoded operation.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005330 */
5331void
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05005332nfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333{
J. Bruce Fieldsbc749ca2009-04-07 16:55:27 -07005334 __be32 *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335 struct nfs4_replay *rp = op->replay;
5336
J. Bruce Fieldsd0a381d2014-01-30 17:18:38 -05005337 p = xdr_reserve_space(xdr, 8 + rp->rp_buflen);
5338 if (!p) {
5339 WARN_ON_ONCE(1);
5340 return;
5341 }
J. Bruce Fieldsc373b0a2014-03-22 17:09:18 -04005342 *p++ = cpu_to_be32(op->opnum);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343 *p++ = rp->rp_status; /* already xdr'ed */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005344
J. Bruce Fields0c0c2672014-03-22 18:43:16 -04005345 p = xdr_encode_opaque_fixed(p, rp->rp_buf, rp->rp_buflen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005346}
5347
Christoph Hellwig85374882017-05-08 18:48:24 +02005348void nfsd4_release_compoundargs(struct svc_rqst *rqstp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005349{
J. Bruce Fields3e98abf2011-07-16 17:15:10 -04005350 struct nfsd4_compoundargs *args = rqstp->rq_argp;
5351
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352 if (args->ops != args->iops) {
5353 kfree(args->ops);
5354 args->ops = args->iops;
5355 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 while (args->to_free) {
J. Bruce Fieldsd5e23382014-06-24 17:43:45 -04005357 struct svcxdr_tmpbuf *tb = args->to_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005358 args->to_free = tb->next;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005359 kfree(tb);
5360 }
5361}
5362
5363int
Christoph Hellwig026fec72017-05-08 19:01:48 +02005364nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365{
Christoph Hellwig026fec72017-05-08 19:01:48 +02005366 struct nfsd4_compoundargs *args = rqstp->rq_argp;
5367
Chuck Leverc1346a122020-11-03 11:54:23 -05005368 /* svcxdr_tmp_alloc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 args->tmpp = NULL;
5370 args->to_free = NULL;
Chuck Leverc1346a122020-11-03 11:54:23 -05005371
5372 args->xdr = &rqstp->rq_arg_stream;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373 args->ops = args->iops;
5374 args->rqstp = rqstp;
5375
J. Bruce Fields3e98abf2011-07-16 17:15:10 -04005376 return !nfsd4_decode_compound(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377}
5378
5379int
Christoph Hellwig63f8de32017-05-08 19:42:02 +02005380nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005381{
Christoph Hellwig63f8de32017-05-08 19:42:02 +02005382 struct nfsd4_compoundres *resp = rqstp->rq_resp;
J. Bruce Fields6ac90392014-02-26 17:39:35 -05005383 struct xdr_buf *buf = resp->xdr.buf;
5384
5385 WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len +
5386 buf->tail[0].iov_len);
J. Bruce Fieldsdd97fdd2014-02-26 17:16:27 -05005387
Chuck Levercc028a12020-10-02 15:52:44 -04005388 *p = resp->cstate.status;
5389
J. Bruce Fields2825a7f2013-08-26 16:04:46 -04005390 rqstp->rq_next_page = resp->xdr.page_ptr + 1;
5391
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 p = resp->tagp;
5393 *p++ = htonl(resp->taglen);
5394 memcpy(p, resp->tag, resp->taglen);
5395 p += XDR_QUADLEN(resp->taglen);
5396 *p++ = htonl(resp->opcnt);
5397
Trond Myklebustb6076642014-06-30 11:48:35 -04005398 nfsd4_sequence_done(resp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 return 1;
5400}
5401
5402/*
5403 * Local variables:
5404 * c-basic-offset: 8
5405 * End:
5406 */