Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull assorted fixes - mostly vfs - from Al Viro:
"Assorted fixes, with an unexpected detour into vfio refcounting logics
(fell out when digging in an analog of eventpoll race in there)."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
task_work: add a scheduling point in task_work_run()
fs: fix fs/namei.c kernel-doc warnings
eventpoll: use-after-possible-free in epoll_create1()
vfio: grab vfio_device reference *before* exposing the sucker via fd_install()
vfio: get rid of vfio_device_put()/vfio_group_get_device* races
vfio: get rid of open-coding kref_put_mutex
introduce kref_put_mutex()
vfio: don't dereference after kfree...
mqueue: lift mnt_want_write() outside ->i_mutex, clean up a bit

+56 -46
+7 -12
drivers/vfio/vfio.c
··· 264 264 return group; 265 265 } 266 266 267 + /* called with vfio.group_lock held */ 267 268 static void vfio_group_release(struct kref *kref) 268 269 { 269 270 struct vfio_group *group = container_of(kref, struct vfio_group, kref); ··· 288 287 289 288 static void vfio_group_put(struct vfio_group *group) 290 289 { 291 - mutex_lock(&vfio.group_lock); 292 - /* 293 - * Release needs to unlock to unregister the notifier, so only 294 - * unlock if not released. 295 - */ 296 - if (!kref_put(&group->kref, vfio_group_release)) 297 - mutex_unlock(&vfio.group_lock); 290 + kref_put_mutex(&group->kref, vfio_group_release, &vfio.group_lock); 298 291 } 299 292 300 293 /* Assume group_lock or group reference is held */ ··· 396 401 struct vfio_device, kref); 397 402 struct vfio_group *group = device->group; 398 403 399 - mutex_lock(&group->device_lock); 400 404 list_del(&device->group_next); 401 405 mutex_unlock(&group->device_lock); 402 406 ··· 410 416 /* Device reference always implies a group reference */ 411 417 static void vfio_device_put(struct vfio_device *device) 412 418 { 413 - kref_put(&device->kref, vfio_device_release); 414 - vfio_group_put(device->group); 419 + struct vfio_group *group = device->group; 420 + kref_put_mutex(&device->kref, vfio_device_release, &group->device_lock); 421 + vfio_group_put(group); 415 422 } 416 423 417 424 static void vfio_device_get(struct vfio_device *device) ··· 1111 1116 */ 1112 1117 filep->f_mode |= (FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); 1113 1118 1114 - fd_install(ret, filep); 1115 - 1116 1119 vfio_device_get(device); 1117 1120 atomic_inc(&group->container_users); 1121 + 1122 + fd_install(ret, filep); 1118 1123 break; 1119 1124 } 1120 1125 mutex_unlock(&group->device_lock);
+1 -1
fs/eventpoll.c
··· 1654 1654 error = PTR_ERR(file); 1655 1655 goto out_free_fd; 1656 1656 } 1657 - fd_install(fd, file); 1658 1657 ep->file = file; 1658 + fd_install(fd, file); 1659 1659 return fd; 1660 1660 1661 1661 out_free_fd:
+2
fs/namei.c
··· 352 352 /** 353 353 * sb_permission - Check superblock-level permissions 354 354 * @sb: Superblock of inode to check permission on 355 + * @inode: Inode to check permission on 355 356 * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) 356 357 * 357 358 * Separate out file-system wide checks from inode-specific permission checks. ··· 657 656 /** 658 657 * may_follow_link - Check symlink following for unsafe situations 659 658 * @link: The path of the symlink 659 + * @nd: nameidata pathwalk data 660 660 * 661 661 * In the case of the sysctl_protected_symlinks sysctl being enabled, 662 662 * CAP_DAC_OVERRIDE needs to be specifically ignored if the symlink is
+18
include/linux/kref.h
··· 18 18 #include <linux/bug.h> 19 19 #include <linux/atomic.h> 20 20 #include <linux/kernel.h> 21 + #include <linux/mutex.h> 21 22 22 23 struct kref { 23 24 atomic_t refcount; ··· 93 92 static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref)) 94 93 { 95 94 return kref_sub(kref, 1, release); 95 + } 96 + 97 + static inline int kref_put_mutex(struct kref *kref, 98 + void (*release)(struct kref *kref), 99 + struct mutex *lock) 100 + { 101 + WARN_ON(release == NULL); 102 + if (unlikely(!atomic_add_unless(&kref->refcount, -1, 1))) { 103 + mutex_lock(lock); 104 + if (unlikely(!atomic_dec_and_test(&kref->refcount))) { 105 + mutex_unlock(lock); 106 + return 0; 107 + } 108 + release(kref); 109 + return 1; 110 + } 111 + return 0; 96 112 } 97 113 #endif /* _KREF_H_ */
+28 -33
ipc/mqueue.c
··· 726 726 struct mq_attr *attr) 727 727 { 728 728 const struct cred *cred = current_cred(); 729 - struct file *result; 730 729 int ret; 731 730 732 731 if (attr) { ··· 747 748 } 748 749 749 750 mode &= ~current_umask(); 750 - ret = mnt_want_write(path->mnt); 751 - if (ret) 752 - return ERR_PTR(ret); 753 751 ret = vfs_create(dir, path->dentry, mode, true); 754 752 path->dentry->d_fsdata = NULL; 755 - if (!ret) 756 - result = dentry_open(path, oflag, cred); 757 - else 758 - result = ERR_PTR(ret); 759 - /* 760 - * dentry_open() took a persistent mnt_want_write(), 761 - * so we can now drop this one. 762 - */ 763 - mnt_drop_write(path->mnt); 764 - return result; 753 + if (ret) 754 + return ERR_PTR(ret); 755 + return dentry_open(path, oflag, cred); 765 756 } 766 757 767 758 /* Opens existing queue */ ··· 777 788 struct mq_attr attr; 778 789 int fd, error; 779 790 struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; 780 - struct dentry *root = ipc_ns->mq_mnt->mnt_root; 791 + struct vfsmount *mnt = ipc_ns->mq_mnt; 792 + struct dentry *root = mnt->mnt_root; 793 + int ro; 781 794 782 795 if (u_attr && copy_from_user(&attr, u_attr, sizeof(struct mq_attr))) 783 796 return -EFAULT; ··· 793 802 if (fd < 0) 794 803 goto out_putname; 795 804 805 + ro = mnt_want_write(mnt); /* we'll drop it in any case */ 796 806 error = 0; 797 807 mutex_lock(&root->d_inode->i_mutex); 798 808 path.dentry = lookup_one_len(name, root, strlen(name)); ··· 801 809 error = PTR_ERR(path.dentry); 802 810 goto out_putfd; 803 811 } 804 - path.mnt = mntget(ipc_ns->mq_mnt); 812 + path.mnt = mntget(mnt); 805 813 806 814 if (oflag & O_CREAT) { 807 815 if (path.dentry->d_inode) { /* entry already exists */ ··· 812 820 } 813 821 filp = do_open(&path, oflag); 814 822 } else { 823 + if (ro) { 824 + error = ro; 825 + goto out; 826 + } 815 827 filp = do_create(ipc_ns, root->d_inode, 816 828 &path, oflag, mode, 817 829 u_attr ? &attr : NULL); ··· 841 845 fd = error; 842 846 } 843 847 mutex_unlock(&root->d_inode->i_mutex); 848 + mnt_drop_write(mnt); 844 849 out_putname: 845 850 putname(name); 846 851 return fd; ··· 854 857 struct dentry *dentry; 855 858 struct inode *inode = NULL; 856 859 struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns; 860 + struct vfsmount *mnt = ipc_ns->mq_mnt; 857 861 858 862 name = getname(u_name); 859 863 if (IS_ERR(name)) 860 864 return PTR_ERR(name); 861 865 862 - mutex_lock_nested(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex, 863 - I_MUTEX_PARENT); 864 - dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name)); 866 + err = mnt_want_write(mnt); 867 + if (err) 868 + goto out_name; 869 + mutex_lock_nested(&mnt->mnt_root->d_inode->i_mutex, I_MUTEX_PARENT); 870 + dentry = lookup_one_len(name, mnt->mnt_root, strlen(name)); 865 871 if (IS_ERR(dentry)) { 866 872 err = PTR_ERR(dentry); 867 873 goto out_unlock; 868 874 } 869 875 870 - if (!dentry->d_inode) { 871 - err = -ENOENT; 872 - goto out_err; 873 - } 874 - 875 876 inode = dentry->d_inode; 876 - if (inode) 877 + if (!inode) { 878 + err = -ENOENT; 879 + } else { 877 880 ihold(inode); 878 - err = mnt_want_write(ipc_ns->mq_mnt); 879 - if (err) 880 - goto out_err; 881 - err = vfs_unlink(dentry->d_parent->d_inode, dentry); 882 - mnt_drop_write(ipc_ns->mq_mnt); 883 - out_err: 881 + err = vfs_unlink(dentry->d_parent->d_inode, dentry); 882 + } 884 883 dput(dentry); 885 884 886 885 out_unlock: 887 - mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex); 888 - putname(name); 886 + mutex_unlock(&mnt->mnt_root->d_inode->i_mutex); 889 887 if (inode) 890 888 iput(inode); 889 + mnt_drop_write(mnt); 890 + out_name: 891 + putname(name); 891 892 892 893 return err; 893 894 }