You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull filesystem fixes from Al Viro: "Several bugfixes (all of them -stable fodder). Alexey's one deals with double mutex_lock() in UFS (apparently, nobody has tried to test "ufs: sb mutex merge + mutex_destroy" on something like file creation/removal on ufs). Mine deal with two kinds of umount bugs, in umount propagation and in handling of automounted submounts, both resulting in bogus transient EBUSY from umount" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: ufs: fix deadlocks introduced by sb mutex merge fix EBUSY on umount() from MNT_SHRINKABLE get rid of propagate_umount() mistakenly treating slaves as busy.
This commit is contained in:
+9
-1
@@ -1217,6 +1217,11 @@ static void namespace_unlock(void)
|
|||||||
head.first->pprev = &head.first;
|
head.first->pprev = &head.first;
|
||||||
INIT_HLIST_HEAD(&unmounted);
|
INIT_HLIST_HEAD(&unmounted);
|
||||||
|
|
||||||
|
/* undo decrements we'd done in umount_tree() */
|
||||||
|
hlist_for_each_entry(mnt, &head, mnt_hash)
|
||||||
|
if (mnt->mnt_ex_mountpoint.mnt)
|
||||||
|
mntget(mnt->mnt_ex_mountpoint.mnt);
|
||||||
|
|
||||||
up_write(&namespace_sem);
|
up_write(&namespace_sem);
|
||||||
|
|
||||||
synchronize_rcu();
|
synchronize_rcu();
|
||||||
@@ -1253,6 +1258,9 @@ void umount_tree(struct mount *mnt, int how)
|
|||||||
hlist_add_head(&p->mnt_hash, &tmp_list);
|
hlist_add_head(&p->mnt_hash, &tmp_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hlist_for_each_entry(p, &tmp_list, mnt_hash)
|
||||||
|
list_del_init(&p->mnt_child);
|
||||||
|
|
||||||
if (how)
|
if (how)
|
||||||
propagate_umount(&tmp_list);
|
propagate_umount(&tmp_list);
|
||||||
|
|
||||||
@@ -1263,9 +1271,9 @@ void umount_tree(struct mount *mnt, int how)
|
|||||||
p->mnt_ns = NULL;
|
p->mnt_ns = NULL;
|
||||||
if (how < 2)
|
if (how < 2)
|
||||||
p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
|
p->mnt.mnt_flags |= MNT_SYNC_UMOUNT;
|
||||||
list_del_init(&p->mnt_child);
|
|
||||||
if (mnt_has_parent(p)) {
|
if (mnt_has_parent(p)) {
|
||||||
put_mountpoint(p->mnt_mp);
|
put_mountpoint(p->mnt_mp);
|
||||||
|
mnt_add_count(p->mnt_parent, -1);
|
||||||
/* move the reference to mountpoint into ->mnt_ex_mountpoint */
|
/* move the reference to mountpoint into ->mnt_ex_mountpoint */
|
||||||
p->mnt_ex_mountpoint.dentry = p->mnt_mountpoint;
|
p->mnt_ex_mountpoint.dentry = p->mnt_mountpoint;
|
||||||
p->mnt_ex_mountpoint.mnt = &p->mnt_parent->mnt;
|
p->mnt_ex_mountpoint.mnt = &p->mnt_parent->mnt;
|
||||||
|
|||||||
@@ -381,6 +381,7 @@ static void __propagate_umount(struct mount *mnt)
|
|||||||
* other children
|
* other children
|
||||||
*/
|
*/
|
||||||
if (child && list_empty(&child->mnt_mounts)) {
|
if (child && list_empty(&child->mnt_mounts)) {
|
||||||
|
list_del_init(&child->mnt_child);
|
||||||
hlist_del_init_rcu(&child->mnt_hash);
|
hlist_del_init_rcu(&child->mnt_hash);
|
||||||
hlist_add_before_rcu(&child->mnt_hash, &mnt->mnt_hash);
|
hlist_add_before_rcu(&child->mnt_hash, &mnt->mnt_hash);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-5
@@ -902,9 +902,6 @@ void ufs_evict_inode(struct inode * inode)
|
|||||||
invalidate_inode_buffers(inode);
|
invalidate_inode_buffers(inode);
|
||||||
clear_inode(inode);
|
clear_inode(inode);
|
||||||
|
|
||||||
if (want_delete) {
|
if (want_delete)
|
||||||
lock_ufs(inode->i_sb);
|
ufs_free_inode(inode);
|
||||||
ufs_free_inode (inode);
|
|
||||||
unlock_ufs(inode->i_sb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-8
@@ -126,12 +126,12 @@ static int ufs_symlink (struct inode * dir, struct dentry * dentry,
|
|||||||
if (l > sb->s_blocksize)
|
if (l > sb->s_blocksize)
|
||||||
goto out_notlocked;
|
goto out_notlocked;
|
||||||
|
|
||||||
lock_ufs(dir->i_sb);
|
|
||||||
inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO);
|
inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO);
|
||||||
err = PTR_ERR(inode);
|
err = PTR_ERR(inode);
|
||||||
if (IS_ERR(inode))
|
if (IS_ERR(inode))
|
||||||
goto out;
|
goto out_notlocked;
|
||||||
|
|
||||||
|
lock_ufs(dir->i_sb);
|
||||||
if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) {
|
if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) {
|
||||||
/* slow symlink */
|
/* slow symlink */
|
||||||
inode->i_op = &ufs_symlink_inode_operations;
|
inode->i_op = &ufs_symlink_inode_operations;
|
||||||
@@ -181,13 +181,9 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
|
|||||||
struct inode * inode;
|
struct inode * inode;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
lock_ufs(dir->i_sb);
|
|
||||||
inode_inc_link_count(dir);
|
|
||||||
|
|
||||||
inode = ufs_new_inode(dir, S_IFDIR|mode);
|
inode = ufs_new_inode(dir, S_IFDIR|mode);
|
||||||
err = PTR_ERR(inode);
|
|
||||||
if (IS_ERR(inode))
|
if (IS_ERR(inode))
|
||||||
goto out_dir;
|
return PTR_ERR(inode);
|
||||||
|
|
||||||
inode->i_op = &ufs_dir_inode_operations;
|
inode->i_op = &ufs_dir_inode_operations;
|
||||||
inode->i_fop = &ufs_dir_operations;
|
inode->i_fop = &ufs_dir_operations;
|
||||||
@@ -195,6 +191,9 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
|
|||||||
|
|
||||||
inode_inc_link_count(inode);
|
inode_inc_link_count(inode);
|
||||||
|
|
||||||
|
lock_ufs(dir->i_sb);
|
||||||
|
inode_inc_link_count(dir);
|
||||||
|
|
||||||
err = ufs_make_empty(inode, dir);
|
err = ufs_make_empty(inode, dir);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_fail;
|
goto out_fail;
|
||||||
@@ -212,7 +211,6 @@ out_fail:
|
|||||||
inode_dec_link_count(inode);
|
inode_dec_link_count(inode);
|
||||||
inode_dec_link_count(inode);
|
inode_dec_link_count(inode);
|
||||||
iput (inode);
|
iput (inode);
|
||||||
out_dir:
|
|
||||||
inode_dec_link_count(dir);
|
inode_dec_link_count(dir);
|
||||||
unlock_ufs(dir->i_sb);
|
unlock_ufs(dir->i_sb);
|
||||||
goto out;
|
goto out;
|
||||||
|
|||||||
Reference in New Issue
Block a user