Linux-2.3.3 and a short hiatus..
[davej-history.git] / fs / nfsd / nfs3proc.c
blob5396a784fb715baa1ede2901e7795f3574546381
1 /*
2 * linux/fs/nfsd/nfs3proc.c
4 * Process version 3 NFS requests.
6 * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de>
7 */
9 #include <linux/linkage.h>
10 #include <linux/sched.h>
11 #include <linux/errno.h>
12 #include <linux/locks.h>
13 #include <linux/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/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); }
34 static void
35 svcbuf_reserve(struct svc_buf *buf, u32 **ptr, int *len, int nr)
37 *ptr = buf->buf + nr;
38 *len = buf->buflen - buf->len - nr;
41 static int
42 nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
44 return nfs_ok;
48 * Get a file's attributes
49 * N.B. After this call resp->fh needs an fh_put
51 static int
52 nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
53 struct nfsd3_attrstat *resp)
55 int nfserr;
57 dprintk("nfsd: GETATTR %x/%ld\n",
58 SVCFH_DEV(&argp->fh),
59 SVCFH_INO(&argp->fh));
61 resp->fh = argp->fh;
62 nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
63 RETURN(nfserr);
67 * Set a file's attributes
68 * N.B. After this call resp->fh needs an fh_put
70 static int
71 nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
72 struct nfsd3_attrstat *resp)
74 int nfserr;
76 dprintk("nfsd: SETATTR %x/%ld\n",
77 SVCFH_DEV(&argp->fh),
78 SVCFH_INO(&argp->fh));
80 resp->fh = argp->fh;
81 nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs);
82 RETURN(nfserr);
86 * Look up a path name component
87 * N.B. After this call _both_ resp->dirfh and resp->fh need an fh_put
89 static int
90 nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
91 struct nfsd3_lookupres *resp)
93 int nfserr;
95 dprintk("nfsd: LOOKUP %x/%ld %s\n",
96 SVCFH_DEV(&argp->fh),
97 SVCFH_INO(&argp->fh),
98 argp->name);
100 resp->dirfh = argp->fh;
101 nfserr = nfsd_lookup(rqstp, &resp->dirfh,
102 argp->name,
103 argp->len,
104 &resp->fh);
105 RETURN(nfserr);
109 * Check file access
111 static int
112 nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
113 struct nfsd3_accessres *resp)
115 /* to be done */
116 resp->fh = argp->fh;
117 return nfserr_notsupp;
121 * Read a symlink.
123 static int
124 nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
125 struct nfsd3_readlinkres *resp)
127 u32 *path;
128 int dummy, nfserr;
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);
140 fh_put(&argp->fh);
141 RETURN(nfserr);
145 * Read a portion of a file.
146 * N.B. After this call resp->fh needs an fh_put
148 static int
149 nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
150 struct nfsd3_readres *resp)
152 u32 * buffer;
153 int nfserr, avail;
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) {
168 printk(KERN_NOTICE
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),
172 argp->count);
173 argp->count = avail;
176 resp->count = argp->count;
177 resp->fh = argp->fh;
178 nfserr = nfsd_read(rqstp, &resp->fh,
179 argp->offset,
180 (char *) buffer,
181 &resp->count);
183 RETURN(nfserr);
187 * Write data to a file
188 * N.B. After this call resp->fh needs an fh_put
190 static int
191 nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
192 struct nfsd3_writeres *resp)
194 int nfserr;
196 dprintk("nfsd: WRITE %x/%ld %d bytes at %ld\n",
197 SVCFH_DEV(&argp->fh),
198 SVCFH_INO(&argp->fh),
199 argp->len,
200 (unsigned long) argp->offset);
202 resp->fh = argp->fh;
203 nfserr = nfsd_write(rqstp, &resp->fh,
204 argp->offset,
205 argp->data,
206 argp->len,
207 argp->stable);
208 resp->committed = argp->stable;
209 RETURN(nfserr);
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
218 static int
219 nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
220 struct nfsd3_createres *resp)
222 svc_fh *dirfhp, *newfhp = NULL;
223 struct iattr *attr;
224 int mode;
225 u32 nfserr;
227 dprintk("nfsd: CREATE %x/%ld %s\n",
228 SVCFH_DEV(&argp->fh),
229 SVCFH_INO(&argp->fh),
230 argp->name);
232 dirfhp = fh_copy(&resp->dirfh, &argp->fh);
233 newfhp = fh_init(&resp->fh);
234 attr = &argp->attrs;
236 /* Get the directory inode */
237 nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_CREATE);
238 if (nfserr)
239 RETURN(nfserr);
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);
253 RETURN(nfserr);
256 /* N.B. Is nfsd3_attrstat * correct for resp?? table says "void" */
257 static int
258 nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
259 struct nfsd3_attrstat *resp)
261 int nfserr;
263 dprintk("nfsd: REMOVE %x/%ld %s\n",
264 SVCFH_DEV(&argp->fh),
265 SVCFH_INO(&argp->fh),
266 argp->name);
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
277 fh_put(&resp->fh);
278 RETURN(nfserr);
281 static int
282 nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
283 void *resp)
285 int nfserr;
287 dprintk("nfsd: RENAME %x/%ld %s -> %x/%ld %s\n",
288 SVCFH_DEV(&argp->ffh),
289 SVCFH_INO(&argp->ffh),
290 argp->fname,
291 SVCFH_DEV(&argp->tfh),
292 SVCFH_INO(&argp->tfh),
293 argp->tname);
295 nfserr = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
296 &argp->tfh, argp->tname, argp->tlen);
297 fh_put(&argp->ffh);
298 fh_put(&argp->tfh);
299 RETURN(nfserr);
302 static int
303 nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
304 void *resp)
306 int nfserr;
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),
313 argp->tname);
315 nfserr = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
316 &argp->ffh);
317 fh_put(&argp->ffh);
318 fh_put(&argp->tfh);
319 RETURN(nfserr);
322 static int
323 nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
324 void *resp)
326 struct svc_fh newfh;
327 int nfserr;
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,
341 &newfh);
342 if (!nfserr) {
343 argp->attrs.ia_valid &= ~ATTR_SIZE;
344 nfserr = nfsd_setattr(rqstp, &newfh, &argp->attrs);
347 fh_put(&argp->ffh);
348 fh_put(&newfh);
349 RETURN(nfserr);
353 * Make directory. This operation is not idempotent.
354 * N.B. After this call resp->fh needs an fh_put
356 static int
357 nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
358 struct nfsd3_diropres *resp)
360 int nfserr;
362 dprintk("nfsd: MKDIR %x/%ld %s\n",
363 SVCFH_DEV(&argp->fh),
364 SVCFH_INO(&argp->fh),
365 argp->name);
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);
370 fh_put(&argp->fh);
371 RETURN(nfserr);
375 * Remove a directory
377 static int
378 nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
379 void *resp)
381 int nfserr;
383 dprintk("nfsd: RMDIR %x/%ld %s\n",
384 SVCFH_DEV(&argp->fh),
385 SVCFH_INO(&argp->fh),
386 argp->name);
388 nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len);
389 fh_put(&argp->fh);
390 RETURN(nfserr);
394 * Read a portion of a directory.
396 static int
397 nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
398 struct nfsd3_readdirres *resp)
400 u32 * buffer;
401 int nfserr, count;
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)
414 count = argp->count;
416 /* Read directory and encode entries on the fly */
417 nfserr = nfsd_readdir(rqstp, &argp->fh, (loff_t) argp->cookie,
418 nfssvc_encode_entry,
419 buffer, &count);
420 resp->count = count;
422 fh_put(&argp->fh);
423 RETURN(nfserr);
427 * Get file system info
429 static int
430 nfsd3_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
431 struct nfsd3_statfsres *resp)
433 int nfserr;
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);
440 fh_put(&argp->fh);
441 RETURN(nfserr);
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), \
461 0, \
462 cache \
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.
490 nfserrno (int errno)
492 static struct {
493 int nfserr;
494 int syserr;
495 } nfs_errtbl[] = {
496 { NFS_OK, 0 },
497 { NFSERR_PERM, EPERM },
498 { NFSERR_NOENT, ENOENT },
499 { NFSERR_IO, EIO },
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 },
512 #ifdef EDQUOT
513 { NFSERR_DQUOT, EDQUOT },
514 #endif
515 { NFSERR_STALE, ESTALE },
516 { NFSERR_WFLUSH, EIO },
517 { -1, EIO }
519 int i;
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);
526 return nfserr_io;
529 #if 0
530 static void
531 nfsd3_dump(char *tag, u32 *buf, int len)
533 int i;
535 printk(KERN_NOTICE
536 "nfsd: %s (%d words)\n", tag, len);
538 for (i = 0; i < len && i < 32; i += 8)
539 printk(KERN_NOTICE
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]);
545 #endif