2 * nfsproc2.c Process version 2 NFS requests.
4 * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de>
7 #include <linux/linkage.h>
8 #include <linux/sched.h>
9 #include <linux/errno.h>
10 #include <linux/locks.h>
12 #include <linux/stat.h>
13 #include <linux/fcntl.h>
14 #include <linux/net.h>
16 #include <linux/version.h>
17 #include <linux/unistd.h>
18 #include <linux/malloc.h>
20 #include <linux/sunrpc/svc.h>
21 #include <linux/nfsd/nfsd.h>
22 #include <linux/nfsd/cache.h>
23 #include <linux/nfsd/xdr.h>
25 typedef struct svc_rqst svc_rqst
;
26 typedef struct svc_buf svc_buf
;
28 #define NFSDDBG_FACILITY NFSDDBG_PROC
30 #define RETURN(st) return st
33 svcbuf_reserve(struct svc_buf
*buf
, u32
**ptr
, int *len
, int nr
)
36 *len
= buf
->buflen
- buf
->len
- nr
;
40 nfsd_proc_null(struct svc_rqst
*rqstp
, void *argp
, void *resp
)
46 * Get a file's attributes
47 * N.B. After this call resp->fh needs an fh_put
50 nfsd_proc_getattr(struct svc_rqst
*rqstp
, struct nfsd_fhandle
*argp
,
51 struct nfsd_attrstat
*resp
)
53 dprintk("nfsd: GETATTR %d/%d\n",
54 SVCFH_DEV(&argp
->fh
), SVCFH_INO(&argp
->fh
));
56 fh_copy(&resp
->fh
, &argp
->fh
);
57 RETURN(fh_verify(rqstp
, &resp
->fh
, 0, MAY_NOP
));
61 * Set a file's attributes
62 * N.B. After this call resp->fh needs an fh_put
65 nfsd_proc_setattr(struct svc_rqst
*rqstp
, struct nfsd_sattrargs
*argp
,
66 struct nfsd_attrstat
*resp
)
68 dprintk("nfsd: SETATTR %d/%d, valid=%x, size=%ld\n",
69 SVCFH_DEV(&argp
->fh
), SVCFH_INO(&argp
->fh
),
70 argp
->attrs
.ia_valid
, (long) argp
->attrs
.ia_size
);
72 fh_copy(&resp
->fh
, &argp
->fh
);
73 RETURN(nfsd_setattr(rqstp
, &resp
->fh
, &argp
->attrs
));
77 * Look up a path name component
78 * Note: the dentry in the resp->fh may be negative if the file
80 * N.B. After this call resp->fh needs an fh_put
83 nfsd_proc_lookup(struct svc_rqst
*rqstp
, struct nfsd_diropargs
*argp
,
84 struct nfsd_diropres
*resp
)
88 dprintk("nfsd: LOOKUP %d/%d %s\n",
89 SVCFH_DEV(&argp
->fh
), SVCFH_INO(&argp
->fh
), argp
->name
);
91 nfserr
= nfsd_lookup(rqstp
, &argp
->fh
, argp
->name
, argp
->len
,
102 nfsd_proc_readlink(struct svc_rqst
*rqstp
, struct nfsd_fhandle
*argp
,
103 struct nfsd_readlinkres
*resp
)
108 dprintk("nfsd: READLINK %p\n", SVCFH_DENTRY(&argp
->fh
));
110 /* Reserve room for status and path length */
111 svcbuf_reserve(&rqstp
->rq_resbuf
, &path
, &dummy
, 2);
113 /* Read the symlink. */
114 resp
->len
= NFS_MAXPATHLEN
;
115 nfserr
= nfsd_readlink(rqstp
, &argp
->fh
, (char *) path
, &resp
->len
);
122 * Read a portion of a file.
123 * N.B. After this call resp->fh needs an fh_put
126 nfsd_proc_read(struct svc_rqst
*rqstp
, struct nfsd_readargs
*argp
,
127 struct nfsd_readres
*resp
)
132 dprintk("nfsd: READ %d/%d %d bytes at %d\n",
133 SVCFH_DEV(&argp
->fh
), SVCFH_INO(&argp
->fh
),
134 argp
->count
, argp
->offset
);
136 /* Obtain buffer pointer for payload. 19 is 1 word for
137 * status, 17 words for fattr, and 1 word for the byte count.
139 svcbuf_reserve(&rqstp
->rq_resbuf
, &buffer
, &avail
, 19);
141 if ((avail
<< 2) < argp
->count
) {
143 "oversized read request from %08lx:%d (%d bytes)\n",
144 ntohl(rqstp
->rq_addr
.sin_addr
.s_addr
),
145 ntohs(rqstp
->rq_addr
.sin_port
),
150 resp
->count
= argp
->count
;
151 nfserr
= nfsd_read(rqstp
, fh_copy(&resp
->fh
, &argp
->fh
),
160 * Write data to a file
161 * N.B. After this call resp->fh needs an fh_put
164 nfsd_proc_write(struct svc_rqst
*rqstp
, struct nfsd_writeargs
*argp
,
165 struct nfsd_attrstat
*resp
)
169 dprintk("nfsd: WRITE %d/%d %d bytes at %d\n",
170 SVCFH_DEV(&argp
->fh
), SVCFH_INO(&argp
->fh
),
171 argp
->len
, argp
->offset
);
173 nfserr
= nfsd_write(rqstp
, fh_copy(&resp
->fh
, &argp
->fh
),
182 * CREATE processing is complicated. The keyword here is `overloaded.'
183 * The parent directory is kept locked between the check for existence
184 * and the actual create() call in compliance with VFS protocols.
185 * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
188 nfsd_proc_create(struct svc_rqst
*rqstp
, struct nfsd_createargs
*argp
,
189 struct nfsd_diropres
*resp
)
191 svc_fh
*dirfhp
= &argp
->fh
;
192 svc_fh
*newfhp
= &resp
->fh
;
193 struct iattr
*attr
= &argp
->attrs
;
195 int nfserr
, type
, mode
, rdonly
= 0;
198 dprintk("nfsd: CREATE %d/%d %s\n",
199 SVCFH_DEV(dirfhp
), SVCFH_INO(dirfhp
), argp
->name
);
201 /* First verify the parent file handle */
202 nfserr
= fh_verify(rqstp
, dirfhp
, S_IFDIR
, MAY_EXEC
);
204 goto done
; /* must fh_put dirfhp even on error */
206 /* Check for MAY_WRITE separately. */
207 nfserr
= nfsd_permission(dirfhp
->fh_export
, dirfhp
->fh_dentry
,
209 if (nfserr
== nfserr_rofs
) {
210 rdonly
= 1; /* Non-fatal error for echo > /dev/null */
215 * Do a lookup to verify the new file handle.
217 nfserr
= nfsd_lookup(rqstp
, dirfhp
, argp
->name
, argp
->len
, newfhp
);
219 if (nfserr
!= nfserr_noent
)
222 * If the new file handle wasn't verified, we can't tell
223 * whether the file exists or not. Time to bail ...
225 nfserr
= nfserr_acces
;
226 if (!newfhp
->fh_dverified
) {
228 "nfsd_proc_create: file handle not verified\n");
234 * Lock the parent directory and check for existence.
236 nfserr
= fh_lock_parent(dirfhp
, newfhp
->fh_dentry
);
239 inode
= newfhp
->fh_dentry
->d_inode
;
241 /* Unfudge the mode bits */
242 if (attr
->ia_valid
& ATTR_MODE
) {
243 type
= attr
->ia_mode
& S_IFMT
;
244 mode
= attr
->ia_mode
& ~S_IFMT
;
245 if (!type
) /* HP weirdness */
248 type
= inode
->i_mode
& S_IFMT
;
249 mode
= inode
->i_mode
& ~S_IFMT
;
255 /* This is for "echo > /dev/null" a la SunOS. Argh. */
256 nfserr
= nfserr_rofs
;
257 if (rdonly
&& (!inode
|| type
== S_IFREG
))
260 attr
->ia_valid
|= ATTR_MODE
;
261 attr
->ia_mode
= type
| mode
;
263 /* Special treatment for non-regular files according to the
264 * gospel of sun micro
266 if (type
!= S_IFREG
) {
268 u32 size
= attr
->ia_size
;
271 if (type
!= S_IFBLK
&& type
!= S_IFCHR
) {
273 } else if (type
== S_IFCHR
&& size
== ~(u32
) 0) {
274 /* If you think you've seen the worst, grok this. */
275 attr
->ia_mode
= S_IFIFO
| mode
;
277 } else if (size
!= rdev
) {
278 /* dev got truncated because of 16bit Linux dev_t */
279 nfserr
= nfserr_io
; /* or nfserr_inval? */
282 /* Okay, char or block special */
286 /* Make sure the type and device matches */
287 nfserr
= nfserr_exist
;
288 if (inode
&& (type
!= (inode
->i_mode
& S_IFMT
) ||
289 (is_borc
&& inode
->i_rdev
!= rdev
)))
295 /* File doesn't exist. Create it and set attrs */
296 nfserr
= nfsd_create(rqstp
, dirfhp
, argp
->name
, argp
->len
,
297 attr
, type
, rdev
, newfhp
);
298 } else if (type
== S_IFREG
) {
299 dprintk("nfsd: existing %s, valid=%x, size=%ld\n",
300 argp
->name
, attr
->ia_valid
, (long) attr
->ia_size
);
301 /* File already exists. We ignore all attributes except
302 * size, so that creat() behaves exactly like
303 * open(..., O_CREAT|O_TRUNC|O_WRONLY).
305 attr
->ia_valid
&= ATTR_SIZE
;
307 nfserr
= nfsd_setattr(rqstp
, newfhp
, attr
);
311 /* We don't really need to unlock, as fh_put does it. */
320 nfsd_proc_remove(struct svc_rqst
*rqstp
, struct nfsd_diropargs
*argp
,
325 dprintk("nfsd: REMOVE %p %s\n", SVCFH_DENTRY(&argp
->fh
), argp
->name
);
327 /* Unlink. -SIFDIR means file must not be a directory */
328 nfserr
= nfsd_unlink(rqstp
, &argp
->fh
, -S_IFDIR
, argp
->name
, argp
->len
);
334 nfsd_proc_rename(struct svc_rqst
*rqstp
, struct nfsd_renameargs
*argp
,
339 dprintk("nfsd: RENAME %p %s -> %p %s\n",
340 SVCFH_DENTRY(&argp
->ffh
), argp
->fname
,
341 SVCFH_DENTRY(&argp
->tfh
), argp
->tname
);
343 nfserr
= nfsd_rename(rqstp
, &argp
->ffh
, argp
->fname
, argp
->flen
,
344 &argp
->tfh
, argp
->tname
, argp
->tlen
);
351 nfsd_proc_link(struct svc_rqst
*rqstp
, struct nfsd_linkargs
*argp
,
356 dprintk("nfsd: LINK %p -> %p %s\n",
357 SVCFH_DENTRY(&argp
->ffh
),
358 SVCFH_DENTRY(&argp
->tfh
),
361 nfserr
= nfsd_link(rqstp
, &argp
->tfh
, argp
->tname
, argp
->tlen
,
369 nfsd_proc_symlink(struct svc_rqst
*rqstp
, struct nfsd_symlinkargs
*argp
,
375 dprintk("nfsd: SYMLINK %p %s -> %s\n",
376 SVCFH_DENTRY(&argp
->ffh
), argp
->fname
, argp
->tname
);
378 memset(&newfh
, 0, sizeof(struct svc_fh
));
380 * Create the link, look up new file and set attrs.
382 nfserr
= nfsd_symlink(rqstp
, &argp
->ffh
, argp
->fname
, argp
->flen
,
383 argp
->tname
, argp
->tlen
,
386 argp
->attrs
.ia_valid
&= ~ATTR_SIZE
;
387 nfserr
= nfsd_setattr(rqstp
, &newfh
, &argp
->attrs
);
396 * Make directory. This operation is not idempotent.
397 * N.B. After this call resp->fh needs an fh_put
400 nfsd_proc_mkdir(struct svc_rqst
*rqstp
, struct nfsd_createargs
*argp
,
401 struct nfsd_diropres
*resp
)
405 dprintk("nfsd: MKDIR %p %s\n", SVCFH_DENTRY(&argp
->fh
), argp
->name
);
407 if (resp
->fh
.fh_dverified
) {
409 "nfsd_proc_mkdir: response already verified??\n");
412 argp
->attrs
.ia_valid
&= ~ATTR_SIZE
;
413 nfserr
= nfsd_create(rqstp
, &argp
->fh
, argp
->name
, argp
->len
,
414 &argp
->attrs
, S_IFDIR
, 0, &resp
->fh
);
423 nfsd_proc_rmdir(struct svc_rqst
*rqstp
, struct nfsd_diropargs
*argp
,
428 dprintk("nfsd: RMDIR %p %s\n", SVCFH_DENTRY(&argp
->fh
), argp
->name
);
430 nfserr
= nfsd_unlink(rqstp
, &argp
->fh
, S_IFDIR
, argp
->name
, argp
->len
);
436 * Read a portion of a directory.
439 nfsd_proc_readdir(struct svc_rqst
*rqstp
, struct nfsd_readdirargs
*argp
,
440 struct nfsd_readdirres
*resp
)
445 dprintk("nfsd: READDIR %d/%d %d bytes at %d\n",
446 SVCFH_DEV(&argp
->fh
), SVCFH_INO(&argp
->fh
),
447 argp
->count
, argp
->cookie
);
449 /* Reserve buffer space for status */
450 svcbuf_reserve(&rqstp
->rq_resbuf
, &buffer
, &count
, 1);
452 /* Shrink to the client read size */
453 if (count
> (argp
->count
>> 2))
454 count
= argp
->count
>> 2;
456 /* Make sure we've room for the NULL ptr & eof flag */
461 /* Read directory and encode entries on the fly */
462 nfserr
= nfsd_readdir(rqstp
, &argp
->fh
, (loff_t
) argp
->cookie
,
463 nfssvc_encode_entry
, buffer
, &count
);
471 * Get file system info
474 nfsd_proc_statfs(struct svc_rqst
* rqstp
, struct nfsd_fhandle
*argp
,
475 struct nfsd_statfsres
*resp
)
479 dprintk("nfsd: STATFS %p\n", SVCFH_DENTRY(&argp
->fh
));
481 nfserr
= nfsd_statfs(rqstp
, &argp
->fh
, &resp
->stats
);
487 * NFSv2 Server procedures.
488 * Only the results of non-idempotent operations are cached.
490 #define nfsd_proc_none NULL
491 #define nfssvc_release_none NULL
492 struct nfsd_void
{ int dummy
; };
494 #define PROC(name, argt, rest, relt, cache) \
495 { (svc_procfunc) nfsd_proc_##name, \
496 (kxdrproc_t) nfssvc_decode_##argt, \
497 (kxdrproc_t) nfssvc_encode_##rest, \
498 (kxdrproc_t) nfssvc_release_##relt, \
499 sizeof(struct nfsd_##argt), \
500 sizeof(struct nfsd_##rest), \
504 struct svc_procedure nfsd_procedures2
[18] = {
505 PROC(null
, void, void, none
, RC_NOCACHE
),
506 PROC(getattr
, fhandle
, attrstat
, fhandle
, RC_NOCACHE
),
507 PROC(setattr
, sattrargs
, attrstat
, fhandle
, RC_REPLBUFF
),
508 PROC(none
, void, void, none
, RC_NOCACHE
),
509 PROC(lookup
, diropargs
, diropres
, fhandle
, RC_NOCACHE
),
510 PROC(readlink
, fhandle
, readlinkres
, none
, RC_NOCACHE
),
511 PROC(read
, readargs
, readres
, fhandle
, RC_NOCACHE
),
512 PROC(none
, void, void, none
, RC_NOCACHE
),
513 PROC(write
, writeargs
, attrstat
, fhandle
, RC_REPLBUFF
),
514 PROC(create
, createargs
, diropres
, fhandle
, RC_REPLBUFF
),
515 PROC(remove
, diropargs
, void, none
, RC_REPLSTAT
),
516 PROC(rename
, renameargs
, void, none
, RC_REPLSTAT
),
517 PROC(link
, linkargs
, void, none
, RC_REPLSTAT
),
518 PROC(symlink
, symlinkargs
, void, none
, RC_REPLSTAT
),
519 PROC(mkdir
, createargs
, diropres
, fhandle
, RC_REPLBUFF
),
520 PROC(rmdir
, diropargs
, void, none
, RC_REPLSTAT
),
521 PROC(readdir
, readdirargs
, readdirres
, none
, RC_REPLBUFF
),
522 PROC(statfs
, fhandle
, statfsres
, none
, RC_NOCACHE
),
527 * Map errnos to NFS errnos.
537 { NFSERR_PERM
, EPERM
},
538 { NFSERR_NOENT
, ENOENT
},
540 { NFSERR_NXIO
, ENXIO
},
541 { NFSERR_ACCES
, EACCES
},
542 { NFSERR_EXIST
, EEXIST
},
543 { NFSERR_NODEV
, ENODEV
},
544 { NFSERR_NOTDIR
, ENOTDIR
},
545 { NFSERR_ISDIR
, EISDIR
},
546 { NFSERR_INVAL
, EINVAL
},
547 { NFSERR_FBIG
, EFBIG
},
548 { NFSERR_NOSPC
, ENOSPC
},
549 { NFSERR_ROFS
, EROFS
},
550 { NFSERR_NAMETOOLONG
, ENAMETOOLONG
},
551 { NFSERR_NOTEMPTY
, ENOTEMPTY
},
553 { NFSERR_DQUOT
, EDQUOT
},
555 { NFSERR_STALE
, ESTALE
},
556 { NFSERR_WFLUSH
, EIO
},
561 for (i
= 0; nfs_errtbl
[i
].nfserr
!= -1; i
++) {
562 if (nfs_errtbl
[i
].syserr
== errno
)
563 return htonl (nfs_errtbl
[i
].nfserr
);
565 printk (KERN_INFO
"nfsd: non-standard errno: %d\n", errno
);
571 nfsd_dump(char *tag
, u32
*buf
, int len
)
576 "nfsd: %s (%d words)\n", tag
, len
);
578 for (i
= 0; i
< len
&& i
< 32; i
+= 8)
580 " %08lx %08lx %08lx %08lx"
581 " %08lx %08lx %08lx %08lx\n",
582 buf
[i
], buf
[i
+1], buf
[i
+2], buf
[i
+3],
583 buf
[i
+4], buf
[i
+5], buf
[i
+6], buf
[i
+7]);