Skip to content

Commit b51ad67

Browse files
committed
Merge tag 'for-7.0-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs fixes from David Sterba: "A few more fixes. There's one that stands out in size as it fixes an edge case in fsync. - fix issue on fsync where file with zero size appears as a non-zero after log replay - in zlib compression, handle a crash when data alignment causes folio reference issues - fix possible crash with enabled tracepoints on a overlayfs mount - handle device stats update error - on zoned filesystems, fix kobject leak on sub-block groups - fix super block offset in an error message in validation" * tag 'for-7.0-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: btrfs: fix lost error when running device stats on multiple devices fs btrfs: tracepoints: get correct superblock from dentry in event btrfs_sync_file() btrfs: zlib: handle page aligned compressed size correctly btrfs: fix leak of kobject name for sub-group space_info btrfs: fix zero size inode with non-zero size after log replay btrfs: fix super block offset in error message in btrfs_validate_super()
2 parents 0bcb517 + 1c37d89 commit b51ad67

6 files changed

Lines changed: 81 additions & 43 deletions

File tree

fs/btrfs/block-group.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4583,7 +4583,7 @@ static void check_removing_space_info(struct btrfs_space_info *space_info)
45834583
for (int i = 0; i < BTRFS_SPACE_INFO_SUB_GROUP_MAX; i++) {
45844584
if (space_info->sub_group[i]) {
45854585
check_removing_space_info(space_info->sub_group[i]);
4586-
kfree(space_info->sub_group[i]);
4586+
btrfs_sysfs_remove_space_info(space_info->sub_group[i]);
45874587
space_info->sub_group[i] = NULL;
45884588
}
45894589
}

fs/btrfs/disk-io.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2531,8 +2531,8 @@ int btrfs_validate_super(const struct btrfs_fs_info *fs_info,
25312531

25322532
if (mirror_num >= 0 &&
25332533
btrfs_super_bytenr(sb) != btrfs_sb_offset(mirror_num)) {
2534-
btrfs_err(fs_info, "super offset mismatch %llu != %u",
2535-
btrfs_super_bytenr(sb), BTRFS_SUPER_INFO_OFFSET);
2534+
btrfs_err(fs_info, "super offset mismatch %llu != %llu",
2535+
btrfs_super_bytenr(sb), btrfs_sb_offset(mirror_num));
25362536
ret = -EINVAL;
25372537
}
25382538

fs/btrfs/tree-log.c

Lines changed: 65 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4616,21 +4616,32 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
46164616
struct inode *inode, bool log_inode_only,
46174617
u64 logged_isize)
46184618
{
4619+
u64 gen = BTRFS_I(inode)->generation;
46194620
u64 flags;
46204621

46214622
if (log_inode_only) {
4622-
/* set the generation to zero so the recover code
4623-
* can tell the difference between an logging
4624-
* just to say 'this inode exists' and a logging
4625-
* to say 'update this inode with these values'
4623+
/*
4624+
* Set the generation to zero so the recover code can tell the
4625+
* difference between a logging just to say 'this inode exists'
4626+
* and a logging to say 'update this inode with these values'.
4627+
* But only if the inode was not already logged before.
4628+
* We access ->logged_trans directly since it was already set
4629+
* up in the call chain by btrfs_log_inode(), and data_race()
4630+
* to avoid false alerts from KCSAN and since it was set already
4631+
* and one can set it to 0 since that only happens on eviction
4632+
* and we are holding a ref on the inode.
46264633
*/
4627-
btrfs_set_inode_generation(leaf, item, 0);
4634+
ASSERT(data_race(BTRFS_I(inode)->logged_trans) > 0);
4635+
if (data_race(BTRFS_I(inode)->logged_trans) < trans->transid)
4636+
gen = 0;
4637+
46284638
btrfs_set_inode_size(leaf, item, logged_isize);
46294639
} else {
4630-
btrfs_set_inode_generation(leaf, item, BTRFS_I(inode)->generation);
46314640
btrfs_set_inode_size(leaf, item, inode->i_size);
46324641
}
46334642

4643+
btrfs_set_inode_generation(leaf, item, gen);
4644+
46344645
btrfs_set_inode_uid(leaf, item, i_uid_read(inode));
46354646
btrfs_set_inode_gid(leaf, item, i_gid_read(inode));
46364647
btrfs_set_inode_mode(leaf, item, inode->i_mode);
@@ -5448,42 +5459,63 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans,
54485459
return 0;
54495460
}
54505461

