Skip to content

Commit 711e9a4

Browse files
committed
Merge tag 'for-6.2-rc7-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: - one more fix for a tree-log 'write time corruption' report, update the last dir index directly and don't keep in the log context - do VFS-level inode lock around FIEMAP to prevent a deadlock with concurrent fsync, the extent-level lock is not sufficient - don't cache a single-device filesystem device to avoid cases when a loop device is reformatted and the entry gets stale * tag 'for-6.2-rc7-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: free device in btrfs_close_devices for a single device filesystem btrfs: lock the inode in shared mode before starting fiemap btrfs: simplify update of last_dir_index_offset when logging a directory
2 parents e2bca0e + 5f58d78 commit 711e9a4

File tree

4 files changed

+34
-9
lines changed

4 files changed

+34
-9
lines changed

fs/btrfs/extent_io.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3826,6 +3826,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
38263826
lockend = round_up(start + len, inode->root->fs_info->sectorsize);
38273827
prev_extent_end = lockstart;
38283828

3829+
btrfs_inode_lock(inode, BTRFS_ILOCK_SHARED);
38293830
lock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
38303831

38313832
ret = fiemap_find_last_extent_offset(inode, path, &last_extent_end);
@@ -4019,6 +4020,7 @@ int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
40194020

40204021
out_unlock:
40214022
unlock_extent(&inode->io_tree, lockstart, lockend, &cached_state);
4023+
btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
40224024
out:
40234025
free_extent_state(delalloc_cached_state);
40244026
btrfs_free_backref_share_ctx(backref_ctx);

fs/btrfs/tree-log.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3576,17 +3576,19 @@ static noinline int insert_dir_log_key(struct btrfs_trans_handle *trans,
35763576
}
35773577

35783578
static int flush_dir_items_batch(struct btrfs_trans_handle *trans,
3579-
struct btrfs_root *log,
3579+
struct btrfs_inode *inode,
35803580
struct extent_buffer *src,
35813581
struct btrfs_path *dst_path,
35823582
int start_slot,
35833583
int count)
35843584
{
3585+
struct btrfs_root *log = inode->root->log_root;
35853586
char *ins_data = NULL;
35863587
struct btrfs_item_batch batch;
35873588
struct extent_buffer *dst;
35883589
unsigned long src_offset;
35893590
unsigned long dst_offset;
3591+
u64 last_index;
35903592
struct btrfs_key key;
35913593
u32 item_size;
35923594
int ret;
@@ -3644,6 +3646,19 @@ static int flush_dir_items_batch(struct btrfs_trans_handle *trans,
36443646
src_offset = btrfs_item_ptr_offset(src, start_slot + count - 1);
36453647
copy_extent_buffer(dst, src, dst_offset, src_offset, batch.total_data_size);
36463648
btrfs_release_path(dst_path);
3649+
3650+
last_index = batch.keys[count - 1].offset;
3651+
ASSERT(last_index > inode->last_dir_index_offset);
3652+
3653+
/*
3654+
* If for some unexpected reason the last item's index is not greater
3655+
* than the last index we logged, warn and return an error to fallback
3656+
* to a transaction commit.
3657+
*/
3658+
if (WARN_ON(last_index <= inode->last_dir_index_offset))
3659+
ret = -EUCLEAN;
3660+
else
3661+
inode->last_dir_index_offset = last_index;
36473662
out:
36483663
kfree(ins_data);
36493664

@@ -3693,7 +3708,6 @@ static int process_dir_items_leaf(struct btrfs_trans_handle *trans,
36933708
}
36943709

36953710
di = btrfs_item_ptr(src, i, struct btrfs_dir_item);
3696-
ctx->last_dir_item_offset = key.offset;
36973711

36983712
/*
36993713
* Skip ranges of items that consist only of dir item keys created
@@ -3756,7 +3770,7 @@ static int process_dir_items_leaf(struct btrfs_trans_handle *trans,
37563770
if (batch_size > 0) {
37573771
int ret;
37583772

3759-
ret = flush_dir_items_batch(trans, log, src, dst_path,
3773+
ret = flush_dir_items_batch(trans, inode, src, dst_path,
37603774
batch_start, batch_size);
37613775
if (ret < 0)
37623776
return ret;
@@ -4044,7 +4058,6 @@ static noinline int log_directory_changes(struct btrfs_trans_handle *trans,
40444058

40454059
min_key = BTRFS_DIR_START_INDEX;
40464060
max_key = 0;
4047-
ctx->last_dir_item_offset = inode->last_dir_index_offset;
40484061

40494062
while (1) {
40504063
ret = log_dir_items(trans, inode, path, dst_path,
@@ -4056,8 +4069,6 @@ static noinline int log_directory_changes(struct btrfs_trans_handle *trans,
40564069
min_key = max_key + 1;
40574070
}
40584071

4059-
inode->last_dir_index_offset = ctx->last_dir_item_offset;
4060-
40614072
return 0;
40624073
}
40634074

fs/btrfs/tree-log.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ struct btrfs_log_ctx {
2424
bool logging_new_delayed_dentries;
2525
/* Indicate if the inode being logged was logged before. */
2626
bool logged_before;
27-
/* Tracks the last logged dir item/index key offset. */
28-
u64 last_dir_item_offset;
2927
struct inode *inode;
3028
struct list_head list;
3129
/* Only used for fast fsyncs. */

fs/btrfs/volumes.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ void btrfs_free_device(struct btrfs_device *device)
403403
static void free_fs_devices(struct btrfs_fs_devices *fs_devices)
404404
{
405405
struct btrfs_device *device;
406+
406407
WARN_ON(fs_devices->opened);
407408
while (!list_empty(&fs_devices->devices)) {
408409
device = list_entry(fs_devices->devices.next,
@@ -1181,9 +1182,22 @@ void btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
11811182

11821183
mutex_lock(&uuid_mutex);
11831184
close_fs_devices(fs_devices);
1184-
if (!fs_devices->opened)
1185+
if (!fs_devices->opened) {
11851186
list_splice_init(&fs_devices->seed_list, &list);
11861187

1188+
/*
1189+
* If the struct btrfs_fs_devices is not assembled with any
1190+
* other device, it can be re-initialized during the next mount
1191+
* without the needing device-scan step. Therefore, it can be
1192+
* fully freed.
1193+
*/
1194+
if (fs_devices->num_devices == 1) {
1195+
list_del(&fs_devices->fs_list);
1196+
free_fs_devices(fs_devices);
1197+
}
1198+
}
1199+
1200+
11871201
list_for_each_entry_safe(fs_devices, tmp, &list, seed_list) {
11881202
close_fs_devices(fs_devices);
11891203
list_del(&fs_devices->seed_list);

0 commit comments

Comments
 (0)