]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - fs/nfsd/nfs3proc.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
[linux-2.6.git] / fs / nfsd / nfs3proc.c
1 /*
2  * Process version 3 NFS requests.
3  *
4  * Copyright (C) 1996, 1997, 1998 Olaf Kirch <okir@monad.swb.de>
5  */
6
7 #include <linux/fs.h>
8 #include <linux/ext2_fs.h>
9 #include <linux/magic.h>
10
11 #include "cache.h"
12 #include "xdr3.h"
13 #include "vfs.h"
14
15 #define NFSDDBG_FACILITY                NFSDDBG_PROC
16
17 #define RETURN_STATUS(st)       { resp->status = (st); return (st); }
18
19 static int      nfs3_ftypes[] = {
20         0,                      /* NF3NON */
21         S_IFREG,                /* NF3REG */
22         S_IFDIR,                /* NF3DIR */
23         S_IFBLK,                /* NF3BLK */
24         S_IFCHR,                /* NF3CHR */
25         S_IFLNK,                /* NF3LNK */
26         S_IFSOCK,               /* NF3SOCK */
27         S_IFIFO,                /* NF3FIFO */
28 };
29
30 /*
31  * NULL call.
32  */
33 static __be32
34 nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
35 {
36         return nfs_ok;
37 }
38
39 /*
40  * Get a file's attributes
41  */
42 static __be32
43 nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
44                                            struct nfsd3_attrstat *resp)
45 {
46         int     err;
47         __be32  nfserr;
48
49         dprintk("nfsd: GETATTR(3)  %s\n",
50                 SVCFH_fmt(&argp->fh));
51
52         fh_copy(&resp->fh, &argp->fh);
53         nfserr = fh_verify(rqstp, &resp->fh, 0,
54                         NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
55         if (nfserr)
56                 RETURN_STATUS(nfserr);
57
58         err = vfs_getattr(resp->fh.fh_export->ex_path.mnt,
59                           resp->fh.fh_dentry, &resp->stat);
60         nfserr = nfserrno(err);
61
62         RETURN_STATUS(nfserr);
63 }
64
65 /*
66  * Set a file's attributes
67  */
68 static __be32
69 nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
70                                            struct nfsd3_attrstat  *resp)
71 {
72         __be32  nfserr;
73
74         dprintk("nfsd: SETATTR(3)  %s\n",
75                                 SVCFH_fmt(&argp->fh));
76
77         fh_copy(&resp->fh, &argp->fh);
78         nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,
79                               argp->check_guard, argp->guardtime);
80         RETURN_STATUS(nfserr);
81 }
82
83 /*
84  * Look up a path name component
85  */
86 static __be32
87 nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
88                                           struct nfsd3_diropres  *resp)
89 {
90         __be32  nfserr;
91
92         dprintk("nfsd: LOOKUP(3)   %s %.*s\n",
93                                 SVCFH_fmt(&argp->fh),
94                                 argp->len,
95                                 argp->name);
96
97         fh_copy(&resp->dirfh, &argp->fh);
98         fh_init(&resp->fh, NFS3_FHSIZE);
99
100         nfserr = nfsd_lookup(rqstp, &resp->dirfh,
101                                     argp->name,
102                                     argp->len,
103                                     &resp->fh);
104         RETURN_STATUS(nfserr);
105 }
106
107 /*
108  * Check file access
109  */
110 static __be32
111 nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
112                                           struct nfsd3_accessres *resp)
113 {
114         __be32  nfserr;
115
116         dprintk("nfsd: ACCESS(3)   %s 0x%x\n",
117                                 SVCFH_fmt(&argp->fh),
118                                 argp->access);
119
120         fh_copy(&resp->fh, &argp->fh);
121         resp->access = argp->access;
122         nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
123         RETURN_STATUS(nfserr);
124 }
125
126 /*
127  * Read a symlink.
128  */
129 static __be32
130 nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp,
131                                            struct nfsd3_readlinkres *resp)
132 {
133         __be32 nfserr;
134
135         dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
136
137         /* Read the symlink. */
138         fh_copy(&resp->fh, &argp->fh);
139         resp->len = NFS3_MAXPATHLEN;
140         nfserr = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len);
141         RETURN_STATUS(nfserr);
142 }
143
144 /*
145  * Read a portion of a file.
146  */
147 static __be32
148 nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
149                                         struct nfsd3_readres  *resp)
150 {
151         __be32  nfserr;
152         u32     max_blocksize = svc_max_payload(rqstp);
153
154         dprintk("nfsd: READ(3) %s %lu bytes at %lu\n",
155                                 SVCFH_fmt(&argp->fh),
156                                 (unsigned long) argp->count,
157                                 (unsigned long) argp->offset);
158
159         /* Obtain buffer pointer for payload.
160          * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
161          * + 1 (xdr opaque byte count) = 26
162          */
163
164         resp->count = argp->count;
165         if (max_blocksize < resp->count)
166                 resp->count = max_blocksize;
167
168         svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
169
170         fh_copy(&resp->fh, &argp->fh);
171         nfserr = nfsd_read(rqstp, &resp->fh, NULL,
172                                   argp->offset,
173                                   rqstp->rq_vec, argp->vlen,
174                                   &resp->count);
175         if (nfserr == 0) {
176                 struct inode    *inode = resp->fh.fh_dentry->d_inode;
177
178                 resp->eof = (argp->offset + resp->count) >= inode->i_size;
179         }
180
181         RETURN_STATUS(nfserr);
182 }
183
184 /*
185  * Write data to a file
186  */
187 static __be32
188 nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
189                                          struct nfsd3_writeres  *resp)
190 {
191         __be32  nfserr;
192         unsigned long cnt = argp->len;
193
194         dprintk("nfsd: WRITE(3)    %s %d bytes at %ld%s\n",
195                                 SVCFH_fmt(&argp->fh),
196                                 argp->len,
197                                 (unsigned long) argp->offset,
198                                 argp->stable? " stable" : "");
199
200         fh_copy(&resp->fh, &argp->fh);
201         resp->committed = argp->stable;
202         nfserr = nfsd_write(rqstp, &resp->fh, NULL,
203                                    argp->offset,
204                                    rqstp->rq_vec, argp->vlen,
205                                    &cnt,
206                                    &resp->committed);
207         resp->count = cnt;
208         RETURN_STATUS(nfserr);
209 }
210
211 /*
212  * With NFSv3, CREATE processing is a lot easier than with NFSv2.
213  * At least in theory; we'll see how it fares in practice when the
214  * first reports about SunOS compatibility problems start to pour in...
215  */
216 static __be32
217 nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
218                                           struct nfsd3_diropres   *resp)
219 {
220         svc_fh          *dirfhp, *newfhp = NULL;
221         struct iattr    *attr;
222         __be32          nfserr;
223
224         dprintk("nfsd: CREATE(3)   %s %.*s\n",
225                                 SVCFH_fmt(&argp->fh),
226                                 argp->len,
227                                 argp->name);
228
229         dirfhp = fh_copy(&resp->dirfh, &argp->fh);
230         newfhp = fh_init(&resp->fh, NFS3_FHSIZE);
231         attr   = &argp->attrs;
232
233         /* Get the directory inode */
234         nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_CREATE);
235         if (nfserr)
236                 RETURN_STATUS(nfserr);
237
238         /* Unfudge the mode bits */
239         attr->ia_mode &= ~S_IFMT;
240         if (!(attr->ia_valid & ATTR_MODE)) { 
241                 attr->ia_valid |= ATTR_MODE;
242                 attr->ia_mode = S_IFREG;
243         } else {
244                 attr->ia_mode = (attr->ia_mode & ~S_IFMT) | S_IFREG;
245         }
246
247         /* Now create the file and set attributes */
248         nfserr = nfsd_create_v3(rqstp, dirfhp, argp->name, argp->len,
249                                 attr, newfhp,
250                                 argp->createmode, argp->verf, NULL, NULL);
251
252         RETURN_STATUS(nfserr);
253 }
254
255 /*
256  * Make directory. This operation is not idempotent.
257  */
258 static __be32
259 nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
260                                          struct nfsd3_diropres   *resp)
261 {
262         __be32  nfserr;
263
264         dprintk("nfsd: MKDIR(3)    %s %.*s\n",
265                                 SVCFH_fmt(&argp->fh),
266                                 argp->len,
267                                 argp->name);
268
269         argp->attrs.ia_valid &= ~ATTR_SIZE;
270         fh_copy(&resp->dirfh, &argp->fh);
271         fh_init(&resp->fh, NFS3_FHSIZE);
272         nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
273                                     &argp->attrs, S_IFDIR, 0, &resp->fh);
274
275         RETURN_STATUS(nfserr);
276 }
277
278 static __be32
279 nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
280                                            struct nfsd3_diropres    *resp)
281 {
282         __be32  nfserr;
283
284         dprintk("nfsd: SYMLINK(3)  %s %.*s -> %.*s\n",
285                                 SVCFH_fmt(&argp->ffh),
286                                 argp->flen, argp->fname,
287                                 argp->tlen, argp->tname);
288
289         fh_copy(&resp->dirfh, &argp->ffh);
290         fh_init(&resp->fh, NFS3_FHSIZE);
291         nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen,
292                                                    argp->tname, argp->tlen,
293                                                    &resp->fh, &argp->attrs);
294         RETURN_STATUS(nfserr);
295 }
296
297 /*
298  * Make socket/fifo/device.
299  */
300 static __be32
301 nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
302                                          struct nfsd3_diropres  *resp)
303 {
304         __be32  nfserr;
305         int type;
306         dev_t   rdev = 0;
307
308         dprintk("nfsd: MKNOD(3)    %s %.*s\n",
309                                 SVCFH_fmt(&argp->fh),
310                                 argp->len,
311                                 argp->name);
312
313         fh_copy(&resp->dirfh, &argp->fh);
314         fh_init(&resp->fh, NFS3_FHSIZE);
315
316         if (argp->ftype == 0 || argp->ftype >= NF3BAD)
317                 RETURN_STATUS(nfserr_inval);
318         if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) {
319                 rdev = MKDEV(argp->major, argp->minor);
320                 if (MAJOR(rdev) != argp->major ||
321                     MINOR(rdev) != argp->minor)
322                         RETURN_STATUS(nfserr_inval);
323         } else
324                 if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO)
325                         RETURN_STATUS(nfserr_inval);
326
327         type = nfs3_ftypes[argp->ftype];
328         nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
329                                     &argp->attrs, type, rdev, &resp->fh);
330
331         RETURN_STATUS(nfserr);
332 }
333
334 /*
335  * Remove file/fifo/socket etc.
336  */
337 static __be32
338 nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
339                                           struct nfsd3_attrstat  *resp)
340 {
341         __be32  nfserr;
342
343         dprintk("nfsd: REMOVE(3)   %s %.*s\n",
344                                 SVCFH_fmt(&argp->fh),
345                                 argp->len,
346                                 argp->name);
347
348         /* Unlink. -S_IFDIR means file must not be a directory */
349         fh_copy(&resp->fh, &argp->fh);
350         nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
351         RETURN_STATUS(nfserr);
352 }
353
354 /*
355  * Remove a directory
356  */
357 static __be32
358 nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
359                                          struct nfsd3_attrstat  *resp)
360 {
361         __be32  nfserr;
362
363         dprintk("nfsd: RMDIR(3)    %s %.*s\n",
364                                 SVCFH_fmt(&argp->fh),
365                                 argp->len,
366                                 argp->name);
367
368         fh_copy(&resp->fh, &argp->fh);
369         nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len);
370         RETURN_STATUS(nfserr);
371 }
372
373 static __be32
374 nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
375                                           struct nfsd3_renameres  *resp)
376 {
377         __be32  nfserr;
378
379         dprintk("nfsd: RENAME(3)   %s %.*s ->\n",
380                                 SVCFH_fmt(&argp->ffh),
381                                 argp->flen,
382                                 argp->fname);
383         dprintk("nfsd: -> %s %.*s\n",
384                                 SVCFH_fmt(&argp->tfh),
385                                 argp->tlen,
386                                 argp->tname);
387
388         fh_copy(&resp->ffh, &argp->ffh);
389         fh_copy(&resp->tfh, &argp->tfh);
390         nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
391                                     &resp->tfh, argp->tname, argp->tlen);
392         RETURN_STATUS(nfserr);
393 }
394
395 static __be32
396 nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
397                                         struct nfsd3_linkres  *resp)
398 {
399         __be32  nfserr;
400
401         dprintk("nfsd: LINK(3)     %s ->\n",
402                                 SVCFH_fmt(&argp->ffh));
403         dprintk("nfsd:   -> %s %.*s\n",
404                                 SVCFH_fmt(&argp->tfh),
405                                 argp->tlen,
406                                 argp->tname);
407
408         fh_copy(&resp->fh,  &argp->ffh);
409         fh_copy(&resp->tfh, &argp->tfh);
410         nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
411                                   &resp->fh);
412         RETURN_STATUS(nfserr);
413 }
414
415 /*
416  * Read a portion of a directory.
417  */
418 static __be32
419 nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
420                                            struct nfsd3_readdirres  *resp)
421 {
422         __be32          nfserr;
423         int             count;
424
425         dprintk("nfsd: READDIR(3)  %s %d bytes at %d\n",
426                                 SVCFH_fmt(&argp->fh),
427                                 argp->count, (u32) argp->cookie);
428
429         /* Make sure we've room for the NULL ptr & eof flag, and shrink to
430          * client read size */
431         count = (argp->count >> 2) - 2;
432
433         /* Read directory and encode entries on the fly */
434         fh_copy(&resp->fh, &argp->fh);
435
436         resp->buflen = count;
437         resp->common.err = nfs_ok;
438         resp->buffer = argp->buffer;
439         resp->rqstp = rqstp;
440         nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie, 
441                                         &resp->common, nfs3svc_encode_entry);
442         memcpy(resp->verf, argp->verf, 8);
443         resp->count = resp->buffer - argp->buffer;
444         if (resp->offset)
445                 xdr_encode_hyper(resp->offset, argp->cookie);
446
447         RETURN_STATUS(nfserr);
448 }
449
450 /*
451  * Read a portion of a directory, including file handles and attrs.
452  * For now, we choose to ignore the dircount parameter.
453  */
454 static __be32
455 nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
456                                                struct nfsd3_readdirres  *resp)
457 {
458         __be32  nfserr;
459         int     count = 0;
460         loff_t  offset;
461         int     i;
462         caddr_t page_addr = NULL;
463
464         dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
465                                 SVCFH_fmt(&argp->fh),
466                                 argp->count, (u32) argp->cookie);
467
468         /* Convert byte count to number of words (i.e. >> 2),
469          * and reserve room for the NULL ptr & eof flag (-2 words) */
470         resp->count = (argp->count >> 2) - 2;
471
472         /* Read directory and encode entries on the fly */
473         fh_copy(&resp->fh, &argp->fh);
474
475         resp->common.err = nfs_ok;
476         resp->buffer = argp->buffer;
477         resp->buflen = resp->count;
478         resp->rqstp = rqstp;
479         offset = argp->cookie;
480         nfserr = nfsd_readdir(rqstp, &resp->fh,
481                                      &offset,
482                                      &resp->common,
483                                      nfs3svc_encode_entry_plus);
484         memcpy(resp->verf, argp->verf, 8);
485         for (i=1; i<rqstp->rq_resused ; i++) {
486                 page_addr = page_address(rqstp->rq_respages[i]);
487
488                 if (((caddr_t)resp->buffer >= page_addr) &&
489                     ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) {
490                         count += (caddr_t)resp->buffer - page_addr;
491                         break;
492                 }
493                 count += PAGE_SIZE;
494         }
495         resp->count = count >> 2;
496         if (resp->offset) {
497                 if (unlikely(resp->offset1)) {
498                         /* we ended up with offset on a page boundary */
499                         *resp->offset = htonl(offset >> 32);
500                         *resp->offset1 = htonl(offset & 0xffffffff);
501                         resp->offset1 = NULL;
502                 } else {
503                         xdr_encode_hyper(resp->offset, offset);
504                 }
505         }
506
507         RETURN_STATUS(nfserr);
508 }
509
510 /*
511  * Get file system stats
512  */
513 static __be32
514 nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
515                                            struct nfsd3_fsstatres *resp)
516 {
517         __be32  nfserr;
518
519         dprintk("nfsd: FSSTAT(3)   %s\n",
520                                 SVCFH_fmt(&argp->fh));
521
522         nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
523         fh_put(&argp->fh);
524         RETURN_STATUS(nfserr);
525 }
526
527 /*
528  * Get file system info
529  */
530 static __be32
531 nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
532                                            struct nfsd3_fsinfores *resp)
533 {
534         __be32  nfserr;
535         u32     max_blocksize = svc_max_payload(rqstp);
536
537         dprintk("nfsd: FSINFO(3)   %s\n",
538                                 SVCFH_fmt(&argp->fh));
539
540         resp->f_rtmax  = max_blocksize;
541         resp->f_rtpref = max_blocksize;
542         resp->f_rtmult = PAGE_SIZE;
543         resp->f_wtmax  = max_blocksize;
544         resp->f_wtpref = max_blocksize;
545         resp->f_wtmult = PAGE_SIZE;
546         resp->f_dtpref = PAGE_SIZE;
547         resp->f_maxfilesize = ~(u32) 0;
548         resp->f_properties = NFS3_FSF_DEFAULT;
549
550         nfserr = fh_verify(rqstp, &argp->fh, 0,
551                         NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
552
553         /* Check special features of the file system. May request
554          * different read/write sizes for file systems known to have
555          * problems with large blocks */
556         if (nfserr == 0) {
557                 struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
558
559                 /* Note that we don't care for remote fs's here */
560                 if (sb->s_magic == MSDOS_SUPER_MAGIC) {
561                         resp->f_properties = NFS3_FSF_BILLYBOY;
562                 }
563                 resp->f_maxfilesize = sb->s_maxbytes;
564         }
565
566         fh_put(&argp->fh);
567         RETURN_STATUS(nfserr);
568 }
569
570 /*
571  * Get pathconf info for the specified file
572  */
573 static __be32
574 nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle      *argp,
575                                              struct nfsd3_pathconfres *resp)
576 {
577         __be32  nfserr;
578
579         dprintk("nfsd: PATHCONF(3) %s\n",
580                                 SVCFH_fmt(&argp->fh));
581
582         /* Set default pathconf */
583         resp->p_link_max = 255;         /* at least */
584         resp->p_name_max = 255;         /* at least */
585         resp->p_no_trunc = 0;
586         resp->p_chown_restricted = 1;
587         resp->p_case_insensitive = 0;
588         resp->p_case_preserving = 1;
589
590         nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
591
592         if (nfserr == 0) {
593                 struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
594
595                 /* Note that we don't care for remote fs's here */
596                 switch (sb->s_magic) {
597                 case EXT2_SUPER_MAGIC:
598                         resp->p_link_max = EXT2_LINK_MAX;
599                         resp->p_name_max = EXT2_NAME_LEN;
600                         break;
601                 case MSDOS_SUPER_MAGIC:
602                         resp->p_case_insensitive = 1;
603                         resp->p_case_preserving  = 0;
604                         break;
605                 }
606         }
607
608         fh_put(&argp->fh);
609         RETURN_STATUS(nfserr);
610 }
611
612
613 /*
614  * Commit a file (range) to stable storage.
615  */
616 static __be32
617 nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp,
618                                            struct nfsd3_commitres  *resp)
619 {
620         __be32  nfserr;
621
622         dprintk("nfsd: COMMIT(3)   %s %u@%Lu\n",
623                                 SVCFH_fmt(&argp->fh),
624                                 argp->count,
625                                 (unsigned long long) argp->offset);
626
627         if (argp->offset > NFS_OFFSET_MAX)
628                 RETURN_STATUS(nfserr_inval);
629
630         fh_copy(&resp->fh, &argp->fh);
631         nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count);
632
633         RETURN_STATUS(nfserr);
634 }
635
636
637 /*
638  * NFSv3 Server procedures.
639  * Only the results of non-idempotent operations are cached.
640  */
641 #define nfs3svc_decode_fhandleargs      nfs3svc_decode_fhandle
642 #define nfs3svc_encode_attrstatres      nfs3svc_encode_attrstat
643 #define nfs3svc_encode_wccstatres       nfs3svc_encode_wccstat
644 #define nfsd3_mkdirargs                 nfsd3_createargs
645 #define nfsd3_readdirplusargs           nfsd3_readdirargs
646 #define nfsd3_fhandleargs               nfsd_fhandle
647 #define nfsd3_fhandleres                nfsd3_attrstat
648 #define nfsd3_attrstatres               nfsd3_attrstat
649 #define nfsd3_wccstatres                nfsd3_attrstat
650 #define nfsd3_createres                 nfsd3_diropres
651 #define nfsd3_voidres                   nfsd3_voidargs
652 struct nfsd3_voidargs { int dummy; };
653
654 #define PROC(name, argt, rest, relt, cache, respsize)   \
655  { (svc_procfunc) nfsd3_proc_##name,            \
656    (kxdrproc_t) nfs3svc_decode_##argt##args,    \
657    (kxdrproc_t) nfs3svc_encode_##rest##res,     \
658    (kxdrproc_t) nfs3svc_release_##relt,         \
659    sizeof(struct nfsd3_##argt##args),           \
660    sizeof(struct nfsd3_##rest##res),            \
661    0,                                           \
662    cache,                                       \
663    respsize,                                    \
664  }
665
666 #define ST 1            /* status*/
667 #define FH 17           /* filehandle with length */
668 #define AT 21           /* attributes */
669 #define pAT (1+AT)      /* post attributes - conditional */
670 #define WC (7+pAT)      /* WCC attributes */
671
672 static struct svc_procedure             nfsd_procedures3[22] = {
673         [NFS3PROC_NULL] = {
674                 .pc_func = (svc_procfunc) nfsd3_proc_null,
675                 .pc_encode = (kxdrproc_t) nfs3svc_encode_voidres,
676                 .pc_argsize = sizeof(struct nfsd3_voidargs),
677                 .pc_ressize = sizeof(struct nfsd3_voidres),
678                 .pc_cachetype = RC_NOCACHE,
679                 .pc_xdrressize = ST,
680         },
681         [NFS3PROC_GETATTR] = {
682                 .pc_func = (svc_procfunc) nfsd3_proc_getattr,
683                 .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
684                 .pc_encode = (kxdrproc_t) nfs3svc_encode_attrstatres,
685                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
686                 .pc_argsize = sizeof(struct nfsd3_fhandleargs),
687                 .pc_ressize = sizeof(struct nfsd3_attrstatres),
688                 .pc_cachetype = RC_NOCACHE,
689                 .pc_xdrressize = ST+AT,
690         },
691         [NFS3PROC_SETATTR] = {
692                 .pc_func = (svc_procfunc) nfsd3_proc_setattr,
693                 .pc_decode = (kxdrproc_t) nfs3svc_decode_sattrargs,
694                 .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
695                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
696                 .pc_argsize = sizeof(struct nfsd3_sattrargs),
697                 .pc_ressize = sizeof(struct nfsd3_wccstatres),
698                 .pc_cachetype = RC_REPLBUFF,
699                 .pc_xdrressize = ST+WC,
700         },
701         [NFS3PROC_LOOKUP] = {
702                 .pc_func = (svc_procfunc) nfsd3_proc_lookup,
703                 .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
704                 .pc_encode = (kxdrproc_t) nfs3svc_encode_diropres,
705                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
706                 .pc_argsize = sizeof(struct nfsd3_diropargs),
707                 .pc_ressize = sizeof(struct nfsd3_diropres),
708                 .pc_cachetype = RC_NOCACHE,
709                 .pc_xdrressize = ST+FH+pAT+pAT,
710         },
711         [NFS3PROC_ACCESS] = {
712                 .pc_func = (svc_procfunc) nfsd3_proc_access,
713                 .pc_decode = (kxdrproc_t) nfs3svc_decode_accessargs,
714                 .pc_encode = (kxdrproc_t) nfs3svc_encode_accessres,
715                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
716                 .pc_argsize = sizeof(struct nfsd3_accessargs),
717                 .pc_ressize = sizeof(struct nfsd3_accessres),
718                 .pc_cachetype = RC_NOCACHE,
719                 .pc_xdrressize = ST+pAT+1,
720         },
721         [NFS3PROC_READLINK] = {
722                 .pc_func = (svc_procfunc) nfsd3_proc_readlink,
723                 .pc_decode = (kxdrproc_t) nfs3svc_decode_readlinkargs,
724                 .pc_encode = (kxdrproc_t) nfs3svc_encode_readlinkres,
725                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
726                 .pc_argsize = sizeof(struct nfsd3_readlinkargs),
727                 .pc_ressize = sizeof(struct nfsd3_readlinkres),
728                 .pc_cachetype = RC_NOCACHE,
729                 .pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4,
730         },
731         [NFS3PROC_READ] = {
732                 .pc_func = (svc_procfunc) nfsd3_proc_read,
733                 .pc_decode = (kxdrproc_t) nfs3svc_decode_readargs,
734                 .pc_encode = (kxdrproc_t) nfs3svc_encode_readres,
735                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
736                 .pc_argsize = sizeof(struct nfsd3_readargs),
737                 .pc_ressize = sizeof(struct nfsd3_readres),
738                 .pc_cachetype = RC_NOCACHE,
739                 .pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4,
740         },
741         [NFS3PROC_WRITE] = {
742                 .pc_func = (svc_procfunc) nfsd3_proc_write,
743                 .pc_decode = (kxdrproc_t) nfs3svc_decode_writeargs,
744                 .pc_encode = (kxdrproc_t) nfs3svc_encode_writeres,
745                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
746                 .pc_argsize = sizeof(struct nfsd3_writeargs),
747                 .pc_ressize = sizeof(struct nfsd3_writeres),
748                 .pc_cachetype = RC_REPLBUFF,
749                 .pc_xdrressize = ST+WC+4,
750         },
751         [NFS3PROC_CREATE] = {
752                 .pc_func = (svc_procfunc) nfsd3_proc_create,
753                 .pc_decode = (kxdrproc_t) nfs3svc_decode_createargs,
754                 .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
755                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
756                 .pc_argsize = sizeof(struct nfsd3_createargs),
757                 .pc_ressize = sizeof(struct nfsd3_createres),
758                 .pc_cachetype = RC_REPLBUFF,
759                 .pc_xdrressize = ST+(1+FH+pAT)+WC,
760         },
761         [NFS3PROC_MKDIR] = {
762                 .pc_func = (svc_procfunc) nfsd3_proc_mkdir,
763                 .pc_decode = (kxdrproc_t) nfs3svc_decode_mkdirargs,
764                 .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
765                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
766                 .pc_argsize = sizeof(struct nfsd3_mkdirargs),
767                 .pc_ressize = sizeof(struct nfsd3_createres),
768                 .pc_cachetype = RC_REPLBUFF,
769                 .pc_xdrressize = ST+(1+FH+pAT)+WC,
770         },
771         [NFS3PROC_SYMLINK] = {
772                 .pc_func = (svc_procfunc) nfsd3_proc_symlink,
773                 .pc_decode = (kxdrproc_t) nfs3svc_decode_symlinkargs,
774                 .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
775                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
776                 .pc_argsize = sizeof(struct nfsd3_symlinkargs),
777                 .pc_ressize = sizeof(struct nfsd3_createres),
778                 .pc_cachetype = RC_REPLBUFF,
779                 .pc_xdrressize = ST+(1+FH+pAT)+WC,
780         },
781         [NFS3PROC_MKNOD] = {
782                 .pc_func = (svc_procfunc) nfsd3_proc_mknod,
783                 .pc_decode = (kxdrproc_t) nfs3svc_decode_mknodargs,
784                 .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
785                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
786                 .pc_argsize = sizeof(struct nfsd3_mknodargs),
787                 .pc_ressize = sizeof(struct nfsd3_createres),
788                 .pc_cachetype = RC_REPLBUFF,
789                 .pc_xdrressize = ST+(1+FH+pAT)+WC,
790         },
791         [NFS3PROC_REMOVE] = {
792                 .pc_func = (svc_procfunc) nfsd3_proc_remove,
793                 .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
794                 .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
795                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
796                 .pc_argsize = sizeof(struct nfsd3_diropargs),
797                 .pc_ressize = sizeof(struct nfsd3_wccstatres),
798                 .pc_cachetype = RC_REPLBUFF,
799                 .pc_xdrressize = ST+WC,
800         },
801         [NFS3PROC_RMDIR] = {
802                 .pc_func = (svc_procfunc) nfsd3_proc_rmdir,
803                 .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
804                 .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
805                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
806                 .pc_argsize = sizeof(struct nfsd3_diropargs),
807                 .pc_ressize = sizeof(struct nfsd3_wccstatres),
808                 .pc_cachetype = RC_REPLBUFF,
809                 .pc_xdrressize = ST+WC,
810         },
811         [NFS3PROC_RENAME] = {
812                 .pc_func = (svc_procfunc) nfsd3_proc_rename,
813                 .pc_decode = (kxdrproc_t) nfs3svc_decode_renameargs,
814                 .pc_encode = (kxdrproc_t) nfs3svc_encode_renameres,
815                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
816                 .pc_argsize = sizeof(struct nfsd3_renameargs),
817                 .pc_ressize = sizeof(struct nfsd3_renameres),
818                 .pc_cachetype = RC_REPLBUFF,
819                 .pc_xdrressize = ST+WC+WC,
820         },
821         [NFS3PROC_LINK] = {
822                 .pc_func = (svc_procfunc) nfsd3_proc_link,
823                 .pc_decode = (kxdrproc_t) nfs3svc_decode_linkargs,
824                 .pc_encode = (kxdrproc_t) nfs3svc_encode_linkres,
825                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
826                 .pc_argsize = sizeof(struct nfsd3_linkargs),
827                 .pc_ressize = sizeof(struct nfsd3_linkres),
828                 .pc_cachetype = RC_REPLBUFF,
829                 .pc_xdrressize = ST+pAT+WC,
830         },
831         [NFS3PROC_READDIR] = {
832                 .pc_func = (svc_procfunc) nfsd3_proc_readdir,
833                 .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirargs,
834                 .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres,
835                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
836                 .pc_argsize = sizeof(struct nfsd3_readdirargs),
837                 .pc_ressize = sizeof(struct nfsd3_readdirres),
838                 .pc_cachetype = RC_NOCACHE,
839         },
840         [NFS3PROC_READDIRPLUS] = {
841                 .pc_func = (svc_procfunc) nfsd3_proc_readdirplus,
842                 .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirplusargs,
843                 .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres,
844                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
845                 .pc_argsize = sizeof(struct nfsd3_readdirplusargs),
846                 .pc_ressize = sizeof(struct nfsd3_readdirres),
847                 .pc_cachetype = RC_NOCACHE,
848         },
849         [NFS3PROC_FSSTAT] = {
850                 .pc_func = (svc_procfunc) nfsd3_proc_fsstat,
851                 .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
852                 .pc_encode = (kxdrproc_t) nfs3svc_encode_fsstatres,
853                 .pc_argsize = sizeof(struct nfsd3_fhandleargs),
854                 .pc_ressize = sizeof(struct nfsd3_fsstatres),
855                 .pc_cachetype = RC_NOCACHE,
856                 .pc_xdrressize = ST+pAT+2*6+1,
857         },
858         [NFS3PROC_FSINFO] = {
859                 .pc_func = (svc_procfunc) nfsd3_proc_fsinfo,
860                 .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
861                 .pc_encode = (kxdrproc_t) nfs3svc_encode_fsinfores,
862                 .pc_argsize = sizeof(struct nfsd3_fhandleargs),
863                 .pc_ressize = sizeof(struct nfsd3_fsinfores),
864                 .pc_cachetype = RC_NOCACHE,
865                 .pc_xdrressize = ST+pAT+12,
866         },
867         [NFS3PROC_PATHCONF] = {
868                 .pc_func = (svc_procfunc) nfsd3_proc_pathconf,
869                 .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
870                 .pc_encode = (kxdrproc_t) nfs3svc_encode_pathconfres,
871                 .pc_argsize = sizeof(struct nfsd3_fhandleargs),
872                 .pc_ressize = sizeof(struct nfsd3_pathconfres),
873                 .pc_cachetype = RC_NOCACHE,
874                 .pc_xdrressize = ST+pAT+6,
875         },
876         [NFS3PROC_COMMIT] = {
877                 .pc_func = (svc_procfunc) nfsd3_proc_commit,
878                 .pc_decode = (kxdrproc_t) nfs3svc_decode_commitargs,
879                 .pc_encode = (kxdrproc_t) nfs3svc_encode_commitres,
880                 .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
881                 .pc_argsize = sizeof(struct nfsd3_commitargs),
882                 .pc_ressize = sizeof(struct nfsd3_commitres),
883                 .pc_cachetype = RC_NOCACHE,
884                 .pc_xdrressize = ST+WC+2,
885         },
886 };
887
888 struct svc_version      nfsd_version3 = {
889                 .vs_vers        = 3,
890                 .vs_nproc       = 22,
891                 .vs_proc        = nfsd_procedures3,
892                 .vs_dispatch    = nfsd_dispatch,
893                 .vs_xdrsize     = NFS3_SVC_XDRSIZE,
894 };