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