for-7.0-rc5-tag
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAmnIO1oACgkQxWXV+ddt
WDuLDQ//eWEAvqyA7ch+aLNm0QVHqsdH3NdVFjqw/3NsZfC9A3txTpQmmWpfqIUl
Yqb3AVIdRqwdytinn3xX17SxkJxzCWExcQ8LckoiJ2ODhLoi/vWGnaK8sUBzUDsm
2etvLGbDmhEEpkTMtIFkbY8fhprqthGCQgRHNrn/cZ+AzwohaboinvACysQJSLlH
Nqv0YxnAxsaGIaGD7wigjZ7a2BDoSZ/Q82+RvacrOkyqEThSOqzLmfl++fmHfxQo
UDzVOt9RSUnZ5LU4MYjF3H5otLczqKqRuoQC66ulIkvCml07jaKxfUVJyjkQ3dzZ
//UiylTXnC6XK/x1ayRrM73dKkXoN9mBmvH4b2FnOQJ3D3oyiCuytEF8s4nCrE+P
Zml+OTvIvWMj7Xy2U7cTMWuQGeggZ1m4nxCRScZBEnububUzt13izODwE7C8Cx1y
5FvfFIkiyeBrI03bWUO48H38lwWsfIKj6KnEk1SUeZIARClnZfM4NGZ7MbxjcntG
SunXzuQAywOZCkpskUDWMASLSH6CEGG4zgHPmbzw1NSCE5ZCHFZYXG7znv4w3CTW
TTeowG9r9cgdVBnMUTIToNWuD0jSMLmUfEPWvcwZF9ptfXdoABsPEQZTrKTLeiq7
TVdunKWzU12ZLr2sl4iku8U4H4aNQFoAwV3XqKnG8VXmzN41+Zw=
=I6JH
-----END PGP SIGNATURE-----
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()
master
commit
b51ad67773
|
|
@ -4583,7 +4583,7 @@ static void check_removing_space_info(struct btrfs_space_info *space_info)
|
|||
for (int i = 0; i < BTRFS_SPACE_INFO_SUB_GROUP_MAX; i++) {
|
||||
if (space_info->sub_group[i]) {
|
||||
check_removing_space_info(space_info->sub_group[i]);
|
||||
kfree(space_info->sub_group[i]);
|
||||
btrfs_sysfs_remove_space_info(space_info->sub_group[i]);
|
||||
space_info->sub_group[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2531,8 +2531,8 @@ int btrfs_validate_super(const struct btrfs_fs_info *fs_info,
|
|||
|
||||
if (mirror_num >= 0 &&
|
||||
btrfs_super_bytenr(sb) != btrfs_sb_offset(mirror_num)) {
|
||||
btrfs_err(fs_info, "super offset mismatch %llu != %u",
|
||||
btrfs_super_bytenr(sb), BTRFS_SUPER_INFO_OFFSET);
|
||||
btrfs_err(fs_info, "super offset mismatch %llu != %llu",
|
||||
btrfs_super_bytenr(sb), btrfs_sb_offset(mirror_num));
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4616,21 +4616,32 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
|
|||
struct inode *inode, bool log_inode_only,
|
||||
u64 logged_isize)
|
||||
{
|
||||
u64 gen = BTRFS_I(inode)->generation;
|
||||
u64 flags;
|
||||
|
||||
if (log_inode_only) {
|
||||
/* set the generation to zero so the recover code
|
||||
* can tell the difference between an logging
|
||||
* just to say 'this inode exists' and a logging
|
||||
* to say 'update this inode with these values'
|
||||
/*
|
||||
* Set the generation to zero so the recover code can tell the
|
||||
* difference between a logging just to say 'this inode exists'
|
||||
* and a logging to say 'update this inode with these values'.
|
||||
* But only if the inode was not already logged before.
|
||||
* We access ->logged_trans directly since it was already set
|
||||
* up in the call chain by btrfs_log_inode(), and data_race()
|
||||
* to avoid false alerts from KCSAN and since it was set already
|
||||
* and one can set it to 0 since that only happens on eviction
|
||||
* and we are holding a ref on the inode.
|
||||
*/
|
||||
btrfs_set_inode_generation(leaf, item, 0);
|
||||
ASSERT(data_race(BTRFS_I(inode)->logged_trans) > 0);
|
||||
if (data_race(BTRFS_I(inode)->logged_trans) < trans->transid)
|
||||
gen = 0;
|
||||
|
||||
btrfs_set_inode_size(leaf, item, logged_isize);
|
||||
} else {
|
||||
btrfs_set_inode_generation(leaf, item, BTRFS_I(inode)->generation);
|
||||
btrfs_set_inode_size(leaf, item, inode->i_size);
|
||||
}
|
||||
|
||||
btrfs_set_inode_generation(leaf, item, gen);
|
||||
|
||||
btrfs_set_inode_uid(leaf, item, i_uid_read(inode));
|
||||
btrfs_set_inode_gid(leaf, item, i_gid_read(inode));
|
||||
btrfs_set_inode_mode(leaf, item, inode->i_mode);
|
||||
|
|
@ -5448,42 +5459,63 @@ process:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int logged_inode_size(struct btrfs_root *log, struct btrfs_inode *inode,
|
||||
struct btrfs_path *path, u64 *size_ret)
|
||||
static int get_inode_size_to_log(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_inode *inode,
|
||||
struct btrfs_path *path, u64 *size_ret)
|
||||
{
|
||||
struct btrfs_key key;
|
||||
struct btrfs_inode_item *item;
|
||||
int ret;
|
||||
|
||||
key.objectid = btrfs_ino(inode);
|
||||
key.type = BTRFS_INODE_ITEM_KEY;
|
||||
key.offset = 0;
|
||||
|
||||
ret = btrfs_search_slot(NULL, log, &key, path, 0, 0);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
} else if (ret > 0) {
|
||||
*size_ret = 0;
|
||||
} else {
|
||||
struct btrfs_inode_item *item;
|
||||
/*
|
||||
* Our caller called inode_logged(), so logged_trans is up to date.
|
||||
* Use data_race() to silence any warning from KCSAN. Once logged_trans
|
||||
* is set, it can only be reset to 0 after inode eviction.
|
||||
*/
|
||||
if (data_race(inode->logged_trans) == trans->transid) {
|
||||
ret = btrfs_search_slot(NULL, inode->root->log_root, &key, path, 0, 0);
|
||||
} else if (inode->generation < trans->transid) {
|
||||
path->search_commit_root = true;
|
||||
path->skip_locking = true;
|
||||
ret = btrfs_search_slot(NULL, inode->root, &key, path, 0, 0);
|
||||
path->search_commit_root = false;
|
||||
path->skip_locking = false;
|
||||
|
||||
item = btrfs_item_ptr(path->nodes[0], path->slots[0],
|
||||
struct btrfs_inode_item);
|
||||
*size_ret = btrfs_inode_size(path->nodes[0], item);
|
||||
/*
|
||||
* If the in-memory inode's i_size is smaller then the inode
|
||||
* size stored in the btree, return the inode's i_size, so
|
||||
* that we get a correct inode size after replaying the log
|
||||
* when before a power failure we had a shrinking truncate
|
||||
* followed by addition of a new name (rename / new hard link).
|
||||
* Otherwise return the inode size from the btree, to avoid
|
||||
* data loss when replaying a log due to previously doing a
|
||||
* write that expands the inode's size and logging a new name
|
||||
* immediately after.
|
||||
*/
|
||||
if (*size_ret > inode->vfs_inode.i_size)
|
||||
*size_ret = inode->vfs_inode.i_size;
|
||||
} else {
|
||||
*size_ret = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the inode was logged before or is from a past transaction, then
|
||||
* its inode item must exist in the log root or in the commit root.
|
||||
*/
|
||||
ASSERT(ret <= 0);
|
||||
if (WARN_ON_ONCE(ret > 0))
|
||||
ret = -ENOENT;
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
item = btrfs_item_ptr(path->nodes[0], path->slots[0],
|
||||
struct btrfs_inode_item);
|
||||
*size_ret = btrfs_inode_size(path->nodes[0], item);
|
||||
/*
|
||||
* If the in-memory inode's i_size is smaller then the inode size stored
|
||||
* in the btree, return the inode's i_size, so that we get a correct
|
||||
* inode size after replaying the log when before a power failure we had
|
||||
* a shrinking truncate followed by addition of a new name (rename / new
|
||||
* hard link). Otherwise return the inode size from the btree, to avoid
|
||||
* data loss when replaying a log due to previously doing a write that
|
||||
* expands the inode's size and logging a new name immediately after.
|
||||
*/
|
||||
if (*size_ret > inode->vfs_inode.i_size)
|
||||
*size_ret = inode->vfs_inode.i_size;
|
||||
|
||||
btrfs_release_path(path);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -6996,7 +7028,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
|
|||
ret = drop_inode_items(trans, log, path, inode,
|
||||
BTRFS_XATTR_ITEM_KEY);
|
||||
} else {
|
||||
if (inode_only == LOG_INODE_EXISTS && ctx->logged_before) {
|
||||
if (inode_only == LOG_INODE_EXISTS) {
|
||||
/*
|
||||
* Make sure the new inode item we write to the log has
|
||||
* the same isize as the current one (if it exists).
|
||||
|
|
@ -7010,7 +7042,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
|
|||
* (zeroes), as if an expanding truncate happened,
|
||||
* instead of getting a file of 4Kb only.
|
||||
*/
|
||||
ret = logged_inode_size(log, inode, path, &logged_isize);
|
||||
ret = get_inode_size_to_log(trans, inode, path, &logged_isize);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8099,8 +8099,9 @@ int btrfs_run_dev_stats(struct btrfs_trans_handle *trans)
|
|||
smp_rmb();
|
||||
|
||||
ret = update_dev_stat_item(trans, device);
|
||||
if (!ret)
|
||||
atomic_sub(stats_cnt, &device->dev_stats_ccnt);
|
||||
if (ret)
|
||||
break;
|
||||
atomic_sub(stats_cnt, &device->dev_stats_ccnt);
|
||||
}
|
||||
mutex_unlock(&fs_devices->device_list_mutex);
|
||||
|
||||
|
|
|
|||
|
|
@ -308,7 +308,9 @@ int zlib_compress_bio(struct list_head *ws, struct compressed_bio *cb)
|
|||
}
|
||||
/* Queue the remaining part of the folio. */
|
||||
if (workspace->strm.total_out > bio->bi_iter.bi_size) {
|
||||
u32 cur_len = offset_in_folio(out_folio, workspace->strm.total_out);
|
||||
const u32 cur_len = workspace->strm.total_out - bio->bi_iter.bi_size;
|
||||
|
||||
ASSERT(cur_len <= folio_size(out_folio));
|
||||
|
||||
if (!bio_add_folio(bio, out_folio, cur_len, 0)) {
|
||||
ret = -E2BIG;
|
||||
|
|
|
|||
|
|
@ -769,12 +769,15 @@ TRACE_EVENT(btrfs_sync_file,
|
|||
),
|
||||
|
||||
TP_fast_assign(
|
||||
const struct dentry *dentry = file->f_path.dentry;
|
||||
const struct inode *inode = d_inode(dentry);
|
||||
struct dentry *dentry = file_dentry(file);
|
||||
struct inode *inode = file_inode(file);
|
||||
struct dentry *parent = dget_parent(dentry);
|
||||
struct inode *parent_inode = d_inode(parent);
|
||||
|
||||
TP_fast_assign_fsid(btrfs_sb(file->f_path.dentry->d_sb));
|
||||
dput(parent);
|
||||
TP_fast_assign_fsid(btrfs_sb(inode->i_sb));
|
||||
__entry->ino = btrfs_ino(BTRFS_I(inode));
|
||||
__entry->parent = btrfs_ino(BTRFS_I(d_inode(dentry->d_parent)));
|
||||
__entry->parent = btrfs_ino(BTRFS_I(parent_inode));
|
||||
__entry->datasync = datasync;
|
||||
__entry->root_objectid = btrfs_root_id(BTRFS_I(inode)->root);
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in New Issue