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

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

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

  1 /*
  2  * linux/fs/nfsd/nfsfh.c
  3  *
  4  * NFS server file handle treatment.
  5  *
  6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
  7  * Portions Copyright (C) 1999 G. Allen Morris III <gam3@acm.org>
  8  * Extensive rewrite by Neil Brown <neilb@cse.unsw.edu.au> Southern-Spring 1999
  9  */
 10 
 11 #include <linux/sched.h>
 12 #include <linux/malloc.h>
 13 #include <linux/fs.h>
 14 #include <linux/unistd.h>
 15 #include <linux/string.h>
 16 #include <linux/stat.h>
 17 #include <linux/dcache.h>
 18 #include <asm/pgtable.h>
 19 
 20 #include <linux/sunrpc/svc.h>
 21 #include <linux/nfsd/nfsd.h>
 22 
 23 #define NFSDDBG_FACILITY                NFSDDBG_FH
 24 #define NFSD_PARANOIA 1
 25 /* #define NFSD_DEBUG_VERBOSE 1 */
 26 
 27 
 28 static int nfsd_nr_verified;
 29 static int nfsd_nr_put;
 30 
 31 
 32 struct nfsd_getdents_callback {
 33         struct qstr *name;      /* name that was found. name->name already points to a buffer */
 34         unsigned long ino;      /* the inum we are looking for */
 35         int found;              /* inode matched? */
 36         int sequence;           /* sequence counter */
 37 };
 38 
 39 /*
 40  * A rather strange filldir function to capture
 41  * the name matching the specified inode number.
 42  */
 43 static int filldir_one(void * __buf, const char * name, int len,
 44                         off_t pos, ino_t ino, unsigned int d_type)
 45 {
 46         struct nfsd_getdents_callback *buf = __buf;
 47         struct qstr *qs = buf->name;
 48         char *nbuf = (char*)qs->name; /* cast is to get rid of "const" */
 49         int result = 0;
 50 
 51         buf->sequence++;
 52 #ifdef NFSD_DEBUG_VERBOSE
 53 dprintk("filldir_one: seq=%d, ino=%ld, name=%s\n", buf->sequence, ino, name);
 54 #endif
 55         if (buf->ino == ino) {
 56                 qs->len = len;
 57                 memcpy(nbuf, name, len);
 58                 nbuf[len] = '\0';
 59                 buf->found = 1;
 60                 result = -1;
 61         }
 62         return result;
 63 }
 64 
 65 /*
 66  * Read a directory and return the name of the specified entry.
 67  * i_sem is already down().
 68  * The whole thing is a total BS. It should not be done via readdir(), damnit!
 69  * Oh, well, as soon as it will be in filesystems...
 70  */
 71 static int get_ino_name(struct dentry *dentry, struct qstr *name, unsigned long ino)
 72 {
 73         struct inode *dir = dentry->d_inode;
 74         int error;
 75         struct file file;
 76         struct nfsd_getdents_callback buffer;
 77 
 78         error = -ENOTDIR;
 79         if (!dir || !S_ISDIR(dir->i_mode))
 80                 goto out;
 81         error = -EINVAL;
 82         if (!dir->i_fop)
 83                 goto out;
 84         /*
 85          * Open the directory ...
 86          */
 87         error = init_private_file(&file, dentry, FMODE_READ);
 88         if (error)
 89                 goto out;
 90         error = -EINVAL;
 91         if (!file.f_op->readdir)
 92                 goto out_close;
 93 
 94         buffer.name = name;
 95         buffer.ino = ino;
 96         buffer.found = 0;
 97         buffer.sequence = 0;
 98         while (1) {
 99                 int old_seq = buffer.sequence;
100                 error = file.f_op->readdir(&file, &buffer, filldir_one);
101                 if (error < 0)
102                         break;
103 
104                 error = 0;
105                 if (buffer.found)
106                         break;
107                 error = -ENOENT;
108                 if (old_seq == buffer.sequence)
109                         break;
110         }
111 
112 out_close:
113         if (file.f_op->release)
114                 file.f_op->release(dir, &file);
115 out:
116         return error;
117 }
118 
119 /* this should be provided by each filesystem in an nfsd_operations interface as
120  * iget isn't really the right interface
121  */
122 static struct dentry *nfsd_iget(struct super_block *sb, unsigned long ino, __u32 generation)
123 {
124 
125         /* iget isn't really right if the inode is currently unallocated!!
126          * This should really all be done inside each filesystem
127          *
128          * ext2fs' read_inode has been strengthed to return a bad_inode if the inode
129          *   had been deleted.
130          *
131          * Currently we don't know the generation for parent directory, so a generation
132          * of 0 means "accept any"
133          */
134         struct inode *inode;
135         struct list_head *lp;
136         struct dentry *result;
137         inode = iget(sb, ino);
138         if (is_bad_inode(inode)
139             || (generation && inode->i_generation != generation)
140                 ) {
141                 /* we didn't find the right inode.. */
142                 dprintk("fh_verify: Inode %lu, Bad count: %d %d or version  %u %u\n",
143                         inode->i_ino,
144                         inode->i_nlink, atomic_read(&inode->i_count),
145                         inode->i_generation,
146                         generation);
147 
148                 iput(inode);
149                 return ERR_PTR(-ESTALE);
150         }
151         /* now to find a dentry.
152          * If possible, get a well-connected one
153          */
154         spin_lock(&dcache_lock);
155         for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) {
156                 result = list_entry(lp,struct dentry, d_alias);
157                 if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) {
158                         dget_locked(result);
159                         spin_unlock(&dcache_lock);
160                         iput(inode);
161                         return result;
162                 }
163         }
164         spin_unlock(&dcache_lock);
165         result = d_alloc_root(inode);
166         if (result == NULL) {
167                 iput(inode);
168                 return ERR_PTR(-ENOMEM);
169         }
170         result->d_flags |= DCACHE_NFSD_DISCONNECTED;
171         d_rehash(result); /* so a dput won't loose it */
172         return result;
173 }
174 
175 /* this routine links an IS_ROOT dentry into the dcache tree.  It gains "parent"
176  * as a parent and "name" as a name
177  * It should possibly go in dcache.c
178  */
179 int d_splice(struct dentry *target, struct dentry *parent, struct qstr *name)
180 {
181         struct dentry *tdentry;
182 #ifdef NFSD_PARANOIA
183         if (!IS_ROOT(target))
184                 printk("nfsd: d_splice with no-root target: %s/%s\n", parent->d_name.name, name->name);
185         if (!(target->d_flags & DCACHE_NFSD_DISCONNECTED))
186                 printk("nfsd: d_splice with non-DISCONNECTED target: %s/%s\n", parent->d_name.name, name->name);
187 #endif
188         name->hash = full_name_hash(name->name, name->len);
189         tdentry = d_alloc(parent, name);
190         if (tdentry == NULL)
191                 return -ENOMEM;
192         d_move(target, tdentry);
193 
194         /* tdentry will have been made a "child" of target (the parent of target)
195          * make it an IS_ROOT instead
196          */
197         spin_lock(&dcache_lock);
198         list_del(&tdentry->d_child);
199         tdentry->d_parent = tdentry;
200         spin_unlock(&dcache_lock);
201         d_rehash(target);
202         dput(tdentry);
203 
204         /* if parent is properly connected, then we can assert that
205          * the children are connected, but it must be a singluar (non-forking)
206          * branch
207          */
208         if (!(parent->d_flags & DCACHE_NFSD_DISCONNECTED)) {
209                 while (target) {
210                         target->d_flags &= ~DCACHE_NFSD_DISCONNECTED;
211                         parent = target;
212                         spin_lock(&dcache_lock);
213                         if (list_empty(&parent->d_subdirs))
214                                 target = NULL;
215                         else {
216                                 target = list_entry(parent->d_subdirs.next, struct dentry, d_child);
217 #ifdef NFSD_PARANOIA
218                                 /* must be only child */
219                                 if (target->d_child.next != &parent->d_subdirs
220                                     || target->d_child.prev != &parent->d_subdirs)
221                                         printk("nfsd: d_splice found non-singular disconnected branch: %s/%s\n",
222                                                parent->d_name.name, target->d_name.name);
223 #endif
224                         }
225                         spin_unlock(&dcache_lock);
226                 }
227         }
228         return 0;
229 }
230 
231 /* this routine finds the dentry of the parent of a given directory
232  * it should be in the filesystem accessed by nfsd_operations
233  * it assumes lookup("..") works.
234  */
235 struct dentry *nfsd_findparent(struct dentry *child)
236 {
237         struct dentry *tdentry, *pdentry;
238         tdentry = d_alloc(child, &(const struct qstr) {"..", 2, 0});
239         if (!tdentry)
240                 return ERR_PTR(-ENOMEM);
241 
242         /* I'm going to assume that if the returned dentry is different, then
243          * it is well connected.  But nobody returns different dentrys do they?
244          */
245         pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry);
246         d_drop(tdentry); /* we never want ".." hashed */
247         if (!pdentry) {
248                 /* I don't want to return a ".." dentry.
249                  * I would prefer to return an unconnected "IS_ROOT" dentry,
250                  * though a properly connected dentry is even better
251                  */
252                 /* if first or last of alias list is not tdentry, use that
253                  * else make a root dentry
254                  */
255                 struct list_head *aliases = &tdentry->d_inode->i_dentry;
256                 spin_lock(&dcache_lock);
257                 if (aliases->next != aliases) {
258                         pdentry = list_entry(aliases->next, struct dentry, d_alias);
259                         if (pdentry == tdentry)
260                                 pdentry = list_entry(aliases->prev, struct dentry, d_alias);
261                         if (pdentry == tdentry)
262                                 pdentry = NULL;
263                         if (pdentry) dget_locked(pdentry);
264                 }
265                 spin_unlock(&dcache_lock);
266                 if (pdentry == NULL) {
267                         pdentry = d_alloc_root(igrab(tdentry->d_inode));
268                         if (pdentry) {
269                                 pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED;
270                                 d_rehash(pdentry);
271                         }
272                 }
273                 if (pdentry == NULL)
274                         pdentry = ERR_PTR(-ENOMEM);
275         }
276         dput(tdentry); /* it is not hashed, it will be discarded */
277         return pdentry;
278 }
279 
280 static struct dentry *splice(struct dentry *child, struct dentry *parent)
281 {
282         int err = 0;
283         struct qstr qs;
284         char namebuf[256];
285         struct list_head *lp;
286         struct dentry *tmp;
287         /* child is an IS_ROOT (anonymous) dentry, but it is hypothesised that
288          * it should be a child of parent.
289          * We see if we can find a name and, if we can - splice it in.
290          * We hold the i_sem on the parent the whole time to try to follow locking protocols.
291          */
292         qs.name = namebuf;
293         down(&parent->d_inode->i_sem);
294 
295         /* Now, things might have changed while we waited.
296          * Possibly a friendly filesystem found child and spliced it in in response
297          * to a lookup (though nobody does this yet).  In this case, just succeed.
298          */
299         if (child->d_parent == parent) goto out;
300         /* Possibly a new dentry has been made for this child->d_inode in
301          * parent by a lookup.  In this case return that dentry. caller must
302          * notice and act accordingly
303          */
304         spin_lock(&dcache_lock);
305         for (lp = child->d_inode->i_dentry.next; lp != &child->d_inode->i_dentry ; lp=lp->next) {
306                 tmp = list_entry(lp,struct dentry, d_alias);
307                 if (tmp->d_parent == parent) {
308                         child = dget_locked(tmp);
309                         spin_unlock(&dcache_lock);
310                         goto out;
311                 }
312         }
313         spin_unlock(&dcache_lock);
314         /* well, if we can find a name for child in parent, it should be safe to splice it in */
315         err = get_ino_name(parent, &qs, child->d_inode->i_ino);
316         if (err)
317                 goto out;
318         tmp = d_lookup(parent, &qs);
319         if (tmp) {
320                 /* Now that IS odd.  I wonder what it means... */
321                 err = -EEXIST;
322                 printk("nfsd-fh: found a name that I didn't expect: %s/%s\n", parent->d_name.name, qs.name);
323                 dput(tmp);
324                 goto out;
325         }
326         err = d_splice(child, parent, &qs);
327         dprintk("nfsd_fh: found name %s for ino %ld\n", child->d_name.name, child->d_inode->i_ino);
328  out:
329         up(&parent->d_inode->i_sem);
330         if (err)
331                 return ERR_PTR(err);
332         else
333                 return child;
334 }
335 
336 /*
337  * This is the basic lookup mechanism for turning an NFS file handle
338  * into a dentry.
339  * We use nfsd_iget and if that doesn't return a suitably connected dentry,
340  * we try to find the parent, and the parent of that and so-on until a
341  * connection if made.
342  */
343 static struct dentry *
344 find_fh_dentry(struct super_block *sb, ino_t ino, int generation, ino_t dirino, int needpath)
345 {
346         struct dentry *dentry, *result = NULL;
347         struct dentry *tmp;
348         int  found =0;
349         int err = -ESTALE;
350         /* the sb->s_nfsd_free_path_sem semaphore is needed to make sure that only one unconnected (free)
351          * dcache path ever exists, as otherwise two partial paths might get
352          * joined together, which would be very confusing.
353          * If there is ever an unconnected non-root directory, then this lock
354          * must be held.
355          */
356 
357 
358         nfsdstats.fh_lookup++;
359         /*
360          * Attempt to find the inode.
361          */
362  retry:
363         down(&sb->s_nfsd_free_path_sem);
364         result = nfsd_iget(sb, ino, generation);
365         if (IS_ERR(result)
366             || !(result->d_flags & DCACHE_NFSD_DISCONNECTED)
367             || (!S_ISDIR(result->d_inode->i_mode) && ! needpath)) {
368                 up(&sb->s_nfsd_free_path_sem);
369             
370                 err = PTR_ERR(result);
371                 if (IS_ERR(result))
372                         goto err_out;
373                 if ((result->d_flags & DCACHE_NFSD_DISCONNECTED))
374                         nfsdstats.fh_anon++;
375                 return result;
376         }
377 
378         /* It's a directory, or we are required to confirm the file's
379          * location in the tree.
380          */
381         dprintk("nfs_fh: need to look harder for %d/%ld\n",sb->s_dev,ino);
382 
383         found = 0;
384         if (!S_ISDIR(result->d_inode->i_mode)) {
385                 nfsdstats.fh_nocache_nondir++;
386                 if (dirino == 0)
387                         goto err_result; /* don't know how to find parent */
388                 else {
389                         /* need to iget dirino and make sure this inode is in that directory */
390                         dentry = nfsd_iget(sb, dirino, 0);
391                         err = PTR_ERR(dentry);
392                         if (IS_ERR(dentry))
393                                 goto err_result;
394                         err = -ESTALE;
395                         if (!dentry->d_inode
396                             || !S_ISDIR(dentry->d_inode->i_mode)) {
397                                 goto err_dentry;
398                         }
399                         if (!(dentry->d_flags & DCACHE_NFSD_DISCONNECTED))
400                                 found = 1;
401                         tmp = splice(result, dentry);
402                         err = PTR_ERR(tmp);
403                         if (IS_ERR(tmp))
404                                 goto err_dentry;
405                         if (tmp != result) {
406                                 /* it is safe to just use tmp instead, but we must discard result first */
407                                 d_drop(result);
408                                 dput(result);
409                                 result = tmp;
410                                 /* If !found, then this is really wierd, but it shouldn't hurt */
411                         }
412                 }
413         } else {
414                 nfsdstats.fh_nocache_dir++;
415                 dentry = dget(result);
416         }
417 
418         while(!found) {
419                 /* LOOP INVARIANT */
420                 /* haven't found a place in the tree yet, but we do have a free path
421                  * from dentry down to result, and dentry is a directory.
422                  * Have a hold on dentry and result */
423                 struct dentry *pdentry;
424                 struct inode *parent;
425 
426                 pdentry = nfsd_findparent(dentry);
427                 err = PTR_ERR(pdentry);
428                 if (IS_ERR(pdentry))
429                         goto err_dentry;
430                 parent = pdentry->d_inode;
431                 err = -EACCES;
432                 if (!parent) {
433                         dput(pdentry);
434                         goto err_dentry;
435                 }
436 
437                 if (!(dentry->d_flags & DCACHE_NFSD_DISCONNECTED))
438                         found = 1;
439 
440                 tmp = splice(dentry, pdentry);
441                 if (tmp != dentry) {
442                         /* Something wrong.  We need to drop thw whole dentry->result path
443                          * whatever it was
444                          */
445                         struct dentry *d;
446                         for (d=result ; d ; d=(d->d_parent == d)?NULL:d->d_parent)
447                                 d_drop(d);
448                 }
449                 if (IS_ERR(tmp)) {
450                         err = PTR_ERR(tmp);
451                         dput(pdentry);
452                         goto err_dentry;
453                 }
454                 if (tmp != dentry) {
455                         /* we lost a race,  try again
456                          */
457                         dput(tmp);
458                         dput(dentry);
459                         dput(result);   /* this will discard the whole free path, so we can up the semaphore */
460                         up(&sb->s_nfsd_free_path_sem);
461                         goto retry;
462                 }
463                 dput(dentry);
464                 dentry = pdentry;
465         }
466         dput(dentry);
467         up(&sb->s_nfsd_free_path_sem);
468         return result;
469 
470 err_dentry:
471         dput(dentry);
472 err_result:
473         dput(result);
474         up(&sb->s_nfsd_free_path_sem);
475 err_out:
476         if (err == -ESTALE)
477                 nfsdstats.fh_stale++;
478         return ERR_PTR(err);
479 }
480 
481 /*
482  * Perform sanity checks on the dentry in a client's file handle.
483  *
484  * Note that the file handle dentry may need to be freed even after
485  * an error return.
486  *
487  * This is only called at the start of an nfsproc call, so fhp points to
488  * a svc_fh which is all 0 except for the over-the-wire file handle.
489  */
490 u32
491 fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
492 {
493         struct knfsd_fh *fh = &fhp->fh_handle;
494         struct svc_export *exp;
495         struct dentry   *dentry;
496         struct inode    *inode;
497         u32             error = 0;
498 
499         dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
500 
501         if (!fhp->fh_dentry) {
502                 kdev_t xdev;
503                 ino_t xino;
504                 __u32 *datap=NULL;
505                 int data_left = fh->fh_size/4;
506                 int nfsdev;
507                 error = nfserr_stale;
508                 if (rqstp->rq_vers == 3)
509                         error = nfserr_badhandle;
510                 if (fh->fh_version == 1) {
511                         
512                         datap = fh->fh_auth;
513                         if (--data_left<0) goto out;
514                         switch (fh->fh_auth_type) {
515                         case 0: break;
516                         default: goto out;
517                         }
518 
519                         switch (fh->fh_fsid_type) {
520                         case 0:
521                                 if ((data_left-=2)<0) goto out;
522                                 nfsdev = ntohl(*datap++);
523                                 xdev = MKDEV(nfsdev>>16, nfsdev&0xFFFF);
524                                 xino = *datap++;
525                                 break;
526                         default:
527                                 goto out;
528                         }
529                 } else {
530                         if (fh->fh_size != NFS_FHSIZE)
531                                 goto out;
532                         /* assume old filehandle format */
533                         xdev = u32_to_kdev_t(fh->ofh_xdev);
534                         xino = u32_to_ino_t(fh->ofh_xino);
535                 }
536 
537                 /*
538                  * Look up the export entry.
539                  */
540                 error = nfserr_stale; 
541                 exp = exp_get(rqstp->rq_client, xdev, xino);
542 
543                 if (!exp) {
544                         /* export entry revoked */
545                         nfsdstats.fh_stale++;
546                         goto out;
547                 }
548 
549                 /* Check if the request originated from a secure port. */
550                 error = nfserr_perm;
551                 if (!rqstp->rq_secure && EX_SECURE(exp)) {
552                         printk(KERN_WARNING
553                                "nfsd: request from insecure port (%08x:%d)!\n",
554                                ntohl(rqstp->rq_addr.sin_addr.s_addr),
555                                ntohs(rqstp->rq_addr.sin_port));
556                         goto out;
557                 }
558 
559                 /* Set user creds if we haven't done so already. */
560                 nfsd_setuser(rqstp, exp);
561 
562                 /*
563                  * Look up the dentry using the NFS file handle.
564                  */
565                 error = nfserr_stale;
566                 if (rqstp->rq_vers == 3)
567                         error = nfserr_badhandle;
568 
569                 if (fh->fh_version == 1) {
570                         /* if fileid_type != 0, and super_operations provide fh_to_dentry lookup,
571                          *  then should use that */
572                         switch (fh->fh_fileid_type) {
573                         case 0:
574                                 dentry = dget(exp->ex_dentry);
575                                 break;
576                         case 1:
577                                 if ((data_left-=2)<0) goto out;
578                                 dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
579                                                         datap[0], datap[1],
580                                                         0,
581                                                         !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
582                                 break;
583                         case 2:
584                                 if ((data_left-=3)<0) goto out;
585                                 dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
586                                                         datap[0], datap[1],
587                                                         datap[2],
588                                                         !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
589                                 break;
590                         default: goto out;
591                         }
592                 } else {
593 
594                         dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
595                                                 fh->ofh_ino, fh->ofh_generation,
596                                                 fh->ofh_dirino,
597                                                 !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
598                 }
599                 if (IS_ERR(dentry)) {
600                         error = nfserrno(PTR_ERR(dentry));
601                         goto out;
602                 }
603 #ifdef NFSD_PARANOIA
604                 if (S_ISDIR(dentry->d_inode->i_mode) &&
605                     (dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) {
606                         printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
607                                dentry->d_parent->d_name.name, dentry->d_name.name);
608                 }
609 #endif
610 
611                 fhp->fh_dentry = dentry;
612                 fhp->fh_export = exp;
613                 nfsd_nr_verified++;
614         } else {
615                 /* just rechecking permissions
616                  * (e.g. nfsproc_create calls fh_verify, then nfsd_create does as well)
617                  */
618                 dprintk("nfsd: fh_verify - just checking\n");
619                 dentry = fhp->fh_dentry;
620                 exp = fhp->fh_export;
621         }
622 
623         inode = dentry->d_inode;
624 
625         /* Type check. The correct error return for type mismatches
626          * does not seem to be generally agreed upon. SunOS seems to
627          * use EISDIR if file isn't S_IFREG; a comment in the NFSv3
628          * spec says this is incorrect (implementation notes for the
629          * write call).
630          */
631 
632         /* When is type ever negative? */
633         if (type > 0 && (inode->i_mode & S_IFMT) != type) {
634                 error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
635                 goto out;
636         }
637         if (type < 0 && (inode->i_mode & S_IFMT) == -type) {
638                 error = (type == -S_IFDIR)? nfserr_notdir : nfserr_isdir;
639                 goto out;
640         }
641 
642         /*
643          * Security: Check that the export is valid for dentry <gam3@acm.org>
644          */
645         error = 0;
646 
647         if (!(exp->ex_flags & NFSEXP_NOSUBTREECHECK)) {
648                 if (exp->ex_dentry != dentry) {
649                         struct dentry *tdentry = dentry;
650 
651                         do {
652                                 tdentry = tdentry->d_parent;
653                                 if (exp->ex_dentry == tdentry)
654                                         break;
655                                 /* executable only by root and we can't be root */
656                                 if (current->fsuid
657                                     && (exp->ex_flags & NFSEXP_ROOTSQUASH)
658                                     && !(tdentry->d_inode->i_uid
659                                          && (tdentry->d_inode->i_mode & S_IXUSR))
660                                     && !(tdentry->d_inode->i_gid
661                                          && (tdentry->d_inode->i_mode & S_IXGRP))
662                                     && !(tdentry->d_inode->i_mode & S_IXOTH)
663                                         ) {
664                                         error = nfserr_stale;
665                                         nfsdstats.fh_stale++;
666                                         dprintk("fh_verify: no root_squashed access.\n");
667                                 }
668                         } while ((tdentry != tdentry->d_parent));
669                         if (exp->ex_dentry != tdentry) {
670                                 error = nfserr_stale;
671                                 nfsdstats.fh_stale++;
672                                 printk("nfsd Security: %s/%s bad export.\n",
673                                        dentry->d_parent->d_name.name,
674                                        dentry->d_name.name);
675                                 goto out;
676                         }
677                 }
678         }
679 
680         /* Finally, check access permissions. */
681         if (!error) {
682                 error = nfsd_permission(exp, dentry, access);
683         }
684 #ifdef NFSD_PARANOIA
685         if (error) {
686                 printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n",
687                        dentry->d_parent->d_name.name, dentry->d_name.name, access, (error >> 24));
688         }
689 #endif
690 out:
691         return error;
692 }
693 
694 /*
695  * Compose a file handle for an NFS reply.
696  *
697  * Note that when first composed, the dentry may not yet have
698  * an inode.  In this case a call to fh_update should be made
699  * before the fh goes out on the wire ...
700  */
701 inline int _fh_update(struct dentry *dentry, struct svc_export *exp,
702                       __u32 **datapp, int maxsize)
703 {
704         __u32 *datap= *datapp;
705         if (dentry == exp->ex_dentry)
706                 return 0;
707         /* if super_operations provides dentry_to_fh lookup, should use that */
708         
709         *datap++ = ino_t_to_u32(dentry->d_inode->i_ino);
710         *datap++ = dentry->d_inode->i_generation;
711         if (S_ISDIR(dentry->d_inode->i_mode) || (exp->ex_flags & NFSEXP_NOSUBTREECHECK)){
712                 *datapp = datap;
713                 return 1;
714         }
715         *datap++ = ino_t_to_u32(dentry->d_parent->d_inode->i_ino);
716         *datapp = datap;
717         return 2;
718 }
719 
720 int
721 fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry)
722 {
723         struct inode * inode = dentry->d_inode;
724         struct dentry *parent = dentry->d_parent;
725         __u32 *datap;
726 
727         dprintk("nfsd: fh_compose(exp %x/%ld %s/%s, ino=%ld)\n",
728                 exp->ex_dev, (long) exp->ex_ino,
729                 parent->d_name.name, dentry->d_name.name,
730                 (inode ? inode->i_ino : 0));
731 
732         if (fhp->fh_locked || fhp->fh_dentry) {
733                 printk(KERN_ERR "fh_compose: fh %s/%s not initialized!\n",
734                         parent->d_name.name, dentry->d_name.name);
735         }
736         if (fhp->fh_maxsize < NFS_FHSIZE)
737                 printk(KERN_ERR "fh_compose: called with maxsize %d! %s/%s\n",
738                        fhp->fh_maxsize, parent->d_name.name, dentry->d_name.name);
739 
740         fhp->fh_dentry = dentry; /* our internal copy */
741         fhp->fh_export = exp;
742 
743         fhp->fh_handle.fh_version = 1;
744         fhp->fh_handle.fh_auth_type = 0;
745         fhp->fh_handle.fh_fsid_type = 0;
746         datap = fhp->fh_handle.fh_auth+0;
747         /* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */
748         *datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
749         *datap++ = ino_t_to_u32(exp->ex_ino);
750 
751         if (inode)
752                 fhp->fh_handle.fh_fileid_type =
753                         _fh_update(dentry, exp, &datap, fhp->fh_maxsize-3);
754 
755         fhp->fh_handle.fh_size = (datap-fhp->fh_handle.fh_auth+1)*4;
756 
757 
758         nfsd_nr_verified++;
759         if (fhp->fh_handle.fh_fileid_type == 255)
760                 return nfserr_opnotsupp;
761         return 0;
762 }
763 
764 /*
765  * Update file handle information after changing a dentry.
766  * This is only called by nfsd_create, nfsd_create_v3 and nfsd_proc_create
767  */
768 int
769 fh_update(struct svc_fh *fhp)
770 {
771         struct dentry *dentry;
772         __u32 *datap;
773         
774         if (!fhp->fh_dentry)
775                 goto out_bad;
776 
777         dentry = fhp->fh_dentry;
778         if (!dentry->d_inode)
779                 goto out_negative;
780         if (fhp->fh_handle.fh_fileid_type != 0)
781                 goto out_uptodate;
782         datap = fhp->fh_handle.fh_auth+
783                           fhp->fh_handle.fh_size/4 -1;
784         fhp->fh_handle.fh_fileid_type =
785                 _fh_update(dentry, fhp->fh_export, &datap, fhp->fh_maxsize-fhp->fh_handle.fh_size);
786         fhp->fh_handle.fh_size = (datap-fhp->fh_handle.fh_auth+1)*4;
787 out:
788         return 0;
789 
790 out_bad:
791         printk(KERN_ERR "fh_update: fh not verified!\n");
792         goto out;
793 out_negative:
794         printk(KERN_ERR "fh_update: %s/%s still negative!\n",
795                 dentry->d_parent->d_name.name, dentry->d_name.name);
796         goto out;
797 out_uptodate:
798         printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
799                 dentry->d_parent->d_name.name, dentry->d_name.name);
800         goto out;
801 }
802 
803 /*
804  * Release a file handle.
805  */
806 void
807 fh_put(struct svc_fh *fhp)
808 {
809         struct dentry * dentry = fhp->fh_dentry;
810         if (dentry) {
811                 fh_unlock(fhp);
812                 fhp->fh_dentry = NULL;
813                 dput(dentry);
814                 nfsd_nr_put++;
815         }
816         return;
817 }
818 

~ [ 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.