2 * linux/fs/nfsd/export.c
4 * NFS exporting and validation.
6 * We maintain a list of clients, each of which has a list of
7 * exports. To export an fs to a given client, you first have
8 * to create the client entry with NFSCTL_ADDCLIENT, which
9 * creates a client control block and adds it to the hash
10 * table. Then, you call NFSCTL_EXPORT for each fs.
12 * You cannot currently read the export information from the
13 * kernel. It would be nice to have a /proc file though.
15 * Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
18 #include <linux/unistd.h>
19 #include <linux/malloc.h>
20 #include <linux/stat.h>
23 #include <linux/sunrpc/svc.h>
24 #include <linux/nfsd/nfsd.h>
25 #include <linux/nfsd/nfsfh.h>
26 #include <linux/nfsd/syscall.h>
27 #include <linux/lockd/bind.h>
29 #define NFSDDBG_FACILITY NFSDDBG_EXPORT
30 #define NFSD_PARANOIA 1
32 typedef struct svc_client svc_client
;
33 typedef struct svc_export svc_export
;
35 static svc_export
* exp_find(svc_client
*clp
, kdev_t dev
);
36 static svc_export
* exp_parent(svc_client
*clp
, kdev_t dev
,
37 struct dentry
*dentry
);
38 static svc_export
* exp_child(svc_client
*clp
, kdev_t dev
,
39 struct dentry
*dentry
);
40 static void exp_unexport_all(svc_client
*clp
);
41 static void exp_do_unexport(svc_export
*unexp
);
42 static svc_client
* exp_getclientbyname(char *name
);
43 static void exp_freeclient(svc_client
*clp
);
44 static void exp_unhashclient(svc_client
*clp
);
45 static int exp_verify_string(char *cp
, int max
);
47 #define CLIENT_HASHBITS 6
48 #define CLIENT_HASHMAX (1 << CLIENT_HASHBITS)
49 #define CLIENT_HASHMASK (CLIENT_HASHMAX - 1)
50 #define CLIENT_HASH(a) \
51 ((((a)>>24) ^ ((a)>>16) ^ ((a)>>8) ^(a)) & CLIENT_HASHMASK)
52 /* XXX: is this adequate for 32bit kdev_t ? */
53 #define EXPORT_HASH(dev) ((dev) & (NFSCLNT_EXPMAX - 1))
56 struct svc_clnthash
* h_next
;
57 struct in_addr h_addr
;
58 struct svc_client
* h_client
;
60 static struct svc_clnthash
* clnt_hash
[CLIENT_HASHMAX
];
61 static svc_client
* clients
= NULL
;
62 static int initialized
= 0;
64 static int hash_lock
= 0;
65 static int want_lock
= 0;
66 static int hash_count
= 0;
67 static DECLARE_WAIT_QUEUE_HEAD( hash_wait
);
71 * Find a client's export for a device.
73 static inline svc_export
*
74 exp_find(svc_client
*clp
, kdev_t dev
)
78 exp
= clp
->cl_export
[EXPORT_HASH(dev
)];
79 while (exp
&& exp
->ex_dev
!= dev
)
85 * Find the client's export entry matching xdev/xino.
88 exp_get(svc_client
*clp
, kdev_t dev
, ino_t ino
)
95 exp
= clp
->cl_export
[EXPORT_HASH(dev
)];
98 if (exp
->ex_ino
== ino
&& exp
->ex_dev
== dev
)
100 } while (NULL
!= (exp
= exp
->ex_next
));
108 * Look up the device of the parent fs.
111 nfsd_parentdev(kdev_t
*devp
)
113 struct super_block
*sb
;
115 if (!(sb
= get_super(*devp
)) || !sb
->s_root
->d_covers
)
117 if (*devp
== sb
->s_root
->d_covers
->d_inode
->i_dev
)
119 *devp
= sb
->s_root
->d_covers
->d_inode
->i_dev
;
124 * Find the export entry for a given dentry. <gam3@acm.org>
127 exp_parent(svc_client
*clp
, kdev_t dev
, struct dentry
*dentry
)
131 struct dentry
*xdentry
= dentry
;
132 struct dentry
*ndentry
= NULL
;
134 if (clp
== NULL
|| dentry
== NULL
)
140 exp
= clp
->cl_export
[EXPORT_HASH(xdev
)];
143 ndentry
= exp
->ex_dentry
;
144 if (ndentry
== xdentry
) {
147 dprintk("nfsd: exp_parent submount over mount.\n");
149 dprintk("nfsd: exp_parent found.\n");
153 } while (NULL
!= (exp
= exp
->ex_next
));
154 } while (nfsd_parentdev(&xdev
));
155 if (IS_ROOT(xdentry
))
157 } while ((xdentry
= xdentry
->d_parent
));
164 * Find the child export entry for a given fs. This function is used
165 * only by the export syscall to keep the export tree consistent.
169 exp_child(svc_client
*clp
, kdev_t dev
, struct dentry
*dentry
)
172 struct dentry
*xdentry
= dentry
;
173 struct dentry
*ndentry
= NULL
;
175 if (clp
== NULL
|| dentry
== NULL
)
178 exp
= clp
->cl_export
[EXPORT_HASH(dev
)];
181 ndentry
= exp
->ex_dentry
;
183 while ((ndentry
= ndentry
->d_parent
)) {
184 if (ndentry
== xdentry
) {
186 dprintk("nfsd: exp_child mount under submount.\n");
190 if (IS_ROOT(ndentry
))
193 } while (NULL
!= (exp
= exp
->ex_next
));
200 * Export a file system.
203 exp_export(struct nfsctl_export
*nxp
)
206 svc_export
*exp
, *parent
;
208 struct dentry
*dentry
= NULL
;
209 struct inode
*inode
= NULL
;
214 /* Consistency check */
216 if (!exp_verify_string(nxp
->ex_path
, NFS_MAXPATHLEN
) ||
217 !exp_verify_string(nxp
->ex_client
, NFSCLNT_IDMAX
))
220 dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
221 nxp
->ex_client
, nxp
->ex_path
,
222 nxp
->ex_dev
, (long) nxp
->ex_ino
, nxp
->ex_flags
);
223 dev
= to_kdev_t(nxp
->ex_dev
);
226 /* Try to lock the export table for update */
227 if ((err
= exp_writelock()) < 0)
230 /* Look up client info */
232 if (!(clp
= exp_getclientbyname(nxp
->ex_client
)))
236 * If there's already an export for this file, assume this
237 * is just a flag update.
239 if ((exp
= exp_get(clp
, dev
, ino
)) != NULL
) {
240 exp
->ex_flags
= nxp
->ex_flags
;
241 exp
->ex_anon_uid
= nxp
->ex_anon_uid
;
242 exp
->ex_anon_gid
= nxp
->ex_anon_gid
;
247 /* Look up the dentry */
249 dentry
= lookup_dentry(nxp
->ex_path
, LOOKUP_POSITIVE
);
253 inode
= dentry
->d_inode
;
255 if (inode
->i_dev
!= dev
|| inode
->i_ino
!= nxp
->ex_ino
) {
256 printk(KERN_DEBUG
"exp_export: i_dev = %x, dev = %x\n",
258 /* I'm just being paranoid... */
262 /* We currently export only dirs and regular files.
263 * This is what umountd does.
266 if (!S_ISDIR(inode
->i_mode
) && !S_ISREG(inode
->i_mode
))
270 if (!(inode
->i_sb
->s_type
->fs_flags
& FS_REQUIRES_DEV
) ||
271 inode
->i_sb
->s_op
->read_inode
== NULL
) {
272 dprintk("exp_export: export of invalid fs type.\n");
276 if ((parent
= exp_child(clp
, dev
, dentry
)) != NULL
) {
277 dprintk("exp_export: export not valid (Rule 3).\n");
280 /* Is this is a sub-export, must be a proper subset of FS */
281 if ((parent
= exp_parent(clp
, dev
, dentry
)) != NULL
) {
282 if (dev
== parent
->ex_dev
) {
283 dprintk("exp_export: sub-export not valid (Rule 2).\n");
289 if (!(exp
= kmalloc(sizeof(*exp
), GFP_USER
)))
291 dprintk("nfsd: created export entry %p for client %p\n", exp
, clp
);
293 strcpy(exp
->ex_path
, nxp
->ex_path
);
294 exp
->ex_client
= clp
;
295 exp
->ex_parent
= parent
;
296 exp
->ex_dentry
= dentry
;
297 exp
->ex_flags
= nxp
->ex_flags
;
300 exp
->ex_anon_uid
= nxp
->ex_anon_uid
;
301 exp
->ex_anon_gid
= nxp
->ex_anon_gid
;
303 /* Update parent pointers of all exports */
305 for (i
= 0; i
< NFSCLNT_EXPMAX
; i
++) {
306 svc_export
*temp
= clp
->cl_export
[i
];
309 if (temp
->ex_parent
== parent
)
310 temp
->ex_parent
= exp
;
311 temp
= temp
->ex_next
;
316 head
= clp
->cl_export
+ EXPORT_HASH(dev
);
317 exp
->ex_next
= *head
;
322 /* Unlock hashtable */
328 /* Release the dentry */
335 * Unexport a file system. The export entry has already
336 * been removed from the client's list of exported fs's.
339 exp_do_unexport(svc_export
*unexp
)
343 struct dentry
*dentry
;
347 /* Update parent pointers. */
348 clp
= unexp
->ex_client
;
349 for (i
= 0; i
< NFSCLNT_EXPMAX
; i
++) {
350 for (exp
= clp
->cl_export
[i
]; exp
; exp
= exp
->ex_next
)
351 if (exp
->ex_parent
== unexp
)
352 exp
->ex_parent
= unexp
->ex_parent
;
355 dentry
= unexp
->ex_dentry
;
356 inode
= dentry
->d_inode
;
357 if (unexp
->ex_dev
!= inode
->i_dev
|| unexp
->ex_ino
!= inode
->i_ino
)
358 printk(KERN_WARNING
"nfsd: bad dentry in unexport!\n");
365 * Revoke all exports for a given client.
366 * This may look very awkward, but we have to do it this way in order
367 * to avoid race conditions (aka mind the parent pointer).
370 exp_unexport_all(svc_client
*clp
)
375 dprintk("unexporting all fs's for clnt %p\n", clp
);
376 for (i
= 0; i
< NFSCLNT_EXPMAX
; i
++) {
377 exp
= clp
->cl_export
[i
];
378 clp
->cl_export
[i
] = NULL
;
380 svc_export
*next
= exp
->ex_next
;
381 exp_do_unexport(exp
);
391 exp_unexport(struct nfsctl_export
*nxp
)
394 svc_export
**expp
, *exp
= NULL
;
397 /* Consistency check */
398 if (!exp_verify_string(nxp
->ex_client
, NFSCLNT_IDMAX
))
401 if ((err
= exp_writelock()) < 0)
405 clp
= exp_getclientbyname(nxp
->ex_client
);
407 expp
= clp
->cl_export
+ EXPORT_HASH(nxp
->ex_dev
);
408 while ((exp
= *expp
) != NULL
) {
409 if (exp
->ex_dev
== nxp
->ex_dev
) {
410 if (exp
->ex_ino
== nxp
->ex_ino
) {
411 *expp
= exp
->ex_next
;
412 exp_do_unexport(exp
);
417 expp
= &(exp
->ex_next
);
427 * Obtain the root fh on behalf of a client.
428 * This could be done in user space, but I feel that it adds some safety
429 * since its harder to fool a kernel module than a user space program.
432 exp_rootfh(struct svc_client
*clp
, kdev_t dev
, ino_t ino
,
433 char *path
, struct knfsd_fh
*f
, int maxsize
)
435 struct svc_export
*exp
;
436 struct dentry
*dentry
= NULL
;
443 if (!(dentry
= lookup_dentry(path
, 0))) {
444 printk("nfsd: exp_rootfh path not found %s", path
);
447 dev
= dentry
->d_inode
->i_dev
;
448 ino
= dentry
->d_inode
->i_ino
;
450 dprintk("nfsd: exp_rootfh(%s [%p] %s:%x/%ld)\n",
451 path
, dentry
, clp
->cl_ident
, dev
, (long) ino
);
452 exp
= exp_parent(clp
, dev
, dentry
);
454 dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n",
455 clp
->cl_ident
, dev
, (long) ino
);
456 if ((exp
= exp_get(clp
, dev
, ino
)))
457 if (!(dentry
= dget(exp
->ex_dentry
))) {
458 printk("exp_rootfh: Aieee, NULL dentry\n");
463 dprintk("nfsd: exp_rootfh export not found.\n");
467 inode
= dentry
->d_inode
;
469 printk("exp_rootfh: Aieee, NULL d_inode\n");
472 if (inode
->i_dev
!= dev
|| inode
->i_ino
!= ino
) {
473 printk("exp_rootfh: Aieee, ino/dev mismatch\n");
474 printk("exp_rootfh: arg[dev(%x):ino(%ld)]"
475 " inode[dev(%x):ino(%ld)]\n",
476 dev
, (long) ino
, inode
->i_dev
, (long) inode
->i_ino
);
480 * fh must be initialized before calling fh_compose
482 fh_init(&fh
, maxsize
);
483 if (fh_compose(&fh
, exp
, dentry
))
487 memcpy(f
, &fh
.fh_handle
, sizeof(struct knfsd_fh
));
497 * Hashtable locking. Write locks are placed only by user processes
498 * wanting to modify export information.
503 while (hash_lock
|| want_lock
)
504 sleep_on(&hash_wait
);
512 if (!hash_count
&& !hash_lock
) {
518 current
->sigpending
= 0;
520 while (hash_count
|| hash_lock
) {
521 interruptible_sleep_on(&hash_wait
);
522 if (signal_pending(current
))
527 /* restore the task's signals */
528 spin_lock_irq(¤t
->sigmask_lock
);
529 recalc_sigpending(current
);
530 spin_unlock_irq(¤t
->sigmask_lock
);
532 if (!hash_count
&& !hash_lock
)
540 if (!hash_count
&& !hash_lock
)
541 printk(KERN_WARNING
"exp_unlock: not locked!\n");
550 * Find a valid client given an inet address. We always move the most
551 * recently used client to the front of the hash chain to speed up
553 * Locking against other processes is the responsibility of the caller.
556 exp_getclient(struct sockaddr_in
*sin
)
558 struct svc_clnthash
**hp
, **head
, *tmp
;
559 unsigned long addr
= sin
->sin_addr
.s_addr
;
564 head
= &clnt_hash
[CLIENT_HASH(addr
)];
566 for (hp
= head
; (tmp
= *hp
) != NULL
; hp
= &(tmp
->h_next
)) {
567 if (tmp
->h_addr
.s_addr
== addr
) {
568 /* Move client to the front */
575 return tmp
->h_client
;
583 * Find a client given its identifier.
586 exp_getclientbyname(char *ident
)
590 for (clp
= clients
; clp
; clp
= clp
->cl_next
) {
591 if (!strcmp(clp
->cl_ident
, ident
))
601 { NFSEXP_READONLY
, {"ro", "rw"}},
602 { NFSEXP_INSECURE_PORT
, {"insecure", ""}},
603 { NFSEXP_ROOTSQUASH
, {"root_squash", "no_root_squash"}},
604 { NFSEXP_ALLSQUASH
, {"all_squash", ""}},
605 { NFSEXP_ASYNC
, {"async", ""}},
606 { NFSEXP_GATHERED_WRITES
, {"wdelay", ""}},
607 { NFSEXP_UIDMAP
, {"uidmap", ""}},
608 { NFSEXP_KERBEROS
, { "kerberos", ""}},
609 { NFSEXP_SUNSECURE
, { "sunsecure", ""}},
610 { NFSEXP_CROSSMNT
, {"nohide", ""}},
611 { NFSEXP_NOSUBTREECHECK
, {"no_subtree_check", ""}},
612 { NFSEXP_NOAUTHNLM
, {"insecure_locks", ""}},
617 exp_flags(char *buffer
, int flag
)
619 int len
= 0, first
= 0;
620 struct flags
*flg
= expflags
;
622 for (;flg
->flag
;flg
++) {
623 int state
= (flg
->flag
& flag
)?0:1;
626 if (*flg
->name
[state
]) {
627 len
+= sprintf(buffer
+ len
, "%s%s",
628 first
++?",":"", flg
->name
[state
]);
635 exp_procfs_exports(char *buffer
, char **start
, off_t offset
,
636 int length
, int *eof
, void *data
)
638 struct svc_clnthash
**hp
, **head
, *tmp
;
639 struct svc_client
*clp
;
646 len
+= sprintf(buffer
, "# Version 1.0\n");
647 len
+= sprintf(buffer
+len
, "# Path Client(Flags) # IPs\n");
649 for (clp
= clients
; clp
; clp
= clp
->cl_next
) {
650 for (i
= 0; i
< NFSCLNT_EXPMAX
; i
++) {
651 exp
= clp
->cl_export
[i
];
654 len
+= sprintf(buffer
+len
, "%s\t", exp
->ex_path
);
655 len
+= sprintf(buffer
+len
, "%s", clp
->cl_ident
);
656 len
+= sprintf(buffer
+len
, "(");
658 len
+= exp_flags(buffer
+len
, exp
->ex_flags
);
659 len
+= sprintf(buffer
+len
, ") # ");
660 for (j
= 0; j
< clp
->cl_naddr
; j
++) {
661 struct in_addr addr
= clp
->cl_addr
[j
];
663 head
= &clnt_hash
[CLIENT_HASH(addr
.s_addr
)];
664 for (hp
= head
; (tmp
= *hp
) != NULL
; hp
= &(tmp
->h_next
)) {
665 if (tmp
->h_addr
.s_addr
== addr
.s_addr
) {
666 if (first
++) len
+= sprintf(buffer
+len
, "%s", " ");
667 if (tmp
->h_client
!= clp
)
668 len
+= sprintf(buffer
+len
, "(");
669 len
+= sprintf(buffer
+len
, "%d.%d.%d.%d",
670 htonl(addr
.s_addr
) >> 24 & 0xff,
671 htonl(addr
.s_addr
) >> 16 & 0xff,
672 htonl(addr
.s_addr
) >> 8 & 0xff,
673 htonl(addr
.s_addr
) >> 0 & 0xff);
674 if (tmp
->h_client
!= clp
)
675 len
+= sprintf(buffer
+len
, ")");
689 if (pos
> offset
+ length
)
698 *start
= buffer
+ (offset
- begin
);
699 len
-= (offset
- begin
);
706 * Add or modify a client.
707 * Change requests may involve the list of host addresses. The list of
708 * exports and possibly existing uid maps are left untouched.
711 exp_addclient(struct nfsctl_client
*ncp
)
713 struct svc_clnthash
* ch
[NFSCLNT_ADDRMAX
];
715 int i
, err
, change
= 0, ilen
;
717 /* First, consistency check. */
719 if (!(ilen
= exp_verify_string(ncp
->cl_ident
, NFSCLNT_IDMAX
)))
721 if (ncp
->cl_naddr
> NFSCLNT_ADDRMAX
)
724 /* Lock the hashtable */
725 if ((err
= exp_writelock()) < 0)
728 /* First check if this is a change request for a client. */
729 for (clp
= clients
; clp
; clp
= clp
->cl_next
)
730 if (!strcmp(clp
->cl_ident
, ncp
->cl_ident
))
737 if (!(clp
= kmalloc(sizeof(*clp
), GFP_KERNEL
)))
739 memset(clp
, 0, sizeof(*clp
));
741 dprintk("created client %s (%p)\n", ncp
->cl_ident
, clp
);
743 strcpy(clp
->cl_ident
, ncp
->cl_ident
);
744 clp
->cl_idlen
= ilen
;
747 /* Allocate hash buckets */
748 for (i
= 0; i
< ncp
->cl_naddr
; i
++) {
749 ch
[i
] = kmalloc(sizeof(struct svc_clnthash
), GFP_KERNEL
);
759 /* Copy addresses. */
760 for (i
= 0; i
< ncp
->cl_naddr
; i
++) {
761 clp
->cl_addr
[i
] = ncp
->cl_addrlist
[i
];
763 clp
->cl_naddr
= ncp
->cl_naddr
;
765 /* Remove old client hash entries. */
767 exp_unhashclient(clp
);
769 /* Insert client into hashtable. */
770 for (i
= 0; i
< ncp
->cl_naddr
; i
++) {
771 struct in_addr addr
= clp
->cl_addr
[i
];
774 hash
= CLIENT_HASH(addr
.s_addr
);
775 ch
[i
]->h_client
= clp
;
776 ch
[i
]->h_addr
= addr
;
777 ch
[i
]->h_next
= clnt_hash
[hash
];
778 clnt_hash
[hash
] = ch
[i
];
782 clp
->cl_next
= clients
;
794 * Delete a client given an identifier.
797 exp_delclient(struct nfsctl_client
*ncp
)
799 svc_client
**clpp
, *clp
;
803 if (!exp_verify_string(ncp
->cl_ident
, NFSCLNT_IDMAX
))
806 /* Lock the hashtable */
807 if ((err
= exp_writelock()) < 0)
811 for (clpp
= &clients
; (clp
= *clpp
); clpp
= &(clp
->cl_next
))
812 if (!strcmp(ncp
->cl_ident
, clp
->cl_ident
))
816 *clpp
= clp
->cl_next
;
827 * Free a client. The caller has already removed it from the client list.
830 exp_freeclient(svc_client
*clp
)
832 exp_unhashclient(clp
);
834 /* umap_free(&(clp->cl_umap)); */
835 exp_unexport_all(clp
);
836 nfsd_lockd_unexport(clp
);
841 * Remove client from hashtable. We first collect all hashtable
842 * entries and free them in one go.
843 * The hash table must be writelocked by the caller.
846 exp_unhashclient(svc_client
*clp
)
848 struct svc_clnthash
**hpp
, *hp
, *ch
[NFSCLNT_ADDRMAX
];
853 for (i
= 0, count
= 0; i
< CLIENT_HASHMAX
&& !err
; i
++) {
855 while ((hp
= *hpp
) && !err
) {
856 if (hp
->h_client
== clp
) {
859 err
= (count
>= NFSCLNT_ADDRMAX
);
865 if (count
!= clp
->cl_naddr
)
866 printk(KERN_WARNING
"nfsd: bad address count in freeclient!\n");
869 for (i
= 0; i
< count
; i
++)
874 * Lockd is shutting down and tells us to unregister all clients
879 struct svc_client
*clp
;
881 for (clp
= clients
; clp
; clp
= clp
->cl_next
)
882 nfsd_lockd_unexport(clp
);
886 * Verify that string is non-empty and does not exceed max length.
889 exp_verify_string(char *cp
, int max
)
893 for (i
= 0; i
< max
; i
++)
897 printk(KERN_NOTICE
"nfsd: couldn't validate string %s\n", cp
);
902 * Initialize the exports module.
905 nfsd_export_init(void)
909 dprintk("nfsd: initializing export module.\n");
912 for (i
= 0; i
< CLIENT_HASHMAX
; i
++)
920 * Shutdown the exports module.
923 nfsd_export_shutdown(void)
927 dprintk("nfsd: shutting down export module.\n");
930 if (exp_writelock() < 0) {
931 printk(KERN_WARNING
"Weird: hashtable locked in exp_shutdown");
934 for (i
= 0; i
< CLIENT_HASHMAX
; i
++) {
936 exp_freeclient(clnt_hash
[i
]->h_client
);
938 clients
= NULL
; /* we may be restarted before the module unloads */
941 dprintk("nfsd: export shutdown complete.\n");