diff options
Diffstat (limited to 'fs/proc/proc_sysctl.c')
-rw-r--r-- | fs/proc/proc_sysctl.c | 78 |
1 files changed, 31 insertions, 47 deletions
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index ac05f33a0dde..71290463a1d3 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
@@ -573,12 +573,12 @@ out: | |||
573 | return ret; | 573 | return ret; |
574 | } | 574 | } |
575 | 575 | ||
576 | static int proc_sys_fill_cache(struct file *filp, void *dirent, | 576 | static bool proc_sys_fill_cache(struct file *file, |
577 | filldir_t filldir, | 577 | struct dir_context *ctx, |
578 | struct ctl_table_header *head, | 578 | struct ctl_table_header *head, |
579 | struct ctl_table *table) | 579 | struct ctl_table *table) |
580 | { | 580 | { |
581 | struct dentry *child, *dir = filp->f_path.dentry; | 581 | struct dentry *child, *dir = file->f_path.dentry; |
582 | struct inode *inode; | 582 | struct inode *inode; |
583 | struct qstr qname; | 583 | struct qstr qname; |
584 | ino_t ino = 0; | 584 | ino_t ino = 0; |
@@ -595,38 +595,38 @@ static int proc_sys_fill_cache(struct file *filp, void *dirent, | |||
595 | inode = proc_sys_make_inode(dir->d_sb, head, table); | 595 | inode = proc_sys_make_inode(dir->d_sb, head, table); |
596 | if (!inode) { | 596 | if (!inode) { |
597 | dput(child); | 597 | dput(child); |
598 | return -ENOMEM; | 598 | return false; |
599 | } else { | 599 | } else { |
600 | d_set_d_op(child, &proc_sys_dentry_operations); | 600 | d_set_d_op(child, &proc_sys_dentry_operations); |
601 | d_add(child, inode); | 601 | d_add(child, inode); |
602 | } | 602 | } |
603 | } else { | 603 | } else { |
604 | return -ENOMEM; | 604 | return false; |
605 | } | 605 | } |
606 | } | 606 | } |
607 | inode = child->d_inode; | 607 | inode = child->d_inode; |
608 | ino = inode->i_ino; | 608 | ino = inode->i_ino; |
609 | type = inode->i_mode >> 12; | 609 | type = inode->i_mode >> 12; |
610 | dput(child); | 610 | dput(child); |
611 | return !!filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type); | 611 | return dir_emit(ctx, qname.name, qname.len, ino, type); |
612 | } | 612 | } |
613 | 613 | ||
614 | static int proc_sys_link_fill_cache(struct file *filp, void *dirent, | 614 | static bool proc_sys_link_fill_cache(struct file *file, |
615 | filldir_t filldir, | 615 | struct dir_context *ctx, |
616 | struct ctl_table_header *head, | 616 | struct ctl_table_header *head, |
617 | struct ctl_table *table) | 617 | struct ctl_table *table) |
618 | { | 618 | { |
619 | int err, ret = 0; | 619 | bool ret = true; |
620 | head = sysctl_head_grab(head); | 620 | head = sysctl_head_grab(head); |
621 | 621 | ||
622 | if (S_ISLNK(table->mode)) { | 622 | if (S_ISLNK(table->mode)) { |
623 | /* It is not an error if we can not follow the link ignore it */ | 623 | /* It is not an error if we can not follow the link ignore it */ |
624 | err = sysctl_follow_link(&head, &table, current->nsproxy); | 624 | int err = sysctl_follow_link(&head, &table, current->nsproxy); |
625 | if (err) | 625 | if (err) |
626 | goto out; | 626 | goto out; |
627 | } | 627 | } |
628 | 628 | ||
629 | ret = proc_sys_fill_cache(filp, dirent, filldir, head, table); | 629 | ret = proc_sys_fill_cache(file, ctx, head, table); |
630 | out: | 630 | out: |
631 | sysctl_head_finish(head); | 631 | sysctl_head_finish(head); |
632 | return ret; | 632 | return ret; |
@@ -634,67 +634,50 @@ out: | |||
634 | 634 | ||
635 | static int scan(struct ctl_table_header *head, ctl_table *table, | 635 | static int scan(struct ctl_table_header *head, ctl_table *table, |
636 | unsigned long *pos, struct file *file, | 636 | unsigned long *pos, struct file *file, |
637 | void *dirent, filldir_t filldir) | 637 | struct dir_context *ctx) |
638 | { | 638 | { |
639 | int res; | 639 | bool res; |
640 | 640 | ||
641 | if ((*pos)++ < file->f_pos) | 641 | if ((*pos)++ < ctx->pos) |
642 | return 0; | 642 | return true; |
643 | 643 | ||
644 | if (unlikely(S_ISLNK(table->mode))) | 644 | if (unlikely(S_ISLNK(table->mode))) |
645 | res = proc_sys_link_fill_cache(file, dirent, filldir, head, table); | 645 | res = proc_sys_link_fill_cache(file, ctx, head, table); |
646 | else | 646 | else |
647 | res = proc_sys_fill_cache(file, dirent, filldir, head, table); | 647 | res = proc_sys_fill_cache(file, ctx, head, table); |
648 | 648 | ||
649 | if (res == 0) | 649 | if (res) |
650 | file->f_pos = *pos; | 650 | ctx->pos = *pos; |
651 | 651 | ||
652 | return res; | 652 | return res; |
653 | } | 653 | } |
654 | 654 | ||
655 | static int proc_sys_readdir(struct file *filp, void *dirent, filldir_t filldir) | 655 | static int proc_sys_readdir(struct file *file, struct dir_context *ctx) |
656 | { | 656 | { |
657 | struct dentry *dentry = filp->f_path.dentry; | 657 | struct ctl_table_header *head = grab_header(file_inode(file)); |
658 | struct inode *inode = dentry->d_inode; | ||
659 | struct ctl_table_header *head = grab_header(inode); | ||
660 | struct ctl_table_header *h = NULL; | 658 | struct ctl_table_header *h = NULL; |
661 | struct ctl_table *entry; | 659 | struct ctl_table *entry; |
662 | struct ctl_dir *ctl_dir; | 660 | struct ctl_dir *ctl_dir; |
663 | unsigned long pos; | 661 | unsigned long pos; |
664 | int ret = -EINVAL; | ||
665 | 662 | ||
666 | if (IS_ERR(head)) | 663 | if (IS_ERR(head)) |
667 | return PTR_ERR(head); | 664 | return PTR_ERR(head); |
668 | 665 | ||
669 | ctl_dir = container_of(head, struct ctl_dir, header); | 666 | ctl_dir = container_of(head, struct ctl_dir, header); |
670 | 667 | ||
671 | ret = 0; | 668 | if (!dir_emit_dots(file, ctx)) |
672 | /* Avoid a switch here: arm builds fail with missing __cmpdi2 */ | 669 | return 0; |
673 | if (filp->f_pos == 0) { | 670 | |
674 | if (filldir(dirent, ".", 1, filp->f_pos, | ||
675 | inode->i_ino, DT_DIR) < 0) | ||
676 | goto out; | ||
677 | filp->f_pos++; | ||
678 | } | ||
679 | if (filp->f_pos == 1) { | ||
680 | if (filldir(dirent, "..", 2, filp->f_pos, | ||
681 | parent_ino(dentry), DT_DIR) < 0) | ||
682 | goto out; | ||
683 | filp->f_pos++; | ||
684 | } | ||
685 | pos = 2; | 671 | pos = 2; |
686 | 672 | ||
687 | for (first_entry(ctl_dir, &h, &entry); h; next_entry(&h, &entry)) { | 673 | for (first_entry(ctl_dir, &h, &entry); h; next_entry(&h, &entry)) { |
688 | ret = scan(h, entry, &pos, filp, dirent, filldir); | 674 | if (!scan(h, entry, &pos, file, ctx)) { |
689 | if (ret) { | ||
690 | sysctl_head_finish(h); | 675 | sysctl_head_finish(h); |
691 | break; | 676 | break; |
692 | } | 677 | } |
693 | } | 678 | } |
694 | ret = 1; | ||
695 | out: | ||
696 | sysctl_head_finish(head); | 679 | sysctl_head_finish(head); |
697 | return ret; | 680 | return 0; |
698 | } | 681 | } |
699 | 682 | ||
700 | static int proc_sys_permission(struct inode *inode, int mask) | 683 | static int proc_sys_permission(struct inode *inode, int mask) |
@@ -769,7 +752,7 @@ static const struct file_operations proc_sys_file_operations = { | |||
769 | 752 | ||
770 | static const struct file_operations proc_sys_dir_file_operations = { | 753 | static const struct file_operations proc_sys_dir_file_operations = { |
771 | .read = generic_read_dir, | 754 | .read = generic_read_dir, |
772 | .readdir = proc_sys_readdir, | 755 | .iterate = proc_sys_readdir, |
773 | .llseek = generic_file_llseek, | 756 | .llseek = generic_file_llseek, |
774 | }; | 757 | }; |
775 | 758 | ||
@@ -813,15 +796,16 @@ static int sysctl_is_seen(struct ctl_table_header *p) | |||
813 | return res; | 796 | return res; |
814 | } | 797 | } |
815 | 798 | ||
816 | static int proc_sys_compare(const struct dentry *parent, | 799 | static int proc_sys_compare(const struct dentry *parent, const struct dentry *dentry, |
817 | const struct inode *pinode, | ||
818 | const struct dentry *dentry, const struct inode *inode, | ||
819 | unsigned int len, const char *str, const struct qstr *name) | 800 | unsigned int len, const char *str, const struct qstr *name) |
820 | { | 801 | { |
821 | struct ctl_table_header *head; | 802 | struct ctl_table_header *head; |
803 | struct inode *inode; | ||
804 | |||
822 | /* Although proc doesn't have negative dentries, rcu-walk means | 805 | /* Although proc doesn't have negative dentries, rcu-walk means |
823 | * that inode here can be NULL */ | 806 | * that inode here can be NULL */ |
824 | /* AV: can it, indeed? */ | 807 | /* AV: can it, indeed? */ |
808 | inode = ACCESS_ONCE(dentry->d_inode); | ||
825 | if (!inode) | 809 | if (!inode) |
826 | return 1; | 810 | return 1; |
827 | if (name->len != len) | 811 | if (name->len != len) |