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/malloc.h>
19 #include <linux/stat.h>
22 #include <linux/sunrpc/svc.h>
23 #include <linux/nfsd/nfsd.h>
24 #include <linux/nfsd/nfsfh.h>
25 #include <linux/nfsd/syscall.h>
26 #include <linux/lockd/bind.h>
28 #define NFSDDBG_FACILITY NFSDDBG_EXPORT
29 #define NFSD_PARANOIA 1
31 typedef struct svc_client svc_client
;
32 typedef struct svc_export svc_export
;
34 static svc_export
* exp_find(svc_client
*clp
, kdev_t dev
);
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))
55 struct svc_clnthash
* h_next
;
56 struct in_addr h_addr
;
57 struct svc_client
* h_client
;
59 static struct svc_clnthash
* clnt_hash
[CLIENT_HASHMAX
];
60 static svc_client
* clients
;
61 static int initialized
;
65 static int hash_count
;
66 static DECLARE_WAIT_QUEUE_HEAD( hash_wait
);
70 * Find a client's export for a device.
72 static inline svc_export
*
73 exp_find(svc_client
*clp
, kdev_t dev
)
77 exp
= clp
->cl_export
[EXPORT_HASH(dev
)];
78 while (exp
&& exp
->ex_dev
!= dev
)
84 * Find the client's export entry matching xdev/xino.
87 exp_get(svc_client
*clp
, kdev_t dev
, ino_t ino
)
94 exp
= clp
->cl_export
[EXPORT_HASH(dev
)];
97 if (exp
->ex_ino
== ino
&& exp
->ex_dev
== dev
)
99 } while (NULL
!= (exp
= exp
->ex_next
));
106 * Find the export entry for a given dentry. <gam3@acm.org>
109 exp_parent(svc_client
*clp
, kdev_t dev
, struct dentry
*dentry
)
116 for (exp
= clp
->cl_export
[EXPORT_HASH(dev
)]; exp
; exp
= exp
->ex_next
)
117 if (is_subdir(dentry
, exp
->ex_dentry
))
123 * Find the child export entry for a given fs. This function is used
124 * only by the export syscall to keep the export tree consistent.
128 exp_child(svc_client
*clp
, kdev_t dev
, struct dentry
*dentry
)
135 for (exp
= clp
->cl_export
[EXPORT_HASH(dev
)]; exp
; exp
= exp
->ex_next
) {
136 struct dentry
*ndentry
= exp
->ex_dentry
;
137 if (ndentry
&& is_subdir(ndentry
->d_parent
, dentry
))
144 * Export a file system.
147 exp_export(struct nfsctl_export
*nxp
)
150 svc_export
*exp
, *parent
;
153 struct inode
*inode
= NULL
;
158 /* Consistency check */
160 if (!exp_verify_string(nxp
->ex_path
, NFS_MAXPATHLEN
) ||
161 !exp_verify_string(nxp
->ex_client
, NFSCLNT_IDMAX
))
164 dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
165 nxp
->ex_client
, nxp
->ex_path
,
166 nxp
->ex_dev
, (long) nxp
->ex_ino
, nxp
->ex_flags
);
167 dev
= to_kdev_t(nxp
->ex_dev
);
170 /* Try to lock the export table for update */
171 if ((err
= exp_writelock()) < 0)
174 /* Look up client info */
176 if (!(clp
= exp_getclientbyname(nxp
->ex_client
)))
180 * If there's already an export for this file, assume this
181 * is just a flag update.
183 if ((exp
= exp_get(clp
, dev
, ino
)) != NULL
) {
184 exp
->ex_flags
= nxp
->ex_flags
;
185 exp
->ex_anon_uid
= nxp
->ex_anon_uid
;
186 exp
->ex_anon_gid
= nxp
->ex_anon_gid
;
191 /* Look up the dentry */
193 if (path_init(nxp
->ex_path
, LOOKUP_POSITIVE
, &nd
))
194 err
= path_walk(nxp
->ex_path
, &nd
);
198 inode
= nd
.dentry
->d_inode
;
200 if (inode
->i_dev
!= dev
|| inode
->i_ino
!= nxp
->ex_ino
) {
201 printk(KERN_DEBUG
"exp_export: i_dev = %x, dev = %x\n",
203 /* I'm just being paranoid... */
207 /* We currently export only dirs and regular files.
208 * This is what umountd does.
211 if (!S_ISDIR(inode
->i_mode
) && !S_ISREG(inode
->i_mode
))
215 if (!(inode
->i_sb
->s_type
->fs_flags
& FS_REQUIRES_DEV
) ||
216 inode
->i_sb
->s_op
->read_inode
== NULL
) {
217 dprintk("exp_export: export of invalid fs type.\n");
221 if ((parent
= exp_child(clp
, dev
, nd
.dentry
)) != NULL
) {
222 dprintk("exp_export: export not valid (Rule 3).\n");
225 /* Is this is a sub-export, must be a proper subset of FS */
226 if ((parent
= exp_parent(clp
, dev
, nd
.dentry
)) != NULL
) {
227 dprintk("exp_export: sub-export not valid (Rule 2).\n");
232 if (!(exp
= kmalloc(sizeof(*exp
), GFP_USER
)))
234 dprintk("nfsd: created export entry %p for client %p\n", exp
, clp
);
236 strcpy(exp
->ex_path
, nxp
->ex_path
);
237 exp
->ex_client
= clp
;
238 exp
->ex_parent
= parent
;
239 exp
->ex_dentry
= nd
.dentry
;
240 exp
->ex_mnt
= nd
.mnt
;
241 exp
->ex_flags
= nxp
->ex_flags
;
244 exp
->ex_anon_uid
= nxp
->ex_anon_uid
;
245 exp
->ex_anon_gid
= nxp
->ex_anon_gid
;
247 /* Update parent pointers of all exports */
249 for (i
= 0; i
< NFSCLNT_EXPMAX
; i
++) {
250 svc_export
*temp
= clp
->cl_export
[i
];
253 if (temp
->ex_parent
== parent
)
254 temp
->ex_parent
= exp
;
255 temp
= temp
->ex_next
;
260 head
= clp
->cl_export
+ EXPORT_HASH(dev
);
261 exp
->ex_next
= *head
;
266 /* Unlock hashtable */
272 /* Release the dentry */
279 * Unexport a file system. The export entry has already
280 * been removed from the client's list of exported fs's.
283 exp_do_unexport(svc_export
*unexp
)
287 struct dentry
*dentry
;
288 struct vfsmount
*mnt
;
292 /* Update parent pointers. */
293 clp
= unexp
->ex_client
;
294 for (i
= 0; i
< NFSCLNT_EXPMAX
; i
++) {
295 for (exp
= clp
->cl_export
[i
]; exp
; exp
= exp
->ex_next
)
296 if (exp
->ex_parent
== unexp
)
297 exp
->ex_parent
= unexp
->ex_parent
;
300 dentry
= unexp
->ex_dentry
;
302 inode
= dentry
->d_inode
;
303 if (unexp
->ex_dev
!= inode
->i_dev
|| unexp
->ex_ino
!= inode
->i_ino
)
304 printk(KERN_WARNING
"nfsd: bad dentry in unexport!\n");
312 * Revoke all exports for a given client.
313 * This may look very awkward, but we have to do it this way in order
314 * to avoid race conditions (aka mind the parent pointer).
317 exp_unexport_all(svc_client
*clp
)
322 dprintk("unexporting all fs's for clnt %p\n", clp
);
323 for (i
= 0; i
< NFSCLNT_EXPMAX
; i
++) {
324 exp
= clp
->cl_export
[i
];
325 clp
->cl_export
[i
] = NULL
;
327 svc_export
*next
= exp
->ex_next
;
328 exp_do_unexport(exp
);
338 exp_unexport(struct nfsctl_export
*nxp
)
341 svc_export
**expp
, *exp
= NULL
;
344 /* Consistency check */
345 if (!exp_verify_string(nxp
->ex_client
, NFSCLNT_IDMAX
))
348 if ((err
= exp_writelock()) < 0)
352 clp
= exp_getclientbyname(nxp
->ex_client
);
354 expp
= clp
->cl_export
+ EXPORT_HASH(nxp
->ex_dev
);
355 while ((exp
= *expp
) != NULL
) {
356 if (exp
->ex_dev
== nxp
->ex_dev
) {
357 if (exp
->ex_ino
== nxp
->ex_ino
) {
358 *expp
= exp
->ex_next
;
359 exp_do_unexport(exp
);
364 expp
= &(exp
->ex_next
);
374 * Obtain the root fh on behalf of a client.
375 * This could be done in user space, but I feel that it adds some safety
376 * since its harder to fool a kernel module than a user space program.
379 exp_rootfh(struct svc_client
*clp
, kdev_t dev
, ino_t ino
,
380 char *path
, struct knfsd_fh
*f
, int maxsize
)
382 struct svc_export
*exp
;
390 if (path_init(path
, LOOKUP_POSITIVE
, &nd
) &&
391 path_walk(path
, &nd
)) {
392 printk("nfsd: exp_rootfh path not found %s", path
);
395 dev
= nd
.dentry
->d_inode
->i_dev
;
396 ino
= nd
.dentry
->d_inode
->i_ino
;
398 dprintk("nfsd: exp_rootfh(%s [%p] %s:%x/%ld)\n",
399 path
, nd
.dentry
, clp
->cl_ident
, dev
, (long) ino
);
400 exp
= exp_parent(clp
, dev
, nd
.dentry
);
402 dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n",
403 clp
->cl_ident
, dev
, (long) ino
);
404 if ((exp
= exp_get(clp
, dev
, ino
))) {
405 nd
.mnt
= mntget(exp
->ex_mnt
);
406 nd
.dentry
= dget(exp
->ex_dentry
);
410 dprintk("nfsd: exp_rootfh export not found.\n");
414 inode
= nd
.dentry
->d_inode
;
416 printk("exp_rootfh: Aieee, NULL d_inode\n");
419 if (inode
->i_dev
!= dev
|| inode
->i_ino
!= ino
) {
420 printk("exp_rootfh: Aieee, ino/dev mismatch\n");
421 printk("exp_rootfh: arg[dev(%x):ino(%ld)]"
422 " inode[dev(%x):ino(%ld)]\n",
423 dev
, (long) ino
, inode
->i_dev
, (long) inode
->i_ino
);
427 * fh must be initialized before calling fh_compose
429 fh_init(&fh
, maxsize
);
430 if (fh_compose(&fh
, exp
, dget(nd
.dentry
)))
434 memcpy(f
, &fh
.fh_handle
, sizeof(struct knfsd_fh
));
444 * Hashtable locking. Write locks are placed only by user processes
445 * wanting to modify export information.
450 while (hash_lock
|| want_lock
)
451 sleep_on(&hash_wait
);
459 if (!hash_count
&& !hash_lock
) {
465 current
->sigpending
= 0;
467 while (hash_count
|| hash_lock
) {
468 interruptible_sleep_on(&hash_wait
);
469 if (signal_pending(current
))
474 /* restore the task's signals */
475 spin_lock_irq(¤t
->sigmask_lock
);
476 recalc_sigpending(current
);
477 spin_unlock_irq(¤t
->sigmask_lock
);
479 if (!hash_count
&& !hash_lock
)
487 if (!hash_count
&& !hash_lock
)
488 printk(KERN_WARNING
"exp_unlock: not locked!\n");
497 * Find a valid client given an inet address. We always move the most
498 * recently used client to the front of the hash chain to speed up
500 * Locking against other processes is the responsibility of the caller.
503 exp_getclient(struct sockaddr_in
*sin
)
505 struct svc_clnthash
**hp
, **head
, *tmp
;
506 unsigned long addr
= sin
->sin_addr
.s_addr
;
511 head
= &clnt_hash
[CLIENT_HASH(addr
)];
513 for (hp
= head
; (tmp
= *hp
) != NULL
; hp
= &(tmp
->h_next
)) {
514 if (tmp
->h_addr
.s_addr
== addr
) {
515 /* Move client to the front */
522 return tmp
->h_client
;
530 * Find a client given its identifier.
533 exp_getclientbyname(char *ident
)
537 for (clp
= clients
; clp
; clp
= clp
->cl_next
) {
538 if (!strcmp(clp
->cl_ident
, ident
))
548 { NFSEXP_READONLY
, {"ro", "rw"}},
549 { NFSEXP_INSECURE_PORT
, {"insecure", ""}},
550 { NFSEXP_ROOTSQUASH
, {"root_squash", "no_root_squash"}},
551 { NFSEXP_ALLSQUASH
, {"all_squash", ""}},
552 { NFSEXP_ASYNC
, {"async", ""}},
553 { NFSEXP_GATHERED_WRITES
, {"wdelay", ""}},
554 { NFSEXP_UIDMAP
, {"uidmap", ""}},
555 { NFSEXP_KERBEROS
, { "kerberos", ""}},
556 { NFSEXP_SUNSECURE
, { "sunsecure", ""}},
557 { NFSEXP_CROSSMNT
, {"nohide", ""}},
558 { NFSEXP_NOSUBTREECHECK
, {"no_subtree_check", ""}},
559 { NFSEXP_NOAUTHNLM
, {"insecure_locks", ""}},
561 { NFSEXP_MSNFS
, {"msnfs", ""}},
567 exp_flags(char *buffer
, int flag
)
569 int len
= 0, first
= 0;
570 struct flags
*flg
= expflags
;
572 for (;flg
->flag
;flg
++) {
573 int state
= (flg
->flag
& flag
)?0:1;
576 if (*flg
->name
[state
]) {
577 len
+= sprintf(buffer
+ len
, "%s%s",
578 first
++?",":"", flg
->name
[state
]);
585 exp_procfs_exports(char *buffer
, char **start
, off_t offset
,
586 int length
, int *eof
, void *data
)
588 struct svc_clnthash
**hp
, **head
, *tmp
;
589 struct svc_client
*clp
;
596 len
+= sprintf(buffer
, "# Version 1.0\n");
597 len
+= sprintf(buffer
+len
, "# Path Client(Flags) # IPs\n");
599 for (clp
= clients
; clp
; clp
= clp
->cl_next
) {
600 for (i
= 0; i
< NFSCLNT_EXPMAX
; i
++) {
601 exp
= clp
->cl_export
[i
];
604 len
+= sprintf(buffer
+len
, "%s\t", exp
->ex_path
);
605 len
+= sprintf(buffer
+len
, "%s", clp
->cl_ident
);
606 len
+= sprintf(buffer
+len
, "(");
608 len
+= exp_flags(buffer
+len
, exp
->ex_flags
);
609 len
+= sprintf(buffer
+len
, ") # ");
610 for (j
= 0; j
< clp
->cl_naddr
; j
++) {
611 struct in_addr addr
= clp
->cl_addr
[j
];
613 head
= &clnt_hash
[CLIENT_HASH(addr
.s_addr
)];
614 for (hp
= head
; (tmp
= *hp
) != NULL
; hp
= &(tmp
->h_next
)) {
615 if (tmp
->h_addr
.s_addr
== addr
.s_addr
) {
616 if (first
++) len
+= sprintf(buffer
+len
, "%s", " ");
617 if (tmp
->h_client
!= clp
)
618 len
+= sprintf(buffer
+len
, "(");
619 len
+= sprintf(buffer
+len
, "%d.%d.%d.%d",
620 htonl(addr
.s_addr
) >> 24 & 0xff,
621 htonl(addr
.s_addr
) >> 16 & 0xff,
622 htonl(addr
.s_addr
) >> 8 & 0xff,
623 htonl(addr
.s_addr
) >> 0 & 0xff);
624 if (tmp
->h_client
!= clp
)
625 len
+= sprintf(buffer
+len
, ")");
639 if (pos
> offset
+ length
)
648 *start
= buffer
+ (offset
- begin
);
649 len
-= (offset
- begin
);
656 * Add or modify a client.
657 * Change requests may involve the list of host addresses. The list of
658 * exports and possibly existing uid maps are left untouched.
661 exp_addclient(struct nfsctl_client
*ncp
)
663 struct svc_clnthash
* ch
[NFSCLNT_ADDRMAX
];
665 int i
, err
, change
= 0, ilen
;
667 /* First, consistency check. */
669 if (!(ilen
= exp_verify_string(ncp
->cl_ident
, NFSCLNT_IDMAX
)))
671 if (ncp
->cl_naddr
> NFSCLNT_ADDRMAX
)
674 /* Lock the hashtable */
675 if ((err
= exp_writelock()) < 0)
678 /* First check if this is a change request for a client. */
679 for (clp
= clients
; clp
; clp
= clp
->cl_next
)
680 if (!strcmp(clp
->cl_ident
, ncp
->cl_ident
))
687 if (!(clp
= kmalloc(sizeof(*clp
), GFP_KERNEL
)))
689 memset(clp
, 0, sizeof(*clp
));
691 dprintk("created client %s (%p)\n", ncp
->cl_ident
, clp
);
693 strcpy(clp
->cl_ident
, ncp
->cl_ident
);
694 clp
->cl_idlen
= ilen
;
697 /* Allocate hash buckets */
698 for (i
= 0; i
< ncp
->cl_naddr
; i
++) {
699 ch
[i
] = kmalloc(sizeof(struct svc_clnthash
), GFP_KERNEL
);
709 /* Copy addresses. */
710 for (i
= 0; i
< ncp
->cl_naddr
; i
++) {
711 clp
->cl_addr
[i
] = ncp
->cl_addrlist
[i
];
713 clp
->cl_naddr
= ncp
->cl_naddr
;
715 /* Remove old client hash entries. */
717 exp_unhashclient(clp
);
719 /* Insert client into hashtable. */
720 for (i
= 0; i
< ncp
->cl_naddr
; i
++) {
721 struct in_addr addr
= clp
->cl_addr
[i
];
724 hash
= CLIENT_HASH(addr
.s_addr
);
725 ch
[i
]->h_client
= clp
;
726 ch
[i
]->h_addr
= addr
;
727 ch
[i
]->h_next
= clnt_hash
[hash
];
728 clnt_hash
[hash
] = ch
[i
];
732 clp
->cl_next
= clients
;
744 * Delete a client given an identifier.
747 exp_delclient(struct nfsctl_client
*ncp
)
749 svc_client
**clpp
, *clp
;
753 if (!exp_verify_string(ncp
->cl_ident
, NFSCLNT_IDMAX
))
756 /* Lock the hashtable */
757 if ((err
= exp_writelock()) < 0)
761 for (clpp
= &clients
; (clp
= *clpp
); clpp
= &(clp
->cl_next
))
762 if (!strcmp(ncp
->cl_ident
, clp
->cl_ident
))
766 *clpp
= clp
->cl_next
;
777 * Free a client. The caller has already removed it from the client list.
780 exp_freeclient(svc_client
*clp
)
782 exp_unhashclient(clp
);
784 /* umap_free(&(clp->cl_umap)); */
785 exp_unexport_all(clp
);
786 nfsd_lockd_unexport(clp
);
791 * Remove client from hashtable. We first collect all hashtable
792 * entries and free them in one go.
793 * The hash table must be writelocked by the caller.
796 exp_unhashclient(svc_client
*clp
)
798 struct svc_clnthash
**hpp
, *hp
, *ch
[NFSCLNT_ADDRMAX
];
803 for (i
= 0, count
= 0; i
< CLIENT_HASHMAX
&& !err
; i
++) {
805 while ((hp
= *hpp
) && !err
) {
806 if (hp
->h_client
== clp
) {
809 err
= (count
>= NFSCLNT_ADDRMAX
);
815 if (count
!= clp
->cl_naddr
)
816 printk(KERN_WARNING
"nfsd: bad address count in freeclient!\n");
819 for (i
= 0; i
< count
; i
++)
824 * Lockd is shutting down and tells us to unregister all clients
829 struct svc_client
*clp
;
831 for (clp
= clients
; clp
; clp
= clp
->cl_next
)
832 nfsd_lockd_unexport(clp
);
836 * Verify that string is non-empty and does not exceed max length.
839 exp_verify_string(char *cp
, int max
)
843 for (i
= 0; i
< max
; i
++)
847 printk(KERN_NOTICE
"nfsd: couldn't validate string %s\n", cp
);
852 * Initialize the exports module.
855 nfsd_export_init(void)
859 dprintk("nfsd: initializing export module.\n");
862 for (i
= 0; i
< CLIENT_HASHMAX
; i
++)
870 * Shutdown the exports module.
873 nfsd_export_shutdown(void)
877 dprintk("nfsd: shutting down export module.\n");
880 if (exp_writelock() < 0) {
881 printk(KERN_WARNING
"Weird: hashtable locked in exp_shutdown");
884 for (i
= 0; i
< CLIENT_HASHMAX
; i
++) {
886 exp_freeclient(clnt_hash
[i
]->h_client
);
888 clients
= NULL
; /* we may be restarted before the module unloads */
891 dprintk("nfsd: export shutdown complete.\n");