diff options
Diffstat (limited to 'ipc')
| -rw-r--r-- | ipc/mqueue.c | 61 |
1 files changed, 28 insertions, 33 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c index f8e54f5b9080..9a08acc9e649 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c | |||
| @@ -726,7 +726,6 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct inode *dir, | |||
| 726 | struct mq_attr *attr) | 726 | struct mq_attr *attr) |
| 727 | { | 727 | { |
| 728 | const struct cred *cred = current_cred(); | 728 | const struct cred *cred = current_cred(); |
| 729 | struct file *result; | ||
| 730 | int ret; | 729 | int ret; |
| 731 | 730 | ||
| 732 | if (attr) { | 731 | if (attr) { |
| @@ -748,21 +747,11 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct inode *dir, | |||
| 748 | } | 747 | } |
| 749 | 748 | ||
| 750 | mode &= ~current_umask(); | 749 | mode &= ~current_umask(); |
| 751 | ret = mnt_want_write(path->mnt); | ||
| 752 | if (ret) | ||
| 753 | return ERR_PTR(ret); | ||
| 754 | ret = vfs_create(dir, path->dentry, mode, true); | 750 | ret = vfs_create(dir, path->dentry, mode, true); |
| 755 | path->dentry->d_fsdata = NULL; | 751 | path->dentry->d_fsdata = NULL; |
| 756 | if (!ret) | 752 | if (ret) |
| 757 | result = dentry_open(path, oflag, cred); | 753 | return ERR_PTR(ret); |
| 758 | else | 754 | return dentry_open(path, oflag, cred); |
| 759 | result = ERR_PTR(ret); | ||
| 760 | /* | ||
| 761 | * dentry_open() took a persistent mnt_want_write(), | ||
| 762 | * so we can now drop this one. | ||
| 763 | */ | ||
| 764 | mnt_drop_write(path->mnt); | ||
| 765 | return result; | ||
| 766 | } | 755 | } |
| 767 | 756 | ||
| 768 | /* Opens existing queue */ | 757 | /* Opens existing queue */ |
| @@ -788,7 +777,9 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, | |||
| 788 | struct mq_attr attr; | 777 | struct mq_attr attr; |
| 789 | int fd, error; | 778 | int fd, error; |
| 790 | struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; | 779 | struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; |
| 791 | struct dentry *root = ipc_ns->mq_mnt->mnt_root; | 780 | struct vfsmount *mnt = ipc_ns->mq_mnt; |
| 781 | struct dentry *root = mnt->mnt_root; | ||
| 782 | int ro; | ||
| 792 | 783 | ||
| 793 | if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr))) | 784 | if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr))) |
| 794 | return -EFAULT; | 785 | return -EFAULT; |
| @@ -802,6 +793,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, | |||
| 802 | if (fd < 0) | 793 | if (fd < 0) |
| 803 | goto out_putname; | 794 | goto out_putname; |
| 804 | 795 | ||
| 796 | ro = mnt_want_write(mnt); /* we'll drop it in any case */ | ||
| 805 | error = 0; | 797 | error = 0; |
| 806 | mutex_lock(&root->d_inode->i_mutex); | 798 | mutex_lock(&root->d_inode->i_mutex); |
| 807 | path.dentry = lookup_one_len(name, root, strlen(name)); | 799 | path.dentry = lookup_one_len(name, root, strlen(name)); |
| @@ -809,7 +801,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, | |||
| 809 | error = PTR_ERR(path.dentry); | 801 | error = PTR_ERR(path.dentry); |
| 810 | goto out_putfd; | 802 | goto out_putfd; |
| 811 | } | 803 | } |
| 812 | path.mnt = mntget(ipc_ns->mq_mnt); | 804 | path.mnt = mntget(mnt); |
| 813 | 805 | ||
| 814 | if (oflag & O_CREAT) { | 806 | if (oflag & O_CREAT) { |
| 815 | if (path.dentry->d_inode) { /* entry already exists */ | 807 | if (path.dentry->d_inode) { /* entry already exists */ |
| @@ -820,6 +812,10 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode, | |||
| 820 | } | 812 | } |
| 821 | filp = do_open(&path, oflag); | 813 | filp = do_open(&path, oflag); |
| 822 | } else { | 814 | } else { |
| 815 | if (ro) { | ||
| 816 | error = ro; | ||
| 817 | goto out; | ||
| 818 | } | ||
| 823 | filp = do_create(ipc_ns, root->d_inode, | 819 | filp = do_create(ipc_ns, root->d_inode, |
| 824 | &path, oflag, mode, | 820 | &path, oflag, mode, |
| 825 | u_attr ? &attr : NULL); | 821 | u_attr ? &attr : NULL); |
| @@ -845,6 +841,7 @@ out_putfd: | |||
| 845 | fd = error; | 841 | fd = error; |
| 846 | } | 842 | } |
| 847 | mutex_unlock(&root->d_inode->i_mutex); | 843 | mutex_unlock(&root->d_inode->i_mutex); |
| 844 | mnt_drop_write(mnt); | ||
| 848 | out_putname: | 845 | out_putname: |
| 849 | putname(name); | 846 | putname(name); |
| 850 | return fd; | 847 | return fd; |
| @@ -857,40 +854,38 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name) | |||
| 857 | struct dentry *dentry; | 854 | struct dentry *dentry; |
| 858 | struct inode *inode = NULL; | 855 | struct inode *inode = NULL; |
| 859 | struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; | 856 | struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; |
| 857 | struct vfsmount *mnt = ipc_ns->mq_mnt; | ||
| 860 | 858 | ||
| 861 | name = getname(u_name); | 859 | name = getname(u_name); |
| 862 | if (IS_ERR(name)) | 860 | if (IS_ERR(name)) |
| 863 | return PTR_ERR(name); | 861 | return PTR_ERR(name); |
| 864 | 862 | ||
| 865 | mutex_lock_nested(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex, | 863 | err = mnt_want_write(mnt); |
| 866 | I_MUTEX_PARENT); | 864 | if (err) |
| 867 | dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name)); | 865 | goto out_name; |
| 866 | mutex_lock_nested(&mnt->mnt_root->d_inode->i_mutex, I_MUTEX_PARENT); | ||
| 867 | dentry = lookup_one_len(name, mnt->mnt_root, strlen(name)); | ||
| 868 | if (IS_ERR(dentry)) { | 868 | if (IS_ERR(dentry)) { |
| 869 | err = PTR_ERR(dentry); | 869 | err = PTR_ERR(dentry); |
| 870 | goto out_unlock; | 870 | goto out_unlock; |
| 871 | } | 871 | } |
| 872 | 872 | ||
| 873 | if (!dentry->d_inode) { | ||
| 874 | err = -ENOENT; | ||
| 875 | goto out_err; | ||
| 876 | } | ||
| 877 | |||
| 878 | inode = dentry->d_inode; | 873 | inode = dentry->d_inode; |
| 879 | if (inode) | 874 | if (!inode) { |
| 875 | err = -ENOENT; | ||
| 876 | } else { | ||
| 880 | ihold(inode); | 877 | ihold(inode); |
| 881 | err = mnt_want_write(ipc_ns->mq_mnt); | 878 | err = vfs_unlink(dentry->d_parent->d_inode, dentry); |
| 882 | if (err) | 879 | } |
| 883 | goto out_err; | ||
| 884 | err = vfs_unlink(dentry->d_parent->d_inode, dentry); | ||
| 885 | mnt_drop_write(ipc_ns->mq_mnt); | ||
| 886 | out_err: | ||
| 887 | dput(dentry); | 880 | dput(dentry); |
| 888 | 881 | ||
| 889 | out_unlock: | 882 | out_unlock: |
| 890 | mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex); | 883 | mutex_unlock(&mnt->mnt_root->d_inode->i_mutex); |
| 891 | putname(name); | ||
| 892 | if (inode) | 884 | if (inode) |
| 893 | iput(inode); | 885 | iput(inode); |
| 886 | mnt_drop_write(mnt); | ||
| 887 | out_name: | ||
| 888 | putname(name); | ||
| 894 | 889 | ||
| 895 | return err; | 890 | return err; |
| 896 | } | 891 | } |
