Skip to content

Commit a1fb2fc

Browse files
committed
Merge tag 'for-6.12-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: - fix dangling pointer to rb-tree of defragmented inodes after cleanup - a followup fix to handle concurrent lseek on the same fd that could leak memory under some conditions - fix wrong root id reported in tree checker when verifying dref * tag 'for-6.12-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: fix use-after-free on rbtree that tracks inodes for auto defrag btrfs: tree-checker: fix the wrong output of data backref objectid btrfs: fix race setting file private on concurrent lseek using same fd
2 parents d0359e4 + 7f1b63f commit a1fb2fc

File tree

5 files changed

+37
-4
lines changed

5 files changed

+37
-4
lines changed

fs/btrfs/btrfs_inode.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ struct btrfs_inode {
152152
* logged_trans), to access/update delalloc_bytes, new_delalloc_bytes,
153153
* defrag_bytes, disk_i_size, outstanding_extents, csum_bytes and to
154154
* update the VFS' inode number of bytes used.
155+
* Also protects setting struct file::private_data.
155156
*/
156157
spinlock_t lock;
157158

fs/btrfs/ctree.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,8 @@ struct btrfs_file_private {
463463
void *filldir_buf;
464464
u64 last_index;
465465
struct extent_state *llseek_cached_state;
466+
/* Task that allocated this structure. */
467+
struct task_struct *owner_task;
466468
};
467469

468470
static inline u32 BTRFS_LEAF_DATA_SIZE(const struct btrfs_fs_info *info)

fs/btrfs/defrag.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info)
213213
&fs_info->defrag_inodes, rb_node)
214214
kmem_cache_free(btrfs_inode_defrag_cachep, defrag);
215215

216+
fs_info->defrag_inodes = RB_ROOT;
217+
216218
spin_unlock(&fs_info->defrag_inodes_lock);
217219
}
218220

fs/btrfs/file.c

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3485,7 +3485,7 @@ static bool find_desired_extent_in_hole(struct btrfs_inode *inode, int whence,
34853485
static loff_t find_desired_extent(struct file *file, loff_t offset, int whence)
34863486
{
34873487
struct btrfs_inode *inode = BTRFS_I(file->f_mapping->host);
3488-
struct btrfs_file_private *private = file->private_data;
3488+
struct btrfs_file_private *private;
34893489
struct btrfs_fs_info *fs_info = inode->root->fs_info;
34903490
struct extent_state *cached_state = NULL;
34913491
struct extent_state **delalloc_cached_state;
@@ -3513,15 +3513,43 @@ static loff_t find_desired_extent(struct file *file, loff_t offset, int whence)
35133513
inode_get_bytes(&inode->vfs_inode) == i_size)
35143514
return i_size;
35153515

3516-
if (!private) {
3516+
spin_lock(&inode->lock);
3517+
private = file->private_data;
3518+
spin_unlock(&inode->lock);
3519+
3520+
if (private && private->owner_task != current) {
3521+
/*
3522+
* Not allocated by us, don't use it as its cached state is used
3523+
* by the task that allocated it and we don't want neither to
3524+
* mess with it nor get incorrect results because it reflects an
3525+
* invalid state for the current task.
3526+
*/
3527+
private = NULL;
3528+
} else if (!private) {
35173529
private = kzalloc(sizeof(*private), GFP_KERNEL);
35183530
/*
35193531
* No worries if memory allocation failed.
35203532
* The private structure is used only for speeding up multiple
35213533
* lseek SEEK_HOLE/DATA calls to a file when there's delalloc,
35223534
* so everything will still be correct.
35233535
*/
3524-
file->private_data = private;
3536+
if (private) {
3537+
bool free = false;
3538+
3539+
private->owner_task = current;
3540+
3541+
spin_lock(&inode->lock);
3542+
if (file->private_data)
3543+
free = true;
3544+
else
3545+
file->private_data = private;
3546+
spin_unlock(&inode->lock);
3547+
3548+
if (free) {
3549+
kfree(private);
3550+
private = NULL;
3551+
}
3552+
}
35253553
}
35263554

35273555
if (private)

fs/btrfs/tree-checker.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1517,7 +1517,7 @@ static int check_extent_item(struct extent_buffer *leaf,
15171517
dref_objectid > BTRFS_LAST_FREE_OBJECTID)) {
15181518
extent_err(leaf, slot,
15191519
"invalid data ref objectid value %llu",
1520-
dref_root);
1520+
dref_objectid);
15211521
return -EUCLEAN;
15221522
}
15231523
if (unlikely(!IS_ALIGNED(dref_offset,

0 commit comments

Comments
 (0)