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