blob: 1a259d313e1429a981ae2ea98fc66286716fff16 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/fs/nfsd/nfs3proc.c
3 *
4 * Process version 3 NFS requests.
5 *
6 * Copyright (C) 1996, 1997, 1998 Olaf Kirch <okir@monad.swb.de>
7 */
8
9#include <linux/linkage.h>
10#include <linux/time.h>
11#include <linux/errno.h>
12#include <linux/fs.h>
13#include <linux/ext2_fs.h>
14#include <linux/stat.h>
15#include <linux/fcntl.h>
16#include <linux/net.h>
17#include <linux/in.h>
18#include <linux/unistd.h>
19#include <linux/slab.h>
20#include <linux/major.h>
Qinghuang Feng12214cb2009-01-12 03:13:53 +080021#include <linux/magic.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
23#include <linux/sunrpc/svc.h>
24#include <linux/nfsd/nfsd.h>
25#include <linux/nfsd/cache.h>
26#include <linux/nfsd/xdr3.h>
27#include <linux/nfs3.h>
J. Bruce Fields0a3adad2009-11-04 18:12:35 -050028#include "vfs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#define NFSDDBG_FACILITY NFSDDBG_PROC
31
32#define RETURN_STATUS(st) { resp->status = (st); return (st); }
33
34static int nfs3_ftypes[] = {
35 0, /* NF3NON */
36 S_IFREG, /* NF3REG */
37 S_IFDIR, /* NF3DIR */
38 S_IFBLK, /* NF3BLK */
39 S_IFCHR, /* NF3CHR */
40 S_IFLNK, /* NF3LNK */
41 S_IFSOCK, /* NF3SOCK */
42 S_IFIFO, /* NF3FIFO */
43};
44
45/*
46 * NULL call.
47 */
Al Viro7111c662006-10-19 23:28:45 -070048static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -070049nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
50{
51 return nfs_ok;
52}
53
54/*
55 * Get a file's attributes
56 */
Al Viro7111c662006-10-19 23:28:45 -070057static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -070058nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
59 struct nfsd3_attrstat *resp)
60{
Al Viroc4d987b2006-10-19 23:29:00 -070061 int err;
62 __be32 nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64 dprintk("nfsd: GETATTR(3) %s\n",
David Shawa334de22006-01-06 00:19:58 -080065 SVCFH_fmt(&argp->fh));
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67 fh_copy(&resp->fh, &argp->fh);
J. Bruce Fields04716e62008-08-07 13:00:20 -040068 nfserr = fh_verify(rqstp, &resp->fh, 0,
69 NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
David Shawa334de22006-01-06 00:19:58 -080070 if (nfserr)
71 RETURN_STATUS(nfserr);
72
Jan Blunck54775492008-02-14 19:38:39 -080073 err = vfs_getattr(resp->fh.fh_export->ex_path.mnt,
David Shawa334de22006-01-06 00:19:58 -080074 resp->fh.fh_dentry, &resp->stat);
75 nfserr = nfserrno(err);
76
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 RETURN_STATUS(nfserr);
78}
79
80/*
81 * Set a file's attributes
82 */
Al Viro7111c662006-10-19 23:28:45 -070083static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -070084nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
85 struct nfsd3_attrstat *resp)
86{
Al Viroc4d987b2006-10-19 23:29:00 -070087 __be32 nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
89 dprintk("nfsd: SETATTR(3) %s\n",
90 SVCFH_fmt(&argp->fh));
91
92 fh_copy(&resp->fh, &argp->fh);
93 nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,
94 argp->check_guard, argp->guardtime);
95 RETURN_STATUS(nfserr);
96}
97
98/*
99 * Look up a path name component
100 */
Al Viro7111c662006-10-19 23:28:45 -0700101static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
103 struct nfsd3_diropres *resp)
104{
Al Viroc4d987b2006-10-19 23:29:00 -0700105 __be32 nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
107 dprintk("nfsd: LOOKUP(3) %s %.*s\n",
108 SVCFH_fmt(&argp->fh),
109 argp->len,
110 argp->name);
111
112 fh_copy(&resp->dirfh, &argp->fh);
113 fh_init(&resp->fh, NFS3_FHSIZE);
114
115 nfserr = nfsd_lookup(rqstp, &resp->dirfh,
116 argp->name,
117 argp->len,
118 &resp->fh);
119 RETURN_STATUS(nfserr);
120}
121
122/*
123 * Check file access
124 */
Al Viro7111c662006-10-19 23:28:45 -0700125static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
127 struct nfsd3_accessres *resp)
128{
Al Viroc4d987b2006-10-19 23:29:00 -0700129 __be32 nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130
131 dprintk("nfsd: ACCESS(3) %s 0x%x\n",
132 SVCFH_fmt(&argp->fh),
133 argp->access);
134
135 fh_copy(&resp->fh, &argp->fh);
136 resp->access = argp->access;
137 nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
138 RETURN_STATUS(nfserr);
139}
140
141/*
142 * Read a symlink.
143 */
Al Viro7111c662006-10-19 23:28:45 -0700144static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp,
146 struct nfsd3_readlinkres *resp)
147{
Al Viroc4d987b2006-10-19 23:29:00 -0700148 __be32 nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
150 dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
151
152 /* Read the symlink. */
153 fh_copy(&resp->fh, &argp->fh);
154 resp->len = NFS3_MAXPATHLEN;
155 nfserr = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len);
156 RETURN_STATUS(nfserr);
157}
158
159/*
160 * Read a portion of a file.
161 */
Al Viro7111c662006-10-19 23:28:45 -0700162static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
164 struct nfsd3_readres *resp)
165{
Al Viroc4d987b2006-10-19 23:29:00 -0700166 __be32 nfserr;
Greg Banks7adae482006-10-04 02:15:47 -0700167 u32 max_blocksize = svc_max_payload(rqstp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168
169 dprintk("nfsd: READ(3) %s %lu bytes at %lu\n",
170 SVCFH_fmt(&argp->fh),
171 (unsigned long) argp->count,
172 (unsigned long) argp->offset);
173
174 /* Obtain buffer pointer for payload.
175 * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
176 * + 1 (xdr opaque byte count) = 26
177 */
178
179 resp->count = argp->count;
Greg Banks7adae482006-10-04 02:15:47 -0700180 if (max_blocksize < resp->count)
181 resp->count = max_blocksize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Jeff Laytoncd123012007-05-09 02:34:50 -0700183 svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
185 fh_copy(&resp->fh, &argp->fh);
186 nfserr = nfsd_read(rqstp, &resp->fh, NULL,
187 argp->offset,
NeilBrown3cc03b12006-10-04 02:15:47 -0700188 rqstp->rq_vec, argp->vlen,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 &resp->count);
190 if (nfserr == 0) {
191 struct inode *inode = resp->fh.fh_dentry->d_inode;
192
193 resp->eof = (argp->offset + resp->count) >= inode->i_size;
194 }
195
196 RETURN_STATUS(nfserr);
197}
198
199/*
200 * Write data to a file
201 */
Al Viro7111c662006-10-19 23:28:45 -0700202static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
204 struct nfsd3_writeres *resp)
205{
Al Viroc4d987b2006-10-19 23:29:00 -0700206 __be32 nfserr;
David Shaw31dec252009-03-05 20:16:14 -0500207 unsigned long cnt = argp->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209 dprintk("nfsd: WRITE(3) %s %d bytes at %ld%s\n",
210 SVCFH_fmt(&argp->fh),
211 argp->len,
212 (unsigned long) argp->offset,
213 argp->stable? " stable" : "");
214
215 fh_copy(&resp->fh, &argp->fh);
216 resp->committed = argp->stable;
217 nfserr = nfsd_write(rqstp, &resp->fh, NULL,
218 argp->offset,
NeilBrown3cc03b12006-10-04 02:15:47 -0700219 rqstp->rq_vec, argp->vlen,
David Shaw31dec252009-03-05 20:16:14 -0500220 &cnt,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 &resp->committed);
David Shaw31dec252009-03-05 20:16:14 -0500222 resp->count = cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 RETURN_STATUS(nfserr);
224}
225
226/*
227 * With NFSv3, CREATE processing is a lot easier than with NFSv2.
228 * At least in theory; we'll see how it fares in practice when the
229 * first reports about SunOS compatibility problems start to pour in...
230 */
Al Viro7111c662006-10-19 23:28:45 -0700231static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
233 struct nfsd3_diropres *resp)
234{
235 svc_fh *dirfhp, *newfhp = NULL;
236 struct iattr *attr;
Al Viroc4d987b2006-10-19 23:29:00 -0700237 __be32 nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
239 dprintk("nfsd: CREATE(3) %s %.*s\n",
240 SVCFH_fmt(&argp->fh),
241 argp->len,
242 argp->name);
243
244 dirfhp = fh_copy(&resp->dirfh, &argp->fh);
245 newfhp = fh_init(&resp->fh, NFS3_FHSIZE);
246 attr = &argp->attrs;
247
248 /* Get the directory inode */
Miklos Szeredi8837abc2008-06-16 13:20:29 +0200249 nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_CREATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 if (nfserr)
251 RETURN_STATUS(nfserr);
252
253 /* Unfudge the mode bits */
254 attr->ia_mode &= ~S_IFMT;
255 if (!(attr->ia_valid & ATTR_MODE)) {
256 attr->ia_valid |= ATTR_MODE;
257 attr->ia_mode = S_IFREG;
258 } else {
259 attr->ia_mode = (attr->ia_mode & ~S_IFMT) | S_IFREG;
260 }
261
262 /* Now create the file and set attributes */
263 nfserr = nfsd_create_v3(rqstp, dirfhp, argp->name, argp->len,
264 attr, newfhp,
J. Bruce Fields81ac95c2006-11-08 17:44:40 -0800265 argp->createmode, argp->verf, NULL, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
267 RETURN_STATUS(nfserr);
268}
269
270/*
271 * Make directory. This operation is not idempotent.
272 */
Al Viro7111c662006-10-19 23:28:45 -0700273static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
275 struct nfsd3_diropres *resp)
276{
Al Viroc4d987b2006-10-19 23:29:00 -0700277 __be32 nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
279 dprintk("nfsd: MKDIR(3) %s %.*s\n",
280 SVCFH_fmt(&argp->fh),
281 argp->len,
282 argp->name);
283
284 argp->attrs.ia_valid &= ~ATTR_SIZE;
285 fh_copy(&resp->dirfh, &argp->fh);
286 fh_init(&resp->fh, NFS3_FHSIZE);
287 nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
288 &argp->attrs, S_IFDIR, 0, &resp->fh);
289
290 RETURN_STATUS(nfserr);
291}
292
Al Viro7111c662006-10-19 23:28:45 -0700293static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
295 struct nfsd3_diropres *resp)
296{
Al Viroc4d987b2006-10-19 23:29:00 -0700297 __be32 nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
299 dprintk("nfsd: SYMLINK(3) %s %.*s -> %.*s\n",
300 SVCFH_fmt(&argp->ffh),
301 argp->flen, argp->fname,
302 argp->tlen, argp->tname);
303
304 fh_copy(&resp->dirfh, &argp->ffh);
305 fh_init(&resp->fh, NFS3_FHSIZE);
306 nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen,
307 argp->tname, argp->tlen,
308 &resp->fh, &argp->attrs);
309 RETURN_STATUS(nfserr);
310}
311
312/*
313 * Make socket/fifo/device.
314 */
Al Viro7111c662006-10-19 23:28:45 -0700315static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
317 struct nfsd3_diropres *resp)
318{
Al Viroc4d987b2006-10-19 23:29:00 -0700319 __be32 nfserr;
320 int type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 dev_t rdev = 0;
322
323 dprintk("nfsd: MKNOD(3) %s %.*s\n",
324 SVCFH_fmt(&argp->fh),
325 argp->len,
326 argp->name);
327
328 fh_copy(&resp->dirfh, &argp->fh);
329 fh_init(&resp->fh, NFS3_FHSIZE);
330
331 if (argp->ftype == 0 || argp->ftype >= NF3BAD)
332 RETURN_STATUS(nfserr_inval);
333 if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) {
334 rdev = MKDEV(argp->major, argp->minor);
335 if (MAJOR(rdev) != argp->major ||
336 MINOR(rdev) != argp->minor)
337 RETURN_STATUS(nfserr_inval);
338 } else
339 if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO)
340 RETURN_STATUS(nfserr_inval);
341
342 type = nfs3_ftypes[argp->ftype];
343 nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
344 &argp->attrs, type, rdev, &resp->fh);
345
346 RETURN_STATUS(nfserr);
347}
348
349/*
350 * Remove file/fifo/socket etc.
351 */
Al Viro7111c662006-10-19 23:28:45 -0700352static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
354 struct nfsd3_attrstat *resp)
355{
Al Viroc4d987b2006-10-19 23:29:00 -0700356 __be32 nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
358 dprintk("nfsd: REMOVE(3) %s %.*s\n",
359 SVCFH_fmt(&argp->fh),
360 argp->len,
361 argp->name);
362
363 /* Unlink. -S_IFDIR means file must not be a directory */
364 fh_copy(&resp->fh, &argp->fh);
365 nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
366 RETURN_STATUS(nfserr);
367}
368
369/*
370 * Remove a directory
371 */
Al Viro7111c662006-10-19 23:28:45 -0700372static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
374 struct nfsd3_attrstat *resp)
375{
Al Viroc4d987b2006-10-19 23:29:00 -0700376 __be32 nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378 dprintk("nfsd: RMDIR(3) %s %.*s\n",
379 SVCFH_fmt(&argp->fh),
380 argp->len,
381 argp->name);
382
383 fh_copy(&resp->fh, &argp->fh);
384 nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len);
385 RETURN_STATUS(nfserr);
386}
387
Al Viro7111c662006-10-19 23:28:45 -0700388static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
390 struct nfsd3_renameres *resp)
391{
Al Viroc4d987b2006-10-19 23:29:00 -0700392 __be32 nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393
394 dprintk("nfsd: RENAME(3) %s %.*s ->\n",
395 SVCFH_fmt(&argp->ffh),
396 argp->flen,
397 argp->fname);
398 dprintk("nfsd: -> %s %.*s\n",
399 SVCFH_fmt(&argp->tfh),
400 argp->tlen,
401 argp->tname);
402
403 fh_copy(&resp->ffh, &argp->ffh);
404 fh_copy(&resp->tfh, &argp->tfh);
405 nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
406 &resp->tfh, argp->tname, argp->tlen);
407 RETURN_STATUS(nfserr);
408}
409
Al Viro7111c662006-10-19 23:28:45 -0700410static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
412 struct nfsd3_linkres *resp)
413{
Al Viroc4d987b2006-10-19 23:29:00 -0700414 __be32 nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
416 dprintk("nfsd: LINK(3) %s ->\n",
417 SVCFH_fmt(&argp->ffh));
418 dprintk("nfsd: -> %s %.*s\n",
419 SVCFH_fmt(&argp->tfh),
420 argp->tlen,
421 argp->tname);
422
423 fh_copy(&resp->fh, &argp->ffh);
424 fh_copy(&resp->tfh, &argp->tfh);
425 nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
426 &resp->fh);
427 RETURN_STATUS(nfserr);
428}
429
430/*
431 * Read a portion of a directory.
432 */
Al Viro7111c662006-10-19 23:28:45 -0700433static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
435 struct nfsd3_readdirres *resp)
436{
Al Viroc4d987b2006-10-19 23:29:00 -0700437 __be32 nfserr;
438 int count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
440 dprintk("nfsd: READDIR(3) %s %d bytes at %d\n",
441 SVCFH_fmt(&argp->fh),
442 argp->count, (u32) argp->cookie);
443
444 /* Make sure we've room for the NULL ptr & eof flag, and shrink to
445 * client read size */
446 count = (argp->count >> 2) - 2;
447
448 /* Read directory and encode entries on the fly */
449 fh_copy(&resp->fh, &argp->fh);
450
451 resp->buflen = count;
452 resp->common.err = nfs_ok;
453 resp->buffer = argp->buffer;
454 resp->rqstp = rqstp;
455 nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie,
456 &resp->common, nfs3svc_encode_entry);
457 memcpy(resp->verf, argp->verf, 8);
458 resp->count = resp->buffer - argp->buffer;
459 if (resp->offset)
460 xdr_encode_hyper(resp->offset, argp->cookie);
461
462 RETURN_STATUS(nfserr);
463}
464
465/*
466 * Read a portion of a directory, including file handles and attrs.
467 * For now, we choose to ignore the dircount parameter.
468 */
Al Viro7111c662006-10-19 23:28:45 -0700469static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
471 struct nfsd3_readdirres *resp)
472{
Al Viroc4d987b2006-10-19 23:29:00 -0700473 __be32 nfserr;
474 int count = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 loff_t offset;
476 int i;
477 caddr_t page_addr = NULL;
478
479 dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
480 SVCFH_fmt(&argp->fh),
481 argp->count, (u32) argp->cookie);
482
483 /* Convert byte count to number of words (i.e. >> 2),
484 * and reserve room for the NULL ptr & eof flag (-2 words) */
485 resp->count = (argp->count >> 2) - 2;
486
487 /* Read directory and encode entries on the fly */
488 fh_copy(&resp->fh, &argp->fh);
489
490 resp->common.err = nfs_ok;
491 resp->buffer = argp->buffer;
492 resp->buflen = resp->count;
493 resp->rqstp = rqstp;
494 offset = argp->cookie;
495 nfserr = nfsd_readdir(rqstp, &resp->fh,
496 &offset,
497 &resp->common,
498 nfs3svc_encode_entry_plus);
499 memcpy(resp->verf, argp->verf, 8);
500 for (i=1; i<rqstp->rq_resused ; i++) {
501 page_addr = page_address(rqstp->rq_respages[i]);
502
503 if (((caddr_t)resp->buffer >= page_addr) &&
504 ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) {
505 count += (caddr_t)resp->buffer - page_addr;
506 break;
507 }
508 count += PAGE_SIZE;
509 }
510 resp->count = count >> 2;
511 if (resp->offset) {
512 if (unlikely(resp->offset1)) {
513 /* we ended up with offset on a page boundary */
514 *resp->offset = htonl(offset >> 32);
515 *resp->offset1 = htonl(offset & 0xffffffff);
516 resp->offset1 = NULL;
517 } else {
518 xdr_encode_hyper(resp->offset, offset);
519 }
520 }
521
522 RETURN_STATUS(nfserr);
523}
524
525/*
526 * Get file system stats
527 */
Al Viro7111c662006-10-19 23:28:45 -0700528static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
530 struct nfsd3_fsstatres *resp)
531{
Al Viroc4d987b2006-10-19 23:29:00 -0700532 __be32 nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
534 dprintk("nfsd: FSSTAT(3) %s\n",
535 SVCFH_fmt(&argp->fh));
536
J. Bruce Fields04716e62008-08-07 13:00:20 -0400537 nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 fh_put(&argp->fh);
539 RETURN_STATUS(nfserr);
540}
541
542/*
543 * Get file system info
544 */
Al Viro7111c662006-10-19 23:28:45 -0700545static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
547 struct nfsd3_fsinfores *resp)
548{
Al Viroc4d987b2006-10-19 23:29:00 -0700549 __be32 nfserr;
Greg Banks7adae482006-10-04 02:15:47 -0700550 u32 max_blocksize = svc_max_payload(rqstp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551
552 dprintk("nfsd: FSINFO(3) %s\n",
553 SVCFH_fmt(&argp->fh));
554
Greg Banks7adae482006-10-04 02:15:47 -0700555 resp->f_rtmax = max_blocksize;
556 resp->f_rtpref = max_blocksize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 resp->f_rtmult = PAGE_SIZE;
Greg Banks7adae482006-10-04 02:15:47 -0700558 resp->f_wtmax = max_blocksize;
559 resp->f_wtpref = max_blocksize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 resp->f_wtmult = PAGE_SIZE;
561 resp->f_dtpref = PAGE_SIZE;
562 resp->f_maxfilesize = ~(u32) 0;
563 resp->f_properties = NFS3_FSF_DEFAULT;
564
J. Bruce Fields04716e62008-08-07 13:00:20 -0400565 nfserr = fh_verify(rqstp, &argp->fh, 0,
566 NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
568 /* Check special features of the file system. May request
569 * different read/write sizes for file systems known to have
570 * problems with large blocks */
571 if (nfserr == 0) {
572 struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
573
574 /* Note that we don't care for remote fs's here */
Qinghuang Feng12214cb2009-01-12 03:13:53 +0800575 if (sb->s_magic == MSDOS_SUPER_MAGIC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 resp->f_properties = NFS3_FSF_BILLYBOY;
577 }
578 resp->f_maxfilesize = sb->s_maxbytes;
579 }
580
581 fh_put(&argp->fh);
582 RETURN_STATUS(nfserr);
583}
584
585/*
586 * Get pathconf info for the specified file
587 */
Al Viro7111c662006-10-19 23:28:45 -0700588static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
590 struct nfsd3_pathconfres *resp)
591{
Al Viroc4d987b2006-10-19 23:29:00 -0700592 __be32 nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
594 dprintk("nfsd: PATHCONF(3) %s\n",
595 SVCFH_fmt(&argp->fh));
596
597 /* Set default pathconf */
598 resp->p_link_max = 255; /* at least */
599 resp->p_name_max = 255; /* at least */
600 resp->p_no_trunc = 0;
601 resp->p_chown_restricted = 1;
602 resp->p_case_insensitive = 0;
603 resp->p_case_preserving = 1;
604
Miklos Szeredi8837abc2008-06-16 13:20:29 +0200605 nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
607 if (nfserr == 0) {
608 struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
609
610 /* Note that we don't care for remote fs's here */
611 switch (sb->s_magic) {
612 case EXT2_SUPER_MAGIC:
613 resp->p_link_max = EXT2_LINK_MAX;
614 resp->p_name_max = EXT2_NAME_LEN;
615 break;
Qinghuang Feng12214cb2009-01-12 03:13:53 +0800616 case MSDOS_SUPER_MAGIC:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 resp->p_case_insensitive = 1;
618 resp->p_case_preserving = 0;
619 break;
620 }
621 }
622
623 fh_put(&argp->fh);
624 RETURN_STATUS(nfserr);
625}
626
627
628/*
629 * Commit a file (range) to stable storage.
630 */
Al Viro7111c662006-10-19 23:28:45 -0700631static __be32
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp,
633 struct nfsd3_commitres *resp)
634{
Al Viroc4d987b2006-10-19 23:29:00 -0700635 __be32 nfserr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
637 dprintk("nfsd: COMMIT(3) %s %u@%Lu\n",
638 SVCFH_fmt(&argp->fh),
639 argp->count,
640 (unsigned long long) argp->offset);
641
642 if (argp->offset > NFS_OFFSET_MAX)
643 RETURN_STATUS(nfserr_inval);
644
645 fh_copy(&resp->fh, &argp->fh);
646 nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count);
647
648 RETURN_STATUS(nfserr);
649}
650
651
652/*
653 * NFSv3 Server procedures.
654 * Only the results of non-idempotent operations are cached.
655 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656#define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle
657#define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat
658#define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat
659#define nfsd3_mkdirargs nfsd3_createargs
660#define nfsd3_readdirplusargs nfsd3_readdirargs
661#define nfsd3_fhandleargs nfsd_fhandle
662#define nfsd3_fhandleres nfsd3_attrstat
663#define nfsd3_attrstatres nfsd3_attrstat
664#define nfsd3_wccstatres nfsd3_attrstat
665#define nfsd3_createres nfsd3_diropres
666#define nfsd3_voidres nfsd3_voidargs
667struct nfsd3_voidargs { int dummy; };
668
669#define PROC(name, argt, rest, relt, cache, respsize) \
670 { (svc_procfunc) nfsd3_proc_##name, \
671 (kxdrproc_t) nfs3svc_decode_##argt##args, \
672 (kxdrproc_t) nfs3svc_encode_##rest##res, \
673 (kxdrproc_t) nfs3svc_release_##relt, \
674 sizeof(struct nfsd3_##argt##args), \
675 sizeof(struct nfsd3_##rest##res), \
676 0, \
677 cache, \
678 respsize, \
679 }
680
681#define ST 1 /* status*/
682#define FH 17 /* filehandle with length */
683#define AT 21 /* attributes */
684#define pAT (1+AT) /* post attributes - conditional */
685#define WC (7+pAT) /* WCC attributes */
686
687static struct svc_procedure nfsd_procedures3[22] = {
Yu Zhiguob9081d92009-06-09 17:33:34 +0800688 [NFS3PROC_NULL] = {
689 .pc_func = (svc_procfunc) nfsd3_proc_null,
690 .pc_encode = (kxdrproc_t) nfs3svc_encode_voidres,
691 .pc_argsize = sizeof(struct nfsd3_voidargs),
692 .pc_ressize = sizeof(struct nfsd3_voidres),
693 .pc_cachetype = RC_NOCACHE,
694 .pc_xdrressize = ST,
695 },
696 [NFS3PROC_GETATTR] = {
697 .pc_func = (svc_procfunc) nfsd3_proc_getattr,
698 .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
699 .pc_encode = (kxdrproc_t) nfs3svc_encode_attrstatres,
700 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
701 .pc_argsize = sizeof(struct nfsd3_fhandleargs),
702 .pc_ressize = sizeof(struct nfsd3_attrstatres),
703 .pc_cachetype = RC_NOCACHE,
704 .pc_xdrressize = ST+AT,
705 },
706 [NFS3PROC_SETATTR] = {
707 .pc_func = (svc_procfunc) nfsd3_proc_setattr,
708 .pc_decode = (kxdrproc_t) nfs3svc_decode_sattrargs,
709 .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
710 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
711 .pc_argsize = sizeof(struct nfsd3_sattrargs),
712 .pc_ressize = sizeof(struct nfsd3_wccstatres),
713 .pc_cachetype = RC_REPLBUFF,
714 .pc_xdrressize = ST+WC,
715 },
716 [NFS3PROC_LOOKUP] = {
717 .pc_func = (svc_procfunc) nfsd3_proc_lookup,
718 .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
719 .pc_encode = (kxdrproc_t) nfs3svc_encode_diropres,
720 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
721 .pc_argsize = sizeof(struct nfsd3_diropargs),
722 .pc_ressize = sizeof(struct nfsd3_diropres),
723 .pc_cachetype = RC_NOCACHE,
724 .pc_xdrressize = ST+FH+pAT+pAT,
725 },
726 [NFS3PROC_ACCESS] = {
727 .pc_func = (svc_procfunc) nfsd3_proc_access,
728 .pc_decode = (kxdrproc_t) nfs3svc_decode_accessargs,
729 .pc_encode = (kxdrproc_t) nfs3svc_encode_accessres,
730 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
731 .pc_argsize = sizeof(struct nfsd3_accessargs),
732 .pc_ressize = sizeof(struct nfsd3_accessres),
733 .pc_cachetype = RC_NOCACHE,
734 .pc_xdrressize = ST+pAT+1,
735 },
736 [NFS3PROC_READLINK] = {
737 .pc_func = (svc_procfunc) nfsd3_proc_readlink,
738 .pc_decode = (kxdrproc_t) nfs3svc_decode_readlinkargs,
739 .pc_encode = (kxdrproc_t) nfs3svc_encode_readlinkres,
740 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
741 .pc_argsize = sizeof(struct nfsd3_readlinkargs),
742 .pc_ressize = sizeof(struct nfsd3_readlinkres),
743 .pc_cachetype = RC_NOCACHE,
744 .pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4,
745 },
746 [NFS3PROC_READ] = {
747 .pc_func = (svc_procfunc) nfsd3_proc_read,
748 .pc_decode = (kxdrproc_t) nfs3svc_decode_readargs,
749 .pc_encode = (kxdrproc_t) nfs3svc_encode_readres,
750 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
751 .pc_argsize = sizeof(struct nfsd3_readargs),
752 .pc_ressize = sizeof(struct nfsd3_readres),
753 .pc_cachetype = RC_NOCACHE,
754 .pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4,
755 },
756 [NFS3PROC_WRITE] = {
757 .pc_func = (svc_procfunc) nfsd3_proc_write,
758 .pc_decode = (kxdrproc_t) nfs3svc_decode_writeargs,
759 .pc_encode = (kxdrproc_t) nfs3svc_encode_writeres,
760 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
761 .pc_argsize = sizeof(struct nfsd3_writeargs),
762 .pc_ressize = sizeof(struct nfsd3_writeres),
763 .pc_cachetype = RC_REPLBUFF,
764 .pc_xdrressize = ST+WC+4,
765 },
766 [NFS3PROC_CREATE] = {
767 .pc_func = (svc_procfunc) nfsd3_proc_create,
768 .pc_decode = (kxdrproc_t) nfs3svc_decode_createargs,
769 .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
770 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
771 .pc_argsize = sizeof(struct nfsd3_createargs),
772 .pc_ressize = sizeof(struct nfsd3_createres),
773 .pc_cachetype = RC_REPLBUFF,
774 .pc_xdrressize = ST+(1+FH+pAT)+WC,
775 },
776 [NFS3PROC_MKDIR] = {
777 .pc_func = (svc_procfunc) nfsd3_proc_mkdir,
778 .pc_decode = (kxdrproc_t) nfs3svc_decode_mkdirargs,
779 .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
780 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
781 .pc_argsize = sizeof(struct nfsd3_mkdirargs),
782 .pc_ressize = sizeof(struct nfsd3_createres),
783 .pc_cachetype = RC_REPLBUFF,
784 .pc_xdrressize = ST+(1+FH+pAT)+WC,
785 },
786 [NFS3PROC_SYMLINK] = {
787 .pc_func = (svc_procfunc) nfsd3_proc_symlink,
788 .pc_decode = (kxdrproc_t) nfs3svc_decode_symlinkargs,
789 .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
790 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
791 .pc_argsize = sizeof(struct nfsd3_symlinkargs),
792 .pc_ressize = sizeof(struct nfsd3_createres),
793 .pc_cachetype = RC_REPLBUFF,
794 .pc_xdrressize = ST+(1+FH+pAT)+WC,
795 },
796 [NFS3PROC_MKNOD] = {
797 .pc_func = (svc_procfunc) nfsd3_proc_mknod,
798 .pc_decode = (kxdrproc_t) nfs3svc_decode_mknodargs,
799 .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
800 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
801 .pc_argsize = sizeof(struct nfsd3_mknodargs),
802 .pc_ressize = sizeof(struct nfsd3_createres),
803 .pc_cachetype = RC_REPLBUFF,
804 .pc_xdrressize = ST+(1+FH+pAT)+WC,
805 },
806 [NFS3PROC_REMOVE] = {
807 .pc_func = (svc_procfunc) nfsd3_proc_remove,
808 .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
809 .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
810 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
811 .pc_argsize = sizeof(struct nfsd3_diropargs),
812 .pc_ressize = sizeof(struct nfsd3_wccstatres),
813 .pc_cachetype = RC_REPLBUFF,
814 .pc_xdrressize = ST+WC,
815 },
816 [NFS3PROC_RMDIR] = {
817 .pc_func = (svc_procfunc) nfsd3_proc_rmdir,
818 .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
819 .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
820 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
821 .pc_argsize = sizeof(struct nfsd3_diropargs),
822 .pc_ressize = sizeof(struct nfsd3_wccstatres),
823 .pc_cachetype = RC_REPLBUFF,
824 .pc_xdrressize = ST+WC,
825 },
826 [NFS3PROC_RENAME] = {
827 .pc_func = (svc_procfunc) nfsd3_proc_rename,
828 .pc_decode = (kxdrproc_t) nfs3svc_decode_renameargs,
829 .pc_encode = (kxdrproc_t) nfs3svc_encode_renameres,
830 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
831 .pc_argsize = sizeof(struct nfsd3_renameargs),
832 .pc_ressize = sizeof(struct nfsd3_renameres),
833 .pc_cachetype = RC_REPLBUFF,
834 .pc_xdrressize = ST+WC+WC,
835 },
836 [NFS3PROC_LINK] = {
837 .pc_func = (svc_procfunc) nfsd3_proc_link,
838 .pc_decode = (kxdrproc_t) nfs3svc_decode_linkargs,
839 .pc_encode = (kxdrproc_t) nfs3svc_encode_linkres,
840 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
841 .pc_argsize = sizeof(struct nfsd3_linkargs),
842 .pc_ressize = sizeof(struct nfsd3_linkres),
843 .pc_cachetype = RC_REPLBUFF,
844 .pc_xdrressize = ST+pAT+WC,
845 },
846 [NFS3PROC_READDIR] = {
847 .pc_func = (svc_procfunc) nfsd3_proc_readdir,
848 .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirargs,
849 .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres,
850 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
851 .pc_argsize = sizeof(struct nfsd3_readdirargs),
852 .pc_ressize = sizeof(struct nfsd3_readdirres),
853 .pc_cachetype = RC_NOCACHE,
854 },
855 [NFS3PROC_READDIRPLUS] = {
856 .pc_func = (svc_procfunc) nfsd3_proc_readdirplus,
857 .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirplusargs,
858 .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres,
859 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
860 .pc_argsize = sizeof(struct nfsd3_readdirplusargs),
861 .pc_ressize = sizeof(struct nfsd3_readdirres),
862 .pc_cachetype = RC_NOCACHE,
863 },
864 [NFS3PROC_FSSTAT] = {
865 .pc_func = (svc_procfunc) nfsd3_proc_fsstat,
866 .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
867 .pc_encode = (kxdrproc_t) nfs3svc_encode_fsstatres,
868 .pc_argsize = sizeof(struct nfsd3_fhandleargs),
869 .pc_ressize = sizeof(struct nfsd3_fsstatres),
870 .pc_cachetype = RC_NOCACHE,
871 .pc_xdrressize = ST+pAT+2*6+1,
872 },
873 [NFS3PROC_FSINFO] = {
874 .pc_func = (svc_procfunc) nfsd3_proc_fsinfo,
875 .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
876 .pc_encode = (kxdrproc_t) nfs3svc_encode_fsinfores,
877 .pc_argsize = sizeof(struct nfsd3_fhandleargs),
878 .pc_ressize = sizeof(struct nfsd3_fsinfores),
879 .pc_cachetype = RC_NOCACHE,
880 .pc_xdrressize = ST+pAT+12,
881 },
882 [NFS3PROC_PATHCONF] = {
883 .pc_func = (svc_procfunc) nfsd3_proc_pathconf,
884 .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
885 .pc_encode = (kxdrproc_t) nfs3svc_encode_pathconfres,
886 .pc_argsize = sizeof(struct nfsd3_fhandleargs),
887 .pc_ressize = sizeof(struct nfsd3_pathconfres),
888 .pc_cachetype = RC_NOCACHE,
889 .pc_xdrressize = ST+pAT+6,
890 },
891 [NFS3PROC_COMMIT] = {
892 .pc_func = (svc_procfunc) nfsd3_proc_commit,
893 .pc_decode = (kxdrproc_t) nfs3svc_decode_commitargs,
894 .pc_encode = (kxdrproc_t) nfs3svc_encode_commitres,
895 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
896 .pc_argsize = sizeof(struct nfsd3_commitargs),
897 .pc_ressize = sizeof(struct nfsd3_commitres),
898 .pc_cachetype = RC_NOCACHE,
899 .pc_xdrressize = ST+WC+2,
900 },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901};
902
903struct svc_version nfsd_version3 = {
904 .vs_vers = 3,
905 .vs_nproc = 22,
906 .vs_proc = nfsd_procedures3,
907 .vs_dispatch = nfsd_dispatch,
908 .vs_xdrsize = NFS3_SVC_XDRSIZE,
909};