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
, dev_t dev
);
36 static svc_export
* exp_parent(svc_client
*clp
, dev_t dev
);
37 static void exp_unexport_all(svc_client
*clp
);
38 static void exp_do_unexport(svc_export
*unexp
);
39 static svc_client
* exp_getclientbyname(char *name
);
40 static void exp_freeclient(svc_client
*clp
);
41 static void exp_unhashclient(svc_client
*clp
);
42 static int exp_verify_string(char *cp
, int max
);
44 #define CLIENT_HASHBITS 6
45 #define CLIENT_HASHMAX (1 << CLIENT_HASHBITS)
46 #define CLIENT_HASHMASK (CLIENT_HASHMAX - 1)
47 #define CLIENT_HASH(a) \
48 ((((a)>>24) ^ ((a)>>16) ^ ((a)>>8) ^(a)) & CLIENT_HASHMASK)
49 #define EXPORT_HASH(dev) ((dev) & (NFSCLNT_EXPMAX - 1))
52 struct svc_clnthash
* h_next
;
53 struct in_addr h_addr
;
54 struct svc_client
* h_client
;
56 static struct svc_clnthash
* clnt_hash
[CLIENT_HASHMAX
];
57 static svc_client
* clients
= NULL
;
58 static int initialized
= 0;
60 static int hash_lock
= 0;
61 static int want_lock
= 0;
62 static int hash_count
= 0;
63 static struct wait_queue
* hash_wait
= NULL
;
69 * Find a client's export for a device.
71 static inline svc_export
*
72 exp_find(svc_client
*clp
, dev_t dev
)
76 exp
= clp
->cl_export
[EXPORT_HASH(dev
)];
77 while (exp
&& exp
->ex_dev
!= dev
)
83 * Find the client's export entry matching xdev/xino.
86 exp_get(svc_client
*clp
, dev_t dev
, ino_t ino
)
92 exp
= exp_find(clp
, dev
);
93 return (exp
&& exp
->ex_ino
== ino
)? exp
: NULL
;
97 * Check whether there are any exports for a device.
100 exp_device_in_use(dev_t dev
)
102 struct svc_client
*clp
;
104 for (clp
= clients
; clp
; clp
= clp
->cl_next
) {
105 if (exp_find(clp
, dev
))
112 * Look up the device of the parent fs.
115 nfsd_parentdev(dev_t
*devp
)
117 struct super_block
*sb
;
119 if (!(sb
= get_super(*devp
)) || !sb
->s_root
->d_covers
)
121 if (*devp
== sb
->s_root
->d_covers
->d_inode
->i_dev
)
123 *devp
= sb
->s_root
->d_covers
->d_inode
->i_dev
;
128 * Find the parent export entry for a given fs. This function is used
129 * only by the export syscall to keep the export tree consistent.
132 exp_parent(svc_client
*clp
, dev_t dev
)
138 exp
= exp_find(clp
, xdev
);
141 } while (nfsd_parentdev(&xdev
));
147 * Export a file system.
150 exp_export(struct nfsctl_export
*nxp
)
153 svc_export
*exp
, *parent
;
155 struct dentry
*dentry
= NULL
;
156 struct inode
*inode
= NULL
;
161 /* Consistency check */
162 if (!exp_verify_string(nxp
->ex_path
, NFS_MAXPATHLEN
) ||
163 !exp_verify_string(nxp
->ex_client
, NFSCLNT_IDMAX
))
166 dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
167 nxp
->ex_client
, nxp
->ex_path
,
168 nxp
->ex_dev
, nxp
->ex_ino
, nxp
->ex_flags
);
172 /* Try to lock the export table for update */
173 if ((err
= exp_writelock()) < 0)
176 /* Look up client info */
178 if (!(clp
= exp_getclientbyname(nxp
->ex_client
)))
182 * If there's already an export for this file, assume this
183 * is just a flag update.
185 if ((exp
= exp_find(clp
, dev
)) != NULL
) {
186 /* Ensure there's only one export per FS. */
188 if (exp
->ex_ino
== ino
) {
189 exp
->ex_flags
= nxp
->ex_flags
;
190 exp
->ex_anon_uid
= nxp
->ex_anon_uid
;
191 exp
->ex_anon_gid
= nxp
->ex_anon_gid
;
197 /* Look up the dentry */
199 dentry
= lookup_dentry(nxp
->ex_path
, NULL
, 0);
204 inode
= dentry
->d_inode
;
208 if(inode
->i_dev
!= nxp
->ex_dev
|| inode
->i_ino
!= nxp
->ex_ino
) {
209 /* I'm just being paranoid... */
213 /* We currently export only dirs. */
215 if (!S_ISDIR(inode
->i_mode
))
218 /* If this is a sub-export, must be root of FS */
220 if ((parent
= exp_parent(clp
, dev
)) != NULL
) {
221 struct super_block
*sb
= inode
->i_sb
;
223 if (inode
!= sb
->s_root
->d_inode
) {
225 printk("exp_export: sub-export %s not root of device %s\n",
226 nxp
->ex_path
, kdevname(sb
->s_dev
));
233 if (!(exp
= kmalloc(sizeof(*exp
), GFP_USER
)))
235 dprintk("nfsd: created export entry %p for client %p\n", exp
, clp
);
237 strcpy(exp
->ex_path
, nxp
->ex_path
);
238 exp
->ex_client
= clp
;
239 exp
->ex_parent
= parent
;
240 exp
->ex_dentry
= dentry
;
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
;
291 /* Update parent pointers. */
292 clp
= unexp
->ex_client
;
293 for (i
= 0; i
< NFSCLNT_EXPMAX
; i
++) {
294 for (exp
= clp
->cl_export
[i
]; exp
; exp
= exp
->ex_next
)
295 if (exp
->ex_parent
== unexp
)
296 exp
->ex_parent
= unexp
->ex_parent
;
300 * Check whether this is the last export for this device,
301 * and if so flush any cached dentries.
303 if (!exp_device_in_use(unexp
->ex_dev
)) {
304 printk("exp_do_unexport: %s last use, flushing cache\n",
305 kdevname(unexp
->ex_dev
));
306 nfsd_fh_flush(unexp
->ex_dev
);
309 dentry
= unexp
->ex_dentry
;
310 inode
= dentry
->d_inode
;
311 if (unexp
->ex_dev
!= inode
->i_dev
|| unexp
->ex_ino
!= inode
->i_ino
)
312 printk(KERN_WARNING
"nfsd: bad dentry in unexport!\n");
319 * Revoke all exports for a given client.
320 * This may look very awkward, but we have to do it this way in order
321 * to avoid race conditions (aka mind the parent pointer).
324 exp_unexport_all(svc_client
*clp
)
329 dprintk("unexporting all fs's for clnt %p\n", clp
);
330 for (i
= 0; i
< NFSCLNT_EXPMAX
; i
++) {
331 exp
= clp
->cl_export
[i
];
332 clp
->cl_export
[i
] = NULL
;
334 svc_export
*next
= exp
->ex_next
;
335 exp_do_unexport(exp
);
345 exp_unexport(struct nfsctl_export
*nxp
)
348 svc_export
**expp
, *exp
= NULL
;
351 /* Consistency check */
352 if (!exp_verify_string(nxp
->ex_client
, NFSCLNT_IDMAX
))
355 if ((err
= exp_writelock()) < 0)
359 clp
= exp_getclientbyname(nxp
->ex_client
);
361 printk("exp_unexport: found client %s\n", nxp
->ex_client
);
362 expp
= clp
->cl_export
+ EXPORT_HASH(nxp
->ex_dev
);
363 while ((exp
= *expp
) != NULL
) {
364 if (exp
->ex_dev
== nxp
->ex_dev
) {
365 if (exp
->ex_ino
!= nxp
->ex_ino
) {
366 printk("exp_unexport: ino mismatch, %ld not %ld\n", exp
->ex_ino
, nxp
->ex_ino
);
369 *expp
= exp
->ex_next
;
370 exp_do_unexport(exp
);
374 expp
= &(exp
->ex_next
);
384 * Obtain the root fh on behalf of a client.
385 * This could be done in user space, but I feel that it adds some safety
386 * since its harder to fool a kernel module than a user space program.
389 exp_rootfh(struct svc_client
*clp
, dev_t dev
, ino_t ino
, struct knfs_fh
*f
)
391 struct svc_export
*exp
= NULL
;
393 struct dentry
*dentry
;
396 dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n", clp
->cl_ident
, dev
, ino
);
398 if (!(exp
= exp_get(clp
, dev
, ino
)))
401 dentry
= exp
->ex_dentry
;
402 inode
= dentry
->d_inode
;
404 printk("exp_rootfh: Aieee, NULL d_inode\n");
407 if(inode
->i_dev
!= dev
|| inode
->i_ino
!= ino
) {
408 printk("exp_rootfh: Aieee, ino/dev mismatch\n");
409 printk("exp_rootfh: arg[dev(%x):ino(%ld)] inode[dev(%x):ino(%ld)]\n",
410 dev
, ino
, inode
->i_dev
, inode
->i_ino
);
414 fh_compose(&fh
, exp
, dentry
);
415 memcpy(f
, &fh
.fh_handle
, sizeof(struct knfs_fh
));
422 * Hashtable locking. Write locks are placed only by user processes
423 * wanting to modify export information.
428 while (hash_lock
|| want_lock
)
429 sleep_on(&hash_wait
);
437 if (!hash_count
&& !hash_lock
) {
443 current
->sigpending
= 0;
445 while (hash_count
|| hash_lock
) {
446 interruptible_sleep_on(&hash_wait
);
447 if (signal_pending(current
))
452 /* restore the task's signals */
453 spin_lock_irq(¤t
->sigmask_lock
);
454 recalc_sigpending(current
);
455 spin_unlock_irq(¤t
->sigmask_lock
);
457 if (!hash_count
&& !hash_lock
)
465 if (!hash_count
&& !hash_lock
)
466 printk(KERN_WARNING
"exp_unlock: not locked!\n");
475 * Find a valid client given an inet address. We always move the most
476 * recently used client to the front of the hash chain to speed up
478 * Locking against other processes is the responsibility of the caller.
481 exp_getclient(struct sockaddr_in
*sin
)
483 struct svc_clnthash
**hp
, **head
, *tmp
;
484 unsigned long addr
= sin
->sin_addr
.s_addr
;
489 head
= &clnt_hash
[CLIENT_HASH(addr
)];
491 for (hp
= head
; (tmp
= *hp
) != NULL
; hp
= &(tmp
->h_next
)) {
492 if (tmp
->h_addr
.s_addr
== addr
) {
493 /* Move client to the front */
500 return tmp
->h_client
;
508 * Find a client given its identifier.
511 exp_getclientbyname(char *ident
)
515 for (clp
= clients
; clp
; clp
= clp
->cl_next
) {
516 if (!strcmp(clp
->cl_ident
, ident
))
523 * Add or modify a client.
524 * Change requests may involve the list of host addresses. The list of
525 * exports and possibly existing uid maps are left untouched.
528 exp_addclient(struct nfsctl_client
*ncp
)
530 struct svc_clnthash
* ch
[NFSCLNT_ADDRMAX
];
532 int i
, err
, change
= 0, ilen
;
534 /* First, consistency check. */
536 if (!(ilen
= exp_verify_string(ncp
->cl_ident
, NFSCLNT_IDMAX
)))
538 if (ncp
->cl_naddr
> NFSCLNT_ADDRMAX
)
541 /* Lock the hashtable */
542 if ((err
= exp_writelock()) < 0)
545 /* First check if this is a change request for a client. */
546 for (clp
= clients
; clp
; clp
= clp
->cl_next
)
547 if (!strcmp(clp
->cl_ident
, ncp
->cl_ident
))
554 if (!(clp
= kmalloc(sizeof(*clp
), GFP_KERNEL
)))
556 memset(clp
, 0, sizeof(*clp
));
558 dprintk("created client %s (%p)\n", ncp
->cl_ident
, clp
);
560 strcpy(clp
->cl_ident
, ncp
->cl_ident
);
561 clp
->cl_idlen
= ilen
;
564 /* Allocate hash buckets */
565 for (i
= 0; i
< ncp
->cl_naddr
; i
++) {
566 ch
[i
] = kmalloc(sizeof(struct svc_clnthash
), GFP_KERNEL
);
576 /* Copy addresses. */
577 for (i
= 0; i
< ncp
->cl_naddr
; i
++) {
578 clp
->cl_addr
[i
] = ncp
->cl_addrlist
[i
];
580 clp
->cl_naddr
= ncp
->cl_naddr
;
582 /* Remove old client hash entries. */
584 exp_unhashclient(clp
);
586 /* Insert client into hashtable. */
587 for (i
= 0; i
< ncp
->cl_naddr
; i
++) {
588 struct in_addr addr
= clp
->cl_addr
[i
];
591 hash
= CLIENT_HASH(addr
.s_addr
);
592 ch
[i
]->h_client
= clp
;
593 ch
[i
]->h_addr
= addr
;
594 ch
[i
]->h_next
= clnt_hash
[hash
];
595 clnt_hash
[hash
] = ch
[i
];
599 clp
->cl_next
= clients
;
611 * Delete a client given an identifier.
614 exp_delclient(struct nfsctl_client
*ncp
)
616 svc_client
**clpp
, *clp
;
619 if (!exp_verify_string(ncp
->cl_ident
, NFSCLNT_IDMAX
))
622 /* Lock the hashtable */
623 if ((err
= exp_writelock()) < 0)
626 for (clpp
= &clients
; (clp
= *clpp
); clpp
= &(clp
->cl_next
))
627 if (!strcmp(ncp
->cl_ident
, clp
->cl_ident
))
634 *clpp
= clp
->cl_next
;
642 * Free a client. The caller has already removed it from the client list.
645 exp_freeclient(svc_client
*clp
)
647 exp_unhashclient(clp
);
649 /* umap_free(&(clp->cl_umap)); */
650 exp_unexport_all(clp
);
651 nfsd_lockd_unexport(clp
);
656 * Remove client from hashtable. We first collect all hashtable
657 * entries and free them in one go.
658 * The hash table must be writelocked by the caller.
661 exp_unhashclient(svc_client
*clp
)
663 struct svc_clnthash
**hpp
, *hp
, *ch
[NFSCLNT_ADDRMAX
];
668 for (i
= 0, count
= 0; i
< CLIENT_HASHMAX
&& !err
; i
++) {
670 while ((hp
= *hpp
) && !err
) {
671 if (hp
->h_client
== clp
) {
674 err
= (count
>= NFSCLNT_ADDRMAX
);
680 if (count
!= clp
->cl_naddr
)
681 printk(KERN_WARNING
"nfsd: bad address count in freeclient!\n");
684 for (i
= 0; i
< count
; i
++)
689 * Lockd is shutting down and tells us to unregister all clients
694 struct svc_client
*clp
;
696 for (clp
= clients
; clp
; clp
= clp
->cl_next
)
697 nfsd_lockd_unexport(clp
);
701 * Verify that string is non-empty and does not exceed max length.
704 exp_verify_string(char *cp
, int max
)
708 for (i
= 0; i
< max
; i
++)
712 printk(KERN_NOTICE
"nfsd: couldn't validate string %s\n", cp
);
717 * Initialize the exports module.
720 nfsd_export_init(void)
724 dprintk("nfsd: initializing export module.\n");
727 for (i
= 0; i
< CLIENT_HASHMAX
; i
++)
735 * Shutdown the exports module.
738 nfsd_export_shutdown(void)
742 dprintk("nfsd: shutting down export module.\n");
745 if (exp_writelock() < 0) {
746 printk(KERN_WARNING
"Weird: hashtable locked in exp_shutdown");
749 for (i
= 0; i
< CLIENT_HASHMAX
; i
++) {
751 exp_freeclient(clnt_hash
[i
]->h_client
);
754 dprintk("nfsd: export shutdown complete.\n");