Skip to content

Commit 8832fc1

Browse files
committed
udf: Fix lock ordering in udf_evict_inode()
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]>
1 parent c1f1b25 commit 8832fc1

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
@@ -1248,7 +1248,6 @@ int udf_setsize(struct inode *inode, loff_t newsize)
12481248
S_ISLNK(inode->i_mode)))
12491249
return -EINVAL;
12501250

1251-
filemap_invalidate_lock(inode->i_mapping);
12521251
iinfo = UDF_I(inode);
12531252
if (newsize > inode->i_size) {
12541253
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
@@ -1261,11 +1260,11 @@ int udf_setsize(struct inode *inode, loff_t newsize)
12611260
}
12621261
err = udf_expand_file_adinicb(inode);
12631262
if (err)
1264-
goto out_unlock;
1263+
return err;
12651264
}
12661265
err = udf_extend_file(inode, newsize);
12671266
if (err)
1268-
goto out_unlock;
1267+
return err;
12691268
set_size:
12701269
truncate_setsize(inode, newsize);
12711270
} else {
@@ -1283,23 +1282,21 @@ int udf_setsize(struct inode *inode, loff_t newsize)
12831282
err = block_truncate_page(inode->i_mapping, newsize,
12841283
udf_get_block);
12851284
if (err)
1286-
goto out_unlock;
1285+
return err;
12871286
truncate_setsize(inode, newsize);
12881287
down_write(&iinfo->i_data_sem);
12891288
udf_clear_extent_cache(inode);
12901289
err = udf_truncate_extents(inode);
12911290
up_write(&iinfo->i_data_sem);
12921291
if (err)
1293-
goto out_unlock;
1292+
return err;
12941293
}
12951294
update_time:
12961295
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
12971296
if (IS_SYNC(inode))
12981297
udf_sync_inode(inode);
12991298
else
13001299
mark_inode_dirty(inode);
1301-
out_unlock:
1302-
filemap_invalidate_unlock(inode->i_mapping);
13031300
return err;
13041301
}
13051302

0 commit comments

Comments
 (0)