FreeBSD/Linux Kernel Cross Reference
sys/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 struct dentry *tdentry = dentry;
701
702 while (tdentry != exp->ex_dentry && !IS_ROOT(tdentry)) {
703 struct dentry *parent = tdentry->d_parent;
704
705 /* make sure parents give x permission to user */
706 error = permission(parent->d_inode, MAY_EXEC);
707 if (error)
708 break;
709 tdentry = parent;
710 }
711 if (exp->ex_dentry != tdentry) {
712 error = nfserr_stale;
713 printk("fh_verify: no root_squashed access at %s/%s.\n",
714 dentry->d_parent->d_name.name,
715 dentry->d_name.name);
716 goto out;
717 }
718 }
719
720 /* Finally, check access permissions. */
721 if (!error) {
722 error = nfsd_permission(exp, dentry, access);
723 }
724 #ifdef NFSD_PARANOIA_EXTREME
725 if (error) {
726 printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n",
727 dentry->d_parent->d_name.name, dentry->d_name.name, access, (error >> 24));
728 }
729 #endif
730 out:
731 if (error == nfserr_stale)
732 nfsdstats.fh_stale++;
733 return error;
734 }
735
736 /*
737 * Compose a file handle for an NFS reply.
738 *
739 * Note that when first composed, the dentry may not yet have
740 * an inode. In this case a call to fh_update should be made
741 * before the fh goes out on the wire ...
742 */
743 inline int _fh_update(struct dentry *dentry, struct svc_export *exp,
744 __u32 *datap, int *maxsize)
745 {
746 struct super_block *sb = dentry->d_inode->i_sb;
747
748 if (dentry == exp->ex_dentry) {
749 *maxsize = 0;
750 return 0;
751 }
752
753 if (sb->s_op->dentry_to_fh) {
754 int need_parent = !S_ISDIR(dentry->d_inode->i_mode) &&
755 !(exp->ex_flags & NFSEXP_NOSUBTREECHECK);
756
757 int type = sb->s_op->dentry_to_fh(dentry, datap, maxsize, need_parent);
758 return type;
759 }
760
761 if (*maxsize < 2)
762 return 255;
763 *datap++ = ino_t_to_u32(dentry->d_inode->i_ino);
764 *datap++ = dentry->d_inode->i_generation;
765 if (*maxsize ==2 ||
766 S_ISDIR(dentry->d_inode->i_mode) ||
767 (exp->ex_flags & NFSEXP_NOSUBTREECHECK)) {
768 *maxsize = 2;
769 return 1;
770 }
771 *datap++ = ino_t_to_u32(dentry->d_parent->d_inode->i_ino);
772 *maxsize = 3;
773 return 2;
774 }
775
776 /*
777 * for composing old style file handles
778 */
779 inline void _fh_update_old(struct dentry *dentry, struct svc_export *exp,
780 struct knfsd_fh *fh)
781 {
782 fh->ofh_ino = ino_t_to_u32(dentry->d_inode->i_ino);
783 fh->ofh_generation = dentry->d_inode->i_generation;
784 if (S_ISDIR(dentry->d_inode->i_mode) ||
785 (exp->ex_flags & NFSEXP_NOSUBTREECHECK))
786 fh->ofh_dirino = 0;
787 }
788
789 int
790 fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, struct svc_fh *ref_fh)
791 {
792 /* ref_fh is a reference file handle.
793 * if it is non-null, then we should compose a filehandle which is
794 * of the same version, where possible.
795 * Currently, that means that if ref_fh->fh_handle.fh_version == 0xca
796 * Then create a 32byte filehandle using nfs_fhbase_old
797 * But only do this if dentry_to_fh is not available
798 *
799 */
800
801 struct inode * inode = dentry->d_inode;
802 struct dentry *parent = dentry->d_parent;
803 __u32 *datap;
804
805 dprintk("nfsd: fh_compose(exp %x/%ld %s/%s, ino=%ld)\n",
806 exp->ex_dev, (long) exp->ex_ino,
807 parent->d_name.name, dentry->d_name.name,
808 (inode ? inode->i_ino : 0));
809
810 if (fhp->fh_locked || fhp->fh_dentry) {
811 printk(KERN_ERR "fh_compose: fh %s/%s not initialized!\n",
812 parent->d_name.name, dentry->d_name.name);
813 }
814 if (fhp->fh_maxsize < NFS_FHSIZE)
815 printk(KERN_ERR "fh_compose: called with maxsize %d! %s/%s\n",
816 fhp->fh_maxsize, parent->d_name.name, dentry->d_name.name);
817
818 fhp->fh_dentry = dentry; /* our internal copy */
819 fhp->fh_export = exp;
820
821 if (ref_fh &&
822 ref_fh->fh_handle.fh_version == 0xca &&
823 parent->d_inode->i_sb->s_op->dentry_to_fh == NULL) {
824 /* old style filehandle please */
825 memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE);
826 fhp->fh_handle.fh_size = NFS_FHSIZE;
827 fhp->fh_handle.ofh_dcookie = 0xfeebbaca;
828 fhp->fh_handle.ofh_dev = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
829 fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev;
830 fhp->fh_handle.ofh_xino = ino_t_to_u32(exp->ex_ino);
831 fhp->fh_handle.ofh_dirino = ino_t_to_u32(dentry->d_parent->d_inode->i_ino);
832 if (inode)
833 _fh_update_old(dentry, exp, &fhp->fh_handle);
834 } else {
835 fhp->fh_handle.fh_version = 1;
836 fhp->fh_handle.fh_auth_type = 0;
837 datap = fhp->fh_handle.fh_auth+0;
838 if ((exp->ex_flags & NFSEXP_FSID) &&
839 (!ref_fh || ref_fh->fh_handle.fh_fsid_type == 1)) {
840 fhp->fh_handle.fh_fsid_type = 1;
841 /* fsid_type 1 == 4 bytes filesystem id */
842 *datap++ = exp->ex_fsid;
843 fhp->fh_handle.fh_size = 2*4;
844 } else {
845 fhp->fh_handle.fh_fsid_type = 0;
846 /* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */
847 *datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
848 *datap++ = ino_t_to_u32(exp->ex_ino);
849 fhp->fh_handle.fh_size = 3*4;
850 }
851 if (inode) {
852 int size = fhp->fh_maxsize/4 - 3;
853 fhp->fh_handle.fh_fileid_type =
854 _fh_update(dentry, exp, datap, &size);
855 fhp->fh_handle.fh_size += size*4;
856 }
857 }
858
859 nfsd_nr_verified++;
860 if (fhp->fh_handle.fh_fileid_type == 255)
861 return nfserr_opnotsupp;
862 return 0;
863 }
864
865 /*
866 * Update file handle information after changing a dentry.
867 * This is only called by nfsd_create, nfsd_create_v3 and nfsd_proc_create
868 */
869 int
870 fh_update(struct svc_fh *fhp)
871 {
872 struct dentry *dentry;
873 __u32 *datap;
874
875 if (!fhp->fh_dentry)
876 goto out_bad;
877
878 dentry = fhp->fh_dentry;
879 if (!dentry->d_inode)
880 goto out_negative;
881 if (fhp->fh_handle.fh_version != 1) {
882 _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle);
883 } else {
884 int size;
885 if (fhp->fh_handle.fh_fileid_type != 0)
886 goto out_uptodate;
887 datap = fhp->fh_handle.fh_auth+
888 fhp->fh_handle.fh_size/4 -1;
889 size = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4;
890 fhp->fh_handle.fh_fileid_type =
891 _fh_update(dentry, fhp->fh_export, datap, &size);
892 fhp->fh_handle.fh_size += size*4;
893 }
894 out:
895 return 0;
896
897 out_bad:
898 printk(KERN_ERR "fh_update: fh not verified!\n");
899 goto out;
900 out_negative:
901 printk(KERN_ERR "fh_update: %s/%s still negative!\n",
902 dentry->d_parent->d_name.name, dentry->d_name.name);
903 goto out;
904 out_uptodate:
905 printk(KERN_ERR "fh_update: %s/%s already up-to-date!\n",
906 dentry->d_parent->d_name.name, dentry->d_name.name);
907 goto out;
908 }
909
910 /*
911 * Release a file handle.
912 */
913 void
914 fh_put(struct svc_fh *fhp)
915 {
916 struct dentry * dentry = fhp->fh_dentry;
917 if (dentry) {
918 fh_unlock(fhp);
919 fhp->fh_dentry = NULL;
920 dput(dentry);
921 nfsd_nr_put++;
922 }
923 return;
924 }
Cache object: b9dbd8f248d305fb2446e73aa735e74d
|