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