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
);
73 * Find a client's export for a device.
75 static inline svc_export
*
76 exp_find(svc_client
*clp
, kdev_t dev
)
80 exp
= clp
->cl_export
[EXPORT_HASH(dev
)];
81 while (exp
&& exp
->ex_dev
!= dev
)
87 * Find the client's export entry matching xdev/xino.
90 exp_get(svc_client
*clp
, kdev_t dev
, ino_t ino
)
97 exp
= clp
->cl_export
[EXPORT_HASH(dev
)];
100 if (exp
->ex_ino
== ino
&& exp
->ex_dev
== dev
)
102 } while (NULL
!= (exp
= exp
->ex_next
));
109 * Check whether there are any exports for a device.
112 exp_device_in_use(kdev_t dev
)
114 struct svc_client
*clp
;
116 for (clp
= clients
; clp
; clp
= clp
->cl_next
) {
117 if (exp_find(clp
, dev
))
124 * Look up the device of the parent fs.
127 nfsd_parentdev(kdev_t
*devp
)
129 struct super_block
*sb
;
131 if (!(sb
= get_super(*devp
)) || !sb
->s_root
->d_covers
)
133 if (*devp
== sb
->s_root
->d_covers
->d_inode
->i_dev
)
135 *devp
= sb
->s_root
->d_covers
->d_inode
->i_dev
;
140 * Find the export entry for a given dentry. <gam3@acm.org>
143 exp_parent(svc_client
*clp
, kdev_t dev
, struct dentry
*dentry
)
147 struct dentry
*xdentry
= dentry
;
148 struct dentry
*ndentry
= NULL
;
150 if (clp
== NULL
|| dentry
== NULL
)
156 exp
= clp
->cl_export
[EXPORT_HASH(xdev
)];
159 ndentry
= exp
->ex_dentry
;
160 if (ndentry
== xdentry
) {
163 dprintk("nfsd: exp_parent submount over mount.\n");
165 dprintk("nfsd: exp_parent found.\n");
169 } while (NULL
!= (exp
= exp
->ex_next
));
170 } while (nfsd_parentdev(&xdev
));
171 if (xdentry
== xdentry
->d_parent
) {
174 } while ((xdentry
= xdentry
->d_parent
));
181 * Find the child export entry for a given fs. This function is used
182 * only by the export syscall to keep the export tree consistent.
186 exp_child(svc_client
*clp
, kdev_t dev
, struct dentry
*dentry
)
189 struct dentry
*xdentry
= dentry
;
190 struct dentry
*ndentry
= NULL
;
192 if (clp
== NULL
|| dentry
== NULL
)
195 exp
= clp
->cl_export
[EXPORT_HASH(dev
)];
198 ndentry
= exp
->ex_dentry
;
200 while ((ndentry
= ndentry
->d_parent
)) {
201 if (ndentry
== xdentry
) {
203 dprintk("nfsd: exp_child mount under submount.\n");
207 if (ndentry
== ndentry
->d_parent
)
210 } while (NULL
!= (exp
= exp
->ex_next
));
217 * Export a file system.
220 exp_export(struct nfsctl_export
*nxp
)
223 svc_export
*exp
, *parent
;
225 struct dentry
*dentry
= NULL
;
226 struct inode
*inode
= NULL
;
231 /* Consistency check */
233 if (!exp_verify_string(nxp
->ex_path
, NFS_MAXPATHLEN
) ||
234 !exp_verify_string(nxp
->ex_client
, NFSCLNT_IDMAX
))
237 dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
238 nxp
->ex_client
, nxp
->ex_path
,
239 nxp
->ex_dev
, nxp
->ex_ino
, nxp
->ex_flags
);
240 dev
= to_kdev_t(nxp
->ex_dev
);
243 /* Try to lock the export table for update */
244 if ((err
= exp_writelock()) < 0)
247 /* Look up client info */
249 if (!(clp
= exp_getclientbyname(nxp
->ex_client
)))
253 * If there's already an export for this file, assume this
254 * is just a flag update.
256 if ((exp
= exp_get(clp
, dev
, ino
)) != NULL
) {
257 exp
->ex_flags
= nxp
->ex_flags
;
258 exp
->ex_anon_uid
= nxp
->ex_anon_uid
;
259 exp
->ex_anon_gid
= nxp
->ex_anon_gid
;
264 /* Look up the dentry */
266 dentry
= lookup_dentry(nxp
->ex_path
, NULL
, 0);
271 inode
= dentry
->d_inode
;
275 if (inode
->i_dev
!= dev
|| inode
->i_ino
!= nxp
->ex_ino
) {
276 printk(KERN_DEBUG
"exp_export: i_dev = %x, dev = %x\n",
278 /* I'm just being paranoid... */
282 /* We currently export only dirs and regular files.
283 * This is what umountd does.
286 if (!S_ISDIR(inode
->i_mode
) && !S_ISREG(inode
->i_mode
))
290 if ((parent
= exp_child(clp
, dev
, dentry
)) != NULL
) {
291 dprintk("exp_export: export not valid (Rule 3).\n");
294 /* Is this is a sub-export, must be a proper subset of FS */
295 if ((parent
= exp_parent(clp
, dev
, dentry
)) != NULL
) {
296 if (dev
== parent
->ex_dev
) {
297 dprintk("exp_export: sub-export not valid (Rule 2).\n");
303 if (!(exp
= kmalloc(sizeof(*exp
), GFP_USER
)))
305 dprintk("nfsd: created export entry %p for client %p\n", exp
, clp
);
307 strcpy(exp
->ex_path
, nxp
->ex_path
);
308 exp
->ex_client
= clp
;
309 exp
->ex_parent
= parent
;
310 exp
->ex_dentry
= dentry
;
311 exp
->ex_flags
= nxp
->ex_flags
;
314 exp
->ex_anon_uid
= nxp
->ex_anon_uid
;
315 exp
->ex_anon_gid
= nxp
->ex_anon_gid
;
317 /* Update parent pointers of all exports */
319 for (i
= 0; i
< NFSCLNT_EXPMAX
; i
++) {
320 svc_export
*temp
= clp
->cl_export
[i
];
323 if (temp
->ex_parent
== parent
)
324 temp
->ex_parent
= exp
;
325 temp
= temp
->ex_next
;
330 head
= clp
->cl_export
+ EXPORT_HASH(dev
);
331 exp
->ex_next
= *head
;
336 /* Unlock hashtable */
342 /* Release the dentry */
349 * Unexport a file system. The export entry has already
350 * been removed from the client's list of exported fs's.
353 exp_do_unexport(svc_export
*unexp
)
357 struct dentry
*dentry
;
361 /* Update parent pointers. */
362 clp
= unexp
->ex_client
;
363 for (i
= 0; i
< NFSCLNT_EXPMAX
; i
++) {
364 for (exp
= clp
->cl_export
[i
]; exp
; exp
= exp
->ex_next
)
365 if (exp
->ex_parent
== unexp
)
366 exp
->ex_parent
= unexp
->ex_parent
;
370 * Check whether this is the last export for this device,
371 * and if so flush any cached dentries.
373 if (!exp_device_in_use(unexp
->ex_dev
)) {
374 printk("exp_do_unexport: %s last use, flushing cache\n",
375 kdevname(unexp
->ex_dev
));
376 nfsd_fh_flush(unexp
->ex_dev
);
379 dentry
= unexp
->ex_dentry
;
380 inode
= dentry
->d_inode
;
381 if (unexp
->ex_dev
!= inode
->i_dev
|| unexp
->ex_ino
!= inode
->i_ino
)
382 printk(KERN_WARNING
"nfsd: bad dentry in unexport!\n");
389 * Revoke all exports for a given client.
390 * This may look very awkward, but we have to do it this way in order
391 * to avoid race conditions (aka mind the parent pointer).
394 exp_unexport_all(svc_client
*clp
)
399 dprintk("unexporting all fs's for clnt %p\n", clp
);
400 for (i
= 0; i
< NFSCLNT_EXPMAX
; i
++) {
401 exp
= clp
->cl_export
[i
];
402 clp
->cl_export
[i
] = NULL
;
404 svc_export
*next
= exp
->ex_next
;
405 exp_do_unexport(exp
);
415 exp_unexport(struct nfsctl_export
*nxp
)
418 svc_export
**expp
, *exp
= NULL
;
421 /* Consistency check */
422 if (!exp_verify_string(nxp
->ex_client
, NFSCLNT_IDMAX
))
425 if ((err
= exp_writelock()) < 0)
429 clp
= exp_getclientbyname(nxp
->ex_client
);
431 expp
= clp
->cl_export
+ EXPORT_HASH(nxp
->ex_dev
);
432 while ((exp
= *expp
) != NULL
) {
433 if (exp
->ex_dev
== nxp
->ex_dev
) {
434 if (exp
->ex_ino
== nxp
->ex_ino
) {
435 *expp
= exp
->ex_next
;
436 exp_do_unexport(exp
);
441 expp
= &(exp
->ex_next
);
451 * Obtain the root fh on behalf of a client.
452 * This could be done in user space, but I feel that it adds some safety
453 * since its harder to fool a kernel module than a user space program.
456 exp_rootfh(struct svc_client
*clp
, kdev_t dev
, ino_t ino
,
457 char *path
, struct knfs_fh
*f
)
459 struct svc_export
*exp
;
460 struct dentry
*dentry
= NULL
;
467 if (!(dentry
= lookup_dentry(path
, NULL
, 0))) {
468 printk("nfsd: exp_rootfh path not found %s", path
);
471 dev
= dentry
->d_inode
->i_dev
;
472 ino
= dentry
->d_inode
->i_ino
;
474 dprintk("nfsd: exp_rootfh(%s [%p] %s:%x/%ld)\n",
475 path
, dentry
, clp
->cl_ident
, dev
, ino
);
476 exp
= exp_parent(clp
, dev
, dentry
);
478 dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n",
479 clp
->cl_ident
, dev
, ino
);
480 if ((exp
= exp_get(clp
, dev
, ino
)))
481 if (!(dentry
= dget(exp
->ex_dentry
))) {
482 printk("exp_rootfh: Aieee, NULL dentry\n");
487 dprintk("nfsd: exp_rootfh export not found.\n");
491 inode
= dentry
->d_inode
;
493 printk("exp_rootfh: Aieee, NULL d_inode\n");
496 if (inode
->i_dev
!= dev
|| inode
->i_ino
!= ino
) {
497 printk("exp_rootfh: Aieee, ino/dev mismatch\n");
498 printk("exp_rootfh: arg[dev(%x):ino(%ld)]"
499 " inode[dev(%x):ino(%ld)]\n",
500 dev
, ino
, inode
->i_dev
, inode
->i_ino
);
504 * fh must be initialized before calling fh_compose
507 fh_compose(&fh
, exp
, dentry
);
508 memcpy(f
, &fh
.fh_handle
, sizeof(struct knfs_fh
));
518 * Hashtable locking. Write locks are placed only by user processes
519 * wanting to modify export information.
524 while (hash_lock
|| want_lock
)
525 sleep_on(&hash_wait
);
533 if (!hash_count
&& !hash_lock
) {
539 current
->sigpending
= 0;
541 while (hash_count
|| hash_lock
) {
542 interruptible_sleep_on(&hash_wait
);
543 if (signal_pending(current
))
548 /* restore the task's signals */
549 spin_lock_irq(¤t
->sigmask_lock
);
550 recalc_sigpending(current
);
551 spin_unlock_irq(¤t
->sigmask_lock
);
553 if (!hash_count
&& !hash_lock
)
561 if (!hash_count
&& !hash_lock
)
562 printk(KERN_WARNING
"exp_unlock: not locked!\n");
571 * Find a valid client given an inet address. We always move the most
572 * recently used client to the front of the hash chain to speed up
574 * Locking against other processes is the responsibility of the caller.
577 exp_getclient(struct sockaddr_in
*sin
)
579 struct svc_clnthash
**hp
, **head
, *tmp
;
580 unsigned long addr
= sin
->sin_addr
.s_addr
;
585 head
= &clnt_hash
[CLIENT_HASH(addr
)];
587 for (hp
= head
; (tmp
= *hp
) != NULL
; hp
= &(tmp
->h_next
)) {
588 if (tmp
->h_addr
.s_addr
== addr
) {
589 /* Move client to the front */
596 return tmp
->h_client
;
604 * Find a client given its identifier.
607 exp_getclientbyname(char *ident
)
611 for (clp
= clients
; clp
; clp
= clp
->cl_next
) {
612 if (!strcmp(clp
->cl_ident
, ident
))
622 { NFSEXP_READONLY
, {"ro", "rw"}},
623 { NFSEXP_INSECURE_PORT
, {"insecure", ""}},
624 { NFSEXP_ROOTSQUASH
, {"root_squash", "no_root_squash"}},
625 { NFSEXP_ALLSQUASH
, {"all_squash", ""}},
626 { NFSEXP_ASYNC
, {"async", ""}},
627 { NFSEXP_GATHERED_WRITES
, {"wdelay", ""}},
628 { NFSEXP_UIDMAP
, {"uidmap", ""}},
629 { NFSEXP_KERBEROS
, { "kerberos", ""}},
630 { NFSEXP_SUNSECURE
, { "sunsecure", ""}},
631 { NFSEXP_CROSSMNT
, {"crossmnt", ""}},
636 exp_flags(char *buffer
, int flag
)
638 int len
= 0, first
= 0;
639 struct flags
*flg
= expflags
;
641 for (;flg
->flag
;flg
++) {
642 int state
= (flg
->flag
& flag
)?0:1;
645 if (*flg
->name
[state
]) {
646 len
+= sprintf(buffer
+ len
, "%s%s",
647 first
++?",":"", flg
->name
[state
]);
654 exp_procfs_exports(char *buffer
, char **start
, off_t offset
,
655 int length
, int *eof
, void *data
)
657 struct svc_clnthash
**hp
, **head
, *tmp
;
658 struct svc_client
*clp
;
665 len
+= sprintf(buffer
, "# Version 1.0\n");
666 len
+= sprintf(buffer
+len
, "# Path Client(Flags) # IPs\n");
668 for (clp
= clients
; clp
; clp
= clp
->cl_next
) {
669 for (i
= 0; i
< NFSCLNT_EXPMAX
; i
++) {
670 exp
= clp
->cl_export
[i
];
673 len
+= sprintf(buffer
+len
, "%s\t", exp
->ex_path
);
674 len
+= sprintf(buffer
+len
, "%s", clp
->cl_ident
);
675 len
+= sprintf(buffer
+len
, "(");
677 len
+= exp_flags(buffer
+len
, exp
->ex_flags
);
678 len
+= sprintf(buffer
+len
, ") # ");
679 for (j
= 0; j
< clp
->cl_naddr
; j
++) {
680 struct in_addr addr
= clp
->cl_addr
[j
];
682 head
= &clnt_hash
[CLIENT_HASH(addr
.s_addr
)];
683 for (hp
= head
; (tmp
= *hp
) != NULL
; hp
= &(tmp
->h_next
)) {
684 if (tmp
->h_addr
.s_addr
== addr
.s_addr
) {
685 if (first
++) len
+= sprintf(buffer
+len
, "%s", " ");
686 if (tmp
->h_client
!= clp
)
687 len
+= sprintf(buffer
+len
, "(");
688 len
+= sprintf(buffer
+len
, "%ld.%ld.%ld.%ld",
689 htonl(addr
.s_addr
) >> 24 & 0xff,
690 htonl(addr
.s_addr
) >> 16 & 0xff,
691 htonl(addr
.s_addr
) >> 8 & 0xff,
692 htonl(addr
.s_addr
) >> 0 & 0xff);
693 if (tmp
->h_client
!= clp
)
694 len
+= sprintf(buffer
+len
, ")");
708 if (pos
> offset
+ length
)
717 *start
= buffer
+ (offset
- begin
);
718 len
-= (offset
- begin
);
725 * Add or modify a client.
726 * Change requests may involve the list of host addresses. The list of
727 * exports and possibly existing uid maps are left untouched.
730 exp_addclient(struct nfsctl_client
*ncp
)
732 struct svc_clnthash
* ch
[NFSCLNT_ADDRMAX
];
734 int i
, err
, change
= 0, ilen
;
736 /* First, consistency check. */
738 if (!(ilen
= exp_verify_string(ncp
->cl_ident
, NFSCLNT_IDMAX
)))
740 if (ncp
->cl_naddr
> NFSCLNT_ADDRMAX
)
743 /* Lock the hashtable */
744 if ((err
= exp_writelock()) < 0)
747 /* First check if this is a change request for a client. */
748 for (clp
= clients
; clp
; clp
= clp
->cl_next
)
749 if (!strcmp(clp
->cl_ident
, ncp
->cl_ident
))
756 if (!(clp
= kmalloc(sizeof(*clp
), GFP_KERNEL
)))
758 memset(clp
, 0, sizeof(*clp
));
760 dprintk("created client %s (%p)\n", ncp
->cl_ident
, clp
);
762 strcpy(clp
->cl_ident
, ncp
->cl_ident
);
763 clp
->cl_idlen
= ilen
;
766 /* Allocate hash buckets */
767 for (i
= 0; i
< ncp
->cl_naddr
; i
++) {
768 ch
[i
] = kmalloc(sizeof(struct svc_clnthash
), GFP_KERNEL
);
778 /* Copy addresses. */
779 for (i
= 0; i
< ncp
->cl_naddr
; i
++) {
780 clp
->cl_addr
[i
] = ncp
->cl_addrlist
[i
];
782 clp
->cl_naddr
= ncp
->cl_naddr
;
784 /* Remove old client hash entries. */
786 exp_unhashclient(clp
);
788 /* Insert client into hashtable. */
789 for (i
= 0; i
< ncp
->cl_naddr
; i
++) {
790 struct in_addr addr
= clp
->cl_addr
[i
];
793 hash
= CLIENT_HASH(addr
.s_addr
);
794 ch
[i
]->h_client
= clp
;
795 ch
[i
]->h_addr
= addr
;
796 ch
[i
]->h_next
= clnt_hash
[hash
];
797 clnt_hash
[hash
] = ch
[i
];
801 clp
->cl_next
= clients
;
813 * Delete a client given an identifier.
816 exp_delclient(struct nfsctl_client
*ncp
)
818 svc_client
**clpp
, *clp
;
822 if (!exp_verify_string(ncp
->cl_ident
, NFSCLNT_IDMAX
))
825 /* Lock the hashtable */
826 if ((err
= exp_writelock()) < 0)
830 for (clpp
= &clients
; (clp
= *clpp
); clpp
= &(clp
->cl_next
))
831 if (!strcmp(ncp
->cl_ident
, clp
->cl_ident
))
835 *clpp
= clp
->cl_next
;
846 * Free a client. The caller has already removed it from the client list.
849 exp_freeclient(svc_client
*clp
)
851 exp_unhashclient(clp
);
853 /* umap_free(&(clp->cl_umap)); */
854 exp_unexport_all(clp
);
855 nfsd_lockd_unexport(clp
);
860 * Remove client from hashtable. We first collect all hashtable
861 * entries and free them in one go.
862 * The hash table must be writelocked by the caller.
865 exp_unhashclient(svc_client
*clp
)
867 struct svc_clnthash
**hpp
, *hp
, *ch
[NFSCLNT_ADDRMAX
];
872 for (i
= 0, count
= 0; i
< CLIENT_HASHMAX
&& !err
; i
++) {
874 while ((hp
= *hpp
) && !err
) {
875 if (hp
->h_client
== clp
) {
878 err
= (count
>= NFSCLNT_ADDRMAX
);
884 if (count
!= clp
->cl_naddr
)
885 printk(KERN_WARNING
"nfsd: bad address count in freeclient!\n");
888 for (i
= 0; i
< count
; i
++)
893 * Lockd is shutting down and tells us to unregister all clients
898 struct svc_client
*clp
;
900 for (clp
= clients
; clp
; clp
= clp
->cl_next
)
901 nfsd_lockd_unexport(clp
);
905 * Verify that string is non-empty and does not exceed max length.
908 exp_verify_string(char *cp
, int max
)
912 for (i
= 0; i
< max
; i
++)
916 printk(KERN_NOTICE
"nfsd: couldn't validate string %s\n", cp
);
921 * Initialize the exports module.
924 nfsd_export_init(void)
928 dprintk("nfsd: initializing export module.\n");
931 for (i
= 0; i
< CLIENT_HASHMAX
; i
++)
939 * Shutdown the exports module.
942 nfsd_export_shutdown(void)
946 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");