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