1#define MSNFS /* HACK HACK */ 2/* 3 * linux/fs/nfsd/export.c 4 * 5 * NFS exporting and validation. 6 * 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. 12 * 13 * 14 * Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de> 15 */ 16 17#include <linux/unistd.h> 18#include <linux/slab.h> 19#include <linux/stat.h> 20#include <linux/in.h> 21#include <linux/seq_file.h> 22 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> 28 29#define NFSDDBG_FACILITY NFSDDBG_EXPORT 30#define NFSD_PARANOIA 1 31 32typedef struct svc_client svc_client; 33typedef struct svc_export svc_export; 34 35static svc_export * exp_parent(svc_client *clp, kdev_t dev, 36 struct dentry *dentry); 37static svc_export * exp_child(svc_client *clp, kdev_t dev, 38 struct dentry *dentry); 39static void exp_unexport_all(svc_client *clp); 40static void exp_do_unexport(svc_export *unexp); 41static svc_client * exp_getclientbyname(char *name); 42static void exp_freeclient(svc_client *clp); 43static void exp_unhashclient(svc_client *clp); 44static int exp_verify_string(char *cp, int max); 45 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#define EXPORT_HASH(dev) ((dev) & (NFSCLNT_EXPMAX - 1)) 52#define EXPORT_FSID_HASH(fsid) ((fsid) & (NFSCLNT_EXPMAX - 1)) 53 54struct svc_clnthash { 55 struct svc_clnthash * h_next; 56 struct in_addr h_addr; 57 struct svc_client * h_client; 58}; 59static struct svc_clnthash * clnt_hash[CLIENT_HASHMAX]; 60static svc_client * clients; 61 62static int hash_lock; 63static int want_lock; 64static int hash_count; 65static DECLARE_WAIT_QUEUE_HEAD( hash_wait ); 66 67/* 68 * Find the client's export entry matching xdev/xino. 69 */ 70svc_export * 71exp_get(svc_client *clp, kdev_t dev, ino_t ino) 72{ 73 struct list_head *head, *p; 74 75 if (!clp) 76 return NULL; 77 78 head = &clp->cl_export[EXPORT_HASH(dev)]; 79 list_for_each(p, head) { 80 svc_export *exp = list_entry(p, svc_export, ex_hash); 81 if (exp->ex_ino == ino && exp->ex_dev == dev) 82 return exp; 83 } 84 85 return NULL; 86} 87 88/* 89 * Find the client's export entry matching fsid 90 */ 91svc_export * 92exp_get_fsid(svc_client *clp, int fsid) 93{ 94 struct list_head *head, *p; 95 96 if (!clp) 97 return NULL; 98 99 head = &clp->cl_expfsid[EXPORT_FSID_HASH(fsid)]; 100 list_for_each(p, head) { 101 svc_export *exp = list_entry(p, svc_export, ex_fsid_hash); 102 if (exp->ex_fsid == fsid) 103 return exp; 104 } 105 return NULL; 106} 107 108/* 109 * Find the export entry for a given dentry. <gam3@acm.org> 110 */ 111static svc_export * 112exp_parent(svc_client *clp, kdev_t dev, struct dentry *dentry) 113{ 114 struct list_head *head = &clp->cl_export[EXPORT_HASH(dev)]; 115 struct list_head *p; 116 117 list_for_each(p,head) { 118 svc_export *exp = list_entry(p, svc_export, ex_hash); 119 if (is_subdir(dentry, exp->ex_dentry)) 120 return exp; 121 } 122 return NULL; 123} 124 125/* 126 * Find the child export entry for a given fs. This function is used 127 * only by the export syscall to keep the export tree consistent. 128 * <gam3@acm.org> 129 */ 130static svc_export * 131exp_child(svc_client *clp, kdev_t dev, struct dentry *dentry) 132{ 133 struct list_head *head = &clp->cl_export[EXPORT_HASH(dev)]; 134 struct list_head *p; 135 136 137 list_for_each(p, head) { 138 svc_export *exp = list_entry(p, svc_export, ex_hash); 139 struct dentry *ndentry = exp->ex_dentry; 140 141 if (ndentry && is_subdir(ndentry->d_parent, dentry)) 142 return exp; 143 } 144 return NULL; 145} 146 147/* Update parent pointers of all exports */ 148static void exp_change_parents(svc_client *clp, svc_export *old, svc_export *new) 149{ 150 struct list_head *head = &clp->cl_list; 151 struct list_head *p; 152 153 list_for_each(p, head) { 154 svc_export *exp = list_entry(p, svc_export, ex_list); 155 if (exp->ex_parent == old) 156 exp->ex_parent = new; 157 } 158} 159 160static void exp_fsid_unhash(struct svc_export *exp) 161{ 162 163 if ((exp->ex_flags & NFSEXP_FSID) == 0) 164 return; 165 166 list_del_init(&exp->ex_fsid_hash); 167} 168 169static void exp_fsid_hash(struct svc_client *clp, struct svc_export *exp) 170{ 171 struct list_head *head; 172 173 if ((exp->ex_flags & NFSEXP_FSID) == 0) 174 return; 175 head = clp->cl_expfsid + EXPORT_FSID_HASH(exp->ex_fsid); 176 list_add(&exp->ex_fsid_hash, head); 177} 178 179/* 180 * Export a file system. 181 */ 182int 183exp_export(struct nfsctl_export *nxp) 184{ 185 svc_client *clp; 186 svc_export *exp = NULL, *parent; 187 svc_export *fsid_exp; 188 struct nameidata nd; 189 struct inode *inode = NULL; 190 int err; 191 kdev_t dev; 192 ino_t ino; 193 194 /* Consistency check */ 195 err = -EINVAL; 196 if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) || 197 !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX)) 198 goto out; 199 200 dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n", 201 nxp->ex_client, nxp->ex_path, 202 nxp->ex_dev, (long) nxp->ex_ino, nxp->ex_flags); 203 204 /* Try to lock the export table for update */ 205 if ((err = exp_writelock()) < 0) 206 goto out; 207 208 /* Look up client info */ 209 err = -EINVAL; 210 if (!(clp = exp_getclientbyname(nxp->ex_client))) 211 goto out_unlock; 212 213 214 /* Look up the dentry */ 215 err = 0; 216 if (path_init(nxp->ex_path, LOOKUP_POSITIVE, &nd)) 217 err = path_walk(nxp->ex_path, &nd); 218 if (err) 219 goto out_unlock; 220 221 inode = nd.dentry->d_inode; 222 dev = inode->i_dev; 223 ino = inode->i_ino; 224 err = -EINVAL; 225 226 exp = exp_get(clp, dev, ino); 227 228 /* must make sure there wont be an ex_fsid clash */ 229 if ((nxp->ex_flags & NFSEXP_FSID) && 230 (fsid_exp = exp_get_fsid(clp, nxp->ex_dev)) && 231 fsid_exp != exp) 232 goto finish; 233 234 if (exp != NULL) { 235 /* just a flags/id/fsid update */ 236 237 exp_fsid_unhash(exp); 238 exp->ex_flags = nxp->ex_flags; 239 exp->ex_anon_uid = nxp->ex_anon_uid; 240 exp->ex_anon_gid = nxp->ex_anon_gid; 241 exp->ex_fsid = nxp->ex_dev; 242 exp_fsid_hash(clp, exp); 243 err = 0; 244 goto finish; 245 } 246 247 /* We currently export only dirs and regular files. 248 * This is what umountd does. 249 */ 250 err = -ENOTDIR; 251 if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode)) 252 goto finish; 253 254 err = -EINVAL; 255 /* There are two requirements on a filesystem to be exportable. 256 * 1: We must be able to identify the filesystem from a number. 257 * either a device number (so FS_REQUIRES_DEV needed) 258 * or an FSID number (so NFSEXP_FSID needed). 259 * 2: We must be able to find an inode from a filehandle. 260 * either using fh_to_dentry (prefered) 261 * or using read_inode (the hack). 262 */ 263 if (!((inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) 264 || (nxp->ex_flags & NFSEXP_FSID)) 265 || 266 (inode->i_sb->s_op->read_inode == NULL 267 && inode->i_sb->s_op->fh_to_dentry == NULL)) { 268 dprintk("exp_export: export of invalid fs type.\n"); 269 goto finish; 270 } 271 272 if ((parent = exp_child(clp, dev, nd.dentry)) != NULL) { 273 dprintk("exp_export: export not valid (Rule 3).\n"); 274 goto finish; 275 } 276 /* Is this is a sub-export, must be a proper subset of FS */ 277 if ((parent = exp_parent(clp, dev, nd.dentry)) != NULL) { 278 dprintk("exp_export: sub-export not valid (Rule 2).\n"); 279 goto finish; 280 } 281 282 err = -ENOMEM; 283 if (!(exp = kmalloc(sizeof(*exp), GFP_USER))) 284 goto finish; 285 dprintk("nfsd: created export entry %p for client %p\n", exp, clp); 286 287 strcpy(exp->ex_path, nxp->ex_path); 288 exp->ex_client = clp; 289 exp->ex_parent = parent; 290 exp->ex_dentry = dget(nd.dentry); 291 exp->ex_mnt = mntget(nd.mnt); 292 exp->ex_flags = nxp->ex_flags; 293 exp->ex_dev = dev; 294 exp->ex_ino = ino; 295 exp->ex_anon_uid = nxp->ex_anon_uid; 296 exp->ex_anon_gid = nxp->ex_anon_gid; 297 exp->ex_fsid = nxp->ex_dev; 298 299 300 /* Update parent pointers of all exports */ 301 if (parent) 302 exp_change_parents(clp, parent, exp); 303 304 list_add(&exp->ex_hash, clp->cl_export + EXPORT_HASH(dev)); 305 list_add_tail(&exp->ex_list, &clp->cl_list); 306 307 exp_fsid_hash(clp, exp); 308 309 err = 0; 310 311finish: 312 path_release(&nd); 313out_unlock: 314 exp_unlock(); 315out: 316 return err; 317} 318 319/* 320 * Unexport a file system. The export entry has already 321 * been removed from the client's list of exported fs's. 322 */ 323static void 324exp_do_unexport(svc_export *unexp) 325{ 326 struct dentry *dentry; 327 struct vfsmount *mnt; 328 struct inode *inode; 329 330 list_del(&unexp->ex_hash); 331 list_del(&unexp->ex_list); 332 exp_fsid_unhash(unexp); 333 334 exp_change_parents(unexp->ex_client, unexp, unexp->ex_parent); 335 336 dentry = unexp->ex_dentry; 337 mnt = unexp->ex_mnt; 338 inode = dentry->d_inode; 339 if (unexp->ex_dev != inode->i_dev || unexp->ex_ino != inode->i_ino) 340 printk(KERN_WARNING "nfsd: bad dentry in unexport!\n"); 341 dput(dentry); 342 mntput(mnt); 343 344 kfree(unexp); 345} 346 347/* 348 * Revoke all exports for a given client. 349 * This may look very awkward, but we have to do it this way in order 350 * to avoid race conditions (aka mind the parent pointer). 351 */ 352static void 353exp_unexport_all(svc_client *clp) 354{ 355 struct list_head *p = &clp->cl_list; 356 357 dprintk("unexporting all fs's for clnt %p\n", clp); 358 359 while (!list_empty(p)) { 360 svc_export *exp = list_entry(p->next, svc_export, ex_list); 361 exp_do_unexport(exp); 362 } 363} 364 365/* 366 * unexport syscall. 367 */ 368int 369exp_unexport(struct nfsctl_export *nxp) 370{ 371 svc_client *clp; 372 int err; 373 374 /* Consistency check */ 375 if (!exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX)) 376 return -EINVAL; 377 378 if ((err = exp_writelock()) < 0) 379 goto out; 380 381 err = -EINVAL; 382 clp = exp_getclientbyname(nxp->ex_client); 383 if (clp) { 384 svc_export *exp = exp_get(clp, nxp->ex_dev, nxp->ex_ino); 385 if (exp) { 386 exp_do_unexport(exp); 387 err = 0; 388 } 389 } 390 391 exp_unlock(); 392out: 393 return err; 394} 395 396/* 397 * Obtain the root fh on behalf of a client. 398 * This could be done in user space, but I feel that it adds some safety 399 * since its harder to fool a kernel module than a user space program. 400 */ 401int 402exp_rootfh(struct svc_client *clp, kdev_t dev, ino_t ino, 403 char *path, struct knfsd_fh *f, int maxsize) 404{ 405 struct svc_export *exp; 406 struct nameidata nd; 407 struct inode *inode; 408 struct svc_fh fh; 409 int err; 410 411 err = -EPERM; 412 if (path) { 413 if (path_init(path, LOOKUP_POSITIVE, &nd) && 414 path_walk(path, &nd)) { 415 printk("nfsd: exp_rootfh path not found %s", path); 416 return err; 417 } 418 dev = nd.dentry->d_inode->i_dev; 419 ino = nd.dentry->d_inode->i_ino; 420 421 dprintk("nfsd: exp_rootfh(%s [%p] %s:%x/%ld)\n", 422 path, nd.dentry, clp->cl_ident, dev, (long) ino); 423 exp = exp_parent(clp, dev, nd.dentry); 424 } else { 425 dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n", 426 clp->cl_ident, dev, (long) ino); 427 if ((exp = exp_get(clp, dev, ino))) { 428 nd.mnt = mntget(exp->ex_mnt); 429 nd.dentry = dget(exp->ex_dentry); 430 } 431 } 432 if (!exp) { 433 dprintk("nfsd: exp_rootfh export not found.\n"); 434 goto out; 435 } 436 437 inode = nd.dentry->d_inode; 438 if (!inode) { 439 printk("exp_rootfh: Aieee, NULL d_inode\n"); 440 goto out; 441 } 442 if (inode->i_dev != dev || inode->i_ino != ino) { 443 printk("exp_rootfh: Aieee, ino/dev mismatch\n"); 444 printk("exp_rootfh: arg[dev(%x):ino(%ld)]" 445 " inode[dev(%x):ino(%ld)]\n", 446 dev, (long) ino, inode->i_dev, (long) inode->i_ino); 447 } 448 449 /* 450 * fh must be initialized before calling fh_compose 451 */ 452 fh_init(&fh, maxsize); 453 if (fh_compose(&fh, exp, dget(nd.dentry), NULL)) 454 err = -EINVAL; 455 else 456 err = 0; 457 memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh)); 458 fh_put(&fh); 459 460out: 461 if (path) 462 path_release(&nd); 463 return err; 464} 465 466/* 467 * Hashtable locking. Write locks are placed only by user processes 468 * wanting to modify export information. 469 */ 470void 471exp_readlock(void) 472{ 473 while (hash_lock || want_lock) 474 sleep_on(&hash_wait); 475 hash_count++; 476} 477 478int 479exp_writelock(void) 480{ 481 /* fast track */ 482 if (!hash_count && !hash_lock) { 483 lock_it: 484 hash_lock = 1; 485 return 0; 486 } 487 488 current->sigpending = 0; 489 want_lock++; 490 while (hash_count || hash_lock) { 491 interruptible_sleep_on(&hash_wait); 492 if (signal_pending(current)) 493 break; 494 } 495 want_lock--; 496 497 /* restore the task's signals */ 498 spin_lock_irq(¤t->sigmask_lock); 499 recalc_sigpending(current); 500 spin_unlock_irq(¤t->sigmask_lock); 501 502 if (!hash_count && !hash_lock) 503 goto lock_it; 504 return -EINTR; 505} 506 507void 508exp_unlock(void) 509{ 510 if (!hash_count && !hash_lock) 511 printk(KERN_WARNING "exp_unlock: not locked!\n"); 512 if (hash_count) 513 hash_count--; 514 else 515 hash_lock = 0; 516 wake_up(&hash_wait); 517} 518 519/* 520 * Find a valid client given an inet address. We always move the most 521 * recently used client to the front of the hash chain to speed up 522 * future lookups. 523 * Locking against other processes is the responsibility of the caller. 524 */ 525struct svc_client * 526exp_getclient(struct sockaddr_in *sin) 527{ 528 struct svc_clnthash **hp, **head, *tmp; 529 unsigned long addr = sin->sin_addr.s_addr; 530 531 head = &clnt_hash[CLIENT_HASH(addr)]; 532 533 for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) { 534 if (tmp->h_addr.s_addr == addr) { 535 /* Move client to the front */ 536 if (head != hp) { 537 *hp = tmp->h_next; 538 tmp->h_next = *head; 539 *head = tmp; 540 } 541 542 return tmp->h_client; 543 } 544 } 545 546 return NULL; 547} 548 549/* 550 * Find a client given its identifier. 551 */ 552static svc_client * 553exp_getclientbyname(char *ident) 554{ 555 svc_client * clp; 556 557 for (clp = clients; clp; clp = clp->cl_next) { 558 if (!strcmp(clp->cl_ident, ident)) 559 return clp; 560 } 561 return NULL; 562} 563 564/* Iterator */ 565 566static void *e_start(struct seq_file *m, loff_t *pos) 567{ 568 loff_t n = *pos; 569 unsigned client, export; 570 svc_client *clp; 571 struct list_head *p; 572 573 exp_readlock(); 574 if (!n--) 575 return (void *)1; 576 client = n >> 32; 577 export = n & ((1LL<<32) - 1); 578 for (clp = clients; client && clp; clp = clp->cl_next, client--) 579 ; 580 if (!clp) 581 return NULL; 582 list_for_each(p, &clp->cl_list) 583 if (!export--) 584 return list_entry(p, svc_export, ex_list); 585 n &= ~((1LL<<32) - 1); 586 do { 587 clp = clp->cl_next; 588 n += 1LL<<32; 589 } while(clp && list_empty(&clp->cl_list)); 590 if (!clp) 591 return NULL; 592 *pos = n+1; 593 return list_entry(clp->cl_list.next, svc_export, ex_list); 594} 595 596static void *e_next(struct seq_file *m, void *p, loff_t *pos) 597{ 598 svc_export *exp = p; 599 svc_client *clp; 600 601 if (p == (void *)1) 602 clp = clients; 603 else if (exp->ex_list.next == &exp->ex_client->cl_list) { 604 clp = exp->ex_client->cl_next; 605 *pos += 1LL<<32; 606 } else { 607 ++*pos; 608 return list_entry(exp->ex_list.next, svc_export, ex_list); 609 } 610 *pos &= ~((1LL<<32) - 1); 611 while (clp && list_empty(&clp->cl_list)) { 612 clp = clp->cl_next; 613 *pos += 1LL<<32; 614 } 615 if (!clp) 616 return NULL; 617 ++*pos; 618 return list_entry(clp->cl_list.next, svc_export, ex_list); 619} 620 621static void e_stop(struct seq_file *m, void *p) 622{ 623 exp_unlock(); 624} 625 626struct flags { 627 int flag; 628 char *name[2]; 629} expflags[] = { 630 { NFSEXP_READONLY, {"ro", "rw"}}, 631 { NFSEXP_INSECURE_PORT, {"insecure", ""}}, 632 { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}}, 633 { NFSEXP_ALLSQUASH, {"all_squash", ""}}, 634 { NFSEXP_ASYNC, {"async", "sync"}}, 635 { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}}, 636 { NFSEXP_UIDMAP, {"uidmap", ""}}, 637 { NFSEXP_KERBEROS, { "kerberos", ""}}, 638 { NFSEXP_SUNSECURE, { "sunsecure", ""}}, 639 { NFSEXP_CROSSMNT, {"nohide", ""}}, 640 { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}}, 641 { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}}, 642#ifdef MSNFS 643 { NFSEXP_MSNFS, {"msnfs", ""}}, 644#endif 645 { 0, {"", ""}} 646}; 647 648static void exp_flags(struct seq_file *m, int flag, int fsid) 649{ 650 int first = 0; 651 struct flags *flg; 652 653 for (flg = expflags; flg->flag; flg++) { 654 int state = (flg->flag & flag)?0:1; 655 if (*flg->name[state]) 656 seq_printf(m, "%s%s", first++?",":"", flg->name[state]); 657 } 658 if (flag & NFSEXP_FSID) 659 seq_printf(m, "%sfsid=%d", first++?",":"", fsid); 660} 661 662static inline void mangle(struct seq_file *m, const char *s) 663{ 664 seq_escape(m, s, " \t\n\\"); 665} 666 667static int e_show(struct seq_file *m, void *p) 668{ 669 struct svc_export *exp = p; 670 struct svc_client *clp; 671 int j, first = 0; 672 673 if (p == (void *)1) { 674 seq_puts(m, "# Version 1.1\n"); 675 seq_puts(m, "# Path Client(Flags) # IPs\n"); 676 return 0; 677 } 678 679 clp = exp->ex_client; 680 681 mangle(m, exp->ex_path); 682 seq_putc(m, '\t'); 683 mangle(m, clp->cl_ident); 684 seq_putc(m, '('); 685 exp_flags(m, exp->ex_flags, exp->ex_fsid); 686 seq_puts(m, ") # "); 687 for (j = 0; j < clp->cl_naddr; j++) { 688 struct svc_clnthash **hp, **head, *tmp; 689 struct in_addr addr = clp->cl_addr[j]; 690 691 head = &clnt_hash[CLIENT_HASH(addr.s_addr)]; 692 for (hp = head; (tmp = *hp) != NULL; hp = &(tmp->h_next)) { 693 if (tmp->h_addr.s_addr == addr.s_addr) 694 break; 695 } 696 if (tmp) { 697 if (first++) 698 seq_putc(m, ' '); 699 if (tmp->h_client != clp) 700 seq_putc(m, '('); 701 seq_printf(m, "%d.%d.%d.%d", 702 htonl(addr.s_addr) >> 24 & 0xff, 703 htonl(addr.s_addr) >> 16 & 0xff, 704 htonl(addr.s_addr) >> 8 & 0xff, 705 htonl(addr.s_addr) >> 0 & 0xff); 706 if (tmp->h_client != clp) 707 seq_putc(m, ')'); 708 } 709 } 710 seq_putc(m, '\n'); 711 return 0; 712} 713 714struct seq_operations nfs_exports_op = { 715 start: e_start, 716 next: e_next, 717 stop: e_stop, 718 show: e_show, 719}; 720 721/* 722 * Add or modify a client. 723 * Change requests may involve the list of host addresses. The list of 724 * exports and possibly existing uid maps are left untouched. 725 */ 726int 727exp_addclient(struct nfsctl_client *ncp) 728{ 729 struct svc_clnthash * ch[NFSCLNT_ADDRMAX]; 730 svc_client * clp; 731 int i, err, change = 0, ilen; 732 733 /* First, consistency check. */ 734 err = -EINVAL; 735 if (!(ilen = exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))) 736 goto out; 737 if (ncp->cl_naddr > NFSCLNT_ADDRMAX) 738 goto out; 739 740 /* Lock the hashtable */ 741 if ((err = exp_writelock()) < 0) 742 goto out; 743 744 /* First check if this is a change request for a client. */ 745 for (clp = clients; clp; clp = clp->cl_next) 746 if (!strcmp(clp->cl_ident, ncp->cl_ident)) 747 break; 748 749 err = -ENOMEM; 750 if (clp) { 751 change = 1; 752 } else { 753 if (!(clp = kmalloc(sizeof(*clp), GFP_KERNEL))) 754 goto out_unlock; 755 memset(clp, 0, sizeof(*clp)); 756 for (i = 0; i < NFSCLNT_EXPMAX; i++) { 757 INIT_LIST_HEAD(&clp->cl_export[i]); 758 INIT_LIST_HEAD(&clp->cl_expfsid[i]); 759 } 760 INIT_LIST_HEAD(&clp->cl_list); 761 762 dprintk("created client %s (%p)\n", ncp->cl_ident, clp); 763 764 strcpy(clp->cl_ident, ncp->cl_ident); 765 clp->cl_idlen = ilen; 766 } 767 768 /* Allocate hash buckets */ 769 for (i = 0; i < ncp->cl_naddr; i++) { 770 ch[i] = kmalloc(sizeof(struct svc_clnthash), GFP_KERNEL); 771 if (!ch[i]) { 772 while (i--) 773 kfree(ch[i]); 774 if (!change) 775 kfree(clp); 776 goto out_unlock; 777 } 778 } 779 780 /* Copy addresses. */ 781 for (i = 0; i < ncp->cl_naddr; i++) { 782 clp->cl_addr[i] = ncp->cl_addrlist[i]; 783 } 784 clp->cl_naddr = ncp->cl_naddr; 785 786 /* Remove old client hash entries. */ 787 if (change) 788 exp_unhashclient(clp); 789 790 /* Insert client into hashtable. */ 791 for (i = 0; i < ncp->cl_naddr; i++) { 792 struct in_addr addr = clp->cl_addr[i]; 793 int hash; 794 795 hash = CLIENT_HASH(addr.s_addr); 796 ch[i]->h_client = clp; 797 ch[i]->h_addr = addr; 798 ch[i]->h_next = clnt_hash[hash]; 799 clnt_hash[hash] = ch[i]; 800 } 801 802 if (!change) { 803 clp->cl_next = clients; 804 clients = clp; 805 } 806 err = 0; 807 808out_unlock: 809 exp_unlock(); 810out: 811 return err; 812} 813 814/* 815 * Delete a client given an identifier. 816 */ 817int 818exp_delclient(struct nfsctl_client *ncp) 819{ 820 svc_client **clpp, *clp; 821 int err; 822 823 err = -EINVAL; 824 if (!exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX)) 825 goto out; 826 827 /* Lock the hashtable */ 828 if ((err = exp_writelock()) < 0) 829 goto out; 830 831 err = -EINVAL; 832 for (clpp = &clients; (clp = *clpp); clpp = &(clp->cl_next)) 833 if (!strcmp(ncp->cl_ident, clp->cl_ident)) 834 break; 835 836 if (clp) { 837 *clpp = clp->cl_next; 838 exp_freeclient(clp); 839 err = 0; 840 } 841 842 exp_unlock(); 843out: 844 return err; 845} 846 847/* 848 * Free a client. The caller has already removed it from the client list. 849 */ 850static void 851exp_freeclient(svc_client *clp) 852{ 853 exp_unhashclient(clp); 854 855 /* umap_free(&(clp->cl_umap)); */ 856 exp_unexport_all(clp); 857 nfsd_lockd_unexport(clp); 858 kfree (clp); 859} 860 861/* 862 * Remove client from hashtable. We first collect all hashtable 863 * entries and free them in one go. 864 * The hash table must be writelocked by the caller. 865 */ 866static void 867exp_unhashclient(svc_client *clp) 868{ 869 struct svc_clnthash **hpp, *hp, *ch[NFSCLNT_ADDRMAX]; 870 int i, count, err; 871 872again: 873 err = 0; 874 for (i = 0, count = 0; i < CLIENT_HASHMAX && !err; i++) { 875 hpp = clnt_hash + i; 876 while ((hp = *hpp) && !err) { 877 if (hp->h_client == clp) { 878 *hpp = hp->h_next; 879 ch[count++] = hp; 880 err = (count >= NFSCLNT_ADDRMAX); 881 } else { 882 hpp = &(hp->h_next); 883 } 884 } 885 } 886 if (count != clp->cl_naddr) 887 printk(KERN_WARNING "nfsd: bad address count in freeclient!\n"); 888 if (err) 889 goto again; 890 for (i = 0; i < count; i++) 891 kfree (ch[i]); 892} 893 894/* 895 * Lockd is shutting down and tells us to unregister all clients 896 */ 897void 898exp_nlmdetach(void) 899{ 900 struct svc_client *clp; 901 902 for (clp = clients; clp; clp = clp->cl_next) 903 nfsd_lockd_unexport(clp); 904} 905 906/* 907 * Verify that string is non-empty and does not exceed max length. 908 */ 909static int 910exp_verify_string(char *cp, int max) 911{ 912 int i; 913 914 for (i = 0; i < max; i++) 915 if (!cp[i]) 916 return i; 917 cp[i] = 0; 918 printk(KERN_NOTICE "nfsd: couldn't validate string %s\n", cp); 919 return 0; 920} 921 922/* 923 * Initialize the exports module. 924 */ 925void 926nfsd_export_init(void) 927{ 928 int i; 929 930 dprintk("nfsd: initializing export module.\n"); 931 932 for (i = 0; i < CLIENT_HASHMAX; i++) 933 clnt_hash[i] = NULL; 934 clients = NULL; 935 936} 937 938/* 939 * Shutdown the exports module. 940 */ 941void 942nfsd_export_shutdown(void) 943{ 944 int i; 945 946 dprintk("nfsd: shutting down export module.\n"); 947 948 if (exp_writelock() < 0) { 949 printk(KERN_WARNING "Weird: hashtable locked in exp_shutdown"); 950 return; 951 } 952 for (i = 0; i < CLIENT_HASHMAX; i++) { 953 while (clnt_hash[i]) 954 exp_freeclient(clnt_hash[i]->h_client); 955 } 956 clients = NULL; /* we may be restarted before the module unloads */ 957 958 exp_unlock(); 959 dprintk("nfsd: export shutdown complete.\n"); 960} 961