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 #include <linux/syscalls.h> 23 #include <linux/rwsem.h> 24 #include <linux/dcache.h> 25 #include <linux/namei.h> 26 #include <linux/mount.h> 27 #include <linux/hash.h> 28 #include <linux/module.h> 29 30 #include <linux/sunrpc/svc.h> 31 #include <linux/nfsd/nfsd.h> 32 #include <linux/nfsd/nfsfh.h> 33 #include <linux/nfsd/syscall.h> 34 #include <linux/lockd/bind.h> 35 36 #define NFSDDBG_FACILITY NFSDDBG_EXPORT 37 38 typedef struct auth_domain svc_client; 39 typedef struct svc_export svc_export; 40 41 static void exp_do_unexport(svc_export *unexp); 42 static int exp_verify_string(char *cp, int max); 43 44 /* 45 * We have two caches. 46 * One maps client+vfsmnt+dentry to export options - the export map 47 * The other maps client+filehandle-fragment to export options. - the expkey map 48 * 49 * The export options are actually stored in the first map, and the 50 * second map contains a reference to the entry in the first map. 51 */ 52 53 #define EXPKEY_HASHBITS 8 54 #define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS) 55 #define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1) 56 static struct cache_head *expkey_table[EXPKEY_HASHMAX]; 57 58 static void expkey_put(struct kref *ref) 59 { 60 struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref); 61 62 if (test_bit(CACHE_VALID, &key->h.flags) && 63 !test_bit(CACHE_NEGATIVE, &key->h.flags)) { 64 dput(key->ek_dentry); 65 mntput(key->ek_mnt); 66 } 67 auth_domain_put(key->ek_client); 68 kfree(key); 69 } 70 71 static void expkey_request(struct cache_detail *cd, 72 struct cache_head *h, 73 char **bpp, int *blen) 74 { 75 /* client fsidtype \xfsid */ 76 struct svc_expkey *ek = container_of(h, struct svc_expkey, h); 77 char type[5]; 78 79 qword_add(bpp, blen, ek->ek_client->name); 80 snprintf(type, 5, "%d", ek->ek_fsidtype); 81 qword_add(bpp, blen, type); 82 qword_addhex(bpp, blen, (char*)ek->ek_fsid, key_len(ek->ek_fsidtype)); 83 (*bpp)[-1] = '\n'; 84 } 85 86 static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old); 87 static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *); 88 static struct cache_detail svc_expkey_cache; 89 90 static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) 91 { 92 /* client fsidtype fsid [path] */ 93 char *buf; 94 int len; 95 struct auth_domain *dom = NULL; 96 int err; 97 int fsidtype; 98 char *ep; 99 struct svc_expkey key; 100 struct svc_expkey *ek; 101 102 if (mesg[mlen-1] != '\n') 103 return -EINVAL; 104 mesg[mlen-1] = 0; 105 106 buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 107 err = -ENOMEM; 108 if (!buf) goto out; 109 110 err = -EINVAL; 111 if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) 112 goto out; 113 114 err = -ENOENT; 115 dom = auth_domain_find(buf); 116 if (!dom) 117 goto out; 118 dprintk("found domain %s\n", buf); 119 120 err = -EINVAL; 121 if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) 122 goto out; 123 fsidtype = simple_strtoul(buf, &ep, 10); 124 if (*ep) 125 goto out; 126 dprintk("found fsidtype %d\n", fsidtype); 127 if (key_len(fsidtype)==0) /* invalid type */ 128 goto out; 129 if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) 130 goto out; 131 dprintk("found fsid length %d\n", len); 132 if (len != key_len(fsidtype)) 133 goto out; 134 135 /* OK, we seem to have a valid key */ 136 key.h.flags = 0; 137 key.h.expiry_time = get_expiry(&mesg); 138 if (key.h.expiry_time == 0) 139 goto out; 140 141 key.ek_client = dom; 142 key.ek_fsidtype = fsidtype; 143 memcpy(key.ek_fsid, buf, len); 144 145 ek = svc_expkey_lookup(&key); 146 err = -ENOMEM; 147 if (!ek) 148 goto out; 149 150 /* now we want a pathname, or empty meaning NEGATIVE */ 151 err = -EINVAL; 152 if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0) 153 goto out; 154 dprintk("Path seems to be <%s>\n", buf); 155 err = 0; 156 if (len == 0) { 157 set_bit(CACHE_NEGATIVE, &key.h.flags); 158 ek = svc_expkey_update(&key, ek); 159 if (ek) 160 cache_put(&ek->h, &svc_expkey_cache); 161 else err = -ENOMEM; 162 } else { 163 struct nameidata nd; 164 err = path_lookup(buf, 0, &nd); 165 if (err) 166 goto out; 167 168 dprintk("Found the path %s\n", buf); 169 key.ek_mnt = nd.mnt; 170 key.ek_dentry = nd.dentry; 171 172 ek = svc_expkey_update(&key, ek); 173 if (ek) 174 cache_put(&ek->h, &svc_expkey_cache); 175 else 176 err = -ENOMEM; 177 path_release(&nd); 178 } 179 cache_flush(); 180 out: 181 if (dom) 182 auth_domain_put(dom); 183 kfree(buf); 184 return err; 185 } 186 187 static int expkey_show(struct seq_file *m, 188 struct cache_detail *cd, 189 struct cache_head *h) 190 { 191 struct svc_expkey *ek ; 192 int i; 193 194 if (h ==NULL) { 195 seq_puts(m, "#domain fsidtype fsid [path]\n"); 196 return 0; 197 } 198 ek = container_of(h, struct svc_expkey, h); 199 seq_printf(m, "%s %d 0x", ek->ek_client->name, 200 ek->ek_fsidtype); 201 for (i=0; i < key_len(ek->ek_fsidtype)/4; i++) 202 seq_printf(m, "%08x", ek->ek_fsid[i]); 203 if (test_bit(CACHE_VALID, &h->flags) && 204 !test_bit(CACHE_NEGATIVE, &h->flags)) { 205 seq_printf(m, " "); 206 seq_path(m, ek->ek_mnt, ek->ek_dentry, "\\ \t\n"); 207 } 208 seq_printf(m, "\n"); 209 return 0; 210 } 211 212 static inline int expkey_match (struct cache_head *a, struct cache_head *b) 213 { 214 struct svc_expkey *orig = container_of(a, struct svc_expkey, h); 215 struct svc_expkey *new = container_of(b, struct svc_expkey, h); 216 217 if (orig->ek_fsidtype != new->ek_fsidtype || 218 orig->ek_client != new->ek_client || 219 memcmp(orig->ek_fsid, new->ek_fsid, key_len(orig->ek_fsidtype)) != 0) 220 return 0; 221 return 1; 222 } 223 224 static inline void expkey_init(struct cache_head *cnew, 225 struct cache_head *citem) 226 { 227 struct svc_expkey *new = container_of(cnew, struct svc_expkey, h); 228 struct svc_expkey *item = container_of(citem, struct svc_expkey, h); 229 230 kref_get(&item->ek_client->ref); 231 new->ek_client = item->ek_client; 232 new->ek_fsidtype = item->ek_fsidtype; 233 234 memcpy(new->ek_fsid, item->ek_fsid, sizeof(new->ek_fsid)); 235 } 236 237 static inline void expkey_update(struct cache_head *cnew, 238 struct cache_head *citem) 239 { 240 struct svc_expkey *new = container_of(cnew, struct svc_expkey, h); 241 struct svc_expkey *item = container_of(citem, struct svc_expkey, h); 242 243 new->ek_mnt = mntget(item->ek_mnt); 244 new->ek_dentry = dget(item->ek_dentry); 245 } 246 247 static struct cache_head *expkey_alloc(void) 248 { 249 struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL); 250 if (i) 251 return &i->h; 252 else 253 return NULL; 254 } 255 256 static struct cache_detail svc_expkey_cache = { 257 .owner = THIS_MODULE, 258 .hash_size = EXPKEY_HASHMAX, 259 .hash_table = expkey_table, 260 .name = "nfsd.fh", 261 .cache_put = expkey_put, 262 .cache_request = expkey_request, 263 .cache_parse = expkey_parse, 264 .cache_show = expkey_show, 265 .match = expkey_match, 266 .init = expkey_init, 267 .update = expkey_update, 268 .alloc = expkey_alloc, 269 }; 270 271 static struct svc_expkey * 272 svc_expkey_lookup(struct svc_expkey *item) 273 { 274 struct cache_head *ch; 275 int hash = item->ek_fsidtype; 276 char * cp = (char*)item->ek_fsid; 277 int len = key_len(item->ek_fsidtype); 278 279 hash ^= hash_mem(cp, len, EXPKEY_HASHBITS); 280 hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS); 281 hash &= EXPKEY_HASHMASK; 282 283 ch = sunrpc_cache_lookup(&svc_expkey_cache, &item->h, 284 hash); 285 if (ch) 286 return container_of(ch, struct svc_expkey, h); 287 else 288 return NULL; 289 } 290 291 static struct svc_expkey * 292 svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old) 293 { 294 struct cache_head *ch; 295 int hash = new->ek_fsidtype; 296 char * cp = (char*)new->ek_fsid; 297 int len = key_len(new->ek_fsidtype); 298 299 hash ^= hash_mem(cp, len, EXPKEY_HASHBITS); 300 hash ^= hash_ptr(new->ek_client, EXPKEY_HASHBITS); 301 hash &= EXPKEY_HASHMASK; 302 303 ch = sunrpc_cache_update(&svc_expkey_cache, &new->h, 304 &old->h, hash); 305 if (ch) 306 return container_of(ch, struct svc_expkey, h); 307 else 308 return NULL; 309 } 310 311 312 #define EXPORT_HASHBITS 8 313 #define EXPORT_HASHMAX (1<< EXPORT_HASHBITS) 314 #define EXPORT_HASHMASK (EXPORT_HASHMAX -1) 315 316 static struct cache_head *export_table[EXPORT_HASHMAX]; 317 318 static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc) 319 { 320 int i; 321 322 for (i = 0; i < fsloc->locations_count; i++) { 323 kfree(fsloc->locations[i].path); 324 kfree(fsloc->locations[i].hosts); 325 } 326 kfree(fsloc->locations); 327 } 328 329 static void svc_export_put(struct kref *ref) 330 { 331 struct svc_export *exp = container_of(ref, struct svc_export, h.ref); 332 dput(exp->ex_dentry); 333 mntput(exp->ex_mnt); 334 auth_domain_put(exp->ex_client); 335 kfree(exp->ex_path); 336 nfsd4_fslocs_free(&exp->ex_fslocs); 337 kfree(exp); 338 } 339 340 static void svc_export_request(struct cache_detail *cd, 341 struct cache_head *h, 342 char **bpp, int *blen) 343 { 344 /* client path */ 345 struct svc_export *exp = container_of(h, struct svc_export, h); 346 char *pth; 347 348 qword_add(bpp, blen, exp->ex_client->name); 349 pth = d_path(exp->ex_dentry, exp->ex_mnt, *bpp, *blen); 350 if (IS_ERR(pth)) { 351 /* is this correct? */ 352 (*bpp)[0] = '\n'; 353 return; 354 } 355 qword_add(bpp, blen, pth); 356 (*bpp)[-1] = '\n'; 357 } 358 359 static struct svc_export *svc_export_update(struct svc_export *new, 360 struct svc_export *old); 361 static struct svc_export *svc_export_lookup(struct svc_export *); 362 363 static int check_export(struct inode *inode, int flags, unsigned char *uuid) 364 { 365 366 /* We currently export only dirs and regular files. 367 * This is what umountd does. 368 */ 369 if (!S_ISDIR(inode->i_mode) && 370 !S_ISREG(inode->i_mode)) 371 return -ENOTDIR; 372 373 /* There are two requirements on a filesystem to be exportable. 374 * 1: We must be able to identify the filesystem from a number. 375 * either a device number (so FS_REQUIRES_DEV needed) 376 * or an FSID number (so NFSEXP_FSID or ->uuid is needed). 377 * 2: We must be able to find an inode from a filehandle. 378 * This means that s_export_op must be set. 379 */ 380 if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) && 381 !(flags & NFSEXP_FSID) && 382 uuid == NULL) { 383 dprintk("exp_export: export of non-dev fs without fsid\n"); 384 return -EINVAL; 385 } 386 if (!inode->i_sb->s_export_op) { 387 dprintk("exp_export: export of invalid fs type.\n"); 388 return -EINVAL; 389 } 390 391 /* Ok, we can export it */; 392 if (!inode->i_sb->s_export_op->find_exported_dentry) 393 inode->i_sb->s_export_op->find_exported_dentry = 394 find_exported_dentry; 395 return 0; 396 397 } 398 399 #ifdef CONFIG_NFSD_V4 400 401 static int 402 fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) 403 { 404 int len; 405 int migrated, i, err; 406 407 /* listsize */ 408 err = get_int(mesg, &fsloc->locations_count); 409 if (err) 410 return err; 411 if (fsloc->locations_count > MAX_FS_LOCATIONS) 412 return -EINVAL; 413 if (fsloc->locations_count == 0) 414 return 0; 415 416 fsloc->locations = kzalloc(fsloc->locations_count 417 * sizeof(struct nfsd4_fs_location), GFP_KERNEL); 418 if (!fsloc->locations) 419 return -ENOMEM; 420 for (i=0; i < fsloc->locations_count; i++) { 421 /* colon separated host list */ 422 err = -EINVAL; 423 len = qword_get(mesg, buf, PAGE_SIZE); 424 if (len <= 0) 425 goto out_free_all; 426 err = -ENOMEM; 427 fsloc->locations[i].hosts = kstrdup(buf, GFP_KERNEL); 428 if (!fsloc->locations[i].hosts) 429 goto out_free_all; 430 err = -EINVAL; 431 /* slash separated path component list */ 432 len = qword_get(mesg, buf, PAGE_SIZE); 433 if (len <= 0) 434 goto out_free_all; 435 err = -ENOMEM; 436 fsloc->locations[i].path = kstrdup(buf, GFP_KERNEL); 437 if (!fsloc->locations[i].path) 438 goto out_free_all; 439 } 440 /* migrated */ 441 err = get_int(mesg, &migrated); 442 if (err) 443 goto out_free_all; 444 err = -EINVAL; 445 if (migrated < 0 || migrated > 1) 446 goto out_free_all; 447 fsloc->migrated = migrated; 448 return 0; 449 out_free_all: 450 nfsd4_fslocs_free(fsloc); 451 return err; 452 } 453 454 #else /* CONFIG_NFSD_V4 */ 455 static inline int fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) { return 0; } 456 #endif 457 458 static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) 459 { 460 /* client path expiry [flags anonuid anongid fsid] */ 461 char *buf; 462 int len; 463 int err; 464 struct auth_domain *dom = NULL; 465 struct nameidata nd; 466 struct svc_export exp, *expp; 467 int an_int; 468 469 nd.dentry = NULL; 470 exp.ex_path = NULL; 471 472 /* fs locations */ 473 exp.ex_fslocs.locations = NULL; 474 exp.ex_fslocs.locations_count = 0; 475 exp.ex_fslocs.migrated = 0; 476 477 exp.ex_uuid = NULL; 478 479 if (mesg[mlen-1] != '\n') 480 return -EINVAL; 481 mesg[mlen-1] = 0; 482 483 buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 484 err = -ENOMEM; 485 if (!buf) goto out; 486 487 /* client */ 488 len = qword_get(&mesg, buf, PAGE_SIZE); 489 err = -EINVAL; 490 if (len <= 0) goto out; 491 492 err = -ENOENT; 493 dom = auth_domain_find(buf); 494 if (!dom) 495 goto out; 496 497 /* path */ 498 err = -EINVAL; 499 if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) 500 goto out; 501 err = path_lookup(buf, 0, &nd); 502 if (err) goto out_no_path; 503 504 exp.h.flags = 0; 505 exp.ex_client = dom; 506 exp.ex_mnt = nd.mnt; 507 exp.ex_dentry = nd.dentry; 508 exp.ex_path = kstrdup(buf, GFP_KERNEL); 509 err = -ENOMEM; 510 if (!exp.ex_path) 511 goto out; 512 513 /* expiry */ 514 err = -EINVAL; 515 exp.h.expiry_time = get_expiry(&mesg); 516 if (exp.h.expiry_time == 0) 517 goto out; 518 519 /* flags */ 520 err = get_int(&mesg, &an_int); 521 if (err == -ENOENT) 522 set_bit(CACHE_NEGATIVE, &exp.h.flags); 523 else { 524 if (err || an_int < 0) goto out; 525 exp.ex_flags= an_int; 526 527 /* anon uid */ 528 err = get_int(&mesg, &an_int); 529 if (err) goto out; 530 exp.ex_anon_uid= an_int; 531 532 /* anon gid */ 533 err = get_int(&mesg, &an_int); 534 if (err) goto out; 535 exp.ex_anon_gid= an_int; 536 537 /* fsid */ 538 err = get_int(&mesg, &an_int); 539 if (err) goto out; 540 exp.ex_fsid = an_int; 541 542 while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) { 543 if (strcmp(buf, "fsloc") == 0) 544 err = fsloc_parse(&mesg, buf, &exp.ex_fslocs); 545 else if (strcmp(buf, "uuid") == 0) { 546 /* expect a 16 byte uuid encoded as \xXXXX... */ 547 len = qword_get(&mesg, buf, PAGE_SIZE); 548 if (len != 16) 549 err = -EINVAL; 550 else { 551 exp.ex_uuid = 552 kmemdup(buf, 16, GFP_KERNEL); 553 if (exp.ex_uuid == NULL) 554 err = -ENOMEM; 555 } 556 } else 557 /* quietly ignore unknown words and anything 558 * following. Newer user-space can try to set 559 * new values, then see what the result was. 560 */ 561 break; 562 if (err) 563 goto out; 564 } 565 566 err = check_export(nd.dentry->d_inode, exp.ex_flags, 567 exp.ex_uuid); 568 if (err) goto out; 569 } 570 571 expp = svc_export_lookup(&exp); 572 if (expp) 573 expp = svc_export_update(&exp, expp); 574 else 575 err = -ENOMEM; 576 cache_flush(); 577 if (expp == NULL) 578 err = -ENOMEM; 579 else 580 exp_put(expp); 581 out: 582 nfsd4_fslocs_free(&exp.ex_fslocs); 583 kfree(exp.ex_uuid); 584 kfree(exp.ex_path); 585 if (nd.dentry) 586 path_release(&nd); 587 out_no_path: 588 if (dom) 589 auth_domain_put(dom); 590 kfree(buf); 591 return err; 592 } 593 594 static void exp_flags(struct seq_file *m, int flag, int fsid, 595 uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs); 596 597 static int svc_export_show(struct seq_file *m, 598 struct cache_detail *cd, 599 struct cache_head *h) 600 { 601 struct svc_export *exp ; 602 603 if (h ==NULL) { 604 seq_puts(m, "#path domain(flags)\n"); 605 return 0; 606 } 607 exp = container_of(h, struct svc_export, h); 608 seq_path(m, exp->ex_mnt, exp->ex_dentry, " \t\n\\"); 609 seq_putc(m, '\t'); 610 seq_escape(m, exp->ex_client->name, " \t\n\\"); 611 seq_putc(m, '('); 612 if (test_bit(CACHE_VALID, &h->flags) && 613 !test_bit(CACHE_NEGATIVE, &h->flags)) { 614 exp_flags(m, exp->ex_flags, exp->ex_fsid, 615 exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs); 616 if (exp->ex_uuid) { 617 int i; 618 seq_puts(m, ",uuid="); 619 for (i=0; i<16; i++) { 620 if ((i&3) == 0 && i) 621 seq_putc(m, ':'); 622 seq_printf(m, "%02x", exp->ex_uuid[i]); 623 } 624 } 625 } 626 seq_puts(m, ")\n"); 627 return 0; 628 } 629 static int svc_export_match(struct cache_head *a, struct cache_head *b) 630 { 631 struct svc_export *orig = container_of(a, struct svc_export, h); 632 struct svc_export *new = container_of(b, struct svc_export, h); 633 return orig->ex_client == new->ex_client && 634 orig->ex_dentry == new->ex_dentry && 635 orig->ex_mnt == new->ex_mnt; 636 } 637 638 static void svc_export_init(struct cache_head *cnew, struct cache_head *citem) 639 { 640 struct svc_export *new = container_of(cnew, struct svc_export, h); 641 struct svc_export *item = container_of(citem, struct svc_export, h); 642 643 kref_get(&item->ex_client->ref); 644 new->ex_client = item->ex_client; 645 new->ex_dentry = dget(item->ex_dentry); 646 new->ex_mnt = mntget(item->ex_mnt); 647 new->ex_path = NULL; 648 new->ex_fslocs.locations = NULL; 649 new->ex_fslocs.locations_count = 0; 650 new->ex_fslocs.migrated = 0; 651 } 652 653 static void export_update(struct cache_head *cnew, struct cache_head *citem) 654 { 655 struct svc_export *new = container_of(cnew, struct svc_export, h); 656 struct svc_export *item = container_of(citem, struct svc_export, h); 657 658 new->ex_flags = item->ex_flags; 659 new->ex_anon_uid = item->ex_anon_uid; 660 new->ex_anon_gid = item->ex_anon_gid; 661 new->ex_fsid = item->ex_fsid; 662 new->ex_uuid = item->ex_uuid; 663 item->ex_uuid = NULL; 664 new->ex_path = item->ex_path; 665 item->ex_path = NULL; 666 new->ex_fslocs.locations = item->ex_fslocs.locations; 667 item->ex_fslocs.locations = NULL; 668 new->ex_fslocs.locations_count = item->ex_fslocs.locations_count; 669 item->ex_fslocs.locations_count = 0; 670 new->ex_fslocs.migrated = item->ex_fslocs.migrated; 671 item->ex_fslocs.migrated = 0; 672 } 673 674 static struct cache_head *svc_export_alloc(void) 675 { 676 struct svc_export *i = kmalloc(sizeof(*i), GFP_KERNEL); 677 if (i) 678 return &i->h; 679 else 680 return NULL; 681 } 682 683 struct cache_detail svc_export_cache = { 684 .owner = THIS_MODULE, 685 .hash_size = EXPORT_HASHMAX, 686 .hash_table = export_table, 687 .name = "nfsd.export", 688 .cache_put = svc_export_put, 689 .cache_request = svc_export_request, 690 .cache_parse = svc_export_parse, 691 .cache_show = svc_export_show, 692 .match = svc_export_match, 693 .init = svc_export_init, 694 .update = export_update, 695 .alloc = svc_export_alloc, 696 }; 697 698 static struct svc_export * 699 svc_export_lookup(struct svc_export *exp) 700 { 701 struct cache_head *ch; 702 int hash; 703 hash = hash_ptr(exp->ex_client, EXPORT_HASHBITS); 704 hash ^= hash_ptr(exp->ex_dentry, EXPORT_HASHBITS); 705 hash ^= hash_ptr(exp->ex_mnt, EXPORT_HASHBITS); 706 707 ch = sunrpc_cache_lookup(&svc_export_cache, &exp->h, 708 hash); 709 if (ch) 710 return container_of(ch, struct svc_export, h); 711 else 712 return NULL; 713 } 714 715 static struct svc_export * 716 svc_export_update(struct svc_export *new, struct svc_export *old) 717 { 718 struct cache_head *ch; 719 int hash; 720 hash = hash_ptr(old->ex_client, EXPORT_HASHBITS); 721 hash ^= hash_ptr(old->ex_dentry, EXPORT_HASHBITS); 722 hash ^= hash_ptr(old->ex_mnt, EXPORT_HASHBITS); 723 724 ch = sunrpc_cache_update(&svc_export_cache, &new->h, 725 &old->h, 726 hash); 727 if (ch) 728 return container_of(ch, struct svc_export, h); 729 else 730 return NULL; 731 } 732 733 734 static struct svc_expkey * 735 exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) 736 { 737 struct svc_expkey key, *ek; 738 int err; 739 740 if (!clp) 741 return NULL; 742 743 key.ek_client = clp; 744 key.ek_fsidtype = fsid_type; 745 memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); 746 747 ek = svc_expkey_lookup(&key); 748 if (ek != NULL) 749 if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp))) 750 ek = ERR_PTR(err); 751 return ek; 752 } 753 754 static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv, 755 struct svc_export *exp) 756 { 757 struct svc_expkey key, *ek; 758 759 key.ek_client = clp; 760 key.ek_fsidtype = fsid_type; 761 memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); 762 key.ek_mnt = exp->ex_mnt; 763 key.ek_dentry = exp->ex_dentry; 764 key.h.expiry_time = NEVER; 765 key.h.flags = 0; 766 767 ek = svc_expkey_lookup(&key); 768 if (ek) 769 ek = svc_expkey_update(&key,ek); 770 if (ek) { 771 cache_put(&ek->h, &svc_expkey_cache); 772 return 0; 773 } 774 return -ENOMEM; 775 } 776 777 /* 778 * Find the client's export entry matching xdev/xino. 779 */ 780 static inline struct svc_expkey * 781 exp_get_key(svc_client *clp, dev_t dev, ino_t ino) 782 { 783 u32 fsidv[3]; 784 785 if (old_valid_dev(dev)) { 786 mk_fsid(FSID_DEV, fsidv, dev, ino, 0, NULL); 787 return exp_find_key(clp, FSID_DEV, fsidv, NULL); 788 } 789 mk_fsid(FSID_ENCODE_DEV, fsidv, dev, ino, 0, NULL); 790 return exp_find_key(clp, FSID_ENCODE_DEV, fsidv, NULL); 791 } 792 793 /* 794 * Find the client's export entry matching fsid 795 */ 796 static inline struct svc_expkey * 797 exp_get_fsid_key(svc_client *clp, int fsid) 798 { 799 u32 fsidv[2]; 800 801 mk_fsid(FSID_NUM, fsidv, 0, 0, fsid, NULL); 802 803 return exp_find_key(clp, FSID_NUM, fsidv, NULL); 804 } 805 806 svc_export * 807 exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry, 808 struct cache_req *reqp) 809 { 810 struct svc_export *exp, key; 811 812 if (!clp) 813 return NULL; 814 815 key.ex_client = clp; 816 key.ex_mnt = mnt; 817 key.ex_dentry = dentry; 818 819 exp = svc_export_lookup(&key); 820 if (exp != NULL) { 821 int err; 822 823 err = cache_check(&svc_export_cache, &exp->h, reqp); 824 switch (err) { 825 case 0: break; 826 case -EAGAIN: 827 case -ETIMEDOUT: 828 exp = ERR_PTR(err); 829 break; 830 default: 831 exp = NULL; 832 } 833 } 834 835 return exp; 836 } 837 838 /* 839 * Find the export entry for a given dentry. 840 */ 841 struct svc_export * 842 exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry, 843 struct cache_req *reqp) 844 { 845 svc_export *exp; 846 847 dget(dentry); 848 exp = exp_get_by_name(clp, mnt, dentry, reqp); 849 850 while (exp == NULL && !IS_ROOT(dentry)) { 851 struct dentry *parent; 852 853 parent = dget_parent(dentry); 854 dput(dentry); 855 dentry = parent; 856 exp = exp_get_by_name(clp, mnt, dentry, reqp); 857 } 858 dput(dentry); 859 return exp; 860 } 861 862 /* 863 * Hashtable locking. Write locks are placed only by user processes 864 * wanting to modify export information. 865 * Write locking only done in this file. Read locking 866 * needed externally. 867 */ 868 869 static DECLARE_RWSEM(hash_sem); 870 871 void 872 exp_readlock(void) 873 { 874 down_read(&hash_sem); 875 } 876 877 static inline void 878 exp_writelock(void) 879 { 880 down_write(&hash_sem); 881 } 882 883 void 884 exp_readunlock(void) 885 { 886 up_read(&hash_sem); 887 } 888 889 static inline void 890 exp_writeunlock(void) 891 { 892 up_write(&hash_sem); 893 } 894 895 static void exp_fsid_unhash(struct svc_export *exp) 896 { 897 struct svc_expkey *ek; 898 899 if ((exp->ex_flags & NFSEXP_FSID) == 0) 900 return; 901 902 ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid); 903 if (ek && !IS_ERR(ek)) { 904 ek->h.expiry_time = get_seconds()-1; 905 cache_put(&ek->h, &svc_expkey_cache); 906 } 907 svc_expkey_cache.nextcheck = get_seconds(); 908 } 909 910 static int exp_fsid_hash(svc_client *clp, struct svc_export *exp) 911 { 912 u32 fsid[2]; 913 914 if ((exp->ex_flags & NFSEXP_FSID) == 0) 915 return 0; 916 917 mk_fsid(FSID_NUM, fsid, 0, 0, exp->ex_fsid, NULL); 918 return exp_set_key(clp, FSID_NUM, fsid, exp); 919 } 920 921 static int exp_hash(struct auth_domain *clp, struct svc_export *exp) 922 { 923 u32 fsid[2]; 924 struct inode *inode = exp->ex_dentry->d_inode; 925 dev_t dev = inode->i_sb->s_dev; 926 927 if (old_valid_dev(dev)) { 928 mk_fsid(FSID_DEV, fsid, dev, inode->i_ino, 0, NULL); 929 return exp_set_key(clp, FSID_DEV, fsid, exp); 930 } 931 mk_fsid(FSID_ENCODE_DEV, fsid, dev, inode->i_ino, 0, NULL); 932 return exp_set_key(clp, FSID_ENCODE_DEV, fsid, exp); 933 } 934 935 static void exp_unhash(struct svc_export *exp) 936 { 937 struct svc_expkey *ek; 938 struct inode *inode = exp->ex_dentry->d_inode; 939 940 ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino); 941 if (ek && !IS_ERR(ek)) { 942 ek->h.expiry_time = get_seconds()-1; 943 cache_put(&ek->h, &svc_expkey_cache); 944 } 945 svc_expkey_cache.nextcheck = get_seconds(); 946 } 947 948 /* 949 * Export a file system. 950 */ 951 int 952 exp_export(struct nfsctl_export *nxp) 953 { 954 svc_client *clp; 955 struct svc_export *exp = NULL; 956 struct svc_export new; 957 struct svc_expkey *fsid_key = NULL; 958 struct nameidata nd; 959 int err; 960 961 /* Consistency check */ 962 err = -EINVAL; 963 if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) || 964 !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX)) 965 goto out; 966 967 dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n", 968 nxp->ex_client, nxp->ex_path, 969 (unsigned)nxp->ex_dev, (long)nxp->ex_ino, 970 nxp->ex_flags); 971 972 /* Try to lock the export table for update */ 973 exp_writelock(); 974 975 /* Look up client info */ 976 if (!(clp = auth_domain_find(nxp->ex_client))) 977 goto out_unlock; 978 979 980 /* Look up the dentry */ 981 err = path_lookup(nxp->ex_path, 0, &nd); 982 if (err) 983 goto out_unlock; 984 err = -EINVAL; 985 986 exp = exp_get_by_name(clp, nd.mnt, nd.dentry, NULL); 987 988 memset(&new, 0, sizeof(new)); 989 990 /* must make sure there won't be an ex_fsid clash */ 991 if ((nxp->ex_flags & NFSEXP_FSID) && 992 (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) && 993 !IS_ERR(fsid_key) && 994 fsid_key->ek_mnt && 995 (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) ) 996 goto finish; 997 998 if (exp) { 999 /* just a flags/id/fsid update */ 1000 1001 exp_fsid_unhash(exp); 1002 exp->ex_flags = nxp->ex_flags; 1003 exp->ex_anon_uid = nxp->ex_anon_uid; 1004 exp->ex_anon_gid = nxp->ex_anon_gid; 1005 exp->ex_fsid = nxp->ex_dev; 1006 1007 err = exp_fsid_hash(clp, exp); 1008 goto finish; 1009 } 1010 1011 err = check_export(nd.dentry->d_inode, nxp->ex_flags, NULL); 1012 if (err) goto finish; 1013 1014 err = -ENOMEM; 1015 1016 dprintk("nfsd: creating export entry %p for client %p\n", exp, clp); 1017 1018 new.h.expiry_time = NEVER; 1019 new.h.flags = 0; 1020 new.ex_path = kstrdup(nxp->ex_path, GFP_KERNEL); 1021 if (!new.ex_path) 1022 goto finish; 1023 new.ex_client = clp; 1024 new.ex_mnt = nd.mnt; 1025 new.ex_dentry = nd.dentry; 1026 new.ex_flags = nxp->ex_flags; 1027 new.ex_anon_uid = nxp->ex_anon_uid; 1028 new.ex_anon_gid = nxp->ex_anon_gid; 1029 new.ex_fsid = nxp->ex_dev; 1030 1031 exp = svc_export_lookup(&new); 1032 if (exp) 1033 exp = svc_export_update(&new, exp); 1034 1035 if (!exp) 1036 goto finish; 1037 1038 if (exp_hash(clp, exp) || 1039 exp_fsid_hash(clp, exp)) { 1040 /* failed to create at least one index */ 1041 exp_do_unexport(exp); 1042 cache_flush(); 1043 } else 1044 err = 0; 1045 finish: 1046 if (new.ex_path) 1047 kfree(new.ex_path); 1048 if (exp) 1049 exp_put(exp); 1050 if (fsid_key && !IS_ERR(fsid_key)) 1051 cache_put(&fsid_key->h, &svc_expkey_cache); 1052 if (clp) 1053 auth_domain_put(clp); 1054 path_release(&nd); 1055 out_unlock: 1056 exp_writeunlock(); 1057 out: 1058 return err; 1059 } 1060 1061 /* 1062 * Unexport a file system. The export entry has already 1063 * been removed from the client's list of exported fs's. 1064 */ 1065 static void 1066 exp_do_unexport(svc_export *unexp) 1067 { 1068 unexp->h.expiry_time = get_seconds()-1; 1069 svc_export_cache.nextcheck = get_seconds(); 1070 exp_unhash(unexp); 1071 exp_fsid_unhash(unexp); 1072 } 1073 1074 1075 /* 1076 * unexport syscall. 1077 */ 1078 int 1079 exp_unexport(struct nfsctl_export *nxp) 1080 { 1081 struct auth_domain *dom; 1082 svc_export *exp; 1083 struct nameidata nd; 1084 int err; 1085 1086 /* Consistency check */ 1087 if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) || 1088 !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX)) 1089 return -EINVAL; 1090 1091 exp_writelock(); 1092 1093 err = -EINVAL; 1094 dom = auth_domain_find(nxp->ex_client); 1095 if (!dom) { 1096 dprintk("nfsd: unexport couldn't find %s\n", nxp->ex_client); 1097 goto out_unlock; 1098 } 1099 1100 err = path_lookup(nxp->ex_path, 0, &nd); 1101 if (err) 1102 goto out_domain; 1103 1104 err = -EINVAL; 1105 exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL); 1106 path_release(&nd); 1107 if (!exp) 1108 goto out_domain; 1109 1110 exp_do_unexport(exp); 1111 exp_put(exp); 1112 err = 0; 1113 1114 out_domain: 1115 auth_domain_put(dom); 1116 cache_flush(); 1117 out_unlock: 1118 exp_writeunlock(); 1119 return err; 1120 } 1121 1122 /* 1123 * Obtain the root fh on behalf of a client. 1124 * This could be done in user space, but I feel that it adds some safety 1125 * since its harder to fool a kernel module than a user space program. 1126 */ 1127 int 1128 exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize) 1129 { 1130 struct svc_export *exp; 1131 struct nameidata nd; 1132 struct inode *inode; 1133 struct svc_fh fh; 1134 int err; 1135 1136 err = -EPERM; 1137 /* NB: we probably ought to check that it's NUL-terminated */ 1138 if (path_lookup(path, 0, &nd)) { 1139 printk("nfsd: exp_rootfh path not found %s", path); 1140 return err; 1141 } 1142 inode = nd.dentry->d_inode; 1143 1144 dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n", 1145 path, nd.dentry, clp->name, 1146 inode->i_sb->s_id, inode->i_ino); 1147 exp = exp_parent(clp, nd.mnt, nd.dentry, NULL); 1148 if (IS_ERR(exp)) { 1149 err = PTR_ERR(exp); 1150 goto out; 1151 } 1152 if (!exp) { 1153 dprintk("nfsd: exp_rootfh export not found.\n"); 1154 goto out; 1155 } 1156 1157 /* 1158 * fh must be initialized before calling fh_compose 1159 */ 1160 fh_init(&fh, maxsize); 1161 if (fh_compose(&fh, exp, nd.dentry, NULL)) 1162 err = -EINVAL; 1163 else 1164 err = 0; 1165 memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh)); 1166 fh_put(&fh); 1167 exp_put(exp); 1168 out: 1169 path_release(&nd); 1170 return err; 1171 } 1172 1173 struct svc_export * 1174 exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, 1175 struct cache_req *reqp) 1176 { 1177 struct svc_export *exp; 1178 struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp); 1179 if (!ek || IS_ERR(ek)) 1180 return ERR_PTR(PTR_ERR(ek)); 1181 1182 exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp); 1183 cache_put(&ek->h, &svc_expkey_cache); 1184 1185 if (!exp || IS_ERR(exp)) 1186 return ERR_PTR(PTR_ERR(exp)); 1187 return exp; 1188 } 1189 1190 1191 /* 1192 * Called when we need the filehandle for the root of the pseudofs, 1193 * for a given NFSv4 client. The root is defined to be the 1194 * export point with fsid==0 1195 */ 1196 __be32 1197 exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, 1198 struct cache_req *creq) 1199 { 1200 struct svc_export *exp; 1201 __be32 rv; 1202 u32 fsidv[2]; 1203 1204 mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL); 1205 1206 exp = exp_find(clp, FSID_NUM, fsidv, creq); 1207 if (IS_ERR(exp)) 1208 return nfserrno(PTR_ERR(exp)); 1209 if (exp == NULL) 1210 return nfserr_perm; 1211 rv = fh_compose(fhp, exp, exp->ex_dentry, NULL); 1212 exp_put(exp); 1213 return rv; 1214 } 1215 1216 /* Iterator */ 1217 1218 static void *e_start(struct seq_file *m, loff_t *pos) 1219 __acquires(svc_export_cache.hash_lock) 1220 { 1221 loff_t n = *pos; 1222 unsigned hash, export; 1223 struct cache_head *ch; 1224 1225 exp_readlock(); 1226 read_lock(&svc_export_cache.hash_lock); 1227 if (!n--) 1228 return SEQ_START_TOKEN; 1229 hash = n >> 32; 1230 export = n & ((1LL<<32) - 1); 1231 1232 1233 for (ch=export_table[hash]; ch; ch=ch->next) 1234 if (!export--) 1235 return ch; 1236 n &= ~((1LL<<32) - 1); 1237 do { 1238 hash++; 1239 n += 1LL<<32; 1240 } while(hash < EXPORT_HASHMAX && export_table[hash]==NULL); 1241 if (hash >= EXPORT_HASHMAX) 1242 return NULL; 1243 *pos = n+1; 1244 return export_table[hash]; 1245 } 1246 1247 static void *e_next(struct seq_file *m, void *p, loff_t *pos) 1248 { 1249 struct cache_head *ch = p; 1250 int hash = (*pos >> 32); 1251 1252 if (p == SEQ_START_TOKEN) 1253 hash = 0; 1254 else if (ch->next == NULL) { 1255 hash++; 1256 *pos += 1LL<<32; 1257 } else { 1258 ++*pos; 1259 return ch->next; 1260 } 1261 *pos &= ~((1LL<<32) - 1); 1262 while (hash < EXPORT_HASHMAX && export_table[hash] == NULL) { 1263 hash++; 1264 *pos += 1LL<<32; 1265 } 1266 if (hash >= EXPORT_HASHMAX) 1267 return NULL; 1268 ++*pos; 1269 return export_table[hash]; 1270 } 1271 1272 static void e_stop(struct seq_file *m, void *p) 1273 __releases(svc_export_cache.hash_lock) 1274 { 1275 read_unlock(&svc_export_cache.hash_lock); 1276 exp_readunlock(); 1277 } 1278 1279 static struct flags { 1280 int flag; 1281 char *name[2]; 1282 } expflags[] = { 1283 { NFSEXP_READONLY, {"ro", "rw"}}, 1284 { NFSEXP_INSECURE_PORT, {"insecure", ""}}, 1285 { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}}, 1286 { NFSEXP_ALLSQUASH, {"all_squash", ""}}, 1287 { NFSEXP_ASYNC, {"async", "sync"}}, 1288 { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}}, 1289 { NFSEXP_NOHIDE, {"nohide", ""}}, 1290 { NFSEXP_CROSSMOUNT, {"crossmnt", ""}}, 1291 { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}}, 1292 { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}}, 1293 #ifdef MSNFS 1294 { NFSEXP_MSNFS, {"msnfs", ""}}, 1295 #endif 1296 { 0, {"", ""}} 1297 }; 1298 1299 static void exp_flags(struct seq_file *m, int flag, int fsid, 1300 uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc) 1301 { 1302 int first = 0; 1303 struct flags *flg; 1304 1305 for (flg = expflags; flg->flag; flg++) { 1306 int state = (flg->flag & flag)?0:1; 1307 if (*flg->name[state]) 1308 seq_printf(m, "%s%s", first++?",":"", flg->name[state]); 1309 } 1310 if (flag & NFSEXP_FSID) 1311 seq_printf(m, "%sfsid=%d", first++?",":"", fsid); 1312 if (anonu != (uid_t)-2 && anonu != (0x10000-2)) 1313 seq_printf(m, "%sanonuid=%d", first++?",":"", anonu); 1314 if (anong != (gid_t)-2 && anong != (0x10000-2)) 1315 seq_printf(m, "%sanongid=%d", first++?",":"", anong); 1316 if (fsloc && fsloc->locations_count > 0) { 1317 char *loctype = (fsloc->migrated) ? "refer" : "replicas"; 1318 int i; 1319 1320 seq_printf(m, "%s%s=", first++?",":"", loctype); 1321 seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\"); 1322 seq_putc(m, '@'); 1323 seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\"); 1324 for (i = 1; i < fsloc->locations_count; i++) { 1325 seq_putc(m, ';'); 1326 seq_escape(m, fsloc->locations[i].path, ",;@ \t\n\\"); 1327 seq_putc(m, '@'); 1328 seq_escape(m, fsloc->locations[i].hosts, ",;@ \t\n\\"); 1329 } 1330 } 1331 } 1332 1333 static int e_show(struct seq_file *m, void *p) 1334 { 1335 struct cache_head *cp = p; 1336 struct svc_export *exp = container_of(cp, struct svc_export, h); 1337 1338 if (p == SEQ_START_TOKEN) { 1339 seq_puts(m, "# Version 1.1\n"); 1340 seq_puts(m, "# Path Client(Flags) # IPs\n"); 1341 return 0; 1342 } 1343 1344 cache_get(&exp->h); 1345 if (cache_check(&svc_export_cache, &exp->h, NULL)) 1346 return 0; 1347 cache_put(&exp->h, &svc_export_cache); 1348 return svc_export_show(m, &svc_export_cache, cp); 1349 } 1350 1351 struct seq_operations nfs_exports_op = { 1352 .start = e_start, 1353 .next = e_next, 1354 .stop = e_stop, 1355 .show = e_show, 1356 }; 1357 1358 /* 1359 * Add or modify a client. 1360 * Change requests may involve the list of host addresses. The list of 1361 * exports and possibly existing uid maps are left untouched. 1362 */ 1363 int 1364 exp_addclient(struct nfsctl_client *ncp) 1365 { 1366 struct auth_domain *dom; 1367 int i, err; 1368 1369 /* First, consistency check. */ 1370 err = -EINVAL; 1371 if (! exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX)) 1372 goto out; 1373 if (ncp->cl_naddr > NFSCLNT_ADDRMAX) 1374 goto out; 1375 1376 /* Lock the hashtable */ 1377 exp_writelock(); 1378 1379 dom = unix_domain_find(ncp->cl_ident); 1380 1381 err = -ENOMEM; 1382 if (!dom) 1383 goto out_unlock; 1384 1385 /* Insert client into hashtable. */ 1386 for (i = 0; i < ncp->cl_naddr; i++) 1387 auth_unix_add_addr(ncp->cl_addrlist[i], dom); 1388 1389 auth_unix_forget_old(dom); 1390 auth_domain_put(dom); 1391 1392 err = 0; 1393 1394 out_unlock: 1395 exp_writeunlock(); 1396 out: 1397 return err; 1398 } 1399 1400 /* 1401 * Delete a client given an identifier. 1402 */ 1403 int 1404 exp_delclient(struct nfsctl_client *ncp) 1405 { 1406 int err; 1407 struct auth_domain *dom; 1408 1409 err = -EINVAL; 1410 if (!exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX)) 1411 goto out; 1412 1413 /* Lock the hashtable */ 1414 exp_writelock(); 1415 1416 dom = auth_domain_find(ncp->cl_ident); 1417 /* just make sure that no addresses work 1418 * and that it will expire soon 1419 */ 1420 if (dom) { 1421 err = auth_unix_forget_old(dom); 1422 auth_domain_put(dom); 1423 } 1424 1425 exp_writeunlock(); 1426 out: 1427 return err; 1428 } 1429 1430 /* 1431 * Verify that string is non-empty and does not exceed max length. 1432 */ 1433 static int 1434 exp_verify_string(char *cp, int max) 1435 { 1436 int i; 1437 1438 for (i = 0; i < max; i++) 1439 if (!cp[i]) 1440 return i; 1441 cp[i] = 0; 1442 printk(KERN_NOTICE "nfsd: couldn't validate string %s\n", cp); 1443 return 0; 1444 } 1445 1446 /* 1447 * Initialize the exports module. 1448 */ 1449 void 1450 nfsd_export_init(void) 1451 { 1452 dprintk("nfsd: initializing export module.\n"); 1453 1454 cache_register(&svc_export_cache); 1455 cache_register(&svc_expkey_cache); 1456 1457 } 1458 1459 /* 1460 * Flush exports table - called when last nfsd thread is killed 1461 */ 1462 void 1463 nfsd_export_flush(void) 1464 { 1465 exp_writelock(); 1466 cache_purge(&svc_expkey_cache); 1467 cache_purge(&svc_export_cache); 1468 exp_writeunlock(); 1469 } 1470 1471 /* 1472 * Shutdown the exports module. 1473 */ 1474 void 1475 nfsd_export_shutdown(void) 1476 { 1477 1478 dprintk("nfsd: shutting down export module.\n"); 1479 1480 exp_writelock(); 1481 1482 if (cache_unregister(&svc_expkey_cache)) 1483 printk(KERN_ERR "nfsd: failed to unregister expkey cache\n"); 1484 if (cache_unregister(&svc_export_cache)) 1485 printk(KERN_ERR "nfsd: failed to unregister export cache\n"); 1486 svcauth_unix_purge(); 1487 1488 exp_writeunlock(); 1489 dprintk("nfsd: export shutdown complete.\n"); 1490 } 1491