2 * linux/fs/nfsd/nfs3proc.c
4 * Process version 3 NFS requests.
6 * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de>
9 #include <linux/linkage.h>
10 #include <linux/sched.h>
11 #include <linux/errno.h>
12 #include <linux/locks.h>
14 #include <linux/stat.h>
15 #include <linux/fcntl.h>
16 #include <linux/net.h>
18 #include <linux/version.h>
19 #include <linux/unistd.h>
20 #include <linux/malloc.h>
22 #include <linux/sunrpc/svc.h>
23 #include <linux/nfsd/nfsd.h>
24 #include <linux/nfsd/cache.h>
25 #include <linux/nfsd/xdr3.h>
27 typedef struct svc_rqst svc_rqst
;
28 typedef struct svc_buf svc_buf
;
30 #define NFSDDBG_FACILITY NFSDDBG_PROC
32 #define RETURN(st) { resp->status = (st); return (st); }
35 svcbuf_reserve(struct svc_buf
*buf
, u32
**ptr
, int *len
, int nr
)
38 *len
= buf
->buflen
- buf
->len
- nr
;
42 nfsd3_proc_null(struct svc_rqst
*rqstp
, void *argp
, void *resp
)
48 * Get a file's attributes
49 * N.B. After this call resp->fh needs an fh_put
52 nfsd3_proc_getattr(struct svc_rqst
*rqstp
, struct nfsd_fhandle
*argp
,
53 struct nfsd3_attrstat
*resp
)
57 dprintk("nfsd: GETATTR %x/%ld\n",
59 SVCFH_INO(&argp
->fh
));
62 nfserr
= fh_verify(rqstp
, &resp
->fh
, 0, MAY_NOP
);
67 * Set a file's attributes
68 * N.B. After this call resp->fh needs an fh_put
71 nfsd3_proc_setattr(struct svc_rqst
*rqstp
, struct nfsd3_sattrargs
*argp
,
72 struct nfsd3_attrstat
*resp
)
76 dprintk("nfsd: SETATTR %x/%ld\n",
78 SVCFH_INO(&argp
->fh
));
81 nfserr
= nfsd_setattr(rqstp
, &resp
->fh
, &argp
->attrs
);
86 * Look up a path name component
87 * N.B. After this call _both_ resp->dirfh and resp->fh need an fh_put
90 nfsd3_proc_lookup(struct svc_rqst
*rqstp
, struct nfsd3_diropargs
*argp
,
91 struct nfsd3_lookupres
*resp
)
95 dprintk("nfsd: LOOKUP %x/%ld %s\n",
100 resp
->dirfh
= argp
->fh
;
101 nfserr
= nfsd_lookup(rqstp
, &resp
->dirfh
,
112 nfsd3_proc_access(struct svc_rqst
*rqstp
, struct nfsd_fhandle
*argp
,
113 struct nfsd3_accessres
*resp
)
117 return nfserr_notsupp
;
124 nfsd3_proc_readlink(struct svc_rqst
*rqstp
, struct nfsd_fhandle
*argp
,
125 struct nfsd3_readlinkres
*resp
)
130 dprintk("nfsd: READLINK %x/%ld\n",
131 SVCFH_DEV(&argp
->fh
),
132 SVCFH_INO(&argp
->fh
));
134 /* Reserve room for status, post_op_attr, and path length */
135 svcbuf_reserve(&rqstp
->rq_resbuf
, &path
, &dummy
, 1 + 22 + 1);
137 /* Read the symlink. */
138 resp
->len
= NFS3_MAXPATHLEN
;
139 nfserr
= nfsd_readlink(rqstp
, &argp
->fh
, (char *) path
, &resp
->len
);
145 * Read a portion of a file.
146 * N.B. After this call resp->fh needs an fh_put
149 nfsd3_proc_read(struct svc_rqst
*rqstp
, struct nfsd3_readargs
*argp
,
150 struct nfsd3_readres
*resp
)
155 dprintk("nfsd: READ %x/%ld %lu bytes at %lu\n",
156 SVCFH_DEV(&argp
->fh
),
157 SVCFH_INO(&argp
->fh
),
158 (unsigned long) argp
->count
,
159 (unsigned long) argp
->offset
);
161 /* Obtain buffer pointer for payload.
162 * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
163 * + 1 (xdr opaque byte count) = 26
165 svcbuf_reserve(&rqstp
->rq_resbuf
, &buffer
, &avail
, 26);
167 if ((avail
<< 2) < argp
->count
) {
169 "oversized read request from %08lx:%d (%d bytes)\n",
170 ntohl(rqstp
->rq_addr
.sin_addr
.s_addr
),
171 ntohs(rqstp
->rq_addr
.sin_port
),
176 resp
->count
= argp
->count
;
178 nfserr
= nfsd_read(rqstp
, &resp
->fh
,
187 * Write data to a file
188 * N.B. After this call resp->fh needs an fh_put
191 nfsd3_proc_write(struct svc_rqst
*rqstp
, struct nfsd3_writeargs
*argp
,
192 struct nfsd3_writeres
*resp
)
196 dprintk("nfsd: WRITE %x/%ld %d bytes at %ld\n",
197 SVCFH_DEV(&argp
->fh
),
198 SVCFH_INO(&argp
->fh
),
200 (unsigned long) argp
->offset
);
203 nfserr
= nfsd_write(rqstp
, &resp
->fh
,
208 resp
->committed
= argp
->stable
;
213 * With NFSv3, CREATE processing is a lot easier than with NFSv2.
214 * At least in theory; we'll see how it fares in practice when the
215 * first reports about SunOS compatibility problems start to pour in...
216 * N.B. After this call _both_ resp->dirfh and resp->fh need an fh_put
219 nfsd3_proc_create(struct svc_rqst
*rqstp
, struct nfsd3_createargs
*argp
,
220 struct nfsd3_createres
*resp
)
222 svc_fh
*dirfhp
, *newfhp
= NULL
;
227 dprintk("nfsd: CREATE %x/%ld %s\n",
228 SVCFH_DEV(&argp
->fh
),
229 SVCFH_INO(&argp
->fh
),
232 dirfhp
= fh_copy(&resp
->dirfh
, &argp
->fh
);
233 newfhp
= fh_init(&resp
->fh
);
236 /* Get the directory inode */
237 nfserr
= fh_verify(rqstp
, dirfhp
, S_IFDIR
, MAY_CREATE
);
241 /* Unfudge the mode bits */
242 attr
->ia_mode
&= ~S_IFMT
;
243 if (!(attr
->ia_valid
& ATTR_MODE
)) {
244 attr
->ia_valid
|= ATTR_MODE
;
245 attr
->ia_mode
= S_IFREG
;
247 mode
= attr
->ia_mode
& ~S_IFMT
;
249 /* Now create the file and set attributes */
250 nfserr
= nfsd_create(rqstp
, dirfhp
, argp
->name
, argp
->len
,
251 attr
, S_IFREG
, 0, newfhp
);
256 /* N.B. Is nfsd3_attrstat * correct for resp?? table says "void" */
258 nfsd3_proc_remove(struct svc_rqst
*rqstp
, struct nfsd3_diropargs
*argp
,
259 struct nfsd3_attrstat
*resp
)
263 dprintk("nfsd: REMOVE %x/%ld %s\n",
264 SVCFH_DEV(&argp
->fh
),
265 SVCFH_INO(&argp
->fh
),
268 /* Is this correct?? */
269 fh_copy(&resp
->fh
, &argp
->fh
);
271 /* Unlink. -S_IFDIR means file must not be a directory */
272 nfserr
= nfsd_unlink(rqstp
, &resp
->fh
, -S_IFDIR
, argp
->name
, argp
->len
);
274 * N.B. Should be an fh_put here ... nfsd3_proc_rmdir has one,
275 * or else as an xdr release function
282 nfsd3_proc_rename(struct svc_rqst
*rqstp
, struct nfsd3_renameargs
*argp
,
287 dprintk("nfsd: RENAME %x/%ld %s -> %x/%ld %s\n",
288 SVCFH_DEV(&argp
->ffh
),
289 SVCFH_INO(&argp
->ffh
),
291 SVCFH_DEV(&argp
->tfh
),
292 SVCFH_INO(&argp
->tfh
),
295 nfserr
= nfsd_rename(rqstp
, &argp
->ffh
, argp
->fname
, argp
->flen
,
296 &argp
->tfh
, argp
->tname
, argp
->tlen
);
303 nfsd3_proc_link(struct svc_rqst
*rqstp
, struct nfsd3_linkargs
*argp
,
308 dprintk("nfsd: LINK %x/%ld -> %x/%ld %s\n",
309 SVCFH_DEV(&argp
->ffh
),
310 SVCFH_INO(&argp
->ffh
),
311 SVCFH_DEV(&argp
->tfh
),
312 SVCFH_INO(&argp
->tfh
),
315 nfserr
= nfsd_link(rqstp
, &argp
->tfh
, argp
->tname
, argp
->tlen
,
323 nfsd3_proc_symlink(struct svc_rqst
*rqstp
, struct nfsd3_symlinkargs
*argp
,
329 dprintk("nfsd: SYMLINK %x/%ld %s -> %s\n",
330 SVCFH_DEV(&argp
->ffh
),
331 SVCFH_INO(&argp
->ffh
),
332 argp
->fname
, argp
->tname
);
334 memset(&newfh
, 0, sizeof(newfh
));
337 * Create the link, look up new file and set attrs.
339 nfserr
= nfsd_symlink(rqstp
, &argp
->ffh
, argp
->fname
, argp
->flen
,
340 argp
->tname
, argp
->tlen
,
343 argp
->attrs
.ia_valid
&= ~ATTR_SIZE
;
344 nfserr
= nfsd_setattr(rqstp
, &newfh
, &argp
->attrs
);
353 * Make directory. This operation is not idempotent.
354 * N.B. After this call resp->fh needs an fh_put
357 nfsd3_proc_mkdir(struct svc_rqst
*rqstp
, struct nfsd3_createargs
*argp
,
358 struct nfsd3_diropres
*resp
)
362 dprintk("nfsd: MKDIR %x/%ld %s\n",
363 SVCFH_DEV(&argp
->fh
),
364 SVCFH_INO(&argp
->fh
),
367 argp
->attrs
.ia_valid
&= ~ATTR_SIZE
;
368 nfserr
= nfsd_create(rqstp
, &argp
->fh
, argp
->name
, argp
->len
,
369 &argp
->attrs
, S_IFDIR
, 0, &resp
->fh
);
378 nfsd3_proc_rmdir(struct svc_rqst
*rqstp
, struct nfsd3_diropargs
*argp
,
383 dprintk("nfsd: RMDIR %x/%ld %s\n",
384 SVCFH_DEV(&argp
->fh
),
385 SVCFH_INO(&argp
->fh
),
388 nfserr
= nfsd_unlink(rqstp
, &argp
->fh
, S_IFDIR
, argp
->name
, argp
->len
);
394 * Read a portion of a directory.
397 nfsd3_proc_readdir(struct svc_rqst
*rqstp
, struct nfsd3_readdirargs
*argp
,
398 struct nfsd3_readdirres
*resp
)
403 dprintk("nfsd: READDIR %x/%ld %d bytes at %d\n",
404 SVCFH_DEV(&argp
->fh
),
405 SVCFH_INO(&argp
->fh
),
406 argp
->count
, argp
->cookie
);
408 /* Reserve buffer space for status */
409 svcbuf_reserve(&rqstp
->rq_resbuf
, &buffer
, &count
, 1);
411 /* Make sure we've room for the NULL ptr & eof flag, and shrink to
412 * client read size */
413 if ((count
-= 8) > argp
->count
)
416 /* Read directory and encode entries on the fly */
417 nfserr
= nfsd_readdir(rqstp
, &argp
->fh
, (loff_t
) argp
->cookie
,
427 * Get file system info
430 nfsd3_proc_statfs(struct svc_rqst
* rqstp
, struct nfsd_fhandle
*argp
,
431 struct nfsd3_statfsres
*resp
)
435 dprintk("nfsd: STATFS %x/%ld\n",
436 SVCFH_DEV(&argp
->fh
),
437 SVCFH_INO(&argp
->fh
));
439 nfserr
= nfsd_statfs(rqstp
, &argp
->fh
, &resp
->stats
);
445 * NFSv2 Server procedures.
446 * Only the results of non-idempotent operations are cached.
448 #define nfsd3_proc_none NULL
449 #define nfssvc_encode_void NULL
450 #define nfssvc_decode_void NULL
451 #define nfssvc_release_void NULL
452 struct nfsd3_void
{ int dummy
; };
454 #define PROC(name, argt, rest, relt, cache) \
455 { (svc_procfunc) nfsd3_proc_##name, \
456 (kxdrproc_t) nfssvc_decode_##argt, \
457 (kxdrproc_t) nfssvc_encode_##rest, \
458 (kxdrproc_t) nfssvc_release_##relt, \
459 sizeof(struct nfsd3_##argt), \
460 sizeof(struct nfsd3_##rest), \
464 struct svc_procedure nfsd3_procedures2
[18] = {
465 PROC(null
, void, void, void, RC_NOCACHE
),
466 PROC(getattr
, fhandle
, attrstat
, fhandle
, RC_NOCACHE
),
467 PROC(setattr
, sattrargs
, attrstat
, fhandle
, RC_REPLBUFF
),
468 PROC(none
, void, void, void, RC_NOCACHE
),
469 PROC(lookup
, diropargs
, diropres
, fhandle2
,RC_NOCACHE
),
470 PROC(readlink
, fhandle
, readlinkres
, void, RC_NOCACHE
),
471 PROC(read
, readargs
, readres
, fhandle
, RC_NOCACHE
),
472 PROC(none
, void, void, void, RC_NOCACHE
),
473 PROC(write
, writeargs
, attrstat
, fhandle
, RC_REPLBUFF
),
474 PROC(create
, createargs
, diropres
, fhandle2
,RC_REPLBUFF
),
475 PROC(remove
, diropargs
, void,/* ??*/ void, RC_REPLSTAT
),
476 PROC(rename
, renameargs
, void, void, RC_REPLSTAT
),
477 PROC(link
, linkargs
, void, void, RC_REPLSTAT
),
478 PROC(symlink
, symlinkargs
, void, void, RC_REPLSTAT
),
479 PROC(mkdir
, createargs
, diropres
, fhandle
, RC_REPLBUFF
),
480 PROC(rmdir
, diropargs
, void, void, RC_REPLSTAT
),
481 PROC(readdir
, readdirargs
, readdirres
, void, RC_REPLSTAT
),
482 PROC(statfs
, fhandle
, statfsres
, void, RC_NOCACHE
),
487 * Map errnos to NFS errnos.
497 { NFSERR_PERM
, EPERM
},
498 { NFSERR_NOENT
, ENOENT
},
500 { NFSERR_NXIO
, ENXIO
},
501 { NFSERR_ACCES
, EACCES
},
502 { NFSERR_EXIST
, EEXIST
},
503 { NFSERR_NODEV
, ENODEV
},
504 { NFSERR_NOTDIR
, ENOTDIR
},
505 { NFSERR_ISDIR
, EISDIR
},
506 { NFSERR_INVAL
, EINVAL
},
507 { NFSERR_FBIG
, EFBIG
},
508 { NFSERR_NOSPC
, ENOSPC
},
509 { NFSERR_ROFS
, EROFS
},
510 { NFSERR_NAMETOOLONG
, ENAMETOOLONG
},
511 { NFSERR_NOTEMPTY
, ENOTEMPTY
},
513 { NFSERR_DQUOT
, EDQUOT
},
515 { NFSERR_STALE
, ESTALE
},
516 { NFSERR_WFLUSH
, EIO
},
521 for (i
= 0; nfs_errtbl
[i
].nfserr
!= -1; i
++) {
522 if (nfs_errtbl
[i
].syserr
== errno
)
523 return htonl (nfs_errtbl
[i
].nfserr
);
525 printk (KERN_INFO
"nfsd: non-standard errno: %d\n", errno
);
531 nfsd3_dump(char *tag
, u32
*buf
, int len
)
536 "nfsd: %s (%d words)\n", tag
, len
);
538 for (i
= 0; i
< len
&& i
< 32; i
+= 8)
540 " %08lx %08lx %08lx %08lx"
541 " %08lx %08lx %08lx %08lx\n",
542 buf
[i
], buf
[i
+1], buf
[i
+2], buf
[i
+3],
543 buf
[i
+4], buf
[i
+5], buf
[i
+6], buf
[i
+7]);