diff options
Diffstat (limited to 'fs/open.c')
| -rw-r--r-- | fs/open.c | 151 |
1 files changed, 94 insertions, 57 deletions
| @@ -244,21 +244,21 @@ static long do_sys_truncate(const char __user * path, loff_t length) | |||
| 244 | if (!S_ISREG(inode->i_mode)) | 244 | if (!S_ISREG(inode->i_mode)) |
| 245 | goto dput_and_out; | 245 | goto dput_and_out; |
| 246 | 246 | ||
| 247 | error = vfs_permission(&nd, MAY_WRITE); | 247 | error = mnt_want_write(nd.path.mnt); |
| 248 | if (error) | 248 | if (error) |
| 249 | goto dput_and_out; | 249 | goto dput_and_out; |
| 250 | 250 | ||
| 251 | error = -EROFS; | 251 | error = vfs_permission(&nd, MAY_WRITE); |
| 252 | if (IS_RDONLY(inode)) | 252 | if (error) |
| 253 | goto dput_and_out; | 253 | goto mnt_drop_write_and_out; |
| 254 | 254 | ||
| 255 | error = -EPERM; | 255 | error = -EPERM; |
| 256 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | 256 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) |
| 257 | goto dput_and_out; | 257 | goto mnt_drop_write_and_out; |
| 258 | 258 | ||
| 259 | error = get_write_access(inode); | 259 | error = get_write_access(inode); |
| 260 | if (error) | 260 | if (error) |
| 261 | goto dput_and_out; | 261 | goto mnt_drop_write_and_out; |
| 262 | 262 | ||
| 263 | /* | 263 | /* |
| 264 | * Make sure that there are no leases. get_write_access() protects | 264 | * Make sure that there are no leases. get_write_access() protects |
| @@ -276,6 +276,8 @@ static long do_sys_truncate(const char __user * path, loff_t length) | |||
| 276 | 276 | ||
| 277 | put_write_and_out: | 277 | put_write_and_out: |
| 278 | put_write_access(inode); | 278 | put_write_access(inode); |
| 279 | mnt_drop_write_and_out: | ||
| 280 | mnt_drop_write(nd.path.mnt); | ||
| 279 | dput_and_out: | 281 | dput_and_out: |
| 280 | path_put(&nd.path); | 282 | path_put(&nd.path); |
| 281 | out: | 283 | out: |
| @@ -457,8 +459,17 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) | |||
| 457 | if(res || !(mode & S_IWOTH) || | 459 | if(res || !(mode & S_IWOTH) || |
| 458 | special_file(nd.path.dentry->d_inode->i_mode)) | 460 | special_file(nd.path.dentry->d_inode->i_mode)) |
| 459 | goto out_path_release; | 461 | goto out_path_release; |
| 460 | 462 | /* | |
| 461 | if(IS_RDONLY(nd.path.dentry->d_inode)) | 463 | * This is a rare case where using __mnt_is_readonly() |
| 464 | * is OK without a mnt_want/drop_write() pair. Since | ||
| 465 | * no actual write to the fs is performed here, we do | ||
| 466 | * not need to telegraph to that to anyone. | ||
| 467 | * | ||
| 468 | * By doing this, we accept that this access is | ||
| 469 | * inherently racy and know that the fs may change | ||
| 470 | * state before we even see this result. | ||
| 471 | */ | ||
| 472 | if (__mnt_is_readonly(nd.path.mnt)) | ||
| 462 | res = -EROFS; | 473 | res = -EROFS; |
| 463 | 474 | ||
| 464 | out_path_release: | 475 | out_path_release: |
| @@ -567,12 +578,12 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode) | |||
| 567 | 578 | ||
| 568 | audit_inode(NULL, dentry); | 579 | audit_inode(NULL, dentry); |
| 569 | 580 | ||
| 570 | err = -EROFS; | 581 | err = mnt_want_write(file->f_path.mnt); |
| 571 | if (IS_RDONLY(inode)) | 582 | if (err) |
| 572 | goto out_putf; | 583 | goto out_putf; |
| 573 | err = -EPERM; | 584 | err = -EPERM; |
| 574 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | 585 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) |
| 575 | goto out_putf; | 586 | goto out_drop_write; |
| 576 | mutex_lock(&inode->i_mutex); | 587 | mutex_lock(&inode->i_mutex); |
| 577 | if (mode == (mode_t) -1) | 588 | if (mode == (mode_t) -1) |
| 578 | mode = inode->i_mode; | 589 | mode = inode->i_mode; |
| @@ -581,6 +592,8 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode) | |||
| 581 | err = notify_change(dentry, &newattrs); | 592 | err = notify_change(dentry, &newattrs); |
| 582 | mutex_unlock(&inode->i_mutex); | 593 | mutex_unlock(&inode->i_mutex); |
| 583 | 594 | ||
| 595 | out_drop_write: | ||
| 596 | mnt_drop_write(file->f_path.mnt); | ||
| 584 | out_putf: | 597 | out_putf: |
| 585 | fput(file); | 598 | fput(file); |
| 586 | out: | 599 | out: |
| @@ -600,13 +613,13 @@ asmlinkage long sys_fchmodat(int dfd, const char __user *filename, | |||
| 600 | goto out; | 613 | goto out; |
| 601 | inode = nd.path.dentry->d_inode; | 614 | inode = nd.path.dentry->d_inode; |
| 602 | 615 | ||
| 603 | error = -EROFS; | 616 | error = mnt_want_write(nd.path.mnt); |
| 604 | if (IS_RDONLY(inode)) | 617 | if (error) |
| 605 | goto dput_and_out; | 618 | goto dput_and_out; |
| 606 | 619 | ||
| 607 | error = -EPERM; | 620 | error = -EPERM; |
| 608 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | 621 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) |
| 609 | goto dput_and_out; | 622 | goto out_drop_write; |
| 610 | 623 | ||
| 611 | mutex_lock(&inode->i_mutex); | 624 | mutex_lock(&inode->i_mutex); |
| 612 | if (mode == (mode_t) -1) | 625 | if (mode == (mode_t) -1) |
| @@ -616,6 +629,8 @@ asmlinkage long sys_fchmodat(int dfd, const char __user *filename, | |||
| 616 | error = notify_change(nd.path.dentry, &newattrs); | 629 | error = notify_change(nd.path.dentry, &newattrs); |
| 617 | mutex_unlock(&inode->i_mutex); | 630 | mutex_unlock(&inode->i_mutex); |
| 618 | 631 | ||
| 632 | out_drop_write: | ||
| 633 | mnt_drop_write(nd.path.mnt); | ||
| 619 | dput_and_out: | 634 | dput_and_out: |
| 620 | path_put(&nd.path); | 635 | path_put(&nd.path); |
| 621 | out: | 636 | out: |
| @@ -638,9 +653,6 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group) | |||
| 638 | printk(KERN_ERR "chown_common: NULL inode\n"); | 653 | printk(KERN_ERR "chown_common: NULL inode\n"); |
| 639 | goto out; | 654 | goto out; |
| 640 | } | 655 | } |
| 641 | error = -EROFS; | ||
| 642 | if (IS_RDONLY(inode)) | ||
| 643 | goto out; | ||
| 644 | error = -EPERM; | 656 | error = -EPERM; |
| 645 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) | 657 | if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) |
| 646 | goto out; | 658 | goto out; |
| @@ -671,7 +683,12 @@ asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group) | |||
| 671 | error = user_path_walk(filename, &nd); | 683 | error = user_path_walk(filename, &nd); |
| 672 | if (error) | 684 | if (error) |
| 673 | goto out; | 685 | goto out; |
| 686 | error = mnt_want_write(nd.path.mnt); | ||
| 687 | if (error) | ||
| 688 | goto out_release; | ||
| 674 | error = chown_common(nd.path.dentry, user, group); | 689 | error = chown_common(nd.path.dentry, user, group); |
| 690 | mnt_drop_write(nd.path.mnt); | ||
| 691 | out_release: | ||
| 675 | path_put(&nd.path); | 692 | path_put(&nd.path); |
| 676 | out: | 693 | out: |
| 677 | return error; | 694 | return error; |
| @@ -691,7 +708,12 @@ asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user, | |||
| 691 | error = __user_walk_fd(dfd, filename, follow, &nd); | 708 | error = __user_walk_fd(dfd, filename, follow, &nd); |
| 692 | if (error) | 709 | if (error) |
| 693 | goto out; | 710 | goto out; |
| 711 | error = mnt_want_write(nd.path.mnt); | ||
| 712 | if (error) | ||
| 713 | goto out_release; | ||
| 694 | error = chown_common(nd.path.dentry, user, group); | 714 | error = chown_common(nd.path.dentry, user, group); |
| 715 | mnt_drop_write(nd.path.mnt); | ||
| 716 | out_release: | ||
| 695 | path_put(&nd.path); | 717 | path_put(&nd.path); |
| 696 | out: | 718 | out: |
| 697 | return error; | 719 | return error; |
| @@ -705,7 +727,12 @@ asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group | |||
| 705 | error = user_path_walk_link(filename, &nd); | 727 | error = user_path_walk_link(filename, &nd); |
| 706 | if (error) | 728 | if (error) |
| 707 | goto out; | 729 | goto out; |
| 730 | error = mnt_want_write(nd.path.mnt); | ||
| 731 | if (error) | ||
| 732 | goto out_release; | ||
| 708 | error = chown_common(nd.path.dentry, user, group); | 733 | error = chown_common(nd.path.dentry, user, group); |
| 734 | mnt_drop_write(nd.path.mnt); | ||
| 735 | out_release: | ||
| 709 | path_put(&nd.path); | 736 | path_put(&nd.path); |
| 710 | out: | 737 | out: |
| 711 | return error; | 738 | return error; |
| @@ -722,14 +749,48 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group) | |||
| 722 | if (!file) | 749 | if (!file) |
| 723 | goto out; | 750 | goto out; |
| 724 | 751 | ||
| 752 | error = mnt_want_write(file->f_path.mnt); | ||
| 753 | if (error) | ||
| 754 | goto out_fput; | ||
| 725 | dentry = file->f_path.dentry; | 755 | dentry = file->f_path.dentry; |
| 726 | audit_inode(NULL, dentry); | 756 | audit_inode(NULL, dentry); |
| 727 | error = chown_common(dentry, user, group); | 757 | error = chown_common(dentry, user, group); |
| 758 | mnt_drop_write(file->f_path.mnt); | ||
| 759 | out_fput: | ||
| 728 | fput(file); | 760 | fput(file); |
| 729 | out: | 761 | out: |
| 730 | return error; | 762 | return error; |
| 731 | } | 763 | } |
| 732 | 764 | ||
| 765 | /* | ||
| 766 | * You have to be very careful that these write | ||
| 767 | * counts get cleaned up in error cases and | ||
| 768 | * upon __fput(). This should probably never | ||
| 769 | * be called outside of __dentry_open(). | ||
| 770 | */ | ||
| 771 | static inline int __get_file_write_access(struct inode *inode, | ||
| 772 | struct vfsmount *mnt) | ||
| 773 | { | ||
| 774 | int error; | ||
| 775 | error = get_write_access(inode); | ||
| 776 | if (error) | ||
| 777 | return error; | ||
| 778 | /* | ||
| 779 | * Do not take mount writer counts on | ||
| 780 | * special files since no writes to | ||
| 781 | * the mount itself will occur. | ||
| 782 | */ | ||
| 783 | if (!special_file(inode->i_mode)) { | ||
| 784 | /* | ||
| 785 | * Balanced in __fput() | ||
| 786 | */ | ||
| 787 | error = mnt_want_write(mnt); | ||
| 788 | if (error) | ||
| 789 | put_write_access(inode); | ||
| 790 | } | ||
| 791 | return error; | ||
| 792 | } | ||
| 793 | |||
| 733 | static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, | 794 | static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, |
| 734 | int flags, struct file *f, | 795 | int flags, struct file *f, |
| 735 | int (*open)(struct inode *, struct file *)) | 796 | int (*open)(struct inode *, struct file *)) |
| @@ -742,9 +803,11 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, | |||
| 742 | FMODE_PREAD | FMODE_PWRITE; | 803 | FMODE_PREAD | FMODE_PWRITE; |
| 743 | inode = dentry->d_inode; | 804 | inode = dentry->d_inode; |
| 744 | if (f->f_mode & FMODE_WRITE) { | 805 | if (f->f_mode & FMODE_WRITE) { |
| 745 | error = get_write_access(inode); | 806 | error = __get_file_write_access(inode, mnt); |
| 746 | if (error) | 807 | if (error) |
| 747 | goto cleanup_file; | 808 | goto cleanup_file; |
| 809 | if (!special_file(inode->i_mode)) | ||
| 810 | file_take_write(f); | ||
| 748 | } | 811 | } |
| 749 | 812 | ||
| 750 | f->f_mapping = inode->i_mapping; | 813 | f->f_mapping = inode->i_mapping; |
| @@ -774,7 +837,7 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, | |||
| 774 | if (f->f_flags & O_DIRECT) { | 837 | if (f->f_flags & O_DIRECT) { |
| 775 | if (!f->f_mapping->a_ops || | 838 | if (!f->f_mapping->a_ops || |
| 776 | ((!f->f_mapping->a_ops->direct_IO) && | 839 | ((!f->f_mapping->a_ops->direct_IO) && |
| 777 | (!f->f_mapping->a_ops->get_xip_page))) { | 840 | (!f->f_mapping->a_ops->get_xip_mem))) { |
| 778 | fput(f); | 841 | fput(f); |
| 779 | f = ERR_PTR(-EINVAL); | 842 | f = ERR_PTR(-EINVAL); |
| 780 | } | 843 | } |
| @@ -784,8 +847,19 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, | |||
| 784 | 847 | ||
| 785 | cleanup_all: | 848 | cleanup_all: |
| 786 | fops_put(f->f_op); | 849 | fops_put(f->f_op); |
| 787 | if (f->f_mode & FMODE_WRITE) | 850 | if (f->f_mode & FMODE_WRITE) { |
| 788 | put_write_access(inode); | 851 | put_write_access(inode); |
| 852 | if (!special_file(inode->i_mode)) { | ||
| 853 | /* | ||
| 854 | * We don't consider this a real | ||
| 855 | * mnt_want/drop_write() pair | ||
| 856 | * because it all happenend right | ||
| 857 | * here, so just reset the state. | ||
| 858 | */ | ||
| 859 | file_reset_write(f); | ||
| 860 | mnt_drop_write(mnt); | ||
| 861 | } | ||
| 862 | } | ||
| 789 | file_kill(f); | 863 | file_kill(f); |
| 790 | f->f_path.dentry = NULL; | 864 | f->f_path.dentry = NULL; |
| 791 | f->f_path.mnt = NULL; | 865 | f->f_path.mnt = NULL; |
| @@ -796,43 +870,6 @@ cleanup_file: | |||
| 796 | return ERR_PTR(error); | 870 | return ERR_PTR(error); |
| 797 | } | 871 | } |
| 798 | 872 | ||
| 799 | /* | ||
| 800 | * Note that while the flag value (low two bits) for sys_open means: | ||
| 801 | * 00 - read-only | ||
| 802 | * 01 - write-only | ||
| 803 | * 10 - read-write | ||
| 804 | * 11 - special | ||
| 805 | * it is changed into | ||
| 806 | * 00 - no permissions needed | ||
| 807 | * 01 - read-permission | ||
| 808 | * 10 - write-permission | ||
| 809 | * 11 - read-write | ||
| 810 | * for the internal routines (ie open_namei()/follow_link() etc). 00 is | ||
| 811 | * used by symlinks. | ||
| 812 | */ | ||
| 813 | static struct file *do_filp_open(int dfd, const char *filename, int flags, | ||
| 814 | int mode) | ||
| 815 | { | ||
| 816 | int namei_flags, error; | ||
| 817 | struct nameidata nd; | ||
| 818 | |||
| 819 | namei_flags = flags; | ||
| 820 | if ((namei_flags+1) & O_ACCMODE) | ||
| 821 | namei_flags++; | ||
| 822 | |||
| 823 | error = open_namei(dfd, filename, namei_flags, mode, &nd); | ||
| 824 | if (!error) | ||
| 825 | return nameidata_to_filp(&nd, flags); | ||
| 826 | |||
| 827 | return ERR_PTR(error); | ||
| 828 | } | ||
| 829 | |||
| 830 | struct file *filp_open(const char *filename, int flags, int mode) | ||
| 831 | { | ||
| 832 | return do_filp_open(AT_FDCWD, filename, flags, mode); | ||
| 833 | } | ||
| 834 | EXPORT_SYMBOL(filp_open); | ||
| 835 | |||
| 836 | /** | 873 | /** |
| 837 | * lookup_instantiate_filp - instantiates the open intent filp | 874 | * lookup_instantiate_filp - instantiates the open intent filp |
| 838 | * @nd: pointer to nameidata | 875 | * @nd: pointer to nameidata |
