diff options
Diffstat (limited to 'net/sunrpc/rpc_pipe.c')
-rw-r--r-- | net/sunrpc/rpc_pipe.c | 678 |
1 files changed, 394 insertions, 284 deletions
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 9ced0628d69c..8dd81535e08f 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/sunrpc/clnt.h> | 26 | #include <linux/sunrpc/clnt.h> |
27 | #include <linux/workqueue.h> | 27 | #include <linux/workqueue.h> |
28 | #include <linux/sunrpc/rpc_pipe_fs.h> | 28 | #include <linux/sunrpc/rpc_pipe_fs.h> |
29 | #include <linux/sunrpc/cache.h> | ||
29 | 30 | ||
30 | static struct vfsmount *rpc_mount __read_mostly; | 31 | static struct vfsmount *rpc_mount __read_mostly; |
31 | static int rpc_mount_count; | 32 | static int rpc_mount_count; |
@@ -125,7 +126,7 @@ static void | |||
125 | rpc_close_pipes(struct inode *inode) | 126 | rpc_close_pipes(struct inode *inode) |
126 | { | 127 | { |
127 | struct rpc_inode *rpci = RPC_I(inode); | 128 | struct rpc_inode *rpci = RPC_I(inode); |
128 | struct rpc_pipe_ops *ops; | 129 | const struct rpc_pipe_ops *ops; |
129 | int need_release; | 130 | int need_release; |
130 | 131 | ||
131 | mutex_lock(&inode->i_mutex); | 132 | mutex_lock(&inode->i_mutex); |
@@ -398,66 +399,12 @@ static const struct file_operations rpc_info_operations = { | |||
398 | 399 | ||
399 | 400 | ||
400 | /* | 401 | /* |
401 | * We have a single directory with 1 node in it. | ||
402 | */ | ||
403 | enum { | ||
404 | RPCAUTH_Root = 1, | ||
405 | RPCAUTH_lockd, | ||
406 | RPCAUTH_mount, | ||
407 | RPCAUTH_nfs, | ||
408 | RPCAUTH_portmap, | ||
409 | RPCAUTH_statd, | ||
410 | RPCAUTH_nfsd4_cb, | ||
411 | RPCAUTH_RootEOF | ||
412 | }; | ||
413 | |||
414 | /* | ||
415 | * Description of fs contents. | 402 | * Description of fs contents. |
416 | */ | 403 | */ |
417 | struct rpc_filelist { | 404 | struct rpc_filelist { |
418 | char *name; | 405 | const char *name; |
419 | const struct file_operations *i_fop; | 406 | const struct file_operations *i_fop; |
420 | int mode; | 407 | umode_t mode; |
421 | }; | ||
422 | |||
423 | static struct rpc_filelist files[] = { | ||
424 | [RPCAUTH_lockd] = { | ||
425 | .name = "lockd", | ||
426 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
427 | }, | ||
428 | [RPCAUTH_mount] = { | ||
429 | .name = "mount", | ||
430 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
431 | }, | ||
432 | [RPCAUTH_nfs] = { | ||
433 | .name = "nfs", | ||
434 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
435 | }, | ||
436 | [RPCAUTH_portmap] = { | ||
437 | .name = "portmap", | ||
438 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
439 | }, | ||
440 | [RPCAUTH_statd] = { | ||
441 | .name = "statd", | ||
442 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
443 | }, | ||
444 | [RPCAUTH_nfsd4_cb] = { | ||
445 | .name = "nfsd4_cb", | ||
446 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
447 | }, | ||
448 | }; | ||
449 | |||
450 | enum { | ||
451 | RPCAUTH_info = 2, | ||
452 | RPCAUTH_EOF | ||
453 | }; | ||
454 | |||
455 | static struct rpc_filelist authfiles[] = { | ||
456 | [RPCAUTH_info] = { | ||
457 | .name = "info", | ||
458 | .i_fop = &rpc_info_operations, | ||
459 | .mode = S_IFREG | S_IRUSR, | ||
460 | }, | ||
461 | }; | 408 | }; |
462 | 409 | ||
463 | struct vfsmount *rpc_get_mount(void) | 410 | struct vfsmount *rpc_get_mount(void) |
@@ -484,39 +431,8 @@ static const struct dentry_operations rpc_dentry_operations = { | |||
484 | .d_delete = rpc_delete_dentry, | 431 | .d_delete = rpc_delete_dentry, |
485 | }; | 432 | }; |
486 | 433 | ||
487 | static int | ||
488 | rpc_lookup_parent(char *path, struct nameidata *nd) | ||
489 | { | ||
490 | struct vfsmount *mnt; | ||
491 | |||
492 | if (path[0] == '\0') | ||
493 | return -ENOENT; | ||
494 | |||
495 | mnt = rpc_get_mount(); | ||
496 | if (IS_ERR(mnt)) { | ||
497 | printk(KERN_WARNING "%s: %s failed to mount " | ||
498 | "pseudofilesystem \n", __FILE__, __func__); | ||
499 | return PTR_ERR(mnt); | ||
500 | } | ||
501 | |||
502 | if (vfs_path_lookup(mnt->mnt_root, mnt, path, LOOKUP_PARENT, nd)) { | ||
503 | printk(KERN_WARNING "%s: %s failed to find path %s\n", | ||
504 | __FILE__, __func__, path); | ||
505 | rpc_put_mount(); | ||
506 | return -ENOENT; | ||
507 | } | ||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | static void | ||
512 | rpc_release_path(struct nameidata *nd) | ||
513 | { | ||
514 | path_put(&nd->path); | ||
515 | rpc_put_mount(); | ||
516 | } | ||
517 | |||
518 | static struct inode * | 434 | static struct inode * |
519 | rpc_get_inode(struct super_block *sb, int mode) | 435 | rpc_get_inode(struct super_block *sb, umode_t mode) |
520 | { | 436 | { |
521 | struct inode *inode = new_inode(sb); | 437 | struct inode *inode = new_inode(sb); |
522 | if (!inode) | 438 | if (!inode) |
@@ -534,212 +450,274 @@ rpc_get_inode(struct super_block *sb, int mode) | |||
534 | return inode; | 450 | return inode; |
535 | } | 451 | } |
536 | 452 | ||
537 | /* | 453 | static int __rpc_create_common(struct inode *dir, struct dentry *dentry, |
538 | * FIXME: This probably has races. | 454 | umode_t mode, |
539 | */ | 455 | const struct file_operations *i_fop, |
540 | static void rpc_depopulate(struct dentry *parent, | 456 | void *private) |
541 | unsigned long start, unsigned long eof) | ||
542 | { | 457 | { |
543 | struct inode *dir = parent->d_inode; | 458 | struct inode *inode; |
544 | struct list_head *pos, *next; | ||
545 | struct dentry *dentry, *dvec[10]; | ||
546 | int n = 0; | ||
547 | 459 | ||
548 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD); | 460 | BUG_ON(!d_unhashed(dentry)); |
549 | repeat: | 461 | inode = rpc_get_inode(dir->i_sb, mode); |
550 | spin_lock(&dcache_lock); | 462 | if (!inode) |
551 | list_for_each_safe(pos, next, &parent->d_subdirs) { | 463 | goto out_err; |
552 | dentry = list_entry(pos, struct dentry, d_u.d_child); | 464 | inode->i_ino = iunique(dir->i_sb, 100); |
553 | if (!dentry->d_inode || | 465 | if (i_fop) |
554 | dentry->d_inode->i_ino < start || | 466 | inode->i_fop = i_fop; |
555 | dentry->d_inode->i_ino >= eof) | 467 | if (private) |
556 | continue; | 468 | rpc_inode_setowner(inode, private); |
557 | spin_lock(&dentry->d_lock); | 469 | d_add(dentry, inode); |
558 | if (!d_unhashed(dentry)) { | 470 | return 0; |
559 | dget_locked(dentry); | 471 | out_err: |
560 | __d_drop(dentry); | 472 | printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", |
561 | spin_unlock(&dentry->d_lock); | 473 | __FILE__, __func__, dentry->d_name.name); |
562 | dvec[n++] = dentry; | 474 | dput(dentry); |
563 | if (n == ARRAY_SIZE(dvec)) | 475 | return -ENOMEM; |
564 | break; | ||
565 | } else | ||
566 | spin_unlock(&dentry->d_lock); | ||
567 | } | ||
568 | spin_unlock(&dcache_lock); | ||
569 | if (n) { | ||
570 | do { | ||
571 | dentry = dvec[--n]; | ||
572 | if (S_ISREG(dentry->d_inode->i_mode)) | ||
573 | simple_unlink(dir, dentry); | ||
574 | else if (S_ISDIR(dentry->d_inode->i_mode)) | ||
575 | simple_rmdir(dir, dentry); | ||
576 | d_delete(dentry); | ||
577 | dput(dentry); | ||
578 | } while (n); | ||
579 | goto repeat; | ||
580 | } | ||
581 | mutex_unlock(&dir->i_mutex); | ||
582 | } | 476 | } |
583 | 477 | ||
584 | static int | 478 | static int __rpc_create(struct inode *dir, struct dentry *dentry, |
585 | rpc_populate(struct dentry *parent, | 479 | umode_t mode, |
586 | struct rpc_filelist *files, | 480 | const struct file_operations *i_fop, |
587 | int start, int eof) | 481 | void *private) |
588 | { | 482 | { |
589 | struct inode *inode, *dir = parent->d_inode; | 483 | int err; |
590 | void *private = RPC_I(dir)->private; | ||
591 | struct dentry *dentry; | ||
592 | int mode, i; | ||
593 | 484 | ||
594 | mutex_lock(&dir->i_mutex); | 485 | err = __rpc_create_common(dir, dentry, S_IFREG | mode, i_fop, private); |
595 | for (i = start; i < eof; i++) { | 486 | if (err) |
596 | dentry = d_alloc_name(parent, files[i].name); | 487 | return err; |
597 | if (!dentry) | 488 | fsnotify_create(dir, dentry); |
598 | goto out_bad; | ||
599 | dentry->d_op = &rpc_dentry_operations; | ||
600 | mode = files[i].mode; | ||
601 | inode = rpc_get_inode(dir->i_sb, mode); | ||
602 | if (!inode) { | ||
603 | dput(dentry); | ||
604 | goto out_bad; | ||
605 | } | ||
606 | inode->i_ino = i; | ||
607 | if (files[i].i_fop) | ||
608 | inode->i_fop = files[i].i_fop; | ||
609 | if (private) | ||
610 | rpc_inode_setowner(inode, private); | ||
611 | if (S_ISDIR(mode)) | ||
612 | inc_nlink(dir); | ||
613 | d_add(dentry, inode); | ||
614 | fsnotify_create(dir, dentry); | ||
615 | } | ||
616 | mutex_unlock(&dir->i_mutex); | ||
617 | return 0; | 489 | return 0; |
618 | out_bad: | ||
619 | mutex_unlock(&dir->i_mutex); | ||
620 | printk(KERN_WARNING "%s: %s failed to populate directory %s\n", | ||
621 | __FILE__, __func__, parent->d_name.name); | ||
622 | return -ENOMEM; | ||
623 | } | 490 | } |
624 | 491 | ||
625 | static int | 492 | static int __rpc_mkdir(struct inode *dir, struct dentry *dentry, |
626 | __rpc_mkdir(struct inode *dir, struct dentry *dentry) | 493 | umode_t mode, |
494 | const struct file_operations *i_fop, | ||
495 | void *private) | ||
627 | { | 496 | { |
628 | struct inode *inode; | 497 | int err; |
629 | 498 | ||
630 | inode = rpc_get_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO); | 499 | err = __rpc_create_common(dir, dentry, S_IFDIR | mode, i_fop, private); |
631 | if (!inode) | 500 | if (err) |
632 | goto out_err; | 501 | return err; |
633 | inode->i_ino = iunique(dir->i_sb, 100); | ||
634 | d_instantiate(dentry, inode); | ||
635 | inc_nlink(dir); | 502 | inc_nlink(dir); |
636 | fsnotify_mkdir(dir, dentry); | 503 | fsnotify_mkdir(dir, dentry); |
637 | return 0; | 504 | return 0; |
638 | out_err: | ||
639 | printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", | ||
640 | __FILE__, __func__, dentry->d_name.name); | ||
641 | return -ENOMEM; | ||
642 | } | 505 | } |
643 | 506 | ||
644 | static int | 507 | static int __rpc_mkpipe(struct inode *dir, struct dentry *dentry, |
645 | __rpc_rmdir(struct inode *dir, struct dentry *dentry) | 508 | umode_t mode, |
509 | const struct file_operations *i_fop, | ||
510 | void *private, | ||
511 | const struct rpc_pipe_ops *ops, | ||
512 | int flags) | ||
646 | { | 513 | { |
647 | int error; | 514 | struct rpc_inode *rpci; |
648 | error = simple_rmdir(dir, dentry); | 515 | int err; |
649 | if (!error) | 516 | |
650 | d_delete(dentry); | 517 | err = __rpc_create_common(dir, dentry, S_IFIFO | mode, i_fop, private); |
651 | return error; | 518 | if (err) |
519 | return err; | ||
520 | rpci = RPC_I(dentry->d_inode); | ||
521 | rpci->nkern_readwriters = 1; | ||
522 | rpci->private = private; | ||
523 | rpci->flags = flags; | ||
524 | rpci->ops = ops; | ||
525 | fsnotify_create(dir, dentry); | ||
526 | return 0; | ||
652 | } | 527 | } |
653 | 528 | ||
654 | static struct dentry * | 529 | static int __rpc_rmdir(struct inode *dir, struct dentry *dentry) |
655 | rpc_lookup_create(struct dentry *parent, const char *name, int len, int exclusive) | 530 | { |
531 | int ret; | ||
532 | |||
533 | dget(dentry); | ||
534 | ret = simple_rmdir(dir, dentry); | ||
535 | d_delete(dentry); | ||
536 | dput(dentry); | ||
537 | return ret; | ||
538 | } | ||
539 | |||
540 | static int __rpc_unlink(struct inode *dir, struct dentry *dentry) | ||
541 | { | ||
542 | int ret; | ||
543 | |||
544 | dget(dentry); | ||
545 | ret = simple_unlink(dir, dentry); | ||
546 | d_delete(dentry); | ||
547 | dput(dentry); | ||
548 | return ret; | ||
549 | } | ||
550 | |||
551 | static int __rpc_rmpipe(struct inode *dir, struct dentry *dentry) | ||
552 | { | ||
553 | struct inode *inode = dentry->d_inode; | ||
554 | struct rpc_inode *rpci = RPC_I(inode); | ||
555 | |||
556 | rpci->nkern_readwriters--; | ||
557 | if (rpci->nkern_readwriters != 0) | ||
558 | return 0; | ||
559 | rpc_close_pipes(inode); | ||
560 | return __rpc_unlink(dir, dentry); | ||
561 | } | ||
562 | |||
563 | static struct dentry *__rpc_lookup_create(struct dentry *parent, | ||
564 | struct qstr *name) | ||
656 | { | 565 | { |
657 | struct inode *dir = parent->d_inode; | ||
658 | struct dentry *dentry; | 566 | struct dentry *dentry; |
659 | 567 | ||
660 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); | 568 | dentry = d_lookup(parent, name); |
661 | dentry = lookup_one_len(name, parent, len); | 569 | if (!dentry) { |
662 | if (IS_ERR(dentry)) | 570 | dentry = d_alloc(parent, name); |
663 | goto out_err; | 571 | if (!dentry) { |
572 | dentry = ERR_PTR(-ENOMEM); | ||
573 | goto out_err; | ||
574 | } | ||
575 | } | ||
664 | if (!dentry->d_inode) | 576 | if (!dentry->d_inode) |
665 | dentry->d_op = &rpc_dentry_operations; | 577 | dentry->d_op = &rpc_dentry_operations; |
666 | else if (exclusive) { | ||
667 | dput(dentry); | ||
668 | dentry = ERR_PTR(-EEXIST); | ||
669 | goto out_err; | ||
670 | } | ||
671 | return dentry; | ||
672 | out_err: | 578 | out_err: |
673 | mutex_unlock(&dir->i_mutex); | ||
674 | return dentry; | 579 | return dentry; |
675 | } | 580 | } |
676 | 581 | ||
677 | static struct dentry * | 582 | static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent, |
678 | rpc_lookup_negative(char *path, struct nameidata *nd) | 583 | struct qstr *name) |
679 | { | 584 | { |
680 | struct dentry *dentry; | 585 | struct dentry *dentry; |
681 | int error; | ||
682 | 586 | ||
683 | if ((error = rpc_lookup_parent(path, nd)) != 0) | 587 | dentry = __rpc_lookup_create(parent, name); |
684 | return ERR_PTR(error); | 588 | if (dentry->d_inode == NULL) |
685 | dentry = rpc_lookup_create(nd->path.dentry, nd->last.name, nd->last.len, | 589 | return dentry; |
686 | 1); | 590 | dput(dentry); |
687 | if (IS_ERR(dentry)) | 591 | return ERR_PTR(-EEXIST); |
688 | rpc_release_path(nd); | ||
689 | return dentry; | ||
690 | } | 592 | } |
691 | 593 | ||
692 | /** | 594 | /* |
693 | * rpc_mkdir - Create a new directory in rpc_pipefs | 595 | * FIXME: This probably has races. |
694 | * @path: path from the rpc_pipefs root to the new directory | ||
695 | * @rpc_client: rpc client to associate with this directory | ||
696 | * | ||
697 | * This creates a directory at the given @path associated with | ||
698 | * @rpc_clnt, which will contain a file named "info" with some basic | ||
699 | * information about the client, together with any "pipes" that may | ||
700 | * later be created using rpc_mkpipe(). | ||
701 | */ | 596 | */ |
702 | struct dentry * | 597 | static void __rpc_depopulate(struct dentry *parent, |
703 | rpc_mkdir(char *path, struct rpc_clnt *rpc_client) | 598 | const struct rpc_filelist *files, |
599 | int start, int eof) | ||
704 | { | 600 | { |
705 | struct nameidata nd; | 601 | struct inode *dir = parent->d_inode; |
706 | struct dentry *dentry; | 602 | struct dentry *dentry; |
707 | struct inode *dir; | 603 | struct qstr name; |
604 | int i; | ||
605 | |||
606 | for (i = start; i < eof; i++) { | ||
607 | name.name = files[i].name; | ||
608 | name.len = strlen(files[i].name); | ||
609 | name.hash = full_name_hash(name.name, name.len); | ||
610 | dentry = d_lookup(parent, &name); | ||
611 | |||
612 | if (dentry == NULL) | ||
613 | continue; | ||
614 | if (dentry->d_inode == NULL) | ||
615 | goto next; | ||
616 | switch (dentry->d_inode->i_mode & S_IFMT) { | ||
617 | default: | ||
618 | BUG(); | ||
619 | case S_IFREG: | ||
620 | __rpc_unlink(dir, dentry); | ||
621 | break; | ||
622 | case S_IFDIR: | ||
623 | __rpc_rmdir(dir, dentry); | ||
624 | } | ||
625 | next: | ||
626 | dput(dentry); | ||
627 | } | ||
628 | } | ||
629 | |||
630 | static void rpc_depopulate(struct dentry *parent, | ||
631 | const struct rpc_filelist *files, | ||
632 | int start, int eof) | ||
633 | { | ||
634 | struct inode *dir = parent->d_inode; | ||
635 | |||
636 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_CHILD); | ||
637 | __rpc_depopulate(parent, files, start, eof); | ||
638 | mutex_unlock(&dir->i_mutex); | ||
639 | } | ||
640 | |||
641 | static int rpc_populate(struct dentry *parent, | ||
642 | const struct rpc_filelist *files, | ||
643 | int start, int eof, | ||
644 | void *private) | ||
645 | { | ||
646 | struct inode *dir = parent->d_inode; | ||
647 | struct dentry *dentry; | ||
648 | int i, err; | ||
649 | |||
650 | mutex_lock(&dir->i_mutex); | ||
651 | for (i = start; i < eof; i++) { | ||
652 | struct qstr q; | ||
653 | |||
654 | q.name = files[i].name; | ||
655 | q.len = strlen(files[i].name); | ||
656 | q.hash = full_name_hash(q.name, q.len); | ||
657 | dentry = __rpc_lookup_create_exclusive(parent, &q); | ||
658 | err = PTR_ERR(dentry); | ||
659 | if (IS_ERR(dentry)) | ||
660 | goto out_bad; | ||
661 | switch (files[i].mode & S_IFMT) { | ||
662 | default: | ||
663 | BUG(); | ||
664 | case S_IFREG: | ||
665 | err = __rpc_create(dir, dentry, | ||
666 | files[i].mode, | ||
667 | files[i].i_fop, | ||
668 | private); | ||
669 | break; | ||
670 | case S_IFDIR: | ||
671 | err = __rpc_mkdir(dir, dentry, | ||
672 | files[i].mode, | ||
673 | NULL, | ||
674 | private); | ||
675 | } | ||
676 | if (err != 0) | ||
677 | goto out_bad; | ||
678 | } | ||
679 | mutex_unlock(&dir->i_mutex); | ||
680 | return 0; | ||
681 | out_bad: | ||
682 | __rpc_depopulate(parent, files, start, eof); | ||
683 | mutex_unlock(&dir->i_mutex); | ||
684 | printk(KERN_WARNING "%s: %s failed to populate directory %s\n", | ||
685 | __FILE__, __func__, parent->d_name.name); | ||
686 | return err; | ||
687 | } | ||
688 | |||
689 | static struct dentry *rpc_mkdir_populate(struct dentry *parent, | ||
690 | struct qstr *name, umode_t mode, void *private, | ||
691 | int (*populate)(struct dentry *, void *), void *args_populate) | ||
692 | { | ||
693 | struct dentry *dentry; | ||
694 | struct inode *dir = parent->d_inode; | ||
708 | int error; | 695 | int error; |
709 | 696 | ||
710 | dentry = rpc_lookup_negative(path, &nd); | 697 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); |
698 | dentry = __rpc_lookup_create_exclusive(parent, name); | ||
711 | if (IS_ERR(dentry)) | 699 | if (IS_ERR(dentry)) |
712 | return dentry; | 700 | goto out; |
713 | dir = nd.path.dentry->d_inode; | 701 | error = __rpc_mkdir(dir, dentry, mode, NULL, private); |
714 | if ((error = __rpc_mkdir(dir, dentry)) != 0) | 702 | if (error != 0) |
715 | goto err_dput; | 703 | goto out_err; |
716 | RPC_I(dentry->d_inode)->private = rpc_client; | 704 | if (populate != NULL) { |
717 | error = rpc_populate(dentry, authfiles, | 705 | error = populate(dentry, args_populate); |
718 | RPCAUTH_info, RPCAUTH_EOF); | 706 | if (error) |
719 | if (error) | 707 | goto err_rmdir; |
720 | goto err_depopulate; | 708 | } |
721 | dget(dentry); | ||
722 | out: | 709 | out: |
723 | mutex_unlock(&dir->i_mutex); | 710 | mutex_unlock(&dir->i_mutex); |
724 | rpc_release_path(&nd); | ||
725 | return dentry; | 711 | return dentry; |
726 | err_depopulate: | 712 | err_rmdir: |
727 | rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF); | ||
728 | __rpc_rmdir(dir, dentry); | 713 | __rpc_rmdir(dir, dentry); |
729 | err_dput: | 714 | out_err: |
730 | dput(dentry); | ||
731 | printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n", | ||
732 | __FILE__, __func__, path, error); | ||
733 | dentry = ERR_PTR(error); | 715 | dentry = ERR_PTR(error); |
734 | goto out; | 716 | goto out; |
735 | } | 717 | } |
736 | 718 | ||
737 | /** | 719 | static int rpc_rmdir_depopulate(struct dentry *dentry, |
738 | * rpc_rmdir - Remove a directory created with rpc_mkdir() | 720 | void (*depopulate)(struct dentry *)) |
739 | * @dentry: directory to remove | ||
740 | */ | ||
741 | int | ||
742 | rpc_rmdir(struct dentry *dentry) | ||
743 | { | 721 | { |
744 | struct dentry *parent; | 722 | struct dentry *parent; |
745 | struct inode *dir; | 723 | struct inode *dir; |
@@ -748,9 +726,9 @@ rpc_rmdir(struct dentry *dentry) | |||
748 | parent = dget_parent(dentry); | 726 | parent = dget_parent(dentry); |
749 | dir = parent->d_inode; | 727 | dir = parent->d_inode; |
750 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); | 728 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); |
751 | rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF); | 729 | if (depopulate != NULL) |
730 | depopulate(dentry); | ||
752 | error = __rpc_rmdir(dir, dentry); | 731 | error = __rpc_rmdir(dir, dentry); |
753 | dput(dentry); | ||
754 | mutex_unlock(&dir->i_mutex); | 732 | mutex_unlock(&dir->i_mutex); |
755 | dput(parent); | 733 | dput(parent); |
756 | return error; | 734 | return error; |
@@ -776,50 +754,54 @@ rpc_rmdir(struct dentry *dentry) | |||
776 | * The @private argument passed here will be available to all these methods | 754 | * The @private argument passed here will be available to all these methods |
777 | * from the file pointer, via RPC_I(file->f_dentry->d_inode)->private. | 755 | * from the file pointer, via RPC_I(file->f_dentry->d_inode)->private. |
778 | */ | 756 | */ |
779 | struct dentry * | 757 | struct dentry *rpc_mkpipe(struct dentry *parent, const char *name, |
780 | rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pipe_ops *ops, int flags) | 758 | void *private, const struct rpc_pipe_ops *ops, |
759 | int flags) | ||
781 | { | 760 | { |
782 | struct dentry *dentry; | 761 | struct dentry *dentry; |
783 | struct inode *dir, *inode; | 762 | struct inode *dir = parent->d_inode; |
784 | struct rpc_inode *rpci; | 763 | umode_t umode = S_IFIFO | S_IRUSR | S_IWUSR; |
764 | struct qstr q; | ||
765 | int err; | ||
785 | 766 | ||
786 | dentry = rpc_lookup_create(parent, name, strlen(name), 0); | 767 | if (ops->upcall == NULL) |
768 | umode &= ~S_IRUGO; | ||
769 | if (ops->downcall == NULL) | ||
770 | umode &= ~S_IWUGO; | ||
771 | |||
772 | q.name = name; | ||
773 | q.len = strlen(name); | ||
774 | q.hash = full_name_hash(q.name, q.len), | ||
775 | |||
776 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); | ||
777 | dentry = __rpc_lookup_create(parent, &q); | ||
787 | if (IS_ERR(dentry)) | 778 | if (IS_ERR(dentry)) |
788 | return dentry; | 779 | goto out; |
789 | dir = parent->d_inode; | ||
790 | if (dentry->d_inode) { | 780 | if (dentry->d_inode) { |
791 | rpci = RPC_I(dentry->d_inode); | 781 | struct rpc_inode *rpci = RPC_I(dentry->d_inode); |
792 | if (rpci->private != private || | 782 | if (rpci->private != private || |
793 | rpci->ops != ops || | 783 | rpci->ops != ops || |
794 | rpci->flags != flags) { | 784 | rpci->flags != flags) { |
795 | dput (dentry); | 785 | dput (dentry); |
796 | dentry = ERR_PTR(-EBUSY); | 786 | err = -EBUSY; |
787 | goto out_err; | ||
797 | } | 788 | } |
798 | rpci->nkern_readwriters++; | 789 | rpci->nkern_readwriters++; |
799 | goto out; | 790 | goto out; |
800 | } | 791 | } |
801 | inode = rpc_get_inode(dir->i_sb, S_IFIFO | S_IRUSR | S_IWUSR); | 792 | |
802 | if (!inode) | 793 | err = __rpc_mkpipe(dir, dentry, umode, &rpc_pipe_fops, |
803 | goto err_dput; | 794 | private, ops, flags); |
804 | inode->i_ino = iunique(dir->i_sb, 100); | 795 | if (err) |
805 | inode->i_fop = &rpc_pipe_fops; | 796 | goto out_err; |
806 | d_instantiate(dentry, inode); | ||
807 | rpci = RPC_I(inode); | ||
808 | rpci->private = private; | ||
809 | rpci->flags = flags; | ||
810 | rpci->ops = ops; | ||
811 | rpci->nkern_readwriters = 1; | ||
812 | fsnotify_create(dir, dentry); | ||
813 | dget(dentry); | ||
814 | out: | 797 | out: |
815 | mutex_unlock(&dir->i_mutex); | 798 | mutex_unlock(&dir->i_mutex); |
816 | return dentry; | 799 | return dentry; |
817 | err_dput: | 800 | out_err: |
818 | dput(dentry); | 801 | dentry = ERR_PTR(err); |
819 | dentry = ERR_PTR(-ENOMEM); | ||
820 | printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n", | 802 | printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n", |
821 | __FILE__, __func__, parent->d_name.name, name, | 803 | __FILE__, __func__, parent->d_name.name, name, |
822 | -ENOMEM); | 804 | err); |
823 | goto out; | 805 | goto out; |
824 | } | 806 | } |
825 | EXPORT_SYMBOL_GPL(rpc_mkpipe); | 807 | EXPORT_SYMBOL_GPL(rpc_mkpipe); |
@@ -842,19 +824,107 @@ rpc_unlink(struct dentry *dentry) | |||
842 | parent = dget_parent(dentry); | 824 | parent = dget_parent(dentry); |
843 | dir = parent->d_inode; | 825 | dir = parent->d_inode; |
844 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); | 826 | mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); |
845 | if (--RPC_I(dentry->d_inode)->nkern_readwriters == 0) { | 827 | error = __rpc_rmpipe(dir, dentry); |
846 | rpc_close_pipes(dentry->d_inode); | ||
847 | error = simple_unlink(dir, dentry); | ||
848 | if (!error) | ||
849 | d_delete(dentry); | ||
850 | } | ||
851 | dput(dentry); | ||
852 | mutex_unlock(&dir->i_mutex); | 828 | mutex_unlock(&dir->i_mutex); |
853 | dput(parent); | 829 | dput(parent); |
854 | return error; | 830 | return error; |
855 | } | 831 | } |
856 | EXPORT_SYMBOL_GPL(rpc_unlink); | 832 | EXPORT_SYMBOL_GPL(rpc_unlink); |
857 | 833 | ||
834 | enum { | ||
835 | RPCAUTH_info, | ||
836 | RPCAUTH_EOF | ||
837 | }; | ||
838 | |||
839 | static const struct rpc_filelist authfiles[] = { | ||
840 | [RPCAUTH_info] = { | ||
841 | .name = "info", | ||
842 | .i_fop = &rpc_info_operations, | ||
843 | .mode = S_IFREG | S_IRUSR, | ||
844 | }, | ||
845 | }; | ||
846 | |||
847 | static int rpc_clntdir_populate(struct dentry *dentry, void *private) | ||
848 | { | ||
849 | return rpc_populate(dentry, | ||
850 | authfiles, RPCAUTH_info, RPCAUTH_EOF, | ||
851 | private); | ||
852 | } | ||
853 | |||
854 | static void rpc_clntdir_depopulate(struct dentry *dentry) | ||
855 | { | ||
856 | rpc_depopulate(dentry, authfiles, RPCAUTH_info, RPCAUTH_EOF); | ||
857 | } | ||
858 | |||
859 | /** | ||
860 | * rpc_create_client_dir - Create a new rpc_client directory in rpc_pipefs | ||
861 | * @path: path from the rpc_pipefs root to the new directory | ||
862 | * @rpc_client: rpc client to associate with this directory | ||
863 | * | ||
864 | * This creates a directory at the given @path associated with | ||
865 | * @rpc_clnt, which will contain a file named "info" with some basic | ||
866 | * information about the client, together with any "pipes" that may | ||
867 | * later be created using rpc_mkpipe(). | ||
868 | */ | ||
869 | struct dentry *rpc_create_client_dir(struct dentry *dentry, | ||
870 | struct qstr *name, | ||
871 | struct rpc_clnt *rpc_client) | ||
872 | { | ||
873 | return rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, NULL, | ||
874 | rpc_clntdir_populate, rpc_client); | ||
875 | } | ||
876 | |||
877 | /** | ||
878 | * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() | ||
879 | * @dentry: directory to remove | ||
880 | */ | ||
881 | int rpc_remove_client_dir(struct dentry *dentry) | ||
882 | { | ||
883 | return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate); | ||
884 | } | ||
885 | |||
886 | static const struct rpc_filelist cache_pipefs_files[3] = { | ||
887 | [0] = { | ||
888 | .name = "channel", | ||
889 | .i_fop = &cache_file_operations_pipefs, | ||
890 | .mode = S_IFIFO|S_IRUSR|S_IWUSR, | ||
891 | }, | ||
892 | [1] = { | ||
893 | .name = "content", | ||
894 | .i_fop = &content_file_operations_pipefs, | ||
895 | .mode = S_IFREG|S_IRUSR, | ||
896 | }, | ||
897 | [2] = { | ||
898 | .name = "flush", | ||
899 | .i_fop = &cache_flush_operations_pipefs, | ||
900 | .mode = S_IFREG|S_IRUSR|S_IWUSR, | ||
901 | }, | ||
902 | }; | ||
903 | |||
904 | static int rpc_cachedir_populate(struct dentry *dentry, void *private) | ||
905 | { | ||
906 | return rpc_populate(dentry, | ||
907 | cache_pipefs_files, 0, 3, | ||
908 | private); | ||
909 | } | ||
910 | |||
911 | static void rpc_cachedir_depopulate(struct dentry *dentry) | ||
912 | { | ||
913 | rpc_depopulate(dentry, cache_pipefs_files, 0, 3); | ||
914 | } | ||
915 | |||
916 | struct dentry *rpc_create_cache_dir(struct dentry *parent, struct qstr *name, | ||
917 | mode_t umode, struct cache_detail *cd) | ||
918 | { | ||
919 | return rpc_mkdir_populate(parent, name, umode, NULL, | ||
920 | rpc_cachedir_populate, cd); | ||
921 | } | ||
922 | |||
923 | void rpc_remove_cache_dir(struct dentry *dentry) | ||
924 | { | ||
925 | rpc_rmdir_depopulate(dentry, rpc_cachedir_depopulate); | ||
926 | } | ||
927 | |||
858 | /* | 928 | /* |
859 | * populate the filesystem | 929 | * populate the filesystem |
860 | */ | 930 | */ |
@@ -866,6 +936,46 @@ static struct super_operations s_ops = { | |||
866 | 936 | ||
867 | #define RPCAUTH_GSSMAGIC 0x67596969 | 937 | #define RPCAUTH_GSSMAGIC 0x67596969 |
868 | 938 | ||
939 | /* | ||
940 | * We have a single directory with 1 node in it. | ||
941 | */ | ||
942 | enum { | ||
943 | RPCAUTH_lockd, | ||
944 | RPCAUTH_mount, | ||
945 | RPCAUTH_nfs, | ||
946 | RPCAUTH_portmap, | ||
947 | RPCAUTH_statd, | ||
948 | RPCAUTH_nfsd4_cb, | ||
949 | RPCAUTH_RootEOF | ||
950 | }; | ||
951 | |||
952 | static const struct rpc_filelist files[] = { | ||
953 | [RPCAUTH_lockd] = { | ||
954 | .name = "lockd", | ||
955 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
956 | }, | ||
957 | [RPCAUTH_mount] = { | ||
958 | .name = "mount", | ||
959 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
960 | }, | ||
961 | [RPCAUTH_nfs] = { | ||
962 | .name = "nfs", | ||
963 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
964 | }, | ||
965 | [RPCAUTH_portmap] = { | ||
966 | .name = "portmap", | ||
967 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
968 | }, | ||
969 | [RPCAUTH_statd] = { | ||
970 | .name = "statd", | ||
971 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
972 | }, | ||
973 | [RPCAUTH_nfsd4_cb] = { | ||
974 | .name = "nfsd4_cb", | ||
975 | .mode = S_IFDIR | S_IRUGO | S_IXUGO, | ||
976 | }, | ||
977 | }; | ||
978 | |||
869 | static int | 979 | static int |
870 | rpc_fill_super(struct super_block *sb, void *data, int silent) | 980 | rpc_fill_super(struct super_block *sb, void *data, int silent) |
871 | { | 981 | { |
@@ -886,7 +996,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) | |||
886 | iput(inode); | 996 | iput(inode); |
887 | return -ENOMEM; | 997 | return -ENOMEM; |
888 | } | 998 | } |
889 | if (rpc_populate(root, files, RPCAUTH_Root + 1, RPCAUTH_RootEOF)) | 999 | if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) |
890 | goto out; | 1000 | goto out; |
891 | sb->s_root = root; | 1001 | sb->s_root = root; |
892 | return 0; | 1002 | return 0; |