diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-09-07 13:59:58 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-09-07 13:59:58 -0400 |
commit | 9142eadefe6aff23511fee143ee1bc9fc26a4c13 (patch) | |
tree | a66df501738e7f5bb06dfd7e0b2a564fd2c40361 /fs | |
parent | 81368f8bb8dd008f15d0300b89cbe1ffa7e675aa (diff) | |
parent | 9ef7db7f38d0472dd9c444e42d5c5175ccbe5451 (diff) |
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.
Diffstat (limited to 'fs')
-rw-r--r-- | fs/namespace.c | 10 | ||||
-rw-r--r-- | fs/pnode.c | 1 | ||||
-rw-r--r-- | fs/ufs/inode.c | 7 | ||||
-rw-r--r-- | fs/ufs/namei.c | 14 |
4 files changed, 18 insertions, 14 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index a01c7730e9af..ef42d9bee212 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -1217,6 +1217,11 @@ static void namespace_unlock(void) | |||
1217 | head.first->pprev = &head.first; | 1217 | head.first->pprev = &head.first; |
1218 | INIT_HLIST_HEAD(&unmounted); | 1218 | INIT_HLIST_HEAD(&unmounted); |
1219 | 1219 | ||
1220 | /* undo decrements we'd done in umount_tree() */ | ||
1221 | hlist_for_each_entry(mnt, &head, mnt_hash) | ||
1222 | if (mnt->mnt_ex_mountpoint.mnt) | ||
1223 | mntget(mnt->mnt_ex_mountpoint.mnt); | ||
1224 | |||
1220 | up_write(&namespace_sem); | 1225 | up_write(&namespace_sem); |
1221 | 1226 | ||
1222 | synchronize_rcu(); | 1227 | synchronize_rcu(); |
@@ -1253,6 +1258,9 @@ void umount_tree(struct mount *mnt, int how) | |||
1253 | hlist_add_head(&p->mnt_hash, &tmp_list); | 1258 | hlist_add_head(&p->mnt_hash, &tmp_list); |
1254 | } | 1259 | } |
1255 | 1260 | ||
1261 | hlist_for_each_entry(p, &tmp_list, mnt_hash) | ||
1262 | list_del_init(&p->mnt_child); | ||
1263 | |||
1256 | if (how) | 1264 | if (how) |
1257 | propagate_umount(&tmp_list); | 1265 | propagate_umount(&tmp_list); |
1258 | 1266 | ||
@@ -1263,9 +1271,9 @@ void umount_tree(struct mount *mnt, int how) | |||
1263 | p->mnt_ns = NULL; | 1271 | p->mnt_ns = NULL; |
1264 | if (how < 2) | 1272 | if (how < 2) |
1265 | p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; | 1273 | p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; |
1266 | list_del_init(&p->mnt_child); | ||
1267 | if (mnt_has_parent(p)) { | 1274 | if (mnt_has_parent(p)) { |
1268 | put_mountpoint(p->mnt_mp); | 1275 | put_mountpoint(p->mnt_mp); |
1276 | mnt_add_count(p->mnt_parent, -1); | ||
1269 | /* move the reference to mountpoint into ->mnt_ex_mountpoint */ | 1277 | /* move the reference to mountpoint into ->mnt_ex_mountpoint */ |
1270 | p->mnt_ex_mountpoint.dentry = p->mnt_mountpoint; | 1278 | p->mnt_ex_mountpoint.dentry = p->mnt_mountpoint; |
1271 | p->mnt_ex_mountpoint.mnt = &p->mnt_parent->mnt; | 1279 | p->mnt_ex_mountpoint.mnt = &p->mnt_parent->mnt; |
diff --git a/fs/pnode.c b/fs/pnode.c index 302bf22c4a30..aae331a5d03b 100644 --- a/fs/pnode.c +++ b/fs/pnode.c | |||
@@ -381,6 +381,7 @@ static void __propagate_umount(struct mount *mnt) | |||
381 | * other children | 381 | * other children |
382 | */ | 382 | */ |
383 | if (child && list_empty(&child->mnt_mounts)) { | 383 | if (child && list_empty(&child->mnt_mounts)) { |
384 | list_del_init(&child->mnt_child); | ||
384 | hlist_del_init_rcu(&child->mnt_hash); | 385 | hlist_del_init_rcu(&child->mnt_hash); |
385 | hlist_add_before_rcu(&child->mnt_hash, &mnt->mnt_hash); | 386 | hlist_add_before_rcu(&child->mnt_hash, &mnt->mnt_hash); |
386 | } | 387 | } |
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 7c580c97990e..be7d42c7d938 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c | |||
@@ -902,9 +902,6 @@ void ufs_evict_inode(struct inode * inode) | |||
902 | invalidate_inode_buffers(inode); | 902 | invalidate_inode_buffers(inode); |
903 | clear_inode(inode); | 903 | clear_inode(inode); |
904 | 904 | ||
905 | if (want_delete) { | 905 | if (want_delete) |
906 | lock_ufs(inode->i_sb); | 906 | ufs_free_inode(inode); |
907 | ufs_free_inode (inode); | ||
908 | unlock_ufs(inode->i_sb); | ||
909 | } | ||
910 | } | 907 | } |
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 90d74b8f8eba..2df62a73f20c 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c | |||
@@ -126,12 +126,12 @@ static int ufs_symlink (struct inode * dir, struct dentry * dentry, | |||
126 | if (l > sb->s_blocksize) | 126 | if (l > sb->s_blocksize) |
127 | goto out_notlocked; | 127 | goto out_notlocked; |
128 | 128 | ||
129 | lock_ufs(dir->i_sb); | ||
130 | inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO); | 129 | inode = ufs_new_inode(dir, S_IFLNK | S_IRWXUGO); |
131 | err = PTR_ERR(inode); | 130 | err = PTR_ERR(inode); |
132 | if (IS_ERR(inode)) | 131 | if (IS_ERR(inode)) |
133 | goto out; | 132 | goto out_notlocked; |
134 | 133 | ||
134 | lock_ufs(dir->i_sb); | ||
135 | if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) { | 135 | if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) { |
136 | /* slow symlink */ | 136 | /* slow symlink */ |
137 | inode->i_op = &ufs_symlink_inode_operations; | 137 | inode->i_op = &ufs_symlink_inode_operations; |
@@ -181,13 +181,9 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) | |||
181 | struct inode * inode; | 181 | struct inode * inode; |
182 | int err; | 182 | int err; |
183 | 183 | ||
184 | lock_ufs(dir->i_sb); | ||
185 | inode_inc_link_count(dir); | ||
186 | |||
187 | inode = ufs_new_inode(dir, S_IFDIR|mode); | 184 | inode = ufs_new_inode(dir, S_IFDIR|mode); |
188 | err = PTR_ERR(inode); | ||
189 | if (IS_ERR(inode)) | 185 | if (IS_ERR(inode)) |
190 | goto out_dir; | 186 | return PTR_ERR(inode); |
191 | 187 | ||
192 | inode->i_op = &ufs_dir_inode_operations; | 188 | inode->i_op = &ufs_dir_inode_operations; |
193 | inode->i_fop = &ufs_dir_operations; | 189 | inode->i_fop = &ufs_dir_operations; |
@@ -195,6 +191,9 @@ static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) | |||
195 | 191 | ||
196 | inode_inc_link_count(inode); | 192 | inode_inc_link_count(inode); |
197 | 193 | ||
194 | lock_ufs(dir->i_sb); | ||
195 | inode_inc_link_count(dir); | ||
196 | |||
198 | err = ufs_make_empty(inode, dir); | 197 | err = ufs_make_empty(inode, dir); |
199 | if (err) | 198 | if (err) |
200 | goto out_fail; | 199 | goto out_fail; |
@@ -212,7 +211,6 @@ out_fail: | |||
212 | inode_dec_link_count(inode); | 211 | inode_dec_link_count(inode); |
213 | inode_dec_link_count(inode); | 212 | inode_dec_link_count(inode); |
214 | iput (inode); | 213 | iput (inode); |
215 | out_dir: | ||
216 | inode_dec_link_count(dir); | 214 | inode_dec_link_count(dir); |
217 | unlock_ufs(dir->i_sb); | 215 | unlock_ufs(dir->i_sb); |
218 | goto out; | 216 | goto out; |