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