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