1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Process version 3 NFS requests.
4 *
5 * Copyright (C) 1996, 1997, 1998 Olaf Kirch <okir@monad.swb.de>
6 */
7
8 #include <linux/fs.h>
9 #include <linux/ext2_fs.h>
10 #include <linux/magic.h>
11 #include <linux/namei.h>
12
13 #include "cache.h"
14 #include "xdr3.h"
15 #include "vfs.h"
16 #include "filecache.h"
17 #include "trace.h"
18
19 #define NFSDDBG_FACILITY NFSDDBG_PROC
20
21 static int nfs3_ftypes[] = {
22 0, /* NF3NON */
23 S_IFREG, /* NF3REG */
24 S_IFDIR, /* NF3DIR */
25 S_IFBLK, /* NF3BLK */
26 S_IFCHR, /* NF3CHR */
27 S_IFLNK, /* NF3LNK */
28 S_IFSOCK, /* NF3SOCK */
29 S_IFIFO, /* NF3FIFO */
30 };
31
nfsd3_map_status(__be32 status)32 static __be32 nfsd3_map_status(__be32 status)
33 {
34 switch (status) {
35 case nfs_ok:
36 break;
37 case nfserr_nofilehandle:
38 status = nfserr_badhandle;
39 break;
40 case nfserr_wrongsec:
41 case nfserr_file_open:
42 status = nfserr_acces;
43 break;
44 case nfserr_symlink_not_dir:
45 status = nfserr_notdir;
46 break;
47 case nfserr_symlink:
48 case nfserr_wrong_type:
49 status = nfserr_inval;
50 break;
51 }
52 return status;
53 }
54
55 /*
56 * NULL call.
57 */
58 static __be32
nfsd3_proc_null(struct svc_rqst * rqstp)59 nfsd3_proc_null(struct svc_rqst *rqstp)
60 {
61 return rpc_success;
62 }
63
64 /*
65 * Get a file's attributes
66 */
67 static __be32
nfsd3_proc_getattr(struct svc_rqst * rqstp)68 nfsd3_proc_getattr(struct svc_rqst *rqstp)
69 {
70 struct nfsd_fhandle *argp = rqstp->rq_argp;
71 struct nfsd3_attrstat *resp = rqstp->rq_resp;
72
73 trace_nfsd_vfs_getattr(rqstp, &argp->fh);
74
75 fh_copy(&resp->fh, &argp->fh);
76 resp->status = fh_verify(rqstp, &resp->fh, 0,
77 NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
78 if (resp->status != nfs_ok)
79 goto out;
80
81 resp->status = fh_getattr(&resp->fh, &resp->stat);
82 out:
83 resp->status = nfsd3_map_status(resp->status);
84 return rpc_success;
85 }
86
87 /*
88 * Set a file's attributes
89 */
90 static __be32
nfsd3_proc_setattr(struct svc_rqst * rqstp)91 nfsd3_proc_setattr(struct svc_rqst *rqstp)
92 {
93 struct nfsd3_sattrargs *argp = rqstp->rq_argp;
94 struct nfsd3_attrstat *resp = rqstp->rq_resp;
95 struct nfsd_attrs attrs = {
96 .na_iattr = &argp->attrs,
97 };
98 const struct timespec64 *guardtime = NULL;
99
100 dprintk("nfsd: SETATTR(3) %s\n",
101 SVCFH_fmt(&argp->fh));
102
103 fh_copy(&resp->fh, &argp->fh);
104 if (argp->check_guard)
105 guardtime = &argp->guardtime;
106 resp->status = nfsd_setattr(rqstp, &resp->fh, &attrs, guardtime);
107 resp->status = nfsd3_map_status(resp->status);
108 return rpc_success;
109 }
110
111 /*
112 * Look up a path name component
113 */
114 static __be32
nfsd3_proc_lookup(struct svc_rqst * rqstp)115 nfsd3_proc_lookup(struct svc_rqst *rqstp)
116 {
117 struct nfsd3_diropargs *argp = rqstp->rq_argp;
118 struct nfsd3_diropres *resp = rqstp->rq_resp;
119
120 dprintk("nfsd: LOOKUP(3) %s %.*s\n",
121 SVCFH_fmt(&argp->fh),
122 argp->len,
123 argp->name);
124
125 fh_copy(&resp->dirfh, &argp->fh);
126 fh_init(&resp->fh, NFS3_FHSIZE);
127
128 resp->status = nfsd_lookup(rqstp, &resp->dirfh,
129 argp->name, argp->len,
130 &resp->fh);
131 resp->status = nfsd3_map_status(resp->status);
132 return rpc_success;
133 }
134
135 /*
136 * Check file access
137 */
138 static __be32
nfsd3_proc_access(struct svc_rqst * rqstp)139 nfsd3_proc_access(struct svc_rqst *rqstp)
140 {
141 struct nfsd3_accessargs *argp = rqstp->rq_argp;
142 struct nfsd3_accessres *resp = rqstp->rq_resp;
143
144 dprintk("nfsd: ACCESS(3) %s 0x%x\n",
145 SVCFH_fmt(&argp->fh),
146 argp->access);
147
148 fh_copy(&resp->fh, &argp->fh);
149 resp->access = argp->access;
150 resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
151 resp->status = nfsd3_map_status(resp->status);
152 return rpc_success;
153 }
154
155 /*
156 * Read a symlink.
157 */
158 static __be32
nfsd3_proc_readlink(struct svc_rqst * rqstp)159 nfsd3_proc_readlink(struct svc_rqst *rqstp)
160 {
161 struct nfsd_fhandle *argp = rqstp->rq_argp;
162 struct nfsd3_readlinkres *resp = rqstp->rq_resp;
163
164 dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
165
166 /* Read the symlink. */
167 fh_copy(&resp->fh, &argp->fh);
168 resp->len = NFS3_MAXPATHLEN;
169 resp->pages = rqstp->rq_next_page++;
170 resp->status = nfsd_readlink(rqstp, &resp->fh,
171 page_address(*resp->pages), &resp->len);
172 resp->status = nfsd3_map_status(resp->status);
173 return rpc_success;
174 }
175
176 /*
177 * Read a portion of a file.
178 */
179 static __be32
nfsd3_proc_read(struct svc_rqst * rqstp)180 nfsd3_proc_read(struct svc_rqst *rqstp)
181 {
182 struct nfsd3_readargs *argp = rqstp->rq_argp;
183 struct nfsd3_readres *resp = rqstp->rq_resp;
184
185 dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
186 SVCFH_fmt(&argp->fh),
187 (unsigned long) argp->count,
188 (unsigned long long) argp->offset);
189
190 argp->count = min_t(u32, argp->count, svc_max_payload(rqstp));
191 argp->count = min_t(u32, argp->count, rqstp->rq_res.buflen);
192 if (argp->offset > (u64)OFFSET_MAX)
193 argp->offset = (u64)OFFSET_MAX;
194 if (argp->offset + argp->count > (u64)OFFSET_MAX)
195 argp->count = (u64)OFFSET_MAX - argp->offset;
196
197 resp->pages = rqstp->rq_next_page;
198
199 /* Obtain buffer pointer for payload.
200 * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
201 * + 1 (xdr opaque byte count) = 26
202 */
203 resp->count = argp->count;
204 svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3) << 2) +
205 resp->count + 4);
206
207 fh_copy(&resp->fh, &argp->fh);
208 resp->status = nfsd_read(rqstp, &resp->fh, argp->offset,
209 &resp->count, &resp->eof);
210 resp->status = nfsd3_map_status(resp->status);
211 return rpc_success;
212 }
213
214 /*
215 * Write data to a file
216 */
217 static __be32
nfsd3_proc_write(struct svc_rqst * rqstp)218 nfsd3_proc_write(struct svc_rqst *rqstp)
219 {
220 struct nfsd3_writeargs *argp = rqstp->rq_argp;
221 struct nfsd3_writeres *resp = rqstp->rq_resp;
222 unsigned long cnt = argp->len;
223
224 dprintk("nfsd: WRITE(3) %s %d bytes at %Lu%s\n",
225 SVCFH_fmt(&argp->fh),
226 argp->len,
227 (unsigned long long) argp->offset,
228 argp->stable ? " stable" : "");
229
230 resp->status = nfserr_fbig;
231 if (argp->offset > (u64)OFFSET_MAX ||
232 argp->offset + argp->len > (u64)OFFSET_MAX)
233 return rpc_success;
234
235 fh_copy(&resp->fh, &argp->fh);
236 resp->committed = argp->stable;
237 resp->status = nfsd_write(rqstp, &resp->fh, argp->offset,
238 &argp->payload, &cnt,
239 resp->committed, resp->verf);
240 resp->count = cnt;
241 resp->status = nfsd3_map_status(resp->status);
242 return rpc_success;
243 }
244
245 /*
246 * Implement NFSv3's unchecked, guarded, and exclusive CREATE
247 * semantics for regular files. Except for the created file,
248 * this operation is stateless on the server.
249 *
250 * Upon return, caller must release @fhp and @resfhp.
251 */
252 static __be32
nfsd3_create_file(struct svc_rqst * rqstp,struct svc_fh * fhp,struct svc_fh * resfhp,struct nfsd3_createargs * argp)253 nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
254 struct svc_fh *resfhp, struct nfsd3_createargs *argp)
255 {
256 struct iattr *iap = &argp->attrs;
257 struct dentry *parent, *child;
258 struct nfsd_attrs attrs = {
259 .na_iattr = iap,
260 };
261 __u32 v_mtime, v_atime;
262 struct inode *inode;
263 __be32 status;
264 int host_err;
265
266 trace_nfsd_vfs_create(rqstp, fhp, S_IFREG, argp->name, argp->len);
267
268 if (isdotent(argp->name, argp->len))
269 return nfserr_exist;
270 if (!(iap->ia_valid & ATTR_MODE))
271 iap->ia_mode = 0;
272
273 status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
274 if (status != nfs_ok)
275 return status;
276
277 parent = fhp->fh_dentry;
278 inode = d_inode(parent);
279
280 host_err = fh_want_write(fhp);
281 if (host_err)
282 return nfserrno(host_err);
283
284 inode_lock_nested(inode, I_MUTEX_PARENT);
285
286 child = lookup_one(&nop_mnt_idmap,
287 &QSTR_LEN(argp->name, argp->len),
288 parent);
289 if (IS_ERR(child)) {
290 status = nfserrno(PTR_ERR(child));
291 goto out;
292 }
293
294 if (d_really_is_negative(child)) {
295 status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
296 if (status != nfs_ok)
297 goto out;
298 }
299
300 status = fh_compose(resfhp, fhp->fh_export, child, fhp);
301 if (status != nfs_ok)
302 goto out;
303
304 v_mtime = 0;
305 v_atime = 0;
306 if (argp->createmode == NFS3_CREATE_EXCLUSIVE) {
307 u32 *verifier = (u32 *)argp->verf;
308
309 /*
310 * Solaris 7 gets confused (bugid 4218508) if these have
311 * the high bit set, as do xfs filesystems without the
312 * "bigtime" feature. So just clear the high bits.
313 */
314 v_mtime = verifier[0] & 0x7fffffff;
315 v_atime = verifier[1] & 0x7fffffff;
316 }
317
318 if (d_really_is_positive(child)) {
319 status = nfs_ok;
320
321 switch (argp->createmode) {
322 case NFS3_CREATE_UNCHECKED:
323 if (!d_is_reg(child))
324 break;
325 iap->ia_valid &= ATTR_SIZE;
326 goto set_attr;
327 case NFS3_CREATE_GUARDED:
328 status = nfserr_exist;
329 break;
330 case NFS3_CREATE_EXCLUSIVE:
331 if (inode_get_mtime_sec(d_inode(child)) == v_mtime &&
332 inode_get_atime_sec(d_inode(child)) == v_atime &&
333 d_inode(child)->i_size == 0) {
334 break;
335 }
336 status = nfserr_exist;
337 }
338 goto out;
339 }
340
341 if (!IS_POSIXACL(inode))
342 iap->ia_mode &= ~current_umask();
343
344 status = fh_fill_pre_attrs(fhp);
345 if (status != nfs_ok)
346 goto out;
347 host_err = vfs_create(&nop_mnt_idmap, inode, child, iap->ia_mode, true);
348 if (host_err < 0) {
349 status = nfserrno(host_err);
350 goto out;
351 }
352 fh_fill_post_attrs(fhp);
353
354 /* A newly created file already has a file size of zero. */
355 if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0))
356 iap->ia_valid &= ~ATTR_SIZE;
357 if (argp->createmode == NFS3_CREATE_EXCLUSIVE) {
358 iap->ia_valid = ATTR_MTIME | ATTR_ATIME |
359 ATTR_MTIME_SET | ATTR_ATIME_SET;
360 iap->ia_mtime.tv_sec = v_mtime;
361 iap->ia_atime.tv_sec = v_atime;
362 iap->ia_mtime.tv_nsec = 0;
363 iap->ia_atime.tv_nsec = 0;
364 }
365
366 set_attr:
367 status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs);
368
369 out:
370 inode_unlock(inode);
371 if (child && !IS_ERR(child))
372 dput(child);
373 fh_drop_write(fhp);
374 return status;
375 }
376
377 static __be32
nfsd3_proc_create(struct svc_rqst * rqstp)378 nfsd3_proc_create(struct svc_rqst *rqstp)
379 {
380 struct nfsd3_createargs *argp = rqstp->rq_argp;
381 struct nfsd3_diropres *resp = rqstp->rq_resp;
382 svc_fh *dirfhp, *newfhp;
383
384 dirfhp = fh_copy(&resp->dirfh, &argp->fh);
385 newfhp = fh_init(&resp->fh, NFS3_FHSIZE);
386
387 resp->status = nfsd3_create_file(rqstp, dirfhp, newfhp, argp);
388 resp->status = nfsd3_map_status(resp->status);
389 return rpc_success;
390 }
391
392 /*
393 * Make directory. This operation is not idempotent.
394 */
395 static __be32
nfsd3_proc_mkdir(struct svc_rqst * rqstp)396 nfsd3_proc_mkdir(struct svc_rqst *rqstp)
397 {
398 struct nfsd3_createargs *argp = rqstp->rq_argp;
399 struct nfsd3_diropres *resp = rqstp->rq_resp;
400 struct nfsd_attrs attrs = {
401 .na_iattr = &argp->attrs,
402 };
403
404 argp->attrs.ia_valid &= ~ATTR_SIZE;
405 fh_copy(&resp->dirfh, &argp->fh);
406 fh_init(&resp->fh, NFS3_FHSIZE);
407 resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
408 &attrs, S_IFDIR, 0, &resp->fh);
409 resp->status = nfsd3_map_status(resp->status);
410 return rpc_success;
411 }
412
413 static __be32
nfsd3_proc_symlink(struct svc_rqst * rqstp)414 nfsd3_proc_symlink(struct svc_rqst *rqstp)
415 {
416 struct nfsd3_symlinkargs *argp = rqstp->rq_argp;
417 struct nfsd3_diropres *resp = rqstp->rq_resp;
418 struct nfsd_attrs attrs = {
419 .na_iattr = &argp->attrs,
420 };
421
422 if (argp->tlen == 0) {
423 resp->status = nfserr_inval;
424 goto out;
425 }
426 if (argp->tlen > NFS3_MAXPATHLEN) {
427 resp->status = nfserr_nametoolong;
428 goto out;
429 }
430
431 argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first,
432 page_address(rqstp->rq_arg.pages[0]),
433 argp->tlen);
434 if (IS_ERR(argp->tname)) {
435 resp->status = nfserrno(PTR_ERR(argp->tname));
436 goto out;
437 }
438
439 fh_copy(&resp->dirfh, &argp->ffh);
440 fh_init(&resp->fh, NFS3_FHSIZE);
441 resp->status = nfsd_symlink(rqstp, &resp->dirfh, argp->fname,
442 argp->flen, argp->tname, &attrs, &resp->fh);
443 kfree(argp->tname);
444 out:
445 resp->status = nfsd3_map_status(resp->status);
446 return rpc_success;
447 }
448
449 /*
450 * Make socket/fifo/device.
451 */
452 static __be32
nfsd3_proc_mknod(struct svc_rqst * rqstp)453 nfsd3_proc_mknod(struct svc_rqst *rqstp)
454 {
455 struct nfsd3_mknodargs *argp = rqstp->rq_argp;
456 struct nfsd3_diropres *resp = rqstp->rq_resp;
457 struct nfsd_attrs attrs = {
458 .na_iattr = &argp->attrs,
459 };
460 int type;
461 dev_t rdev = 0;
462
463 fh_copy(&resp->dirfh, &argp->fh);
464 fh_init(&resp->fh, NFS3_FHSIZE);
465
466 if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) {
467 rdev = MKDEV(argp->major, argp->minor);
468 if (MAJOR(rdev) != argp->major ||
469 MINOR(rdev) != argp->minor) {
470 resp->status = nfserr_inval;
471 goto out;
472 }
473 } else if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO) {
474 resp->status = nfserr_badtype;
475 goto out;
476 }
477
478 type = nfs3_ftypes[argp->ftype];
479 resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
480 &attrs, type, rdev, &resp->fh);
481 out:
482 resp->status = nfsd3_map_status(resp->status);
483 return rpc_success;
484 }
485
486 /*
487 * Remove file/fifo/socket etc.
488 */
489 static __be32
nfsd3_proc_remove(struct svc_rqst * rqstp)490 nfsd3_proc_remove(struct svc_rqst *rqstp)
491 {
492 struct nfsd3_diropargs *argp = rqstp->rq_argp;
493 struct nfsd3_attrstat *resp = rqstp->rq_resp;
494
495 /* Unlink. -S_IFDIR means file must not be a directory */
496 fh_copy(&resp->fh, &argp->fh);
497 resp->status = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR,
498 argp->name, argp->len);
499 resp->status = nfsd3_map_status(resp->status);
500 return rpc_success;
501 }
502
503 /*
504 * Remove a directory
505 */
506 static __be32
nfsd3_proc_rmdir(struct svc_rqst * rqstp)507 nfsd3_proc_rmdir(struct svc_rqst *rqstp)
508 {
509 struct nfsd3_diropargs *argp = rqstp->rq_argp;
510 struct nfsd3_attrstat *resp = rqstp->rq_resp;
511
512 fh_copy(&resp->fh, &argp->fh);
513 resp->status = nfsd_unlink(rqstp, &resp->fh, S_IFDIR,
514 argp->name, argp->len);
515 resp->status = nfsd3_map_status(resp->status);
516 return rpc_success;
517 }
518
519 static __be32
nfsd3_proc_rename(struct svc_rqst * rqstp)520 nfsd3_proc_rename(struct svc_rqst *rqstp)
521 {
522 struct nfsd3_renameargs *argp = rqstp->rq_argp;
523 struct nfsd3_renameres *resp = rqstp->rq_resp;
524
525 fh_copy(&resp->ffh, &argp->ffh);
526 fh_copy(&resp->tfh, &argp->tfh);
527 resp->status = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
528 &resp->tfh, argp->tname, argp->tlen);
529 resp->status = nfsd3_map_status(resp->status);
530 return rpc_success;
531 }
532
533 static __be32
nfsd3_proc_link(struct svc_rqst * rqstp)534 nfsd3_proc_link(struct svc_rqst *rqstp)
535 {
536 struct nfsd3_linkargs *argp = rqstp->rq_argp;
537 struct nfsd3_linkres *resp = rqstp->rq_resp;
538
539 fh_copy(&resp->fh, &argp->ffh);
540 fh_copy(&resp->tfh, &argp->tfh);
541 resp->status = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
542 &resp->fh);
543 resp->status = nfsd3_map_status(resp->status);
544 return rpc_success;
545 }
546
nfsd3_init_dirlist_pages(struct svc_rqst * rqstp,struct nfsd3_readdirres * resp,u32 count)547 static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp,
548 struct nfsd3_readdirres *resp,
549 u32 count)
550 {
551 struct xdr_buf *buf = &resp->dirlist;
552 struct xdr_stream *xdr = &resp->xdr;
553 unsigned int sendbuf = min_t(unsigned int, rqstp->rq_res.buflen,
554 svc_max_payload(rqstp));
555
556 memset(buf, 0, sizeof(*buf));
557
558 /* Reserve room for the NULL ptr & eof flag (-2 words) */
559 buf->buflen = clamp(count, (u32)(XDR_UNIT * 2), sendbuf);
560 buf->buflen -= XDR_UNIT * 2;
561 buf->pages = rqstp->rq_next_page;
562 rqstp->rq_next_page += (buf->buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
563
564 xdr_init_encode_pages(xdr, buf);
565 }
566
567 /*
568 * Read a portion of a directory.
569 */
570 static __be32
nfsd3_proc_readdir(struct svc_rqst * rqstp)571 nfsd3_proc_readdir(struct svc_rqst *rqstp)
572 {
573 struct nfsd3_readdirargs *argp = rqstp->rq_argp;
574 struct nfsd3_readdirres *resp = rqstp->rq_resp;
575 loff_t offset;
576
577 trace_nfsd_vfs_readdir(rqstp, &argp->fh, argp->count, argp->cookie);
578
579 nfsd3_init_dirlist_pages(rqstp, resp, argp->count);
580
581 fh_copy(&resp->fh, &argp->fh);
582 resp->common.err = nfs_ok;
583 resp->cookie_offset = 0;
584 resp->rqstp = rqstp;
585 offset = argp->cookie;
586 resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
587 &resp->common, nfs3svc_encode_entry3);
588 memcpy(resp->verf, argp->verf, 8);
589 nfs3svc_encode_cookie3(resp, offset);
590
591 /* Recycle only pages that were part of the reply */
592 rqstp->rq_next_page = resp->xdr.page_ptr + 1;
593
594 resp->status = nfsd3_map_status(resp->status);
595 return rpc_success;
596 }
597
598 /*
599 * Read a portion of a directory, including file handles and attrs.
600 * For now, we choose to ignore the dircount parameter.
601 */
602 static __be32
nfsd3_proc_readdirplus(struct svc_rqst * rqstp)603 nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
604 {
605 struct nfsd3_readdirargs *argp = rqstp->rq_argp;
606 struct nfsd3_readdirres *resp = rqstp->rq_resp;
607 loff_t offset;
608
609 trace_nfsd_vfs_readdir(rqstp, &argp->fh, argp->count, argp->cookie);
610
611 nfsd3_init_dirlist_pages(rqstp, resp, argp->count);
612
613 fh_copy(&resp->fh, &argp->fh);
614 resp->common.err = nfs_ok;
615 resp->cookie_offset = 0;
616 resp->rqstp = rqstp;
617 offset = argp->cookie;
618
619 resp->status = fh_verify(rqstp, &resp->fh, S_IFDIR, NFSD_MAY_NOP);
620 if (resp->status != nfs_ok)
621 goto out;
622
623 if (resp->fh.fh_export->ex_flags & NFSEXP_NOREADDIRPLUS) {
624 resp->status = nfserr_notsupp;
625 goto out;
626 }
627
628 resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
629 &resp->common, nfs3svc_encode_entryplus3);
630 memcpy(resp->verf, argp->verf, 8);
631 nfs3svc_encode_cookie3(resp, offset);
632
633 /* Recycle only pages that were part of the reply */
634 rqstp->rq_next_page = resp->xdr.page_ptr + 1;
635
636 out:
637 resp->status = nfsd3_map_status(resp->status);
638 return rpc_success;
639 }
640
641 /*
642 * Get file system stats
643 */
644 static __be32
nfsd3_proc_fsstat(struct svc_rqst * rqstp)645 nfsd3_proc_fsstat(struct svc_rqst *rqstp)
646 {
647 struct nfsd_fhandle *argp = rqstp->rq_argp;
648 struct nfsd3_fsstatres *resp = rqstp->rq_resp;
649
650 resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
651 fh_put(&argp->fh);
652 resp->status = nfsd3_map_status(resp->status);
653 return rpc_success;
654 }
655
656 /*
657 * Get file system info
658 */
659 static __be32
nfsd3_proc_fsinfo(struct svc_rqst * rqstp)660 nfsd3_proc_fsinfo(struct svc_rqst *rqstp)
661 {
662 struct nfsd_fhandle *argp = rqstp->rq_argp;
663 struct nfsd3_fsinfores *resp = rqstp->rq_resp;
664 u32 max_blocksize = svc_max_payload(rqstp);
665
666 dprintk("nfsd: FSINFO(3) %s\n",
667 SVCFH_fmt(&argp->fh));
668
669 resp->f_rtmax = max_blocksize;
670 resp->f_rtpref = max_blocksize;
671 resp->f_rtmult = PAGE_SIZE;
672 resp->f_wtmax = max_blocksize;
673 resp->f_wtpref = max_blocksize;
674 resp->f_wtmult = PAGE_SIZE;
675 resp->f_dtpref = max_blocksize;
676 resp->f_maxfilesize = ~(u32) 0;
677 resp->f_properties = NFS3_FSF_DEFAULT;
678
679 resp->status = fh_verify(rqstp, &argp->fh, 0,
680 NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
681
682 /* Check special features of the file system. May request
683 * different read/write sizes for file systems known to have
684 * problems with large blocks */
685 if (resp->status == nfs_ok) {
686 struct super_block *sb = argp->fh.fh_dentry->d_sb;
687
688 /* Note that we don't care for remote fs's here */
689 if (sb->s_magic == MSDOS_SUPER_MAGIC) {
690 resp->f_properties = NFS3_FSF_BILLYBOY;
691 }
692 resp->f_maxfilesize = sb->s_maxbytes;
693 }
694
695 fh_put(&argp->fh);
696 resp->status = nfsd3_map_status(resp->status);
697 return rpc_success;
698 }
699
700 /*
701 * Get pathconf info for the specified file
702 */
703 static __be32
nfsd3_proc_pathconf(struct svc_rqst * rqstp)704 nfsd3_proc_pathconf(struct svc_rqst *rqstp)
705 {
706 struct nfsd_fhandle *argp = rqstp->rq_argp;
707 struct nfsd3_pathconfres *resp = rqstp->rq_resp;
708
709 dprintk("nfsd: PATHCONF(3) %s\n",
710 SVCFH_fmt(&argp->fh));
711
712 /* Set default pathconf */
713 resp->p_link_max = 255; /* at least */
714 resp->p_name_max = 255; /* at least */
715 resp->p_no_trunc = 0;
716 resp->p_chown_restricted = 1;
717 resp->p_case_insensitive = 0;
718 resp->p_case_preserving = 1;
719
720 resp->status = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
721
722 if (resp->status == nfs_ok) {
723 struct super_block *sb = argp->fh.fh_dentry->d_sb;
724
725 /* Note that we don't care for remote fs's here */
726 switch (sb->s_magic) {
727 case EXT2_SUPER_MAGIC:
728 resp->p_link_max = EXT2_LINK_MAX;
729 resp->p_name_max = EXT2_NAME_LEN;
730 break;
731 case MSDOS_SUPER_MAGIC:
732 resp->p_case_insensitive = 1;
733 resp->p_case_preserving = 0;
734 break;
735 }
736 }
737
738 fh_put(&argp->fh);
739 resp->status = nfsd3_map_status(resp->status);
740 return rpc_success;
741 }
742
743 /*
744 * Commit a file (range) to stable storage.
745 */
746 static __be32
nfsd3_proc_commit(struct svc_rqst * rqstp)747 nfsd3_proc_commit(struct svc_rqst *rqstp)
748 {
749 struct nfsd3_commitargs *argp = rqstp->rq_argp;
750 struct nfsd3_commitres *resp = rqstp->rq_resp;
751 struct nfsd_file *nf;
752
753 dprintk("nfsd: COMMIT(3) %s %u@%Lu\n",
754 SVCFH_fmt(&argp->fh),
755 argp->count,
756 (unsigned long long) argp->offset);
757
758 fh_copy(&resp->fh, &argp->fh);
759 resp->status = nfsd_file_acquire_gc(rqstp, &resp->fh, NFSD_MAY_WRITE |
760 NFSD_MAY_NOT_BREAK_LEASE, &nf);
761 if (resp->status)
762 goto out;
763 resp->status = nfsd_commit(rqstp, &resp->fh, nf, argp->offset,
764 argp->count, resp->verf);
765 nfsd_file_put(nf);
766 out:
767 resp->status = nfsd3_map_status(resp->status);
768 return rpc_success;
769 }
770
771
772 /*
773 * NFSv3 Server procedures.
774 * Only the results of non-idempotent operations are cached.
775 */
776 #define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat
777 #define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat
778 #define nfsd3_mkdirargs nfsd3_createargs
779 #define nfsd3_readdirplusargs nfsd3_readdirargs
780 #define nfsd3_fhandleargs nfsd_fhandle
781 #define nfsd3_attrstatres nfsd3_attrstat
782 #define nfsd3_wccstatres nfsd3_attrstat
783 #define nfsd3_createres nfsd3_diropres
784
785 #define ST 1 /* status*/
786 #define FH 17 /* filehandle with length */
787 #define AT 21 /* attributes */
788 #define pAT (1+AT) /* post attributes - conditional */
789 #define WC (7+pAT) /* WCC attributes */
790
791 static const struct svc_procedure nfsd_procedures3[22] = {
792 [NFS3PROC_NULL] = {
793 .pc_func = nfsd3_proc_null,
794 .pc_decode = nfssvc_decode_voidarg,
795 .pc_encode = nfssvc_encode_voidres,
796 .pc_argsize = sizeof(struct nfsd_voidargs),
797 .pc_argzero = sizeof(struct nfsd_voidargs),
798 .pc_ressize = sizeof(struct nfsd_voidres),
799 .pc_cachetype = RC_NOCACHE,
800 .pc_xdrressize = ST,
801 .pc_name = "NULL",
802 },
803 [NFS3PROC_GETATTR] = {
804 .pc_func = nfsd3_proc_getattr,
805 .pc_decode = nfs3svc_decode_fhandleargs,
806 .pc_encode = nfs3svc_encode_getattrres,
807 .pc_release = nfs3svc_release_fhandle,
808 .pc_argsize = sizeof(struct nfsd_fhandle),
809 .pc_argzero = sizeof(struct nfsd_fhandle),
810 .pc_ressize = sizeof(struct nfsd3_attrstatres),
811 .pc_cachetype = RC_NOCACHE,
812 .pc_xdrressize = ST+AT,
813 .pc_name = "GETATTR",
814 },
815 [NFS3PROC_SETATTR] = {
816 .pc_func = nfsd3_proc_setattr,
817 .pc_decode = nfs3svc_decode_sattrargs,
818 .pc_encode = nfs3svc_encode_wccstatres,
819 .pc_release = nfs3svc_release_fhandle,
820 .pc_argsize = sizeof(struct nfsd3_sattrargs),
821 .pc_argzero = sizeof(struct nfsd3_sattrargs),
822 .pc_ressize = sizeof(struct nfsd3_wccstatres),
823 .pc_cachetype = RC_REPLBUFF,
824 .pc_xdrressize = ST+WC,
825 .pc_name = "SETATTR",
826 },
827 [NFS3PROC_LOOKUP] = {
828 .pc_func = nfsd3_proc_lookup,
829 .pc_decode = nfs3svc_decode_diropargs,
830 .pc_encode = nfs3svc_encode_lookupres,
831 .pc_release = nfs3svc_release_fhandle2,
832 .pc_argsize = sizeof(struct nfsd3_diropargs),
833 .pc_argzero = sizeof(struct nfsd3_diropargs),
834 .pc_ressize = sizeof(struct nfsd3_diropres),
835 .pc_cachetype = RC_NOCACHE,
836 .pc_xdrressize = ST+FH+pAT+pAT,
837 .pc_name = "LOOKUP",
838 },
839 [NFS3PROC_ACCESS] = {
840 .pc_func = nfsd3_proc_access,
841 .pc_decode = nfs3svc_decode_accessargs,
842 .pc_encode = nfs3svc_encode_accessres,
843 .pc_release = nfs3svc_release_fhandle,
844 .pc_argsize = sizeof(struct nfsd3_accessargs),
845 .pc_argzero = sizeof(struct nfsd3_accessargs),
846 .pc_ressize = sizeof(struct nfsd3_accessres),
847 .pc_cachetype = RC_NOCACHE,
848 .pc_xdrressize = ST+pAT+1,
849 .pc_name = "ACCESS",
850 },
851 [NFS3PROC_READLINK] = {
852 .pc_func = nfsd3_proc_readlink,
853 .pc_decode = nfs3svc_decode_fhandleargs,
854 .pc_encode = nfs3svc_encode_readlinkres,
855 .pc_release = nfs3svc_release_fhandle,
856 .pc_argsize = sizeof(struct nfsd_fhandle),
857 .pc_argzero = sizeof(struct nfsd_fhandle),
858 .pc_ressize = sizeof(struct nfsd3_readlinkres),
859 .pc_cachetype = RC_NOCACHE,
860 .pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4,
861 .pc_name = "READLINK",
862 },
863 [NFS3PROC_READ] = {
864 .pc_func = nfsd3_proc_read,
865 .pc_decode = nfs3svc_decode_readargs,
866 .pc_encode = nfs3svc_encode_readres,
867 .pc_release = nfs3svc_release_fhandle,
868 .pc_argsize = sizeof(struct nfsd3_readargs),
869 .pc_argzero = sizeof(struct nfsd3_readargs),
870 .pc_ressize = sizeof(struct nfsd3_readres),
871 .pc_cachetype = RC_NOCACHE,
872 .pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4,
873 .pc_name = "READ",
874 },
875 [NFS3PROC_WRITE] = {
876 .pc_func = nfsd3_proc_write,
877 .pc_decode = nfs3svc_decode_writeargs,
878 .pc_encode = nfs3svc_encode_writeres,
879 .pc_release = nfs3svc_release_fhandle,
880 .pc_argsize = sizeof(struct nfsd3_writeargs),
881 .pc_argzero = sizeof(struct nfsd3_writeargs),
882 .pc_ressize = sizeof(struct nfsd3_writeres),
883 .pc_cachetype = RC_REPLBUFF,
884 .pc_xdrressize = ST+WC+4,
885 .pc_name = "WRITE",
886 },
887 [NFS3PROC_CREATE] = {
888 .pc_func = nfsd3_proc_create,
889 .pc_decode = nfs3svc_decode_createargs,
890 .pc_encode = nfs3svc_encode_createres,
891 .pc_release = nfs3svc_release_fhandle2,
892 .pc_argsize = sizeof(struct nfsd3_createargs),
893 .pc_argzero = sizeof(struct nfsd3_createargs),
894 .pc_ressize = sizeof(struct nfsd3_createres),
895 .pc_cachetype = RC_REPLBUFF,
896 .pc_xdrressize = ST+(1+FH+pAT)+WC,
897 .pc_name = "CREATE",
898 },
899 [NFS3PROC_MKDIR] = {
900 .pc_func = nfsd3_proc_mkdir,
901 .pc_decode = nfs3svc_decode_mkdirargs,
902 .pc_encode = nfs3svc_encode_createres,
903 .pc_release = nfs3svc_release_fhandle2,
904 .pc_argsize = sizeof(struct nfsd3_mkdirargs),
905 .pc_argzero = sizeof(struct nfsd3_mkdirargs),
906 .pc_ressize = sizeof(struct nfsd3_createres),
907 .pc_cachetype = RC_REPLBUFF,
908 .pc_xdrressize = ST+(1+FH+pAT)+WC,
909 .pc_name = "MKDIR",
910 },
911 [NFS3PROC_SYMLINK] = {
912 .pc_func = nfsd3_proc_symlink,
913 .pc_decode = nfs3svc_decode_symlinkargs,
914 .pc_encode = nfs3svc_encode_createres,
915 .pc_release = nfs3svc_release_fhandle2,
916 .pc_argsize = sizeof(struct nfsd3_symlinkargs),
917 .pc_argzero = sizeof(struct nfsd3_symlinkargs),
918 .pc_ressize = sizeof(struct nfsd3_createres),
919 .pc_cachetype = RC_REPLBUFF,
920 .pc_xdrressize = ST+(1+FH+pAT)+WC,
921 .pc_name = "SYMLINK",
922 },
923 [NFS3PROC_MKNOD] = {
924 .pc_func = nfsd3_proc_mknod,
925 .pc_decode = nfs3svc_decode_mknodargs,
926 .pc_encode = nfs3svc_encode_createres,
927 .pc_release = nfs3svc_release_fhandle2,
928 .pc_argsize = sizeof(struct nfsd3_mknodargs),
929 .pc_argzero = sizeof(struct nfsd3_mknodargs),
930 .pc_ressize = sizeof(struct nfsd3_createres),
931 .pc_cachetype = RC_REPLBUFF,
932 .pc_xdrressize = ST+(1+FH+pAT)+WC,
933 .pc_name = "MKNOD",
934 },
935 [NFS3PROC_REMOVE] = {
936 .pc_func = nfsd3_proc_remove,
937 .pc_decode = nfs3svc_decode_diropargs,
938 .pc_encode = nfs3svc_encode_wccstatres,
939 .pc_release = nfs3svc_release_fhandle,
940 .pc_argsize = sizeof(struct nfsd3_diropargs),
941 .pc_argzero = sizeof(struct nfsd3_diropargs),
942 .pc_ressize = sizeof(struct nfsd3_wccstatres),
943 .pc_cachetype = RC_REPLBUFF,
944 .pc_xdrressize = ST+WC,
945 .pc_name = "REMOVE",
946 },
947 [NFS3PROC_RMDIR] = {
948 .pc_func = nfsd3_proc_rmdir,
949 .pc_decode = nfs3svc_decode_diropargs,
950 .pc_encode = nfs3svc_encode_wccstatres,
951 .pc_release = nfs3svc_release_fhandle,
952 .pc_argsize = sizeof(struct nfsd3_diropargs),
953 .pc_argzero = sizeof(struct nfsd3_diropargs),
954 .pc_ressize = sizeof(struct nfsd3_wccstatres),
955 .pc_cachetype = RC_REPLBUFF,
956 .pc_xdrressize = ST+WC,
957 .pc_name = "RMDIR",
958 },
959 [NFS3PROC_RENAME] = {
960 .pc_func = nfsd3_proc_rename,
961 .pc_decode = nfs3svc_decode_renameargs,
962 .pc_encode = nfs3svc_encode_renameres,
963 .pc_release = nfs3svc_release_fhandle2,
964 .pc_argsize = sizeof(struct nfsd3_renameargs),
965 .pc_argzero = sizeof(struct nfsd3_renameargs),
966 .pc_ressize = sizeof(struct nfsd3_renameres),
967 .pc_cachetype = RC_REPLBUFF,
968 .pc_xdrressize = ST+WC+WC,
969 .pc_name = "RENAME",
970 },
971 [NFS3PROC_LINK] = {
972 .pc_func = nfsd3_proc_link,
973 .pc_decode = nfs3svc_decode_linkargs,
974 .pc_encode = nfs3svc_encode_linkres,
975 .pc_release = nfs3svc_release_fhandle2,
976 .pc_argsize = sizeof(struct nfsd3_linkargs),
977 .pc_argzero = sizeof(struct nfsd3_linkargs),
978 .pc_ressize = sizeof(struct nfsd3_linkres),
979 .pc_cachetype = RC_REPLBUFF,
980 .pc_xdrressize = ST+pAT+WC,
981 .pc_name = "LINK",
982 },
983 [NFS3PROC_READDIR] = {
984 .pc_func = nfsd3_proc_readdir,
985 .pc_decode = nfs3svc_decode_readdirargs,
986 .pc_encode = nfs3svc_encode_readdirres,
987 .pc_release = nfs3svc_release_fhandle,
988 .pc_argsize = sizeof(struct nfsd3_readdirargs),
989 .pc_argzero = sizeof(struct nfsd3_readdirargs),
990 .pc_ressize = sizeof(struct nfsd3_readdirres),
991 .pc_cachetype = RC_NOCACHE,
992 .pc_name = "READDIR",
993 },
994 [NFS3PROC_READDIRPLUS] = {
995 .pc_func = nfsd3_proc_readdirplus,
996 .pc_decode = nfs3svc_decode_readdirplusargs,
997 .pc_encode = nfs3svc_encode_readdirres,
998 .pc_release = nfs3svc_release_fhandle,
999 .pc_argsize = sizeof(struct nfsd3_readdirplusargs),
1000 .pc_argzero = sizeof(struct nfsd3_readdirplusargs),
1001 .pc_ressize = sizeof(struct nfsd3_readdirres),
1002 .pc_cachetype = RC_NOCACHE,
1003 .pc_name = "READDIRPLUS",
1004 },
1005 [NFS3PROC_FSSTAT] = {
1006 .pc_func = nfsd3_proc_fsstat,
1007 .pc_decode = nfs3svc_decode_fhandleargs,
1008 .pc_encode = nfs3svc_encode_fsstatres,
1009 .pc_argsize = sizeof(struct nfsd3_fhandleargs),
1010 .pc_argzero = sizeof(struct nfsd3_fhandleargs),
1011 .pc_ressize = sizeof(struct nfsd3_fsstatres),
1012 .pc_cachetype = RC_NOCACHE,
1013 .pc_xdrressize = ST+pAT+2*6+1,
1014 .pc_name = "FSSTAT",
1015 },
1016 [NFS3PROC_FSINFO] = {
1017 .pc_func = nfsd3_proc_fsinfo,
1018 .pc_decode = nfs3svc_decode_fhandleargs,
1019 .pc_encode = nfs3svc_encode_fsinfores,
1020 .pc_argsize = sizeof(struct nfsd3_fhandleargs),
1021 .pc_argzero = sizeof(struct nfsd3_fhandleargs),
1022 .pc_ressize = sizeof(struct nfsd3_fsinfores),
1023 .pc_cachetype = RC_NOCACHE,
1024 .pc_xdrressize = ST+pAT+12,
1025 .pc_name = "FSINFO",
1026 },
1027 [NFS3PROC_PATHCONF] = {
1028 .pc_func = nfsd3_proc_pathconf,
1029 .pc_decode = nfs3svc_decode_fhandleargs,
1030 .pc_encode = nfs3svc_encode_pathconfres,
1031 .pc_argsize = sizeof(struct nfsd3_fhandleargs),
1032 .pc_argzero = sizeof(struct nfsd3_fhandleargs),
1033 .pc_ressize = sizeof(struct nfsd3_pathconfres),
1034 .pc_cachetype = RC_NOCACHE,
1035 .pc_xdrressize = ST+pAT+6,
1036 .pc_name = "PATHCONF",
1037 },
1038 [NFS3PROC_COMMIT] = {
1039 .pc_func = nfsd3_proc_commit,
1040 .pc_decode = nfs3svc_decode_commitargs,
1041 .pc_encode = nfs3svc_encode_commitres,
1042 .pc_release = nfs3svc_release_fhandle,
1043 .pc_argsize = sizeof(struct nfsd3_commitargs),
1044 .pc_argzero = sizeof(struct nfsd3_commitargs),
1045 .pc_ressize = sizeof(struct nfsd3_commitres),
1046 .pc_cachetype = RC_NOCACHE,
1047 .pc_xdrressize = ST+WC+2,
1048 .pc_name = "COMMIT",
1049 },
1050 };
1051
1052 static DEFINE_PER_CPU_ALIGNED(unsigned long,
1053 nfsd_count3[ARRAY_SIZE(nfsd_procedures3)]);
1054 const struct svc_version nfsd_version3 = {
1055 .vs_vers = 3,
1056 .vs_nproc = ARRAY_SIZE(nfsd_procedures3),
1057 .vs_proc = nfsd_procedures3,
1058 .vs_dispatch = nfsd_dispatch,
1059 .vs_count = nfsd_count3,
1060 .vs_xdrsize = NFS3_SVC_XDRSIZE,
1061 };
1062