Skip to content

Commit e382588

Browse files
jankaragregkh
authored andcommitted
udf: Fix lock ordering in udf_evict_inode()
[ Upstream commit 8832fc1 ] udf_evict_inode() calls udf_setsize() to truncate deleted inode. However inode deletion through udf_evict_inode() can happen from inode reclaim context and udf_setsize() grabs mapping->invalidate_lock which isn't generally safe to acquire from fs reclaim context since we allocate pages under mapping->invalidate_lock for example in a page fault path. This is however not a real deadlock possibility as by the time udf_evict_inode() is called, nobody can be accessing the inode, even less work with its page cache. So this is just a lockdep triggering false positive. Fix the problem by moving mapping->invalidate_lock locking outsize of udf_setsize() into udf_setattr() as grabbing mapping->invalidate_lock from udf_evict_inode() is pointless. Reported-by: [email protected] Fixes: b9a861f ("udf: Protect truncate and file type conversion with invalidate_lock") Signed-off-by: Jan Kara <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent be953b4 commit e382588

File tree

2 files changed

+6
-7
lines changed

2 files changed

+6
-7
lines changed

fs/udf/file.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,9 @@ static int udf_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
232232

233233
if ((attr->ia_valid & ATTR_SIZE) &&
234234
attr->ia_size != i_size_read(inode)) {
235+
filemap_invalidate_lock(inode->i_mapping);
235236
error = udf_setsize(inode, attr->ia_size);
237+
filemap_invalidate_unlock(inode->i_mapping);
236238
if (error)
237239
return error;
238240
}

fs/udf/inode.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,7 +1252,6 @@ int udf_setsize(struct inode *inode, loff_t newsize)
12521252
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
12531253
return -EPERM;
12541254

1255-
filemap_invalidate_lock(inode->i_mapping);
12561255
iinfo = UDF_I(inode);
12571256
if (newsize > inode->i_size) {
12581257
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
@@ -1265,11 +1264,11 @@ int udf_setsize(struct inode *inode, loff_t newsize)
12651264
}
12661265
err = udf_expand_file_adinicb(inode);
12671266
if (err)
1268-
goto out_unlock;
1267+
return err;
12691268
}
12701269
err = udf_extend_file(inode, newsize);
12711270
if (err)
1272-
goto out_unlock;
1271+
return err;
12731272
set_size:
12741273
truncate_setsize(inode, newsize);
12751274
} else {
@@ -1287,23 +1286,21 @@ int udf_setsize(struct inode *inode, loff_t newsize)
12871286
err = block_truncate_page(inode->i_mapping, newsize,
12881287
udf_get_block);
12891288
if (err)
1290-
goto out_unlock;
1289+
return err;
12911290
truncate_setsize(inode, newsize);
12921291
down_write(&iinfo->i_data_sem);
12931292
udf_clear_extent_cache(inode);
12941293
err = udf_truncate_extents(inode);
12951294
up_write(&iinfo->i_data_sem);
12961295
if (err)
1297-
goto out_unlock;
1296+
return err;
12981297
}
12991298
update_time:
13001299
inode->i_mtime = inode_set_ctime_current(inode);
13011300
if (IS_SYNC(inode))
13021301
udf_sync_inode(inode);
13031302
else
13041303
mark_inode_dirty(inode);
1305-
out_unlock:
1306-
filemap_invalidate_unlock(inode->i_mapping);
13071304
return err;
13081305
}
13091306

0 commit comments

Comments
 (0)