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/sched.h> 20 #include <linux/stat.h> 21 #include <linux/in.h> 22 #include <linux/seq_file.h> 23 #include <linux/syscalls.h> 24 #include <linux/rwsem.h> 25 #include <linux/dcache.h> 26 #include <linux/namei.h> 27 #include <linux/mount.h> 28 #include <linux/hash.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 #define NFSD_PARANOIA 1 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 inline int svc_expkey_hash(struct svc_expkey *item) 60 { 61 int hash = item->ek_fsidtype; 62 char * cp = (char*)item->ek_fsid; 63 int len = key_len(item->ek_fsidtype); 64 65 hash ^= hash_mem(cp, len, EXPKEY_HASHBITS); 66 hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS); 67 return hash & EXPKEY_HASHMASK; 68 } 69 70 void expkey_put(struct cache_head *item, struct cache_detail *cd) 71 { 72 if (cache_put(item, cd)) { 73 struct svc_expkey *key = container_of(item, struct svc_expkey, h); 74 if (test_bit(CACHE_VALID, &item->flags) && 75 !test_bit(CACHE_NEGATIVE, &item->flags)) 76 exp_put(key->ek_export); 77 auth_domain_put(key->ek_client); 78 kfree(key); 79 } 80 } 81 82 static void expkey_request(struct cache_detail *cd, 83 struct cache_head *h, 84 char **bpp, int *blen) 85 { 86 /* client fsidtype \xfsid */ 87 struct svc_expkey *ek = container_of(h, struct svc_expkey, h); 88 char type[5]; 89 90 qword_add(bpp, blen, ek->ek_client->name); 91 snprintf(type, 5, "%d", ek->ek_fsidtype); 92 qword_add(bpp, blen, type); 93 qword_addhex(bpp, blen, (char*)ek->ek_fsid, key_len(ek->ek_fsidtype)); 94 (*bpp)[-1] = '\n'; 95 } 96 97 static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *, int); 98 static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) 99 { 100 /* client fsidtype fsid [path] */ 101 char *buf; 102 int len; 103 struct auth_domain *dom = NULL; 104 int err; 105 int fsidtype; 106 char *ep; 107 struct svc_expkey key; 108 109 if (mesg[mlen-1] != '\n') 110 return -EINVAL; 111 mesg[mlen-1] = 0; 112 113 buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 114 err = -ENOMEM; 115 if (!buf) goto out; 116 117 err = -EINVAL; 118 if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) 119 goto out; 120 121 err = -ENOENT; 122 dom = auth_domain_find(buf); 123 if (!dom) 124 goto out; 125 dprintk("found domain %s\n", buf); 126 127 err = -EINVAL; 128 if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) 129 goto out; 130 fsidtype = simple_strtoul(buf, &ep, 10); 131 if (*ep) 132 goto out; 133 dprintk("found fsidtype %d\n", fsidtype); 134 if (fsidtype > 2) 135 goto out; 136 if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) 137 goto out; 138 dprintk("found fsid length %d\n", len); 139 if (len != key_len(fsidtype)) 140 goto out; 141 142 /* OK, we seem to have a valid key */ 143 key.h.flags = 0; 144 key.h.expiry_time = get_expiry(&mesg); 145 if (key.h.expiry_time == 0) 146 goto out; 147 148 key.ek_client = dom; 149 key.ek_fsidtype = fsidtype; 150 memcpy(key.ek_fsid, buf, len); 151 152 /* now we want a pathname, or empty meaning NEGATIVE */ 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 struct svc_expkey *ek; 159 set_bit(CACHE_NEGATIVE, &key.h.flags); 160 ek = svc_expkey_lookup(&key, 1); 161 if (ek) 162 expkey_put(&ek->h, &svc_expkey_cache); 163 } else { 164 struct nameidata nd; 165 struct svc_expkey *ek; 166 struct svc_export *exp; 167 err = path_lookup(buf, 0, &nd); 168 if (err) 169 goto out; 170 171 dprintk("Found the path %s\n", buf); 172 exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL); 173 174 err = -ENOENT; 175 if (!exp) 176 goto out_nd; 177 key.ek_export = exp; 178 dprintk("And found export\n"); 179 180 ek = svc_expkey_lookup(&key, 1); 181 if (ek) 182 expkey_put(&ek->h, &svc_expkey_cache); 183 exp_put(exp); 184 err = 0; 185 out_nd: 186 path_release(&nd); 187 } 188 cache_flush(); 189 out: 190 if (dom) 191 auth_domain_put(dom); 192 if (buf) 193 kfree(buf); 194 return err; 195 } 196 197 static int expkey_show(struct seq_file *m, 198 struct cache_detail *cd, 199 struct cache_head *h) 200 { 201 struct svc_expkey *ek ; 202 203 if (h ==NULL) { 204 seq_puts(m, "#domain fsidtype fsid [path]\n"); 205 return 0; 206 } 207 ek = container_of(h, struct svc_expkey, h); 208 seq_printf(m, "%s %d 0x%08x", ek->ek_client->name, 209 ek->ek_fsidtype, ek->ek_fsid[0]); 210 if (ek->ek_fsidtype != 1) 211 seq_printf(m, "%08x", ek->ek_fsid[1]); 212 if (ek->ek_fsidtype == 2) 213 seq_printf(m, "%08x", ek->ek_fsid[2]); 214 if (test_bit(CACHE_VALID, &h->flags) && 215 !test_bit(CACHE_NEGATIVE, &h->flags)) { 216 seq_printf(m, " "); 217 seq_path(m, ek->ek_export->ex_mnt, ek->ek_export->ex_dentry, "\\ \t\n"); 218 } 219 seq_printf(m, "\n"); 220 return 0; 221 } 222 223 struct cache_detail svc_expkey_cache = { 224 .hash_size = EXPKEY_HASHMAX, 225 .hash_table = expkey_table, 226 .name = "nfsd.fh", 227 .cache_put = expkey_put, 228 .cache_request = expkey_request, 229 .cache_parse = expkey_parse, 230 .cache_show = expkey_show, 231 }; 232 233 static inline int svc_expkey_match (struct svc_expkey *a, struct svc_expkey *b) 234 { 235 if (a->ek_fsidtype != b->ek_fsidtype || 236 a->ek_client != b->ek_client || 237 memcmp(a->ek_fsid, b->ek_fsid, key_len(a->ek_fsidtype)) != 0) 238 return 0; 239 return 1; 240 } 241 242 static inline void svc_expkey_init(struct svc_expkey *new, struct svc_expkey *item) 243 { 244 cache_get(&item->ek_client->h); 245 new->ek_client = item->ek_client; 246 new->ek_fsidtype = item->ek_fsidtype; 247 new->ek_fsid[0] = item->ek_fsid[0]; 248 new->ek_fsid[1] = item->ek_fsid[1]; 249 new->ek_fsid[2] = item->ek_fsid[2]; 250 } 251 252 static inline void svc_expkey_update(struct svc_expkey *new, struct svc_expkey *item) 253 { 254 cache_get(&item->ek_export->h); 255 new->ek_export = item->ek_export; 256 } 257 258 static DefineSimpleCacheLookup(svc_expkey,0) /* no inplace updates */ 259 260 #define EXPORT_HASHBITS 8 261 #define EXPORT_HASHMAX (1<< EXPORT_HASHBITS) 262 #define EXPORT_HASHMASK (EXPORT_HASHMAX -1) 263 264 static struct cache_head *export_table[EXPORT_HASHMAX]; 265 266 static inline int svc_export_hash(struct svc_export *item) 267 { 268 int rv; 269 270 rv = hash_ptr(item->ex_client, EXPORT_HASHBITS); 271 rv ^= hash_ptr(item->ex_dentry, EXPORT_HASHBITS); 272 rv ^= hash_ptr(item->ex_mnt, EXPORT_HASHBITS); 273 return rv; 274 } 275 276 void svc_export_put(struct cache_head *item, struct cache_detail *cd) 277 { 278 if (cache_put(item, cd)) { 279 struct svc_export *exp = container_of(item, struct svc_export, h); 280 dput(exp->ex_dentry); 281 mntput(exp->ex_mnt); 282 auth_domain_put(exp->ex_client); 283 kfree(exp); 284 } 285 } 286 287 static void svc_export_request(struct cache_detail *cd, 288 struct cache_head *h, 289 char **bpp, int *blen) 290 { 291 /* client path */ 292 struct svc_export *exp = container_of(h, struct svc_export, h); 293 char *pth; 294 295 qword_add(bpp, blen, exp->ex_client->name); 296 pth = d_path(exp->ex_dentry, exp->ex_mnt, *bpp, *blen); 297 if (IS_ERR(pth)) { 298 /* is this correct? */ 299 (*bpp)[0] = '\n'; 300 return; 301 } 302 qword_add(bpp, blen, pth); 303 (*bpp)[-1] = '\n'; 304 } 305 306 static struct svc_export *svc_export_lookup(struct svc_export *, int); 307 308 static int check_export(struct inode *inode, int flags) 309 { 310 311 /* We currently export only dirs and regular files. 312 * This is what umountd does. 313 */ 314 if (!S_ISDIR(inode->i_mode) && 315 !S_ISREG(inode->i_mode)) 316 return -ENOTDIR; 317 318 /* There are two requirements on a filesystem to be exportable. 319 * 1: We must be able to identify the filesystem from a number. 320 * either a device number (so FS_REQUIRES_DEV needed) 321 * or an FSID number (so NFSEXP_FSID needed). 322 * 2: We must be able to find an inode from a filehandle. 323 * This means that s_export_op must be set. 324 */ 325 if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) && 326 !(flags & NFSEXP_FSID)) { 327 dprintk("exp_export: export of non-dev fs without fsid"); 328 return -EINVAL; 329 } 330 if (!inode->i_sb->s_export_op) { 331 dprintk("exp_export: export of invalid fs type.\n"); 332 return -EINVAL; 333 } 334 335 /* Ok, we can export it */; 336 if (!inode->i_sb->s_export_op->find_exported_dentry) 337 inode->i_sb->s_export_op->find_exported_dentry = 338 find_exported_dentry; 339 return 0; 340 341 } 342 343 static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) 344 { 345 /* client path expiry [flags anonuid anongid fsid] */ 346 char *buf; 347 int len; 348 int err; 349 struct auth_domain *dom = NULL; 350 struct nameidata nd; 351 struct svc_export exp, *expp; 352 int an_int; 353 354 nd.dentry = NULL; 355 356 if (mesg[mlen-1] != '\n') 357 return -EINVAL; 358 mesg[mlen-1] = 0; 359 360 buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 361 err = -ENOMEM; 362 if (!buf) goto out; 363 364 /* client */ 365 len = qword_get(&mesg, buf, PAGE_SIZE); 366 err = -EINVAL; 367 if (len <= 0) goto out; 368 369 err = -ENOENT; 370 dom = auth_domain_find(buf); 371 if (!dom) 372 goto out; 373 374 /* path */ 375 err = -EINVAL; 376 if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) 377 goto out; 378 err = path_lookup(buf, 0, &nd); 379 if (err) goto out; 380 381 exp.h.flags = 0; 382 exp.ex_client = dom; 383 exp.ex_mnt = nd.mnt; 384 exp.ex_dentry = nd.dentry; 385 386 /* expiry */ 387 err = -EINVAL; 388 exp.h.expiry_time = get_expiry(&mesg); 389 if (exp.h.expiry_time == 0) 390 goto out; 391 392 /* flags */ 393 err = get_int(&mesg, &an_int); 394 if (err == -ENOENT) 395 set_bit(CACHE_NEGATIVE, &exp.h.flags); 396 else { 397 if (err || an_int < 0) goto out; 398 exp.ex_flags= an_int; 399 400 /* anon uid */ 401 err = get_int(&mesg, &an_int); 402 if (err) goto out; 403 exp.ex_anon_uid= an_int; 404 405 /* anon gid */ 406 err = get_int(&mesg, &an_int); 407 if (err) goto out; 408 exp.ex_anon_gid= an_int; 409 410 /* fsid */ 411 err = get_int(&mesg, &an_int); 412 if (err) goto out; 413 exp.ex_fsid = an_int; 414 415 err = check_export(nd.dentry->d_inode, exp.ex_flags); 416 if (err) goto out; 417 } 418 419 expp = svc_export_lookup(&exp, 1); 420 if (expp) 421 exp_put(expp); 422 err = 0; 423 cache_flush(); 424 out: 425 if (nd.dentry) 426 path_release(&nd); 427 if (dom) 428 auth_domain_put(dom); 429 if (buf) 430 kfree(buf); 431 return err; 432 } 433 434 static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong); 435 436 static int svc_export_show(struct seq_file *m, 437 struct cache_detail *cd, 438 struct cache_head *h) 439 { 440 struct svc_export *exp ; 441 442 if (h ==NULL) { 443 seq_puts(m, "#path domain(flags)\n"); 444 return 0; 445 } 446 exp = container_of(h, struct svc_export, h); 447 seq_path(m, exp->ex_mnt, exp->ex_dentry, " \t\n\\"); 448 seq_putc(m, '\t'); 449 seq_escape(m, exp->ex_client->name, " \t\n\\"); 450 seq_putc(m, '('); 451 if (test_bit(CACHE_VALID, &h->flags) && 452 !test_bit(CACHE_NEGATIVE, &h->flags)) 453 exp_flags(m, exp->ex_flags, exp->ex_fsid, 454 exp->ex_anon_uid, exp->ex_anon_gid); 455 seq_puts(m, ")\n"); 456 return 0; 457 } 458 struct cache_detail svc_export_cache = { 459 .hash_size = EXPORT_HASHMAX, 460 .hash_table = export_table, 461 .name = "nfsd.export", 462 .cache_put = svc_export_put, 463 .cache_request = svc_export_request, 464 .cache_parse = svc_export_parse, 465 .cache_show = svc_export_show, 466 }; 467 468 static inline int svc_export_match(struct svc_export *a, struct svc_export *b) 469 { 470 return a->ex_client == b->ex_client && 471 a->ex_dentry == b->ex_dentry && 472 a->ex_mnt == b->ex_mnt; 473 } 474 static inline void svc_export_init(struct svc_export *new, struct svc_export *item) 475 { 476 cache_get(&item->ex_client->h); 477 new->ex_client = item->ex_client; 478 new->ex_dentry = dget(item->ex_dentry); 479 new->ex_mnt = mntget(item->ex_mnt); 480 } 481 482 static inline void svc_export_update(struct svc_export *new, struct svc_export *item) 483 { 484 new->ex_flags = item->ex_flags; 485 new->ex_anon_uid = item->ex_anon_uid; 486 new->ex_anon_gid = item->ex_anon_gid; 487 new->ex_fsid = item->ex_fsid; 488 } 489 490 static DefineSimpleCacheLookup(svc_export,1) /* allow inplace updates */ 491 492 493 struct svc_expkey * 494 exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) 495 { 496 struct svc_expkey key, *ek; 497 int err; 498 499 if (!clp) 500 return NULL; 501 502 key.ek_client = clp; 503 key.ek_fsidtype = fsid_type; 504 memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); 505 506 ek = svc_expkey_lookup(&key, 0); 507 if (ek != NULL) 508 if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp))) 509 ek = ERR_PTR(err); 510 return ek; 511 } 512 513 static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv, 514 struct svc_export *exp) 515 { 516 struct svc_expkey key, *ek; 517 518 key.ek_client = clp; 519 key.ek_fsidtype = fsid_type; 520 memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); 521 key.ek_export = exp; 522 key.h.expiry_time = NEVER; 523 key.h.flags = 0; 524 525 ek = svc_expkey_lookup(&key, 1); 526 if (ek) { 527 expkey_put(&ek->h, &svc_expkey_cache); 528 return 0; 529 } 530 return -ENOMEM; 531 } 532 533 /* 534 * Find the client's export entry matching xdev/xino. 535 */ 536 static inline struct svc_expkey * 537 exp_get_key(svc_client *clp, dev_t dev, ino_t ino) 538 { 539 u32 fsidv[3]; 540 541 if (old_valid_dev(dev)) { 542 mk_fsid_v0(fsidv, dev, ino); 543 return exp_find_key(clp, 0, fsidv, NULL); 544 } 545 mk_fsid_v3(fsidv, dev, ino); 546 return exp_find_key(clp, 3, fsidv, NULL); 547 } 548 549 /* 550 * Find the client's export entry matching fsid 551 */ 552 static inline struct svc_expkey * 553 exp_get_fsid_key(svc_client *clp, int fsid) 554 { 555 u32 fsidv[2]; 556 557 mk_fsid_v1(fsidv, fsid); 558 559 return exp_find_key(clp, 1, fsidv, NULL); 560 } 561 562 svc_export * 563 exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry, 564 struct cache_req *reqp) 565 { 566 struct svc_export *exp, key; 567 568 if (!clp) 569 return NULL; 570 571 key.ex_client = clp; 572 key.ex_mnt = mnt; 573 key.ex_dentry = dentry; 574 575 exp = svc_export_lookup(&key, 0); 576 if (exp != NULL) 577 switch (cache_check(&svc_export_cache, &exp->h, reqp)) { 578 case 0: break; 579 case -EAGAIN: 580 exp = ERR_PTR(-EAGAIN); 581 break; 582 default: 583 exp = NULL; 584 } 585 586 return exp; 587 } 588 589 /* 590 * Find the export entry for a given dentry. 591 */ 592 struct svc_export * 593 exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry, 594 struct cache_req *reqp) 595 { 596 svc_export *exp; 597 598 dget(dentry); 599 exp = exp_get_by_name(clp, mnt, dentry, reqp); 600 601 while (exp == NULL && !IS_ROOT(dentry)) { 602 struct dentry *parent; 603 604 parent = dget_parent(dentry); 605 dput(dentry); 606 dentry = parent; 607 exp = exp_get_by_name(clp, mnt, dentry, reqp); 608 } 609 dput(dentry); 610 return exp; 611 } 612 613 /* 614 * Hashtable locking. Write locks are placed only by user processes 615 * wanting to modify export information. 616 * Write locking only done in this file. Read locking 617 * needed externally. 618 */ 619 620 static DECLARE_RWSEM(hash_sem); 621 622 void 623 exp_readlock(void) 624 { 625 down_read(&hash_sem); 626 } 627 628 static inline void 629 exp_writelock(void) 630 { 631 down_write(&hash_sem); 632 } 633 634 void 635 exp_readunlock(void) 636 { 637 up_read(&hash_sem); 638 } 639 640 static inline void 641 exp_writeunlock(void) 642 { 643 up_write(&hash_sem); 644 } 645 646 static void exp_fsid_unhash(struct svc_export *exp) 647 { 648 struct svc_expkey *ek; 649 650 if ((exp->ex_flags & NFSEXP_FSID) == 0) 651 return; 652 653 ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid); 654 if (ek && !IS_ERR(ek)) { 655 ek->h.expiry_time = get_seconds()-1; 656 expkey_put(&ek->h, &svc_expkey_cache); 657 } 658 svc_expkey_cache.nextcheck = get_seconds(); 659 } 660 661 static int exp_fsid_hash(svc_client *clp, struct svc_export *exp) 662 { 663 u32 fsid[2]; 664 665 if ((exp->ex_flags & NFSEXP_FSID) == 0) 666 return 0; 667 668 mk_fsid_v1(fsid, exp->ex_fsid); 669 return exp_set_key(clp, 1, fsid, exp); 670 } 671 672 static int exp_hash(struct auth_domain *clp, struct svc_export *exp) 673 { 674 u32 fsid[2]; 675 struct inode *inode = exp->ex_dentry->d_inode; 676 dev_t dev = inode->i_sb->s_dev; 677 678 if (old_valid_dev(dev)) { 679 mk_fsid_v0(fsid, dev, inode->i_ino); 680 return exp_set_key(clp, 0, fsid, exp); 681 } 682 mk_fsid_v3(fsid, dev, inode->i_ino); 683 return exp_set_key(clp, 3, fsid, exp); 684 } 685 686 static void exp_unhash(struct svc_export *exp) 687 { 688 struct svc_expkey *ek; 689 struct inode *inode = exp->ex_dentry->d_inode; 690 691 ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino); 692 if (ek && !IS_ERR(ek)) { 693 ek->h.expiry_time = get_seconds()-1; 694 expkey_put(&ek->h, &svc_expkey_cache); 695 } 696 svc_expkey_cache.nextcheck = get_seconds(); 697 } 698 699 /* 700 * Export a file system. 701 */ 702 int 703 exp_export(struct nfsctl_export *nxp) 704 { 705 svc_client *clp; 706 struct svc_export *exp = NULL; 707 struct svc_export new; 708 struct svc_expkey *fsid_key = NULL; 709 struct nameidata nd; 710 int err; 711 712 /* Consistency check */ 713 err = -EINVAL; 714 if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) || 715 !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX)) 716 goto out; 717 718 dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n", 719 nxp->ex_client, nxp->ex_path, 720 (unsigned)nxp->ex_dev, (long)nxp->ex_ino, 721 nxp->ex_flags); 722 723 /* Try to lock the export table for update */ 724 exp_writelock(); 725 726 /* Look up client info */ 727 if (!(clp = auth_domain_find(nxp->ex_client))) 728 goto out_unlock; 729 730 731 /* Look up the dentry */ 732 err = path_lookup(nxp->ex_path, 0, &nd); 733 if (err) 734 goto out_unlock; 735 err = -EINVAL; 736 737 exp = exp_get_by_name(clp, nd.mnt, nd.dentry, NULL); 738 739 /* must make sure there won't be an ex_fsid clash */ 740 if ((nxp->ex_flags & NFSEXP_FSID) && 741 (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) && 742 !IS_ERR(fsid_key) && 743 fsid_key->ek_export && 744 fsid_key->ek_export != exp) 745 goto finish; 746 747 if (exp) { 748 /* just a flags/id/fsid update */ 749 750 exp_fsid_unhash(exp); 751 exp->ex_flags = nxp->ex_flags; 752 exp->ex_anon_uid = nxp->ex_anon_uid; 753 exp->ex_anon_gid = nxp->ex_anon_gid; 754 exp->ex_fsid = nxp->ex_dev; 755 756 err = exp_fsid_hash(clp, exp); 757 goto finish; 758 } 759 760 err = check_export(nd.dentry->d_inode, nxp->ex_flags); 761 if (err) goto finish; 762 763 err = -ENOMEM; 764 765 dprintk("nfsd: creating export entry %p for client %p\n", exp, clp); 766 767 new.h.expiry_time = NEVER; 768 new.h.flags = 0; 769 new.ex_client = clp; 770 new.ex_mnt = nd.mnt; 771 new.ex_dentry = nd.dentry; 772 new.ex_flags = nxp->ex_flags; 773 new.ex_anon_uid = nxp->ex_anon_uid; 774 new.ex_anon_gid = nxp->ex_anon_gid; 775 new.ex_fsid = nxp->ex_dev; 776 777 exp = svc_export_lookup(&new, 1); 778 779 if (exp == NULL) 780 goto finish; 781 782 err = 0; 783 784 if (exp_hash(clp, exp) || 785 exp_fsid_hash(clp, exp)) { 786 /* failed to create at least one index */ 787 exp_do_unexport(exp); 788 cache_flush(); 789 err = -ENOMEM; 790 } 791 792 finish: 793 if (exp) 794 exp_put(exp); 795 if (fsid_key && !IS_ERR(fsid_key)) 796 expkey_put(&fsid_key->h, &svc_expkey_cache); 797 if (clp) 798 auth_domain_put(clp); 799 path_release(&nd); 800 out_unlock: 801 exp_writeunlock(); 802 out: 803 return err; 804 } 805 806 /* 807 * Unexport a file system. The export entry has already 808 * been removed from the client's list of exported fs's. 809 */ 810 static void 811 exp_do_unexport(svc_export *unexp) 812 { 813 unexp->h.expiry_time = get_seconds()-1; 814 svc_export_cache.nextcheck = get_seconds(); 815 exp_unhash(unexp); 816 exp_fsid_unhash(unexp); 817 } 818 819 820 /* 821 * unexport syscall. 822 */ 823 int 824 exp_unexport(struct nfsctl_export *nxp) 825 { 826 struct auth_domain *dom; 827 svc_export *exp; 828 struct nameidata nd; 829 int err; 830 831 /* Consistency check */ 832 if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) || 833 !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX)) 834 return -EINVAL; 835 836 exp_writelock(); 837 838 err = -EINVAL; 839 dom = auth_domain_find(nxp->ex_client); 840 if (!dom) { 841 dprintk("nfsd: unexport couldn't find %s\n", nxp->ex_client); 842 goto out_unlock; 843 } 844 845 err = path_lookup(nxp->ex_path, 0, &nd); 846 if (err) 847 goto out_domain; 848 849 err = -EINVAL; 850 exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL); 851 path_release(&nd); 852 if (!exp) 853 goto out_domain; 854 855 exp_do_unexport(exp); 856 exp_put(exp); 857 err = 0; 858 859 out_domain: 860 auth_domain_put(dom); 861 cache_flush(); 862 out_unlock: 863 exp_writeunlock(); 864 return err; 865 } 866 867 /* 868 * Obtain the root fh on behalf of a client. 869 * This could be done in user space, but I feel that it adds some safety 870 * since its harder to fool a kernel module than a user space program. 871 */ 872 int 873 exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize) 874 { 875 struct svc_export *exp; 876 struct nameidata nd; 877 struct inode *inode; 878 struct svc_fh fh; 879 int err; 880 881 err = -EPERM; 882 /* NB: we probably ought to check that it's NUL-terminated */ 883 if (path_lookup(path, 0, &nd)) { 884 printk("nfsd: exp_rootfh path not found %s", path); 885 return err; 886 } 887 inode = nd.dentry->d_inode; 888 889 dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n", 890 path, nd.dentry, clp->name, 891 inode->i_sb->s_id, inode->i_ino); 892 exp = exp_parent(clp, nd.mnt, nd.dentry, NULL); 893 if (!exp) { 894 dprintk("nfsd: exp_rootfh export not found.\n"); 895 goto out; 896 } 897 898 /* 899 * fh must be initialized before calling fh_compose 900 */ 901 fh_init(&fh, maxsize); 902 if (fh_compose(&fh, exp, nd.dentry, NULL)) 903 err = -EINVAL; 904 else 905 err = 0; 906 memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh)); 907 fh_put(&fh); 908 exp_put(exp); 909 out: 910 path_release(&nd); 911 return err; 912 } 913 914 /* 915 * Called when we need the filehandle for the root of the pseudofs, 916 * for a given NFSv4 client. The root is defined to be the 917 * export point with fsid==0 918 */ 919 int 920 exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, 921 struct cache_req *creq) 922 { 923 struct svc_expkey *fsid_key; 924 int rv; 925 u32 fsidv[2]; 926 927 mk_fsid_v1(fsidv, 0); 928 929 fsid_key = exp_find_key(clp, 1, fsidv, creq); 930 if (IS_ERR(fsid_key) && PTR_ERR(fsid_key) == -EAGAIN) 931 return nfserr_dropit; 932 if (!fsid_key || IS_ERR(fsid_key)) 933 return nfserr_perm; 934 935 rv = fh_compose(fhp, fsid_key->ek_export, 936 fsid_key->ek_export->ex_dentry, NULL); 937 expkey_put(&fsid_key->h, &svc_expkey_cache); 938 return rv; 939 } 940 941 /* Iterator */ 942 943 static void *e_start(struct seq_file *m, loff_t *pos) 944 { 945 loff_t n = *pos; 946 unsigned hash, export; 947 struct cache_head *ch; 948 949 exp_readlock(); 950 read_lock(&svc_export_cache.hash_lock); 951 if (!n--) 952 return (void *)1; 953 hash = n >> 32; 954 export = n & ((1LL<<32) - 1); 955 956 957 for (ch=export_table[hash]; ch; ch=ch->next) 958 if (!export--) 959 return ch; 960 n &= ~((1LL<<32) - 1); 961 do { 962 hash++; 963 n += 1LL<<32; 964 } while(hash < EXPORT_HASHMAX && export_table[hash]==NULL); 965 if (hash >= EXPORT_HASHMAX) 966 return NULL; 967 *pos = n+1; 968 return export_table[hash]; 969 } 970 971 static void *e_next(struct seq_file *m, void *p, loff_t *pos) 972 { 973 struct cache_head *ch = p; 974 int hash = (*pos >> 32); 975 976 if (p == (void *)1) 977 hash = 0; 978 else if (ch->next == NULL) { 979 hash++; 980 *pos += 1LL<<32; 981 } else { 982 ++*pos; 983 return ch->next; 984 } 985 *pos &= ~((1LL<<32) - 1); 986 while (hash < EXPORT_HASHMAX && export_table[hash] == NULL) { 987 hash++; 988 *pos += 1LL<<32; 989 } 990 if (hash >= EXPORT_HASHMAX) 991 return NULL; 992 ++*pos; 993 return export_table[hash]; 994 } 995 996 static void e_stop(struct seq_file *m, void *p) 997 { 998 read_unlock(&svc_export_cache.hash_lock); 999 exp_readunlock(); 1000 } 1001 1002 static struct flags { 1003 int flag; 1004 char *name[2]; 1005 } expflags[] = { 1006 { NFSEXP_READONLY, {"ro", "rw"}}, 1007 { NFSEXP_INSECURE_PORT, {"insecure", ""}}, 1008 { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}}, 1009 { NFSEXP_ALLSQUASH, {"all_squash", ""}}, 1010 { NFSEXP_ASYNC, {"async", "sync"}}, 1011 { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}}, 1012 { NFSEXP_NOHIDE, {"nohide", ""}}, 1013 { NFSEXP_CROSSMOUNT, {"crossmnt", ""}}, 1014 { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}}, 1015 { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}}, 1016 #ifdef MSNFS 1017 { NFSEXP_MSNFS, {"msnfs", ""}}, 1018 #endif 1019 { 0, {"", ""}} 1020 }; 1021 1022 static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong) 1023 { 1024 int first = 0; 1025 struct flags *flg; 1026 1027 for (flg = expflags; flg->flag; flg++) { 1028 int state = (flg->flag & flag)?0:1; 1029 if (*flg->name[state]) 1030 seq_printf(m, "%s%s", first++?",":"", flg->name[state]); 1031 } 1032 if (flag & NFSEXP_FSID) 1033 seq_printf(m, "%sfsid=%d", first++?",":"", fsid); 1034 if (anonu != (uid_t)-2 && anonu != (0x10000-2)) 1035 seq_printf(m, "%sanonuid=%d", first++?",":"", anonu); 1036 if (anong != (gid_t)-2 && anong != (0x10000-2)) 1037 seq_printf(m, "%sanongid=%d", first++?",":"", anong); 1038 } 1039 1040 static int e_show(struct seq_file *m, void *p) 1041 { 1042 struct cache_head *cp = p; 1043 struct svc_export *exp = container_of(cp, struct svc_export, h); 1044 svc_client *clp; 1045 1046 if (p == (void *)1) { 1047 seq_puts(m, "# Version 1.1\n"); 1048 seq_puts(m, "# Path Client(Flags) # IPs\n"); 1049 return 0; 1050 } 1051 1052 clp = exp->ex_client; 1053 cache_get(&exp->h); 1054 if (cache_check(&svc_export_cache, &exp->h, NULL)) 1055 return 0; 1056 if (cache_put(&exp->h, &svc_export_cache)) BUG(); 1057 return svc_export_show(m, &svc_export_cache, cp); 1058 } 1059 1060 struct seq_operations nfs_exports_op = { 1061 .start = e_start, 1062 .next = e_next, 1063 .stop = e_stop, 1064 .show = e_show, 1065 }; 1066 1067 /* 1068 * Add or modify a client. 1069 * Change requests may involve the list of host addresses. The list of 1070 * exports and possibly existing uid maps are left untouched. 1071 */ 1072 int 1073 exp_addclient(struct nfsctl_client *ncp) 1074 { 1075 struct auth_domain *dom; 1076 int i, err; 1077 1078 /* First, consistency check. */ 1079 err = -EINVAL; 1080 if (! exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX)) 1081 goto out; 1082 if (ncp->cl_naddr > NFSCLNT_ADDRMAX) 1083 goto out; 1084 1085 /* Lock the hashtable */ 1086 exp_writelock(); 1087 1088 dom = unix_domain_find(ncp->cl_ident); 1089 1090 err = -ENOMEM; 1091 if (!dom) 1092 goto out_unlock; 1093 1094 /* Insert client into hashtable. */ 1095 for (i = 0; i < ncp->cl_naddr; i++) 1096 auth_unix_add_addr(ncp->cl_addrlist[i], dom); 1097 1098 auth_unix_forget_old(dom); 1099 auth_domain_put(dom); 1100 1101 err = 0; 1102 1103 out_unlock: 1104 exp_writeunlock(); 1105 out: 1106 return err; 1107 } 1108 1109 /* 1110 * Delete a client given an identifier. 1111 */ 1112 int 1113 exp_delclient(struct nfsctl_client *ncp) 1114 { 1115 int err; 1116 struct auth_domain *dom; 1117 1118 err = -EINVAL; 1119 if (!exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX)) 1120 goto out; 1121 1122 /* Lock the hashtable */ 1123 exp_writelock(); 1124 1125 dom = auth_domain_find(ncp->cl_ident); 1126 /* just make sure that no addresses work 1127 * and that it will expire soon 1128 */ 1129 if (dom) { 1130 err = auth_unix_forget_old(dom); 1131 dom->h.expiry_time = get_seconds(); 1132 auth_domain_put(dom); 1133 } 1134 1135 exp_writeunlock(); 1136 out: 1137 return err; 1138 } 1139 1140 /* 1141 * Verify that string is non-empty and does not exceed max length. 1142 */ 1143 static int 1144 exp_verify_string(char *cp, int max) 1145 { 1146 int i; 1147 1148 for (i = 0; i < max; i++) 1149 if (!cp[i]) 1150 return i; 1151 cp[i] = 0; 1152 printk(KERN_NOTICE "nfsd: couldn't validate string %s\n", cp); 1153 return 0; 1154 } 1155 1156 /* 1157 * Initialize the exports module. 1158 */ 1159 void 1160 nfsd_export_init(void) 1161 { 1162 dprintk("nfsd: initializing export module.\n"); 1163 1164 cache_register(&svc_export_cache); 1165 cache_register(&svc_expkey_cache); 1166 1167 } 1168 1169 /* 1170 * Flush exports table - called when last nfsd thread is killed 1171 */ 1172 void 1173 nfsd_export_flush(void) 1174 { 1175 exp_writelock(); 1176 cache_purge(&svc_expkey_cache); 1177 cache_purge(&svc_export_cache); 1178 exp_writeunlock(); 1179 } 1180 1181 /* 1182 * Shutdown the exports module. 1183 */ 1184 void 1185 nfsd_export_shutdown(void) 1186 { 1187 1188 dprintk("nfsd: shutting down export module.\n"); 1189 1190 exp_writelock(); 1191 1192 if (cache_unregister(&svc_expkey_cache)) 1193 printk(KERN_ERR "nfsd: failed to unregister expkey cache\n"); 1194 if (cache_unregister(&svc_export_cache)) 1195 printk(KERN_ERR "nfsd: failed to unregister export cache\n"); 1196 svcauth_unix_purge(); 1197 1198 exp_writeunlock(); 1199 dprintk("nfsd: export shutdown complete.\n"); 1200 } 1201