5451-
static int logged_inode_size(struct btrfs_root *log, struct btrfs_inode *inode,
5452-
struct btrfs_path *path, u64 *size_ret)
5462+
static int get_inode_size_to_log(struct btrfs_trans_handle *trans,
5463+
struct btrfs_inode *inode,
5464+
struct btrfs_path *path, u64 *size_ret)
54535465
{
54545466
struct btrfs_key key;
5467+
struct btrfs_inode_item *item;
54555468
int ret;
54565469

54575470
key.objectid = btrfs_ino(inode);
54585471
key.type = BTRFS_INODE_ITEM_KEY;
54595472
key.offset = 0;
54605473

5461-
ret = btrfs_search_slot(NULL, log, &key, path, 0, 0);
5462-
if (ret < 0) {
5463-
return ret;
5464-
} else if (ret > 0) {
5465-
*size_ret = 0;
5466-
} else {
5467-
struct btrfs_inode_item *item;
5474+
/*
5475+
* Our caller called inode_logged(), so logged_trans is up to date.
5476+
* Use data_race() to silence any warning from KCSAN. Once logged_trans
5477+
* is set, it can only be reset to 0 after inode eviction.
5478+
*/
5479+
if (data_race(inode->logged_trans) == trans->transid) {
5480+
ret = btrfs_search_slot(NULL, inode->root->log_root, &key, path, 0, 0);
5481+
} else if (inode->generation < trans->transid) {
5482+
path->search_commit_root = true;
5483+
path->skip_locking = true;
5484+
ret = btrfs_search_slot(NULL, inode->root, &key, path, 0, 0);
5485+
path->search_commit_root = false;
5486+
path->skip_locking = false;
54685487

5469-
item = btrfs_item_ptr(path->nodes[0], path->slots[0],
5470-
struct btrfs_inode_item);
5471-
*size_ret = btrfs_inode_size(path->nodes[0], item);
5472-
/*
5473-
* If the in-memory inode's i_size is smaller then the inode
5474-
* size stored in the btree, return the inode's i_size, so
5475-
* that we get a correct inode size after replaying the log
5476-
* when before a power failure we had a shrinking truncate
5477-
* followed by addition of a new name (rename / new hard link).
5478-
* Otherwise return the inode size from the btree, to avoid
5479-
* data loss when replaying a log due to previously doing a
5480-
* write that expands the inode's size and logging a new name
5481-
* immediately after.
5482-
*/
5483-
if (*size_ret > inode->vfs_inode.i_size)
5484-
*size_ret = inode->vfs_inode.i_size;
5488+
} else {
5489+
*size_ret = 0;
5490+
return 0;
54855491
}
54865492

5493+
/*
5494+
* If the inode was logged before or is from a past transaction, then
5495+
* its inode item must exist in the log root or in the commit root.
5496+
*/
5497+
ASSERT(ret <= 0);
5498+
if (WARN_ON_ONCE(ret > 0))
5499+
ret = -ENOENT;
5500+
5501+
if (ret < 0)
5502+
return ret;
5503+
5504+
item = btrfs_item_ptr(path->nodes[0], path->slots[0],
5505+
struct btrfs_inode_item);
5506+
*size_ret = btrfs_inode_size(path->nodes[0], item);
5507+
/*
5508+
* If the in-memory inode's i_size is smaller then the inode size stored
5509+
* in the btree, return the inode's i_size, so that we get a correct
5510+
* inode size after replaying the log when before a power failure we had
5511+
* a shrinking truncate followed by addition of a new name (rename / new
5512+
* hard link). Otherwise return the inode size from the btree, to avoid
5513+
* data loss when replaying a log due to previously doing a write that
5514+
* expands the inode's size and logging a new name immediately after.
5515+
*/
5516+
if (*size_ret > inode->vfs_inode.i_size)
5517+
*size_ret = inode->vfs_inode.i_size;
5518+
54875519
btrfs_release_path(path);
54885520
return 0;
54895521
}
@@ -6996,7 +7028,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
69967028
ret = drop_inode_items(trans, log, path, inode,
69977029
BTRFS_XATTR_ITEM_KEY);
69987030
} else {
6999-
if (inode_only == LOG_INODE_EXISTS && ctx->logged_before) {
7031+
if (inode_only == LOG_INODE_EXISTS) {
70007032
/*
70017033
* Make sure the new inode item we write to the log has
70027034
* the same isize as the current one (if it exists).
@@ -7010,7 +7042,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
70107042
* (zeroes), as if an expanding truncate happened,
70117043
* instead of getting a file of 4Kb only.
70127044
*/
7013-
ret = logged_inode_size(log, inode, path, &logged_isize);
7045+
ret = get_inode_size_to_log(trans, inode, path, &logged_isize);
70147046
if (ret)
70157047
goto out_unlock;
70167048
}

fs/btrfs/volumes.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8099,8 +8099,9 @@ int btrfs_run_dev_stats(struct btrfs_trans_handle *trans)
80998099
smp_rmb();
81008100

81018101
ret = update_dev_stat_item(trans, device);
8102-
if (!ret)
8103-
atomic_sub(stats_cnt, &device->dev_stats_ccnt);
8102+
if (ret)
8103+
break;
8104+
atomic_sub(stats_cnt, &device->dev_stats_ccnt);
81048105
}
81058106
mutex_unlock(&fs_devices->device_list_mutex);
81068107

fs/btrfs/zlib.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,9 @@ int zlib_compress_bio(struct list_head *ws, struct compressed_bio *cb)
308308
}
309309
/* Queue the remaining part of the folio. */
310310
if (workspace->strm.total_out > bio->bi_iter.bi_size) {
311-
u32 cur_len = offset_in_folio(out_folio, workspace->strm.total_out);
311+
const u32 cur_len = workspace->strm.total_out - bio->bi_iter.bi_size;
312+
313+
ASSERT(cur_len <= folio_size(out_folio));
312314

313315
if (!bio_add_folio(bio, out_folio, cur_len, 0)) {
314316
ret = -E2BIG;

include/trace/events/btrfs.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -769,12 +769,15 @@ TRACE_EVENT(btrfs_sync_file,
769769
),
770770

771771
TP_fast_assign(
772-
const struct dentry *dentry = file->f_path.dentry;
773-
const struct inode *inode = d_inode(dentry);
772+
struct dentry *dentry = file_dentry(file);
773+
struct inode *inode = file_inode(file);
774+
struct dentry *parent = dget_parent(dentry);
775+
struct inode *parent_inode = d_inode(parent);
774776

775-
TP_fast_assign_fsid(btrfs_sb(file->f_path.dentry->d_sb));
777+
dput(parent);
778+
TP_fast_assign_fsid(btrfs_sb(inode->i_sb));
776779
__entry->ino = btrfs_ino(BTRFS_I(inode));
777-
__entry->parent = btrfs_ino(BTRFS_I(d_inode(dentry->d_parent)));
780+
__entry->parent = btrfs_ino(BTRFS_I(parent_inode));
778781
__entry->datasync = datasync;
779782
__entry->root_objectid = btrfs_root_id(BTRFS_I(inode)->root);
780783
),

0 commit comments

Comments
 (0)