~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/nfsd/nfsproc.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * nfsproc2.c   Process version 2 NFS requests.
  3  * linux/fs/nfsd/nfs2proc.c
  4  * 
  5  * Process version 2 NFS requests.
  6  *
  7  * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
  8  */
  9 
 10 #include <linux/linkage.h>
 11 #include <linux/sched.h>
 12 #include <linux/errno.h>
 13 #include <linux/locks.h>
 14 #include <linux/fs.h>
 15 #include <linux/stat.h>
 16 #include <linux/fcntl.h>
 17 #include <linux/net.h>
 18 #include <linux/in.h>
 19 #include <linux/version.h>
 20 #include <linux/unistd.h>
 21 #include <linux/malloc.h>
 22 
 23 #include <linux/sunrpc/svc.h>
 24 #include <linux/nfsd/nfsd.h>
 25 #include <linux/nfsd/cache.h>
 26 #include <linux/nfsd/xdr.h>
 27 
 28 typedef struct svc_rqst svc_rqst;
 29 typedef struct svc_buf  svc_buf;
 30 
 31 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 32 
 33 
 34 static void
 35 svcbuf_reserve(struct svc_buf *buf, u32 **ptr, int *len, int nr)
 36 {
 37         *ptr = buf->buf + nr;
 38         *len = buf->buflen - buf->len - nr;
 39 }
 40 
 41 static int
 42 nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 43 {
 44         return nfs_ok;
 45 }
 46 
 47 /*
 48  * Get a file's attributes
 49  * N.B. After this call resp->fh needs an fh_put
 50  */
 51 static int
 52 nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
 53                                           struct nfsd_attrstat *resp)
 54 {
 55         dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
 56 
 57         fh_copy(&resp->fh, &argp->fh);
 58         return fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
 59 }
 60 
 61 /*
 62  * Set a file's attributes
 63  * N.B. After this call resp->fh needs an fh_put
 64  */
 65 static int
 66 nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
 67                                           struct nfsd_attrstat  *resp)
 68 {
 69         dprintk("nfsd: SETATTR  %s, valid=%x, size=%ld\n",
 70                 SVCFH_fmt(&argp->fh),
 71                 argp->attrs.ia_valid, (long) argp->attrs.ia_size);
 72 
 73         fh_copy(&resp->fh, &argp->fh);
 74         return nfsd_setattr(rqstp, &resp->fh, &argp->attrs);
 75 }
 76 
 77 /*
 78  * Look up a path name component
 79  * Note: the dentry in the resp->fh may be negative if the file
 80  * doesn't exist yet.
 81  * N.B. After this call resp->fh needs an fh_put
 82  */
 83 static int
 84 nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
 85                                          struct nfsd_diropres  *resp)
 86 {
 87         int     nfserr;
 88 
 89         dprintk("nfsd: LOOKUP   %s %s\n",
 90                 SVCFH_fmt(&argp->fh), argp->name);
 91 
 92         fh_init(&resp->fh, NFS_FHSIZE);
 93         nfserr = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
 94                                  &resp->fh);
 95 
 96         fh_put(&argp->fh);
 97         return nfserr;
 98 }
 99 
