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
11 #include <linux/config.h>
12 #include <linux/sched.h>
13 #include <linux/malloc.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
,
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" */
53 #ifdef NFSD_DEBUG_VERBOSE
54 dprintk("filldir_one: seq=%d, ino=%ld, name=%s\n", buf
->sequence
, ino
, name
);
56 if (buf
->ino
== ino
) {
58 memcpy(nbuf
, name
, len
);
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
;
77 struct nfsd_getdents_callback buffer
;
80 if (!dir
|| !S_ISDIR(dir
->i_mode
))
86 * Open the directory ...
88 error
= init_private_file(&file
, dentry
, FMODE_READ
);
92 if (!file
.f_op
->readdir
)
100 int old_seq
= buffer
.sequence
;
101 error
= file
.f_op
->readdir(&file
, &buffer
, filldir_one
);
109 if (old_seq
== buffer
.sequence
)
114 if (file
.f_op
->release
)
115 file
.f_op
->release(dir
, &file
);
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
132 * Currently we don't know the generation for parent directory, so a generation
133 * of 0 means "accept any"
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",
145 inode
->i_nlink
, atomic_read(&inode
->i_count
),
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
)) {
163 result
= d_alloc_root(inode
);
164 if (result
== NULL
) {
166 return ERR_PTR(-ENOMEM
);
168 result
->d_flags
|= DCACHE_NFSD_DISCONNECTED
;
169 d_rehash(result
); /* so a dput won't loose it */
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
;
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
);
186 name
->hash
= full_name_hash(name
->name
, name
->len
);
187 tdentry
= d_alloc(parent
, name
);
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
;
200 /* if parent is properly connected, then we can assert that
201 * the children are connected, but it must be a singluar (non-forking)
204 if (!(parent
->d_flags
& DCACHE_NFSD_DISCONNECTED
)) {
206 target
->d_flags
&= ~DCACHE_NFSD_DISCONNECTED
;
208 if (list_empty(&parent
->d_subdirs
))
211 target
= list_entry(parent
->d_subdirs
.next
, struct dentry
, d_child
);
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
);
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});
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 */
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
)
256 if (pdentry
) dget(pdentry
);
258 if (pdentry
== NULL
) {
259 pdentry
= d_alloc_root(igrab(tdentry
->d_inode
));
261 pdentry
->d_flags
|= DCACHE_NFSD_DISCONNECTED
;
266 pdentry
= ERR_PTR(-ENOMEM
);
268 dput(tdentry
); /* it is not hashed, it will be discarded */
272 static struct dentry
*splice(struct dentry
*child
, struct dentry
*parent
)
277 struct list_head
*lp
;
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.
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
) {
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
);
306 tmp
= d_lookup(parent
, &qs
);
308 /* Now that IS odd. I wonder what it means... */
310 printk("nfsd-fh: found a name that I didn't expect: %s/%s\n", parent
->d_name
.name
, qs
.name
);
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
);
317 up(&parent
->d_inode
->i_sem
);
325 * This is the basic lookup mechanism for turning an NFS file handle
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
;
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
346 nfsdstats
.fh_lookup
++;
348 * Attempt to find the inode.
351 result
= nfsd_iget(sb
, ino
, generation
);
352 err
= PTR_ERR(result
);
356 if (! (result
->d_flags
& DCACHE_NFSD_DISCONNECTED
))
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
) {
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
);
381 if (!S_ISDIR(result
->d_inode
->i_mode
)) {
382 nfsdstats
.fh_nocache_nondir
++;
384 goto err_result
; /* don't know how to find parent */
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
);
393 || !S_ISDIR(dentry
->d_inode
->i_mode
)) {
396 if ((!dentry
->d_flags
& DCACHE_NFSD_DISCONNECTED
))
398 tmp
= splice(result
, dentry
);
403 /* it is safe to just use tmp instead, but we must discard result first */
407 /* If !found, then this is really wierd, but it shouldn't hurt */
411 nfsdstats
.fh_nocache_dir
++;
412 dentry
= dget(result
);
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
);
427 parent
= pdentry
->d_inode
;
434 if (!(dentry
->d_flags
& DCACHE_NFSD_DISCONNECTED
))
437 tmp
= splice(dentry
, pdentry
);
439 /* Something wrong. We need to drop thw whole dentry->result path
443 for (d
=result
; d
; d
=(d
->d_parent
== d
)?NULL
:d
->d_parent
)
452 /* we lost a race, try again
456 dput(result
); /* this will discard the whole free path, so we can up the semaphore */
457 up(&sb
->s_nfsd_free_path_sem
);
464 up(&sb
->s_nfsd_free_path_sem
);
471 up(&sb
->s_nfsd_free_path_sem
);
474 nfsdstats
.fh_stale
++;
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
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
;
496 dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp
));
498 if (!fhp
->fh_dverified
) {
502 int data_left
= fh
->fh_size
/4;
504 error
= nfserr_stale
;
506 if (rqstp
->rq_vers
== 3)
507 error
= nfserr_badhandle
;
509 if (fh
->fh_version
== 1) {
512 if (--data_left
<0) goto out
;
513 switch (fh
->fh_auth_type
) {
518 switch (fh
->fh_fsid_type
) {
520 if ((data_left
-=2)<0) goto out
;
521 nfsdev
= ntohl(*datap
++);
522 xdev
= MKDEV(nfsdev
>>16, nfsdev
&0xFFFF);
529 if (fh
->fh_size
!= NFS_FHSIZE
)
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
);
543 /* export entry revoked */
544 nfsdstats
.fh_stale
++;
548 /* Check if the request originated from a secure port. */
550 if (!rqstp
->rq_secure
&& EX_SECURE(exp
)) {
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
));
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
;
566 if (rqstp
->rq_vers
== 3)
567 error
= nfserr_badhandle
;
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
) {
575 dentry
= dget(exp
->ex_dentry
);
578 if ((data_left
-=2)<0) goto out
;
579 dentry
= find_fh_dentry(exp
->ex_dentry
->d_inode
->i_sb
,
582 !(exp
->ex_flags
& NFSEXP_NOSUBTREECHECK
));
585 if ((data_left
-=3)<0) goto out
;
586 dentry
= find_fh_dentry(exp
->ex_dentry
->d_inode
->i_sb
,
589 !(exp
->ex_flags
& NFSEXP_NOSUBTREECHECK
));
595 dentry
= find_fh_dentry(exp
->ex_dentry
->d_inode
->i_sb
,
596 fh
->ofh_ino
, fh
->ofh_generation
,
598 !(exp
->ex_flags
& NFSEXP_NOSUBTREECHECK
));
600 if (IS_ERR(dentry
)) {
601 error
= nfserrno(PTR_ERR(dentry
));
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
);
612 fhp
->fh_dentry
= dentry
;
613 fhp
->fh_export
= exp
;
614 fhp
->fh_dverified
= 1;
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
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
;
639 if (type
< 0 && (inode
->i_mode
& S_IFMT
) == -type
) {
640 error
= (type
== -S_IFDIR
)? nfserr_notdir
: nfserr_isdir
;
645 * Security: Check that the export is valid for dentry <gam3@acm.org>
649 if (!(exp
->ex_flags
& NFSEXP_NOSUBTREECHECK
)) {
650 if (exp
->ex_dentry
!= dentry
) {
651 struct dentry
*tdentry
= dentry
;
654 tdentry
= tdentry
->d_parent
;
655 if (exp
->ex_dentry
== tdentry
)
657 /* executable only by root and we can't be root */
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
);
682 /* Finally, check access permissions. */
684 error
= nfsd_permission(exp
, dentry
, access
);
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));
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
)
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
)){
717 *datap
++ = ino_t_to_u32(dentry
->d_parent
->d_inode
->i_ino
);
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
;
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
);
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;
763 if (fhp
->fh_handle
.fh_fileid_type
== 255)
764 return nfserr_opnotsupp
;
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
;
778 if (!fhp
->fh_dverified
)
781 dentry
= fhp
->fh_dentry
;
782 if (!dentry
->d_inode
)
784 if (fhp
->fh_handle
.fh_fileid_type
!= 0)
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;
795 printk(KERN_ERR
"fh_update: fh not verified!\n");
798 printk(KERN_ERR
"fh_update: %s/%s still negative!\n",
799 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
);
802 printk(KERN_ERR
"fh_update: %s/%s already up-to-date!\n",
803 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
);
808 * Release a file handle.
811 fh_put(struct svc_fh
*fhp
)
813 struct dentry
* dentry
= fhp
->fh_dentry
;
814 if (fhp
->fh_dverified
) {
816 fhp
->fh_dentry
= NULL
;
817 fhp
->fh_dverified
= 0;