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