100 /*
101  * Read a symlink.
102  */
103 static int
104 nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_fhandle     *argp,
105                                            struct nfsd_readlinkres *resp)
106 {
107         u32             *path;
108         int             dummy, nfserr;
109 
110         dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
111 
112         /* Reserve room for status and path length */
113         svcbuf_reserve(&rqstp->rq_resbuf, &path, &dummy, 2);
114 
115         /* Read the symlink. */
116         resp->len = NFS_MAXPATHLEN;
117         nfserr = nfsd_readlink(rqstp, &argp->fh, (char *) path, &resp->len);
118 
119         fh_put(&argp->fh);
120         return nfserr;
121 }
122 
123 /*
124  * Read a portion of a file.
125  * N.B. After this call resp->fh needs an fh_put
126  */
127 static int
128 nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
129                                        struct nfsd_readres  *resp)
130 {
131         u32 *   buffer;
132         int     nfserr, avail;
133 
134         dprintk("nfsd: READ    %s %d bytes at %d\n",
135                 SVCFH_fmt(&argp->fh),
136                 argp->count, argp->offset);
137 
138         /* Obtain buffer pointer for payload. 19 is 1 word for
139          * status, 17 words for fattr, and 1 word for the byte count.
140          */
141         svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &avail, 19);
142 
143         if ((avail << 2) < argp->count) {
144                 printk(KERN_NOTICE
145                         "oversized read request from %08x:%d (%d bytes)\n",
146                                 ntohl(rqstp->rq_addr.sin_addr.s_addr),
147                                 ntohs(rqstp->rq_addr.sin_port),
148                                 argp->count);
149                 argp->count = avail << 2;
150         }
151 
152         resp->count = argp->count;
153         nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
154                                   argp->offset,
155                                   (char *) buffer,
156                                   &resp->count);
157 
158         return nfserr;
159 }
160 
161 /*
162  * Write data to a file
163  * N.B. After this call resp->fh needs an fh_put
164  */
165 static int
166 nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
167                                         struct nfsd_attrstat  *resp)
168 {
169         int     nfserr;
170         int     stable = 1;
171 
172         dprintk("nfsd: WRITE    %s %d bytes at %d\n",
173                 SVCFH_fmt(&argp->fh),
174                 argp->len, argp->offset);
175 
176         nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
177                                    argp->offset,
178                                    argp->data,
179                                    argp->len,
180                                    &stable);
181         return nfserr;
182 }
183 
184 /*
185  * CREATE processing is complicated. The keyword here is `overloaded.'
186  * The parent directory is kept locked between the check for existence
187  * and the actual create() call in compliance with VFS protocols.
188  * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
189  */
190 static int
191 nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
192                                          struct nfsd_diropres   *resp)
193 {
194         svc_fh          *dirfhp = &argp->fh;
195         svc_fh          *newfhp = &resp->fh;
196         struct iattr    *attr = &argp->attrs;
197         struct inode    *inode;
198         struct dentry   *dchild;
199         int             nfserr, type, mode, rdonly = 0;
200         dev_t           rdev = NODEV;
201 
202         dprintk("nfsd: CREATE   %s %s\n",
203                 SVCFH_fmt(dirfhp), argp->name);
204 
205         /* First verify the parent file handle */
206         nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_EXEC);
207         if (nfserr)
208                 goto done; /* must fh_put dirfhp even on error */
209 
210         /* Check for MAY_WRITE separately. */
211         nfserr = nfsd_permission(dirfhp->fh_export, dirfhp->fh_dentry,
212                                  MAY_WRITE);
213         if (nfserr == nfserr_rofs) {
214                 rdonly = 1;     /* Non-fatal error for echo > /dev/null */
215         } else if (nfserr)
216                 goto done;
217 
218         nfserr = nfserr_acces;
219         if (!argp->len)
220                 goto done;
221         nfserr = nfserr_exist;
222         if (isdotent(argp->name, argp->len))
223                 goto done;
224         fh_lock(dirfhp);
225         dchild = lookup_one(argp->name, dirfhp->fh_dentry);
226         if (IS_ERR(dchild)) {
227                 nfserr = nfserrno(PTR_ERR(dchild));
228                 goto out_unlock;
229         }
230         fh_init(newfhp, NFS_FHSIZE);
231         nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild);
232         if (!nfserr && !dchild->d_inode)
233                 nfserr = nfserr_noent;
234         if (nfserr) {
235                 if (nfserr != nfserr_noent)
236                         goto out_unlock;
237                 /*
238                  * If the new file handle wasn't verified, we can't tell
239                  * whether the file exists or not. Time to bail ...
240                  */
241                 nfserr = nfserr_acces;
242                 if (!newfhp->fh_dentry) {
243                         printk(KERN_WARNING 
244                                 "nfsd_proc_create: file handle not verified\n");
245                         goto out_unlock;
246                 }
247         }
248 
249         inode = newfhp->fh_dentry->d_inode;
250 
251         /* Unfudge the mode bits */
252         if (attr->ia_valid & ATTR_MODE) { 
253                 type = attr->ia_mode & S_IFMT;
254                 mode = attr->ia_mode & ~S_IFMT;
255                 if (!type)      /* HP weirdness */
256                         type = S_IFREG;
257         } else if (inode) {
258                 type = inode->i_mode & S_IFMT;
259                 mode = inode->i_mode & ~S_IFMT;
260         } else {
261                 type = S_IFREG;
262                 mode = 0;       /* ??? */
263         }
264 
265         /* This is for "echo > /dev/null" a la SunOS. Argh. */
266         nfserr = nfserr_rofs;
267         if (rdonly && (!inode || type == S_IFREG))
268                 goto out_unlock;
269 
270         attr->ia_valid |= ATTR_MODE;
271         attr->ia_mode = mode;
272 
273         /* Special treatment for non-regular files according to the
274          * gospel of sun micro
275          */
276         if (type != S_IFREG) {
277                 int     is_borc = 0;
278                 u32     size = attr->ia_size;
279 
280                 rdev = (dev_t) size;
281                 if (type != S_IFBLK && type != S_IFCHR) {
282                         rdev = 0;
283                 } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
284                         /* If you think you've seen the worst, grok this. */
285                         type = S_IFIFO;
286                 } else if (size != rdev) {
287                         /* dev got truncated because of 16bit Linux dev_t */
288                         nfserr = nfserr_inval;
289                         goto out_unlock;
290                 } else {
291                         /* Okay, char or block special */
292                         is_borc = 1;
293                 }
294 
295                 /* we've used the SIZE information, so discard it */
296                 attr->ia_valid &= ~ATTR_SIZE;
297 
298                 /* Make sure the type and device matches */
299                 nfserr = nfserr_exist;
300                 if (inode && (type != (inode->i_mode & S_IFMT) || 
301                     (is_borc && inode->i_rdev != rdev)))
302                         goto out_unlock;
303         }
304         
305         nfserr = 0;
306         if (!inode) {
307                 /* File doesn't exist. Create it and set attrs */
308                 nfserr = nfsd_create(rqstp, dirfhp, argp->name, argp->len,
309                                         attr, type, rdev, newfhp);
310         } else if (type == S_IFREG) {
311                 dprintk("nfsd:   existing %s, valid=%x, size=%ld\n",
312                         argp->name, attr->ia_valid, (long) attr->ia_size);
313                 /* File already exists. We ignore all attributes except
314                  * size, so that creat() behaves exactly like
315                  * open(..., O_CREAT|O_TRUNC|O_WRONLY).
316                  */
317                 attr->ia_valid &= ATTR_SIZE;
318                 if (attr->ia_valid)
319                         nfserr = nfsd_setattr(rqstp, newfhp, attr);
320         }
321 
322 out_unlock:
323         /* We don't really need to unlock, as fh_put does it. */
324         fh_unlock(dirfhp);
325 
326 done:
327         fh_put(dirfhp);
328         return nfserr;
329 }
330 
331 static int
332 nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
333                                          void                  *resp)
334 {
335         int     nfserr;
336 
337         dprintk("nfsd: REMOVE   %s %s\n", SVCFH_fmt(&argp->fh), argp->name);
338 
339         /* Unlink. -SIFDIR means file must not be a directory */
340         nfserr = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, argp->name, argp->len);
341         fh_put(&argp->fh);
342         return nfserr;
343 }
344 
345 static int
346 nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp,
347                                          void                   *resp)
348 {
349         int     nfserr;
350 
351         dprintk("nfsd: RENAME   %s %s -> \n",
352                 SVCFH_fmt(&argp->ffh), argp->fname);
353         dprintk("nfsd:        ->  %s %s\n",
354                 SVCFH_fmt(&argp->tfh), argp->tname);
355 
356         nfserr = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
357                                     &argp->tfh, argp->tname, argp->tlen);
358         fh_put(&argp->ffh);
359         fh_put(&argp->tfh);
360         return nfserr;
361 }
362 
363 static int
364 nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp,
365                                 void                        *resp)
366 {
367         int     nfserr;
368 
369         dprintk("nfsd: LINK     %s ->\n",
370                 SVCFH_fmt(&argp->ffh));
371         dprintk("nfsd:    %s %s\n",
372                 SVCFH_fmt(&argp->tfh),
373                 argp->tname);
374 
375         nfserr = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
376                                   &argp->ffh);
377         fh_put(&argp->ffh);
378         fh_put(&argp->tfh);
379         return nfserr;
380 }
381 
382 static int
383 nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
384                                           void                    *resp)
385 {
386         struct svc_fh   newfh;
387         int             nfserr;
388 
389         dprintk("nfsd: SYMLINK  %s %s -> %s\n",
390                 SVCFH_fmt(&argp->ffh), argp->fname, argp->tname);
391 
392         fh_init(&newfh, NFS_FHSIZE);
393         /*
394          * Create the link, look up new file and set attrs.
395          */
396         nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
397                                                  argp->tname, argp->tlen,
398                                                  &newfh, &argp->attrs);
399 
400 
401         fh_put(&argp->ffh);
402         fh_put(&newfh);
403         return nfserr;
404 }
405 
406 /*
407  * Make directory. This operation is not idempotent.
408  * N.B. After this call resp->fh needs an fh_put
409  */
410 static int
411 nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
412                                         struct nfsd_diropres   *resp)
413 {
414         int     nfserr;
415 
416         dprintk("nfsd: MKDIR    %s %s\n", SVCFH_fmt(&argp->fh), argp->name);
417 
418         if (resp->fh.fh_dentry) {
419                 printk(KERN_WARNING
420                         "nfsd_proc_mkdir: response already verified??\n");
421         }
422 
423         argp->attrs.ia_valid &= ~ATTR_SIZE;
424         fh_init(&resp->fh, NFS_FHSIZE);
425         nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
426                                     &argp->attrs, S_IFDIR, 0, &resp->fh);
427         fh_put(&argp->fh);
428         return nfserr;
429 }
430 
431 /*
432  * Remove a directory
433  */
434 static int
435 nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
436                                         void                  *resp)
437 {
438         int     nfserr;
439 
440         dprintk("nfsd: RMDIR    %s %s\n", SVCFH_fmt(&argp->fh), argp->name);
441 
442         nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len);
443         fh_put(&argp->fh);
444         return nfserr;
445 }
446 
447 /*
448  * Read a portion of a directory.
449  */
450 static int
451 nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
452                                           struct nfsd_readdirres  *resp)
453 {
454         u32 *           buffer;
455         int             nfserr, count;
456 
457         dprintk("nfsd: READDIR  %s %d bytes at %d\n",
458                 SVCFH_fmt(&argp->fh),           
459                 argp->count, argp->cookie);
460 
461         /* Reserve buffer space for status */
462         svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &count, 1);
463 
464         /* Shrink to the client read size */
465         if (count > (argp->count >> 2))
466                 count = argp->count >> 2;
467 
468         /* Make sure we've room for the NULL ptr & eof flag */
469         count -= 2;
470         if (count < 0)
471                 count = 0;
472 
473         /* Read directory and encode entries on the fly */
474         nfserr = nfsd_readdir(rqstp, &argp->fh, (loff_t) argp->cookie, 
475                               nfssvc_encode_entry,
476                               buffer, &count, NULL);
477         resp->count = count;
478 
479         fh_put(&argp->fh);
480         return nfserr;
481 }
482 
483 /*
484  * Get file system info
485  */
486 static int
487 nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle   *argp,
488                                           struct nfsd_statfsres *resp)
489 {
490         int     nfserr;
491 
492         dprintk("nfsd: STATFS   %s\n", SVCFH_fmt(&argp->fh));
493 
494         nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
495         fh_put(&argp->fh);
496         return nfserr;
497 }
498 
499 /*
500  * NFSv2 Server procedures.
501  * Only the results of non-idempotent operations are cached.
502  */
503 #define nfsd_proc_none          NULL
504 #define nfssvc_release_none     NULL
505 struct nfsd_void { int dummy; };
506 
507 #define PROC(name, argt, rest, relt, cache)     \
508  { (svc_procfunc) nfsd_proc_##name,             \
509    (kxdrproc_t) nfssvc_decode_##argt,           \
510    (kxdrproc_t) nfssvc_encode_##rest,           \
511    (kxdrproc_t) nfssvc_release_##relt,          \
512    sizeof(struct nfsd_##argt),                  \
513    sizeof(struct nfsd_##rest),                  \
514    0,                                           \
515    cache                                        \
516  }
517 struct svc_procedure            nfsd_procedures2[18] = {
518   PROC(null,     void,          void,           none,           RC_NOCACHE),
519   PROC(getattr,  fhandle,       attrstat,       fhandle,        RC_NOCACHE),
520   PROC(setattr,  sattrargs,     attrstat,       fhandle,        RC_REPLBUFF),
521   PROC(none,     void,          void,           none,           RC_NOCACHE),
522   PROC(lookup,   diropargs,     diropres,       fhandle,        RC_NOCACHE),
523   PROC(readlink, fhandle,       readlinkres,    none,           RC_NOCACHE),
524   PROC(read,     readargs,      readres,        fhandle,        RC_NOCACHE),
525   PROC(none,     void,          void,           none,           RC_NOCACHE),
526   PROC(write,    writeargs,     attrstat,       fhandle,        RC_REPLBUFF),
527   PROC(create,   createargs,    diropres,       fhandle,        RC_REPLBUFF),
528   PROC(remove,   diropargs,     void,           none,           RC_REPLSTAT),
529   PROC(rename,   renameargs,    void,           none,           RC_REPLSTAT),
530   PROC(link,     linkargs,      void,           none,           RC_REPLSTAT),
531   PROC(symlink,  symlinkargs,   void,           none,           RC_REPLSTAT),
532   PROC(mkdir,    createargs,    diropres,       fhandle,        RC_REPLBUFF),
533   PROC(rmdir,    diropargs,     void,           none,           RC_REPLSTAT),
534   PROC(readdir,  readdirargs,   readdirres,     none,           RC_REPLBUFF),
535   PROC(statfs,   fhandle,       statfsres,      none,           RC_NOCACHE),
536 };
537 
538 
539 /*
540  * Map errnos to NFS errnos.
541  */
542 int
543 nfserrno (int errno)
544 {
545         static struct {
546                 int     nfserr;
547                 int     syserr;
548         } nfs_errtbl[] = {
549                 { nfs_ok, 0 },
550                 { nfserr_perm, -EPERM },
551                 { nfserr_noent, -ENOENT },
552                 { nfserr_io, -EIO },
553                 { nfserr_nxio, -ENXIO },
554                 { nfserr_acces, -EACCES },
555                 { nfserr_exist, -EEXIST },
556                 { nfserr_xdev, -EXDEV },
557                 { nfserr_mlink, -EMLINK },
558                 { nfserr_nodev, -ENODEV },
559                 { nfserr_notdir, -ENOTDIR },
560                 { nfserr_isdir, -EISDIR },
561                 { nfserr_inval, -EINVAL },
562                 { nfserr_fbig, -EFBIG },
563                 { nfserr_nospc, -ENOSPC },
564                 { nfserr_rofs, -EROFS },
565                 { nfserr_mlink, -EMLINK },
566                 { nfserr_nametoolong, -ENAMETOOLONG },
567                 { nfserr_notempty, -ENOTEMPTY },
568 #ifdef EDQUOT
569                 { nfserr_dquot, -EDQUOT },
570 #endif
571                 { nfserr_stale, -ESTALE },
572                 { -1, -EIO }
573         };
574         int     i;
575 
576         for (i = 0; nfs_errtbl[i].nfserr != -1; i++) {
577                 if (nfs_errtbl[i].syserr == errno)
578                         return nfs_errtbl[i].nfserr;
579         }
580         printk (KERN_INFO "nfsd: non-standard errno: %d\n", errno);
581         return nfserr_io;
582 }
583 
584 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.