diff options
author | Jan Kara <jack@suse.cz> | 2017-06-13 10:20:25 -0400 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2017-06-14 05:21:01 -0400 |
commit | f2e95355891153f66d4156bf3a142c6489cd78c6 (patch) | |
tree | 1ed9e9466224522d8a6aaf2b0336b071f9a9324b /fs/udf | |
parent | 146c4ad6ec034a1fbfbf90ba76cb69b6504c374a (diff) |
udf: Fix deadlock between writeback and udf_setsize()
udf_setsize() called truncate_setsize() with i_data_sem held. Thus
truncate_pagecache() called from truncate_setsize() could lock a page
under i_data_sem which can deadlock as page lock ranks below
i_data_sem - e. g. writeback can hold page lock and try to acquire
i_data_sem to map a block.
Fix the problem by moving truncate_setsize() calls from under
i_data_sem. It is safe for us to change i_size without holding
i_data_sem as all the places that depend on i_size being stable already
hold inode_lock.
CC: stable@vger.kernel.org
Fixes: 7e49b6f2480cb9a9e7322a91592e56a5c85361f5
Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/udf')
-rw-r--r-- | fs/udf/inode.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 98c510e17203..18fdb9d90812 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c | |||
@@ -1222,8 +1222,8 @@ int udf_setsize(struct inode *inode, loff_t newsize) | |||
1222 | return err; | 1222 | return err; |
1223 | } | 1223 | } |
1224 | set_size: | 1224 | set_size: |
1225 | truncate_setsize(inode, newsize); | ||
1226 | up_write(&iinfo->i_data_sem); | 1225 | up_write(&iinfo->i_data_sem); |
1226 | truncate_setsize(inode, newsize); | ||
1227 | } else { | 1227 | } else { |
1228 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { | 1228 | if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { |
1229 | down_write(&iinfo->i_data_sem); | 1229 | down_write(&iinfo->i_data_sem); |
@@ -1240,9 +1240,9 @@ set_size: | |||
1240 | udf_get_block); | 1240 | udf_get_block); |
1241 | if (err) | 1241 | if (err) |
1242 | return err; | 1242 | return err; |
1243 | truncate_setsize(inode, newsize); | ||
1243 | down_write(&iinfo->i_data_sem); | 1244 | down_write(&iinfo->i_data_sem); |
1244 | udf_clear_extent_cache(inode); | 1245 | udf_clear_extent_cache(inode); |
1245 | truncate_setsize(inode, newsize); | ||
1246 | udf_truncate_extents(inode); | 1246 | udf_truncate_extents(inode); |
1247 | up_write(&iinfo->i_data_sem); | 1247 | up_write(&iinfo->i_data_sem); |
1248 | } | 1248 | } |