diff options
Diffstat (limited to 'ipc/mqueue.c')
-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 | } |