1 #define MSNFS /* HACK HACK */
3 * linux/fs/nfsd/export.c
5 * NFS exporting and validation.
7 * We maintain a list of clients, each of which has a list of
8 * exports. To export an fs to a given client, you first have
9 * to create the client entry with NFSCTL_ADDCLIENT, which
10 * creates a client control block and adds it to the hash
11 * table. Then, you call NFSCTL_EXPORT for each fs.
14 * Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
17 #include <linux/unistd.h>
18 #include <linux/slab.h>
19 #include <linux/stat.h>
21 #include <linux/seq_file.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_parent(svc_client *clp, kdev_t dev,
36 struct dentry *dentry);
37 static svc_export * exp_child(svc_client *clp, kdev_t dev,
38 struct dentry *dentry);
39 static void exp_unexport_all(svc_client *clp);
40 static void exp_do_unexport(svc_export *unexp);
41 static svc_client * exp_getclientbyname(char *name);
42 static void exp_freeclient(svc_client *clp);
43 static void exp_unhashclient(svc_client *clp);
44 static int exp_verify_string(char *cp, int max);
46 #define CLIENT_HASHBITS 6
47 #define CLIENT_HASHMAX (1 << CLIENT_HASHBITS)
48 #define CLIENT_HASHMASK (CLIENT_HASHMAX - 1)
49 #define CLIENT_HASH(a) \
50 ((((a)>>24) ^ ((a)>>16) ^ ((a)>>8) ^(a)) & CLIENT_HASHMASK)
51 /* XXX: is this adequate for 32bit kdev_t ? */
52 #define EXPORT_HASH(dev) ((dev) & (NFSCLNT_EXPMAX - 1))
53 #define EXPORT_FSID_HASH(fsid) ((fsid) & (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;
65 static int hash_count;
66 static DECLARE_WAIT_QUEUE_HEAD( hash_wait );
69 * Find the client's export entry matching xdev/xino.
72 exp_get(svc_client *clp, kdev_t dev, ino_t ino)
74 struct list_head *head, *p;
79 head = &clp->cl_export[EXPORT_HASH(dev)];
80 list_for_each(p, head) {
81 svc_export *exp = list_entry(p, svc_export, ex_hash);
82 if (exp->ex_ino == ino && exp->ex_dev == dev)
90 * Find the client's export entry matching fsid
93 exp_get_fsid(svc_client *clp, int fsid)
95 struct list_head *head, *p;
100 head = &clp->cl_expfsid[EXPORT_FSID_HASH(fsid)];
101 list_for_each(p, head) {
102 svc_export *exp = list_entry(p, svc_export, ex_fsid_hash);
103 if (exp->ex_fsid == fsid)
110 * Find the export entry for a given dentry. <gam3@acm.org>
113 exp_parent(svc_client *clp, kdev_t dev, struct dentry *dentry)
115 struct list_head *head = &clp->cl_export[EXPORT_HASH(dev)];
118 list_for_each(p,head) {
119 svc_export *exp = list_entry(p, svc_export, ex_hash);
120 if (is_subdir(dentry, exp->ex_dentry))
127 * Find the child export entry for a given fs. This function is used
128 * only by the export syscall to keep the export tree consistent.
132 exp_child(svc_client *clp, kdev_t dev, struct dentry *dentry)
134 struct list_head *head = &clp->cl_export[EXPORT_HASH(dev)];
138 list_for_each(p, head) {
139 svc_export *exp = list_entry(p, svc_export, ex_hash);
140 struct dentry *ndentry = exp->ex_dentry;
142 if (ndentry && is_subdir(ndentry->d_parent, dentry))
148 /* Update parent pointers of all exports */
149 static void exp_change_parents(svc_client *clp, svc_export *old, svc_export *new)
151 struct list_head *head = &clp->cl_list;
154 list_for_each(p, head) {
155 svc_export *exp = list_entry(p, svc_export, ex_list);
156 if (exp->ex_parent == old)
157 exp->ex_parent = new;
161 static void exp_fsid_unhash(struct svc_export *exp)
164 if ((exp->ex_flags & NFSEXP_FSID) == 0)
167 list_del_init(&exp->ex_fsid_hash);
170 static void exp_fsid_hash(struct svc_client *clp, struct svc_export *exp)
172 struct list_head *head;
174 if ((exp->ex_flags & NFSEXP_FSID) == 0)
176 head = clp->cl_expfsid + EXPORT_FSID_HASH(exp->ex_fsid);
177 list_add(&exp->ex_fsid_hash, head);
181 * Export a file system.
184 exp_export(struct nfsctl_export *nxp)
187 svc_export *exp = NULL, *parent;
188 svc_export *fsid_exp;
190 struct inode *inode = NULL;
195 /* Consistency check */
197 if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
198 !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
201 dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
202 nxp->ex_client, nxp->ex_path,
203 nxp->ex_dev, (long) nxp->ex_ino, nxp->ex_flags);
205 /* Try to lock the export table for update */
206 if ((err = exp_writelock()) < 0)
209 /* Look up client info */
211 if (!(clp = exp_getclientbyname(nxp->ex_client)))
215 /* Look up the dentry */
217 if (path_init(nxp->ex_path, LOOKUP_POSITIVE, &nd))
218 err = path_walk(nxp->ex_path, &nd);
222 inode = nd.dentry->d_inode;
227 exp = exp_get(clp, dev, ino);
229 /* must make sure there wont be an ex_fsid clash */
230 if ((nxp->ex_flags & NFSEXP_FSID) &&
231 (fsid_exp = exp_get_fsid(clp, nxp->ex_dev)) &&
236 /* just a flags/id/fsid update */
238 exp_fsid_unhash(exp);
239 exp->ex_flags = nxp->ex_flags;
240 exp->ex_anon_uid = nxp->ex_anon_uid;
241 exp->ex_anon_gid = nxp->ex_anon_gid;
242 exp->ex_fsid = nxp->ex_dev;
243 exp_fsid_hash(clp, exp);
248 /* We currently export only dirs and regular files.
249 * This is what umountd does.
252 if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode))
256 /* There are two requirements on a filesystem to be exportable.
257 * 1: We must be able to identify the filesystem from a number.
258 * either a device number (so FS_REQUIRES_DEV needed)
259 * or an FSID number (so NFSEXP_FSID needed).
260 * 2: We must be able to find an inode from a filehandle.
261 * either using fh_to_dentry (prefered)
262 * or using read_inode (the hack).
264 if (!((inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV)
265 || (nxp->ex_flags & NFSEXP_FSID))
267 (inode->i_sb->s_op->read_inode == NULL
268 && inode->i_sb->s_op->fh_to_dentry == NULL)) {
269 dprintk("exp_export: export of invalid fs type.\n");
273 if ((parent = exp_child(clp, dev, nd.dentry)) != NULL) {
274 dprintk("exp_export: export not valid (Rule 3).\n");
277 /* Is this is a sub-export, must be a proper subset of FS */
278 if ((parent = exp_parent(clp, dev, nd.dentry)) != NULL) {
279 dprintk("exp_export: sub-export not valid (Rule 2).\n");
284 if (!(exp = kmalloc(sizeof(*exp), GFP_USER)))
286 dprintk("nfsd: created export entry %p for client %p\n", exp, clp);
288 strcpy(exp->ex_path, nxp->ex_path);
289 exp->ex_client = clp;
290 exp->ex_parent = parent;
291 exp->ex_dentry = dget(nd.dentry);
292 exp->ex_mnt = mntget(nd.mnt);
293 exp->ex_flags = nxp->ex_flags;
296 exp->ex_anon_uid = nxp->ex_anon_uid;
297 exp->ex_anon_gid = nxp->ex_anon_gid;
298 exp->ex_fsid = nxp->ex_dev;
301 /* Update parent pointers of all exports */
303 exp_change_parents(clp, parent, exp);
305 list_add(&exp->ex_hash, clp->cl_export + EXPORT_HASH(dev));
306 list_add_tail(&exp->ex_list, &clp->cl_list);
308 exp_fsid_hash(clp, exp);
321 * Unexport a file system. The export entry has already
322 * been removed from the client's list of exported fs's.
325 exp_do_unexport(svc_export *unexp)
327 struct dentry *dentry;
328 struct vfsmount *mnt;
331 list_del(&unexp->ex_hash);
332 list_del(&unexp->ex_list);
333 exp_fsid_unhash(unexp);
335 exp_change_parents(unexp->ex_client, unexp, unexp->ex_parent);
337 dentry = unexp->ex_dentry;
339 inode = dentry->d_inode;
340 if (unexp->ex_dev != inode->i_dev || unexp->ex_ino != inode->i_ino)
341 printk(KERN_WARNING "nfsd: bad dentry in unexport!\n");
349 * Revoke all exports for a given client.
350 * This may look very awkward, but we have to do it this way in order
351 * to avoid race conditions (aka mind the parent pointer).
354 exp_unexport_all(svc_client *clp)
356 struct list_head *p = &clp->cl_list;
358 dprintk("unexporting all fs's for clnt %p\n", clp);
360 while (!list_empty(p)) {
361 svc_export *exp = list_entry(p->next, svc_export, ex_list);
362 exp_do_unexport(exp);
370 exp_unexport(struct nfsctl_export *nxp)
375 /* Consistency check */
376 if (!exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
379 if ((err = exp_writelock()) < 0)
383 clp = exp_getclientbyname(nxp->ex_client);
385 svc_export *exp = exp_get(clp, nxp->ex_dev, nxp->ex_ino);
387 exp_do_unexport(exp);
398 * Obtain the root fh on behalf of a client.
399 * This could be done in user space, but I feel that it adds some safety
400 * since its harder to fool a kernel module than a user space program.
403 exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino,
404 char *path, struct knfsd_fh *f, int maxsize)
406 struct svc_export *exp;
414 if (path_init(path, LOOKUP_POSITIVE, &nd) &&
415 path_walk(path, &nd)) {
416 printk("nfsd: exp_rootfh path not found %s", path);
419 dev = nd.dentry->d_inode->i_dev;
420 ino = nd.dentry->d_inode->i_ino;
422 dprintk("nfsd: exp_rootfh(%s [%p] %s:%x/%ld)\n",
423 path, nd.dentry, clp->cl_ident, dev, (long) ino);
424 exp = exp_parent(clp, dev, nd.dentry);
426 dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n",
427 clp->cl_ident, dev, (long) ino);
428 if ((exp = exp_get(clp, dev, ino))) {
429 nd.mnt = mntget(exp->ex_mnt);
430 nd.dentry = dget(exp->ex_dentry);
434 dprintk("nfsd: exp_rootfh export not found.\n");
438 inode = nd.dentry->d_inode;
440 printk("exp_rootfh: Aieee, NULL d_inode\n");
443 if (inode->i_dev != dev || inode->i_ino != ino) {
444 printk("exp_rootfh: Aieee, ino/dev mismatch\n");
445 printk("exp_rootfh: arg[dev(%x):ino(%ld)]"
446 " inode[dev(%x):ino(%ld)]\n",
447 dev, (long) ino, inode->i_dev, (long) inode->i_ino);
451 * fh must be initialized before calling fh_compose
453 fh_init(&fh, maxsize);
454 if (fh_compose(&fh, exp, dget(nd.dentry), NULL))
458 memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh));
468 * Hashtable locking. Write locks are placed only by user processes
469 * wanting to modify export information.
474 while (hash_lock || want_lock)
475 sleep_on(&hash_wait);
483 if (!hash_count && !hash_lock) {
489 current->sigpending = 0;
491 while (hash_count || hash_lock) {
492 interruptible_sleep_on(&hash_wait);
493 if (signal_pending(current))
498 /* restore the task's signals */
499 spin_lock_irq(¤t->sigmask_lock);
500 recalc_sigpending(current);
501 spin_unlock_irq(¤t->sigmask_lock);
503 if (!hash_count && !hash_lock)
511 if (!hash_count && !hash_lock)
512 printk(KERN_WARNING "exp_unlock: not locked!\n");
521 * Find a valid client given an inet address. We always move the most
522 * recently used client to the front of the hash chain to speed up
524 * Locking against other processes is the responsibility of the caller.
527 exp_getclient(struct sockaddr_in *sin)
529 struct svc_clnthash **hp, **head, *tmp;
530 unsigned long addr = sin->sin_addr.s_addr;
532 head = &clnt_hash[CLIENT_HASH(addr)];
534 for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
535 if (tmp->h_addr.s_addr == addr) {
536 /* Move client to the front */
543 return tmp->h_client;
551 * Find a client given its identifier.
554 exp_getclientbyname(char *ident)
558 for (clp = clients; clp; clp = clp->cl_next) {
559 if (!strcmp(clp->cl_ident, ident))
567 static void *e_start(struct seq_file *m, loff_t *pos)
570 unsigned client, export;
578 export = n & ((1LL<<32) - 1);
579 for (clp = clients; client && clp; clp = clp->cl_next, client--)
583 list_for_each(p, &clp->cl_list)
585 return list_entry(p, svc_export, ex_list);
586 n &= ~((1LL<<32) - 1);
590 } while(clp && list_empty(&clp->cl_list));
594 return list_entry(clp->cl_list.next, svc_export, ex_list);
597 static void *e_next(struct seq_file *m, void *p, loff_t *pos)
604 else if (exp->ex_list.next == &exp->ex_client->cl_list) {
605 clp = exp->ex_client->cl_next;
609 return list_entry(exp->ex_list.next, svc_export, ex_list);
611 *pos &= ~((1LL<<32) - 1);
612 while (clp && list_empty(&clp->cl_list)) {
619 return list_entry(clp->cl_list.next, svc_export, ex_list);
622 static void e_stop(struct seq_file *m, void *p)
631 { NFSEXP_READONLY, {"ro", "rw"}},
632 { NFSEXP_INSECURE_PORT, {"insecure", ""}},
633 { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},
634 { NFSEXP_ALLSQUASH, {"all_squash", ""}},
635 { NFSEXP_ASYNC, {"async", "sync"}},
636 { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
637 { NFSEXP_UIDMAP, {"uidmap", ""}},
638 { NFSEXP_KERBEROS, { "kerberos", ""}},
639 { NFSEXP_SUNSECURE, { "sunsecure", ""}},
640 { NFSEXP_CROSSMNT, {"nohide", ""}},
641 { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
642 { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
644 { NFSEXP_MSNFS, {"msnfs", ""}},
649 static void exp_flags(struct seq_file *m, int flag, int fsid)
654 for (flg = expflags; flg->flag; flg++) {
655 int state = (flg->flag & flag)?0:1;
656 if (*flg->name[state])
657 seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
659 if (flag & NFSEXP_FSID)
660 seq_printf(m, "%sfsid=%d", first++?",":"", fsid);
663 static inline void mangle(struct seq_file *m, const char *s)
665 seq_escape(m, s, " \t\n\\");
668 static int e_show(struct seq_file *m, void *p)
670 struct svc_export *exp = p;
671 struct svc_client *clp;
674 if (p == (void *)1) {
675 seq_puts(m, "# Version 1.1\n");
676 seq_puts(m, "# Path Client(Flags) # IPs\n");
680 clp = exp->ex_client;
682 mangle(m, exp->ex_path);
684 mangle(m, clp->cl_ident);
686 exp_flags(m, exp->ex_flags, exp->ex_fsid);
688 for (j = 0; j < clp->cl_naddr; j++) {
689 struct svc_clnthash **hp, **head, *tmp;
690 struct in_addr addr = clp->cl_addr[j];
692 head = &clnt_hash[CLIENT_HASH(addr.s_addr)];
693 for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) {
694 if (tmp->h_addr.s_addr == addr.s_addr)
700 if (tmp->h_client != clp)
702 seq_printf(m, "%d.%d.%d.%d",
703 htonl(addr.s_addr) >> 24 & 0xff,
704 htonl(addr.s_addr) >> 16 & 0xff,
705 htonl(addr.s_addr) >> 8 & 0xff,
706 htonl(addr.s_addr) >> 0 & 0xff);
707 if (tmp->h_client != clp)
715 struct seq_operations nfs_exports_op = {
723 * Add or modify a client.
724 * Change requests may involve the list of host addresses. The list of
725 * exports and possibly existing uid maps are left untouched.
728 exp_addclient(struct nfsctl_client *ncp)
730 struct svc_clnthash * ch[NFSCLNT_ADDRMAX];
732 int i, err, change = 0, ilen;
734 /* First, consistency check. */
736 if (!(ilen = exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX)))
738 if (ncp->cl_naddr > NFSCLNT_ADDRMAX)
741 /* Lock the hashtable */
742 if ((err = exp_writelock()) < 0)
745 /* First check if this is a change request for a client. */
746 for (clp = clients; clp; clp = clp->cl_next)
747 if (!strcmp(clp->cl_ident, ncp->cl_ident))
754 if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL)))
756 memset(clp, 0, sizeof(*clp));
757 for (i = 0; i < NFSCLNT_EXPMAX; i++) {
758 INIT_LIST_HEAD(&clp->cl_export[i]);
759 INIT_LIST_HEAD(&clp->cl_expfsid[i]);
761 INIT_LIST_HEAD(&clp->cl_list);
763 dprintk("created client %s (%p)\n", ncp->cl_ident, clp);
765 strcpy(clp->cl_ident, ncp->cl_ident);
766 clp->cl_idlen = ilen;
769 /* Allocate hash buckets */
770 for (i = 0; i < ncp->cl_naddr; i++) {
771 ch[i] = kmalloc(sizeof(struct svc_clnthash), GFP_KERNEL);
781 /* Copy addresses. */
782 for (i = 0; i < ncp->cl_naddr; i++) {
783 clp->cl_addr[i] = ncp->cl_addrlist[i];
785 clp->cl_naddr = ncp->cl_naddr;
787 /* Remove old client hash entries. */
789 exp_unhashclient(clp);
791 /* Insert client into hashtable. */
792 for (i = 0; i < ncp->cl_naddr; i++) {
793 struct in_addr addr = clp->cl_addr[i];
796 hash = CLIENT_HASH(addr.s_addr);
797 ch[i]->h_client = clp;
798 ch[i]->h_addr = addr;
799 ch[i]->h_next = clnt_hash[hash];
800 clnt_hash[hash] = ch[i];
804 clp->cl_next = clients;
816 * Delete a client given an identifier.
819 exp_delclient(struct nfsctl_client *ncp)
821 svc_client **clpp, *clp;
825 if (!exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))
828 /* Lock the hashtable */
829 if ((err = exp_writelock()) < 0)
833 for (clpp = &clients; (clp = *clpp); clpp = &(clp->cl_next))
834 if (!strcmp(ncp->cl_ident, clp->cl_ident))
838 *clpp = clp->cl_next;
849 * Free a client. The caller has already removed it from the client list.
852 exp_freeclient(svc_client *clp)
854 exp_unhashclient(clp);
856 /* umap_free(&(clp->cl_umap)); */
857 exp_unexport_all(clp);
858 nfsd_lockd_unexport(clp);
863 * Remove client from hashtable. We first collect all hashtable
864 * entries and free them in one go.
865 * The hash table must be writelocked by the caller.
868 exp_unhashclient(svc_client *clp)
870 struct svc_clnthash **hpp, *hp, *ch[NFSCLNT_ADDRMAX];
875 for (i = 0, count = 0; i < CLIENT_HASHMAX && !err; i++) {
877 while ((hp = *hpp) && !err) {
878 if (hp->h_client == clp) {
881 err = (count >= NFSCLNT_ADDRMAX);
887 if (count != clp->cl_naddr)
888 printk(KERN_WARNING "nfsd: bad address count in freeclient!\n");
891 for (i = 0; i < count; i++)
896 * Lockd is shutting down and tells us to unregister all clients
901 struct svc_client *clp;
903 for (clp = clients; clp; clp = clp->cl_next)
904 nfsd_lockd_unexport(clp);
908 * Verify that string is non-empty and does not exceed max length.
911 exp_verify_string(char *cp, int max)
915 for (i = 0; i < max; i++)
919 printk(KERN_NOTICE "nfsd: couldn't validate string %s\n", cp);
924 * Initialize the exports module.
927 nfsd_export_init(void)
931 dprintk("nfsd: initializing export module.\n");
933 for (i = 0; i < CLIENT_HASHMAX; i++)
940 * Shutdown the exports module.
943 nfsd_export_shutdown(void)
947 dprintk("nfsd: shutting down export module.\n");
949 if (exp_writelock() < 0) {
950 printk(KERN_WARNING "Weird: hashtable locked in exp_shutdown");
953 for (i = 0; i < CLIENT_HASHMAX; i++) {
955 exp_freeclient(clnt_hash[i]->h_client);
957 clients = NULL; /* we may be restarted before the module unloads */
960 dprintk("nfsd: export shutdown complete.\n");