mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'for-6.19-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs updates from David Sterba:
"Features:
- shutdown ioctl support (needs CONFIG_BTRFS_EXPERIMENTAL for now):
- set filesystem state as being shut down (also named going down
in other filesystems), where all active operations return EIO
and this cannot be changed until unmount
- pending operations are attempted to be finished but error
messages may still show up depending on where exactly the
shutdown happened
- scrub (and device replace) vs suspend/hibernate:
- a running scrub will prevent suspend, which can be annoying as
suspend is an immediate request and scrub is not critical
- filesystem freezing before suspend was not sufficient as the
problem was in process freezing
- behaviour change: on suspend scrub and device replace are
cancelled, where scrub can record the last state and continue
from there; the device replace has to be restarted from the
beginning
- zone stats exported in sysfs, from the perspective of the
filesystem this includes active, reclaimable, relocation etc zones
Performance:
- improvements when processing space reservation tickets by
optimizing locking and shrinking critical sections, cumulative
improvements in lockstat numbers show +15%
Notable fixes:
- use vmalloc fallback when allocating bios as high order allocations
can happen with wide checksums (like sha256)
- scrub will always track the last position of progress so it's not
starting from zero after an error
Core:
- under experimental config, checksum calculations are offloaded to
process context, simplifies locking and allows to remove
compression write worker kthread(s):
- speed improvement in direct IO throughput with buffered IO
fallback is +15% when not offloaded but this is more related to
internal crypto subsystem improvements
- this will be probably default in the future removing the sysfs
tunable
- (experimental) block size > page size updates:
- support more operations when not using large folios (encoded
read/write and send)
- raid56
- more preparations for fscrypt support
Other:
- more conversions to auto-cleaned variables
- parameter cleanups and removals
- extended warning fixes
- improved printing of structured values like keys
- lots of other cleanups and refactoring"
* tag 'for-6.19-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: (147 commits)
btrfs: remove unnecessary inode key in btrfs_log_all_parents()
btrfs: remove redundant zero/NULL initializations in btrfs_alloc_root()
btrfs: remaining BTRFS_PATH_AUTO_FREE conversions
btrfs: send: do not allocate memory for xattr data when checking it exists
btrfs: send: add unlikely to all unexpected overflow checks
btrfs: reduce arguments to btrfs_del_inode_ref_in_log()
btrfs: remove root argument from btrfs_del_dir_entries_in_log()
btrfs: use test_and_set_bit() in btrfs_delayed_delete_inode_ref()
btrfs: don't search back for dir inode item in INO_LOOKUP_USER
btrfs: don't rewrite ret from inode_permission
btrfs: add orig_logical to btrfs_bio for encryption
btrfs: disable verity on encrypted inodes
btrfs: disable various operations on encrypted inodes
btrfs: remove redundant level reset in btrfs_del_items()
btrfs: simplify leaf traversal after path release in btrfs_next_old_leaf()
btrfs: optimize balance_level() path reference handling
btrfs: factor out root promotion logic into promote_child_to_root()
btrfs: raid56: remove the "_step" infix
btrfs: raid56: enable bs > ps support
btrfs: raid56: prepare finish_parity_scrub() to support bs > ps cases
...
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/mm.h>
|
||||
#include <uapi/linux/btrfs_tree.h>
|
||||
#include "fs.h"
|
||||
#include "extent_io.h"
|
||||
|
||||
struct extent_buffer;
|
||||
|
||||
+10
-15
@@ -14,12 +14,13 @@
|
||||
#include "ctree.h"
|
||||
#include "xattr.h"
|
||||
#include "acl.h"
|
||||
#include "misc.h"
|
||||
|
||||
struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu)
|
||||
{
|
||||
int size;
|
||||
const char *name;
|
||||
char *value = NULL;
|
||||
char AUTO_KFREE(value);
|
||||
struct posix_acl *acl;
|
||||
|
||||
if (rcu)
|
||||
@@ -49,7 +50,6 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu)
|
||||
acl = NULL;
|
||||
else
|
||||
acl = ERR_PTR(size);
|
||||
kfree(value);
|
||||
|
||||
return acl;
|
||||
}
|
||||
@@ -59,7 +59,7 @@ int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
|
||||
{
|
||||
int ret, size = 0;
|
||||
const char *name;
|
||||
char *value = NULL;
|
||||
char AUTO_KFREE(value);
|
||||
|
||||
switch (type) {
|
||||
case ACL_TYPE_ACCESS:
|
||||
@@ -85,28 +85,23 @@ int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
|
||||
nofs_flag = memalloc_nofs_save();
|
||||
value = kmalloc(size, GFP_KERNEL);
|
||||
memalloc_nofs_restore(nofs_flag);
|
||||
if (!value) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if (!value)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (trans)
|
||||
ret = btrfs_setxattr(trans, inode, name, value, size, 0);
|
||||
else
|
||||
ret = btrfs_setxattr_trans(inode, name, value, size, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
out:
|
||||
kfree(value);
|
||||
|
||||
if (!ret)
|
||||
set_cached_acl(inode, type, acl);
|
||||
|
||||
return ret;
|
||||
set_cached_acl(inode, type, acl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
|
||||
+14
-23
@@ -666,10 +666,9 @@ static int resolve_indirect_ref(struct btrfs_backref_walk_ctx *ctx,
|
||||
ret = btrfs_search_old_slot(root, &search_key, path, ctx->time_seq);
|
||||
|
||||
btrfs_debug(ctx->fs_info,
|
||||
"search slot in root %llu (level %d, ref count %d) returned %d for key (%llu %u %llu)",
|
||||
ref->root_id, level, ref->count, ret,
|
||||
ref->key_for_search.objectid, ref->key_for_search.type,
|
||||
ref->key_for_search.offset);
|
||||
"search slot in root %llu (level %d, ref count %d) returned %d for key " BTRFS_KEY_FMT,
|
||||
ref->root_id, level, ref->count, ret,
|
||||
BTRFS_KEY_FMT_VALUE(&ref->key_for_search));
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
@@ -1409,12 +1408,12 @@ static int find_parent_nodes(struct btrfs_backref_walk_ctx *ctx,
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
if (!ctx->trans) {
|
||||
path->search_commit_root = 1;
|
||||
path->skip_locking = 1;
|
||||
path->search_commit_root = true;
|
||||
path->skip_locking = true;
|
||||
}
|
||||
|
||||
if (ctx->time_seq == BTRFS_SEQ_LAST)
|
||||
path->skip_locking = 1;
|
||||
path->skip_locking = true;
|
||||
|
||||
again:
|
||||
head = NULL;
|
||||
@@ -1561,7 +1560,7 @@ again:
|
||||
|
||||
btrfs_release_path(path);
|
||||
|
||||
ret = add_missing_keys(ctx->fs_info, &preftrees, path->skip_locking == 0);
|
||||
ret = add_missing_keys(ctx->fs_info, &preftrees, !path->skip_locking);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@@ -2786,7 +2785,7 @@ struct btrfs_data_container *init_data_container(u32 total_bytes)
|
||||
* allocates space to return multiple file system paths for an inode.
|
||||
* total_bytes to allocate are passed, note that space usable for actual path
|
||||
* information will be total_bytes - sizeof(struct inode_fs_paths).
|
||||
* the returned pointer must be freed with free_ipath() in the end.
|
||||
* the returned pointer must be freed with __free_inode_fs_paths() in the end.
|
||||
*/
|
||||
struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root,
|
||||
struct btrfs_path *path)
|
||||
@@ -2811,14 +2810,6 @@ struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root,
|
||||
return ifp;
|
||||
}
|
||||
|
||||
void free_ipath(struct inode_fs_paths *ipath)
|
||||
{
|
||||
if (!ipath)
|
||||
return;
|
||||
kvfree(ipath->fspath);
|
||||
kfree(ipath);
|
||||
}
|
||||
|
||||
struct btrfs_backref_iter *btrfs_backref_iter_alloc(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
struct btrfs_backref_iter *ret;
|
||||
@@ -2834,8 +2825,8 @@ struct btrfs_backref_iter *btrfs_backref_iter_alloc(struct btrfs_fs_info *fs_inf
|
||||
}
|
||||
|
||||
/* Current backref iterator only supports iteration in commit root */
|
||||
ret->path->search_commit_root = 1;
|
||||
ret->path->skip_locking = 1;
|
||||
ret->path->search_commit_root = true;
|
||||
ret->path->skip_locking = true;
|
||||
ret->fs_info = fs_info;
|
||||
|
||||
return ret;
|
||||
@@ -3308,8 +3299,8 @@ static int handle_indirect_tree_backref(struct btrfs_trans_handle *trans,
|
||||
level = cur->level + 1;
|
||||
|
||||
/* Search the tree to find parent blocks referring to the block */
|
||||
path->search_commit_root = 1;
|
||||
path->skip_locking = 1;
|
||||
path->search_commit_root = true;
|
||||
path->skip_locking = true;
|
||||
path->lowest_level = level;
|
||||
ret = btrfs_search_slot(NULL, root, tree_key, path, 0, 0);
|
||||
path->lowest_level = 0;
|
||||
@@ -3323,9 +3314,9 @@ static int handle_indirect_tree_backref(struct btrfs_trans_handle *trans,
|
||||
eb = path->nodes[level];
|
||||
if (btrfs_node_blockptr(eb, path->slots[level]) != cur->bytenr) {
|
||||
btrfs_err(fs_info,
|
||||
"couldn't find block (%llu) (level %d) in tree (%llu) with key (%llu %u %llu)",
|
||||
"couldn't find block (%llu) (level %d) in tree (%llu) with key " BTRFS_KEY_FMT,
|
||||
cur->bytenr, level - 1, btrfs_root_id(root),
|
||||
tree_key->objectid, tree_key->type, tree_key->offset);
|
||||
BTRFS_KEY_FMT_VALUE(tree_key));
|
||||
btrfs_put_root(root);
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
|
||||
+6
-1
@@ -241,7 +241,12 @@ char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
|
||||
struct btrfs_data_container *init_data_container(u32 total_bytes);
|
||||
struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root,
|
||||
struct btrfs_path *path);
|
||||
void free_ipath(struct inode_fs_paths *ipath);
|
||||
|
||||
DEFINE_FREE(inode_fs_paths, struct inode_fs_paths *,
|
||||
if (_T) {
|
||||
kvfree(_T->fspath);
|
||||
kfree(_T);
|
||||
})
|
||||
|
||||
int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
|
||||
u64 start_off, struct btrfs_path *path,
|
||||
|
||||
+202
-88
File diff suppressed because it is too large
Load Diff
+24
-15
@@ -18,13 +18,6 @@ struct btrfs_inode;
|
||||
|
||||
#define BTRFS_BIO_INLINE_CSUM_SIZE 64
|
||||
|
||||
/*
|
||||
* Maximum number of sectors for a single bio to limit the size of the
|
||||
* checksum array. This matches the number of bio_vecs per bio and thus the
|
||||
* I/O size for buffered I/O.
|
||||
*/
|
||||
#define BTRFS_MAX_BIO_SECTORS (256)
|
||||
|
||||
typedef void (*btrfs_bio_end_io_t)(struct btrfs_bio *bbio);
|
||||
|
||||
/*
|
||||
@@ -34,7 +27,10 @@ typedef void (*btrfs_bio_end_io_t)(struct btrfs_bio *bbio);
|
||||
struct btrfs_bio {
|
||||
/*
|
||||
* Inode and offset into it that this I/O operates on.
|
||||
* Only set for data I/O.
|
||||
*
|
||||
* If the inode is a data one, csum verification and read-repair
|
||||
* will be done automatically.
|
||||
* If the inode is a metadata one, everything is handled by the caller.
|
||||
*/
|
||||
struct btrfs_inode *inode;
|
||||
u64 file_offset;
|
||||
@@ -56,11 +52,16 @@ struct btrfs_bio {
|
||||
* - pointer to the checksums for this bio
|
||||
* - original physical address from the allocator
|
||||
* (for zone append only)
|
||||
* - original logical address, used for checksumming fscrypt bios
|
||||
*/
|
||||
struct {
|
||||
struct btrfs_ordered_extent *ordered;
|
||||
struct btrfs_ordered_sum *sums;
|
||||
struct work_struct csum_work;
|
||||
struct completion csum_done;
|
||||
struct bvec_iter csum_saved_iter;
|
||||
u64 orig_physical;
|
||||
u64 orig_logical;
|
||||
};
|
||||
|
||||
/* For metadata reads: parentness verification. */
|
||||
@@ -76,14 +77,21 @@ struct btrfs_bio {
|
||||
atomic_t pending_ios;
|
||||
struct work_struct end_io_work;
|
||||
|
||||
/* File system that this I/O operates on. */
|
||||
struct btrfs_fs_info *fs_info;
|
||||
|
||||
/* Save the first error status of split bio. */
|
||||
blk_status_t status;
|
||||
|
||||
/* Use the commit root to look up csums (data read bio only). */
|
||||
bool csum_search_commit_root;
|
||||
|
||||
/*
|
||||
* Since scrub will reuse btree inode, we need this flag to distinguish
|
||||
* scrub bios.
|
||||
*/
|
||||
bool is_scrub;
|
||||
|
||||
/* Whether the csum generation for data write is async. */
|
||||
bool async_csum;
|
||||
|
||||
/*
|
||||
* This member must come last, bio_alloc_bioset will allocate enough
|
||||
* bytes for entire btrfs_bio but relies on bio being last.
|
||||
@@ -99,10 +107,10 @@ static inline struct btrfs_bio *btrfs_bio(struct bio *bio)
|
||||
int __init btrfs_bioset_init(void);
|
||||
void __cold btrfs_bioset_exit(void);
|
||||
|
||||
void btrfs_bio_init(struct btrfs_bio *bbio, struct btrfs_fs_info *fs_info,
|
||||
void btrfs_bio_init(struct btrfs_bio *bbio, struct btrfs_inode *inode, u64 file_offset,
|
||||
btrfs_bio_end_io_t end_io, void *private);
|
||||
struct btrfs_bio *btrfs_bio_alloc(unsigned int nr_vecs, blk_opf_t opf,
|
||||
struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_inode *inode, u64 file_offset,
|
||||
btrfs_bio_end_io_t end_io, void *private);
|
||||
void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status);
|
||||
|
||||
@@ -111,7 +119,8 @@ void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status);
|
||||
|
||||
void btrfs_submit_bbio(struct btrfs_bio *bbio, int mirror_num);
|
||||
void btrfs_submit_repair_write(struct btrfs_bio *bbio, int mirror_num, bool dev_replace);
|
||||
int btrfs_repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 start,
|
||||
u64 length, u64 logical, phys_addr_t paddr, int mirror_num);
|
||||
int btrfs_repair_io_failure(struct btrfs_fs_info *fs_info, u64 ino, u64 fileoff,
|
||||
u32 length, u64 logical, const phys_addr_t paddrs[],
|
||||
unsigned int step, int mirror_num);
|
||||
|
||||
#endif
|
||||
|
||||
+46
-37
@@ -613,8 +613,8 @@ static int sample_block_group_extent_item(struct btrfs_caching_control *caching_
|
||||
extent_root = btrfs_extent_root(fs_info, max_t(u64, block_group->start,
|
||||
BTRFS_SUPER_INFO_OFFSET));
|
||||
|
||||
path->skip_locking = 1;
|
||||
path->search_commit_root = 1;
|
||||
path->skip_locking = true;
|
||||
path->search_commit_root = true;
|
||||
path->reada = READA_FORWARD;
|
||||
|
||||
search_offset = index * div_u64(block_group->length, max_index);
|
||||
@@ -744,8 +744,8 @@ static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl)
|
||||
* root to add free space. So we skip locking and search the commit
|
||||
* root, since its read-only
|
||||
*/
|
||||
path->skip_locking = 1;
|
||||
path->search_commit_root = 1;
|
||||
path->skip_locking = true;
|
||||
path->search_commit_root = true;
|
||||
path->reada = READA_FORWARD;
|
||||
|
||||
key.objectid = last;
|
||||
@@ -1065,7 +1065,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_chunk_map *map)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = trans->fs_info;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct btrfs_block_group *block_group;
|
||||
struct btrfs_free_cluster *cluster;
|
||||
struct inode *inode;
|
||||
@@ -1305,7 +1305,6 @@ out:
|
||||
btrfs_put_block_group(block_group);
|
||||
if (remove_rsv)
|
||||
btrfs_dec_delayed_refs_rsv_bg_updates(fs_info);
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1403,8 +1402,7 @@ static int inc_block_group_ro(struct btrfs_block_group *cache, bool force)
|
||||
* BTRFS_RESERVE_NO_FLUSH to give ourselves the most amount of
|
||||
* leeway to allow us to mark this block group as read only.
|
||||
*/
|
||||
if (btrfs_can_overcommit(cache->fs_info, sinfo, num_bytes,
|
||||
BTRFS_RESERVE_NO_FLUSH))
|
||||
if (btrfs_can_overcommit(sinfo, num_bytes, BTRFS_RESERVE_NO_FLUSH))
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
@@ -1425,7 +1423,7 @@ out:
|
||||
if (ret == -ENOSPC && btrfs_test_opt(cache->fs_info, ENOSPC_DEBUG)) {
|
||||
btrfs_info(cache->fs_info,
|
||||
"unable to make block group %llu ro", cache->start);
|
||||
btrfs_dump_space_info(cache->fs_info, cache->space_info, 0, false);
|
||||
btrfs_dump_space_info(cache->space_info, 0, false);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -3068,7 +3066,7 @@ int btrfs_inc_block_group_ro(struct btrfs_block_group *cache,
|
||||
* We have allocated a new chunk. We also need to activate that chunk to
|
||||
* grant metadata tickets for zoned filesystem.
|
||||
*/
|
||||
ret = btrfs_zoned_activate_one_bg(fs_info, space_info, true);
|
||||
ret = btrfs_zoned_activate_one_bg(space_info, true);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
@@ -3799,7 +3797,7 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
|
||||
* reservation and return -EAGAIN, otherwise this function always succeeds.
|
||||
*/
|
||||
int btrfs_add_reserved_bytes(struct btrfs_block_group *cache,
|
||||
u64 ram_bytes, u64 num_bytes, int delalloc,
|
||||
u64 ram_bytes, u64 num_bytes, bool delalloc,
|
||||
bool force_wrong_size_class)
|
||||
{
|
||||
struct btrfs_space_info *space_info = cache->space_info;
|
||||
@@ -3810,30 +3808,38 @@ int btrfs_add_reserved_bytes(struct btrfs_block_group *cache,
|
||||
spin_lock(&cache->lock);
|
||||
if (cache->ro) {
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
if (btrfs_block_group_should_use_size_class(cache)) {
|
||||
size_class = btrfs_calc_block_group_size_class(num_bytes);
|
||||
ret = btrfs_use_block_group_size_class(cache, size_class, force_wrong_size_class);
|
||||
if (ret)
|
||||
goto out;
|
||||
goto out_error;
|
||||
}
|
||||
|
||||
cache->reserved += num_bytes;
|
||||
space_info->bytes_reserved += num_bytes;
|
||||
trace_btrfs_space_reservation(cache->fs_info, "space_info",
|
||||
space_info->flags, num_bytes, 1);
|
||||
btrfs_space_info_update_bytes_may_use(space_info, -ram_bytes);
|
||||
if (delalloc)
|
||||
cache->delalloc_bytes += num_bytes;
|
||||
|
||||
trace_btrfs_space_reservation(cache->fs_info, "space_info",
|
||||
space_info->flags, num_bytes, 1);
|
||||
spin_unlock(&cache->lock);
|
||||
|
||||
space_info->bytes_reserved += num_bytes;
|
||||
btrfs_space_info_update_bytes_may_use(space_info, -ram_bytes);
|
||||
|
||||
/*
|
||||
* Compression can use less space than we reserved, so wake tickets if
|
||||
* that happens.
|
||||
*/
|
||||
if (num_bytes < ram_bytes)
|
||||
btrfs_try_granting_tickets(cache->fs_info, space_info);
|
||||
out:
|
||||
btrfs_try_granting_tickets(space_info);
|
||||
spin_unlock(&space_info->lock);
|
||||
|
||||
return 0;
|
||||
|
||||
out_error:
|
||||
spin_unlock(&cache->lock);
|
||||
spin_unlock(&space_info->lock);
|
||||
return ret;
|
||||
@@ -3855,22 +3861,25 @@ void btrfs_free_reserved_bytes(struct btrfs_block_group *cache, u64 num_bytes,
|
||||
bool is_delalloc)
|
||||
{
|
||||
struct btrfs_space_info *space_info = cache->space_info;
|
||||
bool bg_ro;
|
||||
|
||||
spin_lock(&space_info->lock);
|
||||
spin_lock(&cache->lock);
|
||||
if (cache->ro)
|
||||
space_info->bytes_readonly += num_bytes;
|
||||
else if (btrfs_is_zoned(cache->fs_info))
|
||||
space_info->bytes_zone_unusable += num_bytes;
|
||||
bg_ro = cache->ro;
|
||||
cache->reserved -= num_bytes;
|
||||
space_info->bytes_reserved -= num_bytes;
|
||||
space_info->max_extent_size = 0;
|
||||
|
||||
if (is_delalloc)
|
||||
cache->delalloc_bytes -= num_bytes;
|
||||
spin_unlock(&cache->lock);
|
||||
|
||||
btrfs_try_granting_tickets(cache->fs_info, space_info);
|
||||
if (bg_ro)
|
||||
space_info->bytes_readonly += num_bytes;
|
||||
else if (btrfs_is_zoned(cache->fs_info))
|
||||
space_info->bytes_zone_unusable += num_bytes;
|
||||
|
||||
space_info->bytes_reserved -= num_bytes;
|
||||
space_info->max_extent_size = 0;
|
||||
|
||||
btrfs_try_granting_tickets(space_info);
|
||||
spin_unlock(&space_info->lock);
|
||||
}
|
||||
|
||||
@@ -4188,11 +4197,11 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans,
|
||||
should_alloc = should_alloc_chunk(fs_info, space_info, force);
|
||||
if (space_info->full) {
|
||||
/* No more free physical space */
|
||||
spin_unlock(&space_info->lock);
|
||||
if (should_alloc)
|
||||
ret = -ENOSPC;
|
||||
else
|
||||
ret = 0;
|
||||
spin_unlock(&space_info->lock);
|
||||
return ret;
|
||||
} else if (!should_alloc) {
|
||||
spin_unlock(&space_info->lock);
|
||||
@@ -4204,16 +4213,16 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans,
|
||||
* recheck if we should continue with our allocation
|
||||
* attempt.
|
||||
*/
|
||||
spin_unlock(&space_info->lock);
|
||||
wait_for_alloc = true;
|
||||
force = CHUNK_ALLOC_NO_FORCE;
|
||||
spin_unlock(&space_info->lock);
|
||||
mutex_lock(&fs_info->chunk_mutex);
|
||||
mutex_unlock(&fs_info->chunk_mutex);
|
||||
} else {
|
||||
/* Proceed with allocation */
|
||||
space_info->chunk_alloc = 1;
|
||||
wait_for_alloc = false;
|
||||
space_info->chunk_alloc = true;
|
||||
spin_unlock(&space_info->lock);
|
||||
wait_for_alloc = false;
|
||||
}
|
||||
|
||||
cond_resched();
|
||||
@@ -4260,7 +4269,7 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans,
|
||||
spin_lock(&space_info->lock);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOSPC)
|
||||
space_info->full = 1;
|
||||
space_info->full = true;
|
||||
else
|
||||
goto out;
|
||||
} else {
|
||||
@@ -4270,7 +4279,7 @@ int btrfs_chunk_alloc(struct btrfs_trans_handle *trans,
|
||||
|
||||
space_info->force_alloc = CHUNK_ALLOC_NO_FORCE;
|
||||
out:
|
||||
space_info->chunk_alloc = 0;
|
||||
space_info->chunk_alloc = false;
|
||||
spin_unlock(&space_info->lock);
|
||||
mutex_unlock(&fs_info->chunk_mutex);
|
||||
|
||||
@@ -4311,7 +4320,7 @@ static void reserve_chunk_space(struct btrfs_trans_handle *trans,
|
||||
if (left < bytes && btrfs_test_opt(fs_info, ENOSPC_DEBUG)) {
|
||||
btrfs_info(fs_info, "left=%llu, need=%llu, flags=%llu",
|
||||
left, bytes, type);
|
||||
btrfs_dump_space_info(fs_info, info, 0, false);
|
||||
btrfs_dump_space_info(info, 0, false);
|
||||
}
|
||||
|
||||
if (left < bytes) {
|
||||
@@ -4336,7 +4345,7 @@ static void reserve_chunk_space(struct btrfs_trans_handle *trans,
|
||||
* We have a new chunk. We also need to activate it for
|
||||
* zoned filesystem.
|
||||
*/
|
||||
ret = btrfs_zoned_activate_one_bg(fs_info, info, true);
|
||||
ret = btrfs_zoned_activate_one_bg(info, true);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
@@ -4456,7 +4465,7 @@ static void check_removing_space_info(struct btrfs_space_info *space_info)
|
||||
* indicates a real bug if this happens.
|
||||
*/
|
||||
if (WARN_ON(space_info->bytes_pinned > 0 || space_info->bytes_may_use > 0))
|
||||
btrfs_dump_space_info(info, space_info, 0, false);
|
||||
btrfs_dump_space_info(space_info, 0, false);
|
||||
|
||||
/*
|
||||
* If there was a failure to cleanup a log tree, very likely due to an
|
||||
@@ -4467,7 +4476,7 @@ static void check_removing_space_info(struct btrfs_space_info *space_info)
|
||||
if (!(space_info->flags & BTRFS_BLOCK_GROUP_METADATA) ||
|
||||
!BTRFS_FS_LOG_CLEANUP_ERROR(info)) {
|
||||
if (WARN_ON(space_info->bytes_reserved > 0))
|
||||
btrfs_dump_space_info(info, space_info, 0, false);
|
||||
btrfs_dump_space_info(space_info, 0, false);
|
||||
}
|
||||
|
||||
WARN_ON(space_info->reclaim_size > 0);
|
||||
|
||||
@@ -345,7 +345,7 @@ int btrfs_setup_space_cache(struct btrfs_trans_handle *trans);
|
||||
int btrfs_update_block_group(struct btrfs_trans_handle *trans,
|
||||
u64 bytenr, u64 num_bytes, bool alloc);
|
||||
int btrfs_add_reserved_bytes(struct btrfs_block_group *cache,
|
||||
u64 ram_bytes, u64 num_bytes, int delalloc,
|
||||
u64 ram_bytes, u64 num_bytes, bool delalloc,
|
||||
bool force_wrong_size_class);
|
||||
void btrfs_free_reserved_bytes(struct btrfs_block_group *cache, u64 num_bytes,
|
||||
bool is_delalloc);
|
||||
|
||||
@@ -218,8 +218,7 @@ int btrfs_block_rsv_add(struct btrfs_fs_info *fs_info,
|
||||
if (num_bytes == 0)
|
||||
return 0;
|
||||
|
||||
ret = btrfs_reserve_metadata_bytes(fs_info, block_rsv->space_info,
|
||||
num_bytes, flush);
|
||||
ret = btrfs_reserve_metadata_bytes(block_rsv->space_info, num_bytes, flush);
|
||||
if (!ret)
|
||||
btrfs_block_rsv_add_bytes(block_rsv, num_bytes, true);
|
||||
|
||||
@@ -259,8 +258,7 @@ int btrfs_block_rsv_refill(struct btrfs_fs_info *fs_info,
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
ret = btrfs_reserve_metadata_bytes(fs_info, block_rsv->space_info,
|
||||
num_bytes, flush);
|
||||
ret = btrfs_reserve_metadata_bytes(block_rsv->space_info, num_bytes, flush);
|
||||
if (!ret) {
|
||||
btrfs_block_rsv_add_bytes(block_rsv, num_bytes, false);
|
||||
return 0;
|
||||
@@ -387,7 +385,7 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info)
|
||||
num_bytes = block_rsv->reserved - block_rsv->size;
|
||||
btrfs_space_info_update_bytes_may_use(sinfo, -num_bytes);
|
||||
block_rsv->reserved = block_rsv->size;
|
||||
btrfs_try_granting_tickets(fs_info, sinfo);
|
||||
btrfs_try_granting_tickets(sinfo);
|
||||
}
|
||||
|
||||
block_rsv->full = (block_rsv->reserved == block_rsv->size);
|
||||
@@ -530,8 +528,8 @@ again:
|
||||
block_rsv->type, ret);
|
||||
}
|
||||
try_reserve:
|
||||
ret = btrfs_reserve_metadata_bytes(fs_info, block_rsv->space_info,
|
||||
blocksize, BTRFS_RESERVE_NO_FLUSH);
|
||||
ret = btrfs_reserve_metadata_bytes(block_rsv->space_info, blocksize,
|
||||
BTRFS_RESERVE_NO_FLUSH);
|
||||
if (!ret)
|
||||
return block_rsv;
|
||||
/*
|
||||
@@ -552,7 +550,7 @@ try_reserve:
|
||||
* one last time to force a reservation if there's enough actual space
|
||||
* on disk to make the reservation.
|
||||
*/
|
||||
ret = btrfs_reserve_metadata_bytes(fs_info, block_rsv->space_info, blocksize,
|
||||
ret = btrfs_reserve_metadata_bytes(block_rsv->space_info, blocksize,
|
||||
BTRFS_RESERVE_FLUSH_EMERGENCY);
|
||||
if (!ret)
|
||||
return block_rsv;
|
||||
|
||||
+9
-11
@@ -18,20 +18,20 @@
|
||||
#include <linux/lockdep.h>
|
||||
#include <uapi/linux/btrfs_tree.h>
|
||||
#include <trace/events/btrfs.h>
|
||||
#include "ctree.h"
|
||||
#include "block-rsv.h"
|
||||
#include "extent_map.h"
|
||||
#include "extent_io.h"
|
||||
#include "extent-io-tree.h"
|
||||
#include "ordered-data.h"
|
||||
#include "delayed-inode.h"
|
||||
|
||||
struct extent_state;
|
||||
struct posix_acl;
|
||||
struct iov_iter;
|
||||
struct writeback_control;
|
||||
struct btrfs_root;
|
||||
struct btrfs_fs_info;
|
||||
struct btrfs_trans_handle;
|
||||
struct btrfs_bio;
|
||||
struct btrfs_file_extent;
|
||||
struct btrfs_delayed_node;
|
||||
|
||||
/*
|
||||
* Since we search a directory based on f_pos (struct dir_context::pos) we have
|
||||
@@ -543,16 +543,14 @@ static inline void btrfs_set_inode_mapping_order(struct btrfs_inode *inode)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Array of bytes with variable length, hexadecimal format 0x1234 */
|
||||
#define CSUM_FMT "0x%*phN"
|
||||
#define CSUM_FMT_VALUE(size, bytes) size, bytes
|
||||
|
||||
void btrfs_calculate_block_csum(struct btrfs_fs_info *fs_info, phys_addr_t paddr,
|
||||
u8 *dest);
|
||||
void btrfs_calculate_block_csum_folio(struct btrfs_fs_info *fs_info,
|
||||
const phys_addr_t paddr, u8 *dest);
|
||||
void btrfs_calculate_block_csum_pages(struct btrfs_fs_info *fs_info,
|
||||
const phys_addr_t paddrs[], u8 *dest);
|
||||
int btrfs_check_block_csum(struct btrfs_fs_info *fs_info, phys_addr_t paddr, u8 *csum,
|
||||
const u8 * const csum_expected);
|
||||
bool btrfs_data_csum_ok(struct btrfs_bio *bbio, struct btrfs_device *dev,
|
||||
u32 bio_offset, phys_addr_t paddr);
|
||||
u32 bio_offset, const phys_addr_t paddrs[]);
|
||||
noinline int can_nocow_extent(struct btrfs_inode *inode, u64 offset, u64 *len,
|
||||
struct btrfs_file_extent *file_extent,
|
||||
bool nowait);
|
||||
|
||||
+16
-31
@@ -67,9 +67,7 @@ static struct compressed_bio *alloc_compressed_bio(struct btrfs_inode *inode,
|
||||
|
||||
bbio = btrfs_bio(bio_alloc_bioset(NULL, BTRFS_MAX_COMPRESSED_PAGES, op,
|
||||
GFP_NOFS, &btrfs_compressed_bioset));
|
||||
btrfs_bio_init(bbio, inode->root->fs_info, end_io, NULL);
|
||||
bbio->inode = inode;
|
||||
bbio->file_offset = start;
|
||||
btrfs_bio_init(bbio, inode, start, end_io, NULL);
|
||||
return to_compressed_bio(bbio);
|
||||
}
|
||||
|
||||
@@ -194,15 +192,13 @@ static unsigned long btrfs_compr_pool_count(struct shrinker *sh, struct shrink_c
|
||||
|
||||
static unsigned long btrfs_compr_pool_scan(struct shrinker *sh, struct shrink_control *sc)
|
||||
{
|
||||
struct list_head remove;
|
||||
LIST_HEAD(remove);
|
||||
struct list_head *tmp, *next;
|
||||
int freed;
|
||||
|
||||
if (compr_pool.count == 0)
|
||||
return SHRINK_STOP;
|
||||
|
||||
INIT_LIST_HEAD(&remove);
|
||||
|
||||
/* For now, just simply drain the whole list. */
|
||||
spin_lock(&compr_pool.lock);
|
||||
list_splice_init(&compr_pool.list, &remove);
|
||||
@@ -321,22 +317,6 @@ static noinline void end_compressed_writeback(const struct compressed_bio *cb)
|
||||
/* the inode may be gone now */
|
||||
}
|
||||
|
||||
static void btrfs_finish_compressed_write_work(struct work_struct *work)
|
||||
{
|
||||
struct compressed_bio *cb =
|
||||
container_of(work, struct compressed_bio, write_end_work);
|
||||
|
||||
btrfs_finish_ordered_extent(cb->bbio.ordered, NULL, cb->start, cb->len,
|
||||
cb->bbio.bio.bi_status == BLK_STS_OK);
|
||||
|
||||
if (cb->writeback)
|
||||
end_compressed_writeback(cb);
|
||||
/* Note, our inode could be gone now */
|
||||
|
||||
btrfs_free_compressed_folios(cb);
|
||||
bio_put(&cb->bbio.bio);
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the cleanup once all the compressed pages hit the disk. This will clear
|
||||
* writeback on the file pages and free the compressed pages.
|
||||
@@ -347,28 +327,33 @@ static void btrfs_finish_compressed_write_work(struct work_struct *work)
|
||||
static void end_bbio_compressed_write(struct btrfs_bio *bbio)
|
||||
{
|
||||
struct compressed_bio *cb = to_compressed_bio(bbio);
|
||||
struct btrfs_fs_info *fs_info = bbio->inode->root->fs_info;
|
||||
|
||||
queue_work(fs_info->compressed_write_workers, &cb->write_end_work);
|
||||
btrfs_finish_ordered_extent(cb->bbio.ordered, NULL, cb->start, cb->len,
|
||||
cb->bbio.bio.bi_status == BLK_STS_OK);
|
||||
|
||||
if (cb->writeback)
|
||||
end_compressed_writeback(cb);
|
||||
/* Note, our inode could be gone now. */
|
||||
btrfs_free_compressed_folios(cb);
|
||||
bio_put(&cb->bbio.bio);
|
||||
}
|
||||
|
||||
static void btrfs_add_compressed_bio_folios(struct compressed_bio *cb)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = cb->bbio.fs_info;
|
||||
struct bio *bio = &cb->bbio.bio;
|
||||
u32 offset = 0;
|
||||
unsigned int findex = 0;
|
||||
|
||||
while (offset < cb->compressed_len) {
|
||||
struct folio *folio;
|
||||
struct folio *folio = cb->compressed_folios[findex];
|
||||
u32 len = min_t(u32, cb->compressed_len - offset, folio_size(folio));
|
||||
int ret;
|
||||
u32 len = min_t(u32, cb->compressed_len - offset,
|
||||
btrfs_min_folio_size(fs_info));
|
||||
|
||||
folio = cb->compressed_folios[offset >> (PAGE_SHIFT + fs_info->block_min_order)];
|
||||
/* Maximum compressed extent is smaller than bio size limit. */
|
||||
ret = bio_add_folio(bio, folio, len, 0);
|
||||
ASSERT(ret);
|
||||
offset += len;
|
||||
findex++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,7 +387,6 @@ void btrfs_submit_compressed_write(struct btrfs_ordered_extent *ordered,
|
||||
cb->compressed_folios = compressed_folios;
|
||||
cb->compressed_len = ordered->disk_num_bytes;
|
||||
cb->writeback = writeback;
|
||||
INIT_WORK(&cb->write_end_work, btrfs_finish_compressed_write_work);
|
||||
cb->nr_folios = nr_folios;
|
||||
cb->bbio.bio.bi_iter.bi_sector = ordered->disk_bytenr >> SECTOR_SHIFT;
|
||||
cb->bbio.ordered = ordered;
|
||||
@@ -1100,7 +1084,8 @@ static int btrfs_decompress_bio(struct compressed_bio *cb)
|
||||
/*
|
||||
* a less complex decompression routine. Our compressed data fits in a
|
||||
* single page, and we want to read a single page out of it.
|
||||
* start_byte tells us the offset into the compressed data we're interested in
|
||||
* dest_pgoff tells us the offset into the destination folio where we write the
|
||||
* decompressed data.
|
||||
*/
|
||||
int btrfs_decompress(int type, const u8 *data_in, struct folio *dest_folio,
|
||||
unsigned long dest_pgoff, size_t srclen, size_t destlen)
|
||||
|
||||
+5
-10
@@ -14,14 +14,12 @@
|
||||
#include <linux/pagemap.h>
|
||||
#include "bio.h"
|
||||
#include "fs.h"
|
||||
#include "messages.h"
|
||||
#include "btrfs_inode.h"
|
||||
|
||||
struct address_space;
|
||||
struct page;
|
||||
struct inode;
|
||||
struct btrfs_inode;
|
||||
struct btrfs_ordered_extent;
|
||||
struct btrfs_bio;
|
||||
|
||||
/*
|
||||
* We want to make sure that amount of RAM required to uncompress an extent is
|
||||
@@ -65,11 +63,8 @@ struct compressed_bio {
|
||||
/* Whether this is a write for writeback. */
|
||||
bool writeback;
|
||||
|
||||
union {
|
||||
/* For reads, this is the bio we are copying the data into */
|
||||
struct btrfs_bio *orig_bbio;
|
||||
struct work_struct write_end_work;
|
||||
};
|
||||
/* For reads, this is the bio we are copying the data into. */
|
||||
struct btrfs_bio *orig_bbio;
|
||||
|
||||
/* Must be last. */
|
||||
struct btrfs_bio bbio;
|
||||
@@ -77,7 +72,7 @@ struct compressed_bio {
|
||||
|
||||
static inline struct btrfs_fs_info *cb_to_fs_info(const struct compressed_bio *cb)
|
||||
{
|
||||
return cb->bbio.fs_info;
|
||||
return cb->bbio.inode->root->fs_info;
|
||||
}
|
||||
|
||||
/* @range_end must be exclusive. */
|
||||
@@ -100,7 +95,7 @@ int btrfs_compress_folios(unsigned int type, int level, struct btrfs_inode *inod
|
||||
u64 start, struct folio **folios, unsigned long *out_folios,
|
||||
unsigned long *total_in, unsigned long *total_out);
|
||||
int btrfs_decompress(int type, const u8 *data_in, struct folio *dest_folio,
|
||||
unsigned long start_byte, size_t srclen, size_t destlen);
|
||||
unsigned long dest_pgoff, size_t srclen, size_t destlen);
|
||||
int btrfs_decompress_buf2page(const char *buf, u32 buf_len,
|
||||
struct compressed_bio *cb, u32 decompressed);
|
||||
|
||||
|
||||
+124
-116
@@ -861,6 +861,75 @@ struct extent_buffer *btrfs_read_node_slot(struct extent_buffer *parent,
|
||||
return eb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Promote a child node to become the new tree root.
|
||||
*
|
||||
* @trans: Transaction handle
|
||||
* @root: Tree root structure to update
|
||||
* @path: Path holding nodes and locks
|
||||
* @level: Level of the parent (old root)
|
||||
* @parent: The parent (old root) with exactly one item
|
||||
*
|
||||
* This helper is called during rebalancing when the root node contains only
|
||||
* a single item (nritems == 1). We can reduce the tree height by promoting
|
||||
* that child to become the new root and freeing the old root node. The path
|
||||
* locks and references are updated accordingly.
|
||||
*
|
||||
* Return: 0 on success, negative errno on failure. The transaction is aborted
|
||||
* on critical errors.
|
||||
*/
|
||||
static int promote_child_to_root(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct btrfs_path *path,
|
||||
int level, struct extent_buffer *parent)
|
||||
{
|
||||
struct extent_buffer *child;
|
||||
int ret;
|
||||
|
||||
ASSERT(btrfs_header_nritems(parent) == 1);
|
||||
|
||||
child = btrfs_read_node_slot(parent, 0);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
btrfs_tree_lock(child);
|
||||
ret = btrfs_cow_block(trans, root, child, parent, 0, &child, BTRFS_NESTING_COW);
|
||||
if (ret) {
|
||||
btrfs_tree_unlock(child);
|
||||
free_extent_buffer(child);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = btrfs_tree_mod_log_insert_root(root->node, child, true);
|
||||
if (unlikely(ret < 0)) {
|
||||
btrfs_tree_unlock(child);
|
||||
free_extent_buffer(child);
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
return ret;
|
||||
}
|
||||
rcu_assign_pointer(root->node, child);
|
||||
|
||||
add_root_to_dirty_list(root);
|
||||
btrfs_tree_unlock(child);
|
||||
|
||||
path->locks[level] = 0;
|
||||
path->nodes[level] = NULL;
|
||||
btrfs_clear_buffer_dirty(trans, parent);
|
||||
btrfs_tree_unlock(parent);
|
||||
/* Once for the path. */
|
||||
free_extent_buffer(parent);
|
||||
|
||||
root_sub_used_bytes(root);
|
||||
ret = btrfs_free_tree_block(trans, btrfs_root_id(root), parent, 0, 1);
|
||||
/* Once for the root ptr. */
|
||||
free_extent_buffer_stale(parent);
|
||||
if (unlikely(ret < 0)) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* node level balancing, used to make sure nodes are in proper order for
|
||||
* item deletion. We balance from the top down, so we have to make sure
|
||||
@@ -900,55 +969,10 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
|
||||
* by promoting the node below to a root
|
||||
*/
|
||||
if (!parent) {
|
||||
struct extent_buffer *child;
|
||||
|
||||
if (btrfs_header_nritems(mid) != 1)
|
||||
return 0;
|
||||
|
||||
/* promote the child to a root */
|
||||
child = btrfs_read_node_slot(mid, 0);
|
||||
if (IS_ERR(child)) {
|
||||
ret = PTR_ERR(child);
|
||||
goto out;
|
||||
}
|
||||
|
||||
btrfs_tree_lock(child);
|
||||
ret = btrfs_cow_block(trans, root, child, mid, 0, &child,
|
||||
BTRFS_NESTING_COW);
|
||||
if (ret) {
|
||||
btrfs_tree_unlock(child);
|
||||
free_extent_buffer(child);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = btrfs_tree_mod_log_insert_root(root->node, child, true);
|
||||
if (unlikely(ret < 0)) {
|
||||
btrfs_tree_unlock(child);
|
||||
free_extent_buffer(child);
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
rcu_assign_pointer(root->node, child);
|
||||
|
||||
add_root_to_dirty_list(root);
|
||||
btrfs_tree_unlock(child);
|
||||
|
||||
path->locks[level] = 0;
|
||||
path->nodes[level] = NULL;
|
||||
btrfs_clear_buffer_dirty(trans, mid);
|
||||
btrfs_tree_unlock(mid);
|
||||
/* once for the path */
|
||||
free_extent_buffer(mid);
|
||||
|
||||
root_sub_used_bytes(root);
|
||||
ret = btrfs_free_tree_block(trans, btrfs_root_id(root), mid, 0, 1);
|
||||
/* once for the root ptr */
|
||||
free_extent_buffer_stale(mid);
|
||||
if (unlikely(ret < 0)) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
}
|
||||
return 0;
|
||||
return promote_child_to_root(trans, root, path, level, mid);
|
||||
}
|
||||
if (btrfs_header_nritems(mid) >
|
||||
BTRFS_NODEPTRS_PER_BLOCK(fs_info) / 4)
|
||||
@@ -1101,11 +1125,12 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
|
||||
/* update the path */
|
||||
if (left) {
|
||||
if (btrfs_header_nritems(left) > orig_slot) {
|
||||
refcount_inc(&left->refs);
|
||||
/* left was locked after cow */
|
||||
path->nodes[level] = left;
|
||||
path->slots[level + 1] -= 1;
|
||||
path->slots[level] = orig_slot;
|
||||
/* Left is now owned by path. */
|
||||
left = NULL;
|
||||
if (mid) {
|
||||
btrfs_tree_unlock(mid);
|
||||
free_extent_buffer(mid);
|
||||
@@ -1125,8 +1150,7 @@ out:
|
||||
free_extent_buffer(right);
|
||||
}
|
||||
if (left) {
|
||||
if (path->nodes[level] != left)
|
||||
btrfs_tree_unlock(left);
|
||||
btrfs_tree_unlock(left);
|
||||
free_extent_buffer(left);
|
||||
}
|
||||
return ret;
|
||||
@@ -1435,8 +1459,8 @@ static noinline void unlock_up(struct btrfs_path *path, int level,
|
||||
}
|
||||
|
||||
if (i >= lowest_unlock && i > skip_level) {
|
||||
check_skip = false;
|
||||
btrfs_tree_unlock_rw(path->nodes[i], path->locks[i]);
|
||||
check_skip = false;
|
||||
path->locks[i] = 0;
|
||||
if (write_lock_level &&
|
||||
i > min_write_lock_level &&
|
||||
@@ -1709,9 +1733,9 @@ static struct extent_buffer *btrfs_search_slot_get_root(struct btrfs_root *root,
|
||||
level = btrfs_header_level(b);
|
||||
/*
|
||||
* Ensure that all callers have set skip_locking when
|
||||
* p->search_commit_root = 1.
|
||||
* p->search_commit_root is true.
|
||||
*/
|
||||
ASSERT(p->skip_locking == 1);
|
||||
ASSERT(p->skip_locking);
|
||||
|
||||
goto out;
|
||||
}
|
||||
@@ -2599,12 +2623,11 @@ void btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
|
||||
if (unlikely(btrfs_comp_keys(&disk_key, new_key) >= 0)) {
|
||||
btrfs_print_leaf(eb);
|
||||
btrfs_crit(fs_info,
|
||||
"slot %u key (%llu %u %llu) new key (%llu %u %llu)",
|
||||
"slot %u key " BTRFS_KEY_FMT " new key " BTRFS_KEY_FMT,
|
||||
slot, btrfs_disk_key_objectid(&disk_key),
|
||||
btrfs_disk_key_type(&disk_key),
|
||||
btrfs_disk_key_offset(&disk_key),
|
||||
new_key->objectid, new_key->type,
|
||||
new_key->offset);
|
||||
BTRFS_KEY_FMT_VALUE(new_key));
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
@@ -2613,12 +2636,11 @@ void btrfs_set_item_key_safe(struct btrfs_trans_handle *trans,
|
||||
if (unlikely(btrfs_comp_keys(&disk_key, new_key) <= 0)) {
|
||||
btrfs_print_leaf(eb);
|
||||
btrfs_crit(fs_info,
|
||||
"slot %u key (%llu %u %llu) new key (%llu %u %llu)",
|
||||
"slot %u key " BTRFS_KEY_FMT " new key " BTRFS_KEY_FMT,
|
||||
slot, btrfs_disk_key_objectid(&disk_key),
|
||||
btrfs_disk_key_type(&disk_key),
|
||||
btrfs_disk_key_offset(&disk_key),
|
||||
new_key->objectid, new_key->type,
|
||||
new_key->offset);
|
||||
BTRFS_KEY_FMT_VALUE(new_key));
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
@@ -2677,10 +2699,9 @@ static bool check_sibling_keys(const struct extent_buffer *left,
|
||||
btrfs_crit(left->fs_info, "right extent buffer:");
|
||||
btrfs_print_tree(right, false);
|
||||
btrfs_crit(left->fs_info,
|
||||
"bad key order, sibling blocks, left last (%llu %u %llu) right first (%llu %u %llu)",
|
||||
left_last.objectid, left_last.type,
|
||||
left_last.offset, right_first.objectid,
|
||||
right_first.type, right_first.offset);
|
||||
"bad key order, sibling blocks, left last " BTRFS_KEY_FMT " right first " BTRFS_KEY_FMT,
|
||||
BTRFS_KEY_FMT_VALUE(&left_last),
|
||||
BTRFS_KEY_FMT_VALUE(&right_first));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -3217,10 +3238,8 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
|
||||
/* then fixup the leaf pointer in the path */
|
||||
if (path->slots[0] >= left_nritems) {
|
||||
path->slots[0] -= left_nritems;
|
||||
if (btrfs_header_nritems(path->nodes[0]) == 0)
|
||||
btrfs_clear_buffer_dirty(trans, path->nodes[0]);
|
||||
btrfs_tree_unlock(path->nodes[0]);
|
||||
free_extent_buffer(path->nodes[0]);
|
||||
btrfs_tree_unlock(left);
|
||||
free_extent_buffer(left);
|
||||
path->nodes[0] = right;
|
||||
path->slots[1] += 1;
|
||||
} else {
|
||||
@@ -3398,9 +3417,13 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
|
||||
btrfs_set_header_nritems(left, old_left_nritems + push_items);
|
||||
|
||||
/* fixup right node */
|
||||
if (push_items > right_nritems)
|
||||
WARN(1, KERN_CRIT "push items %d nr %u\n", push_items,
|
||||
right_nritems);
|
||||
if (unlikely(push_items > right_nritems)) {
|
||||
ret = -EUCLEAN;
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
btrfs_crit(fs_info, "push items (%d) > right leaf items (%u)",
|
||||
push_items, right_nritems);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (push_items < right_nritems) {
|
||||
push_space = btrfs_item_offset(right, push_items - 1) -
|
||||
@@ -3433,8 +3456,8 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
|
||||
/* then fixup the leaf pointer in the path */
|
||||
if (path->slots[0] < push_items) {
|
||||
path->slots[0] += old_left_nritems;
|
||||
btrfs_tree_unlock(path->nodes[0]);
|
||||
free_extent_buffer(path->nodes[0]);
|
||||
btrfs_tree_unlock(right);
|
||||
free_extent_buffer(right);
|
||||
path->nodes[0] = left;
|
||||
path->slots[1] -= 1;
|
||||
} else {
|
||||
@@ -3861,10 +3884,10 @@ static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
btrfs_release_path(path);
|
||||
|
||||
path->keep_locks = 1;
|
||||
path->search_for_split = 1;
|
||||
path->keep_locks = true;
|
||||
path->search_for_split = true;
|
||||
ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
|
||||
path->search_for_split = 0;
|
||||
path->search_for_split = false;
|
||||
if (ret > 0)
|
||||
ret = -EAGAIN;
|
||||
if (ret < 0)
|
||||
@@ -3891,11 +3914,11 @@ static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans,
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
path->keep_locks = 0;
|
||||
path->keep_locks = false;
|
||||
btrfs_unlock_up_safe(path, 1);
|
||||
return 0;
|
||||
err:
|
||||
path->keep_locks = 0;
|
||||
path->keep_locks = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -4109,7 +4132,7 @@ void btrfs_extend_item(struct btrfs_trans_handle *trans,
|
||||
nritems = btrfs_header_nritems(leaf);
|
||||
data_end = leaf_data_end(leaf);
|
||||
|
||||
if (btrfs_leaf_free_space(leaf) < data_size) {
|
||||
if (unlikely(btrfs_leaf_free_space(leaf) < data_size)) {
|
||||
btrfs_print_leaf(leaf);
|
||||
BUG();
|
||||
}
|
||||
@@ -4139,7 +4162,6 @@ void btrfs_extend_item(struct btrfs_trans_handle *trans,
|
||||
memmove_leaf_data(leaf, data_end - data_size, data_end,
|
||||
old_data - data_end);
|
||||
|
||||
data_end = old_data;
|
||||
old_size = btrfs_item_size(leaf, slot);
|
||||
btrfs_set_item_size(leaf, slot, old_size + data_size);
|
||||
btrfs_mark_buffer_dirty(trans, leaf);
|
||||
@@ -4498,9 +4520,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
|
||||
/* delete the leaf if we've emptied it */
|
||||
if (nritems == 0) {
|
||||
if (leaf == root->node) {
|
||||
btrfs_set_header_level(leaf, 0);
|
||||
} else {
|
||||
if (leaf != root->node) {
|
||||
btrfs_clear_buffer_dirty(trans, leaf);
|
||||
ret = btrfs_del_leaf(trans, root, path, leaf);
|
||||
if (ret < 0)
|
||||
@@ -4566,10 +4586,9 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
if (btrfs_header_nritems(leaf) == 0) {
|
||||
path->slots[1] = slot;
|
||||
ret = btrfs_del_leaf(trans, root, path, leaf);
|
||||
free_extent_buffer(leaf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
free_extent_buffer(leaf);
|
||||
ret = 0;
|
||||
} else {
|
||||
/* if we're still in the path, make sure
|
||||
* we're dirty. Otherwise, one of the
|
||||
@@ -4613,11 +4632,11 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
|
||||
u32 nritems;
|
||||
int level;
|
||||
int ret = 1;
|
||||
int keep_locks = path->keep_locks;
|
||||
const bool keep_locks = path->keep_locks;
|
||||
|
||||
ASSERT(!path->nowait);
|
||||
ASSERT(path->lowest_level == 0);
|
||||
path->keep_locks = 1;
|
||||
path->keep_locks = true;
|
||||
again:
|
||||
cur = btrfs_read_lock_root_node(root);
|
||||
level = btrfs_header_level(cur);
|
||||
@@ -4707,7 +4726,7 @@ out:
|
||||
* 0 is returned if another key is found, < 0 if there are any errors
|
||||
* and 1 is returned if there are no higher keys in the tree
|
||||
*
|
||||
* path->keep_locks should be set to 1 on the search made before
|
||||
* path->keep_locks should be set to true on the search made before
|
||||
* calling this function.
|
||||
*/
|
||||
int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
|
||||
@@ -4806,13 +4825,13 @@ again:
|
||||
next = NULL;
|
||||
btrfs_release_path(path);
|
||||
|
||||
path->keep_locks = 1;
|
||||
path->keep_locks = true;
|
||||
|
||||
if (time_seq) {
|
||||
ret = btrfs_search_old_slot(root, &key, path, time_seq);
|
||||
} else {
|
||||
if (path->need_commit_sem) {
|
||||
path->need_commit_sem = 0;
|
||||
path->need_commit_sem = false;
|
||||
need_commit_sem = true;
|
||||
if (path->nowait) {
|
||||
if (!down_read_trylock(&fs_info->commit_root_sem)) {
|
||||
@@ -4825,41 +4844,30 @@ again:
|
||||
}
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
}
|
||||
path->keep_locks = 0;
|
||||
path->keep_locks = false;
|
||||
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
|
||||
nritems = btrfs_header_nritems(path->nodes[0]);
|
||||
/*
|
||||
* by releasing the path above we dropped all our locks. A balance
|
||||
* could have added more items next to the key that used to be
|
||||
* at the very end of the block. So, check again here and
|
||||
* advance the path if there are now more items available.
|
||||
* By releasing the path above we dropped all our locks. A balance
|
||||
* could have happened and
|
||||
*
|
||||
* 1. added more items after the previous last item
|
||||
* 2. deleted the previous last item
|
||||
*
|
||||
* So, check again here and advance the path if there are now more
|
||||
* items available.
|
||||
*/
|
||||
if (nritems > 0 && path->slots[0] < nritems - 1) {
|
||||
if (ret == 0)
|
||||
if (nritems > 0 && path->slots[0] <= nritems - 1) {
|
||||
if (ret == 0 && path->slots[0] != nritems - 1) {
|
||||
path->slots[0]++;
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
/*
|
||||
* So the above check misses one case:
|
||||
* - after releasing the path above, someone has removed the item that
|
||||
* used to be at the very end of the block, and balance between leafs
|
||||
* gets another one with bigger key.offset to replace it.
|
||||
*
|
||||
* This one should be returned as well, or we can get leaf corruption
|
||||
* later(esp. in __btrfs_drop_extents()).
|
||||
*
|
||||
* And a bit more explanation about this check,
|
||||
* with ret > 0, the key isn't found, the path points to the slot
|
||||
* where it should be inserted, so the path->slots[0] item must be the
|
||||
* bigger one.
|
||||
*/
|
||||
if (nritems > 0 && ret > 0 && path->slots[0] == nritems - 1) {
|
||||
ret = 0;
|
||||
goto done;
|
||||
goto done;
|
||||
} else if (ret > 0) {
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
while (level < BTRFS_MAX_LEVEL) {
|
||||
@@ -4964,7 +4972,7 @@ done:
|
||||
if (need_commit_sem) {
|
||||
int ret2;
|
||||
|
||||
path->need_commit_sem = 1;
|
||||
path->need_commit_sem = true;
|
||||
ret2 = finish_need_commit_sem_search(path);
|
||||
up_read(&fs_info->commit_root_sem);
|
||||
if (ret2)
|
||||
|
||||
+8
-10
@@ -17,9 +17,7 @@
|
||||
#include <linux/refcount.h>
|
||||
#include <uapi/linux/btrfs_tree.h>
|
||||
#include "locking.h"
|
||||
#include "fs.h"
|
||||
#include "accessors.h"
|
||||
#include "extent-io-tree.h"
|
||||
|
||||
struct extent_buffer;
|
||||
struct btrfs_block_rsv;
|
||||
@@ -67,21 +65,21 @@ struct btrfs_path {
|
||||
* set by btrfs_split_item, tells search_slot to keep all locks
|
||||
* and to force calls to keep space in the nodes
|
||||
*/
|
||||
unsigned int search_for_split:1;
|
||||
bool search_for_split:1;
|
||||
/* Keep some upper locks as we walk down. */
|
||||
unsigned int keep_locks:1;
|
||||
unsigned int skip_locking:1;
|
||||
unsigned int search_commit_root:1;
|
||||
unsigned int need_commit_sem:1;
|
||||
unsigned int skip_release_on_error:1;
|
||||
bool keep_locks:1;
|
||||
bool skip_locking:1;
|
||||
bool search_commit_root:1;
|
||||
bool need_commit_sem:1;
|
||||
bool skip_release_on_error:1;
|
||||
/*
|
||||
* Indicate that new item (btrfs_search_slot) is extending already
|
||||
* existing item and ins_len contains only the data size and not item
|
||||
* header (ie. sizeof(struct btrfs_item) is not included).
|
||||
*/
|
||||
unsigned int search_for_extension:1;
|
||||
bool search_for_extension:1;
|
||||
/* Stop search if any locks need to be taken (for read) */
|
||||
unsigned int nowait:1;
|
||||
bool nowait:1;
|
||||
};
|
||||
|
||||
#define BTRFS_PATH_AUTO_FREE(path_name) \
|
||||
|
||||
+3
-2
@@ -15,6 +15,7 @@
|
||||
#include "defrag.h"
|
||||
#include "file-item.h"
|
||||
#include "super.h"
|
||||
#include "compression.h"
|
||||
|
||||
static struct kmem_cache *btrfs_inode_defrag_cachep;
|
||||
|
||||
@@ -470,7 +471,7 @@ static int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
|
||||
memcpy(&key, &root->defrag_progress, sizeof(key));
|
||||
}
|
||||
|
||||
path->keep_locks = 1;
|
||||
path->keep_locks = true;
|
||||
|
||||
ret = btrfs_search_forward(root, &key, path, BTRFS_OLDEST_GENERATION);
|
||||
if (ret < 0)
|
||||
@@ -513,7 +514,7 @@ static int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
|
||||
/*
|
||||
* Now that we reallocated the node we can find the next key. Note that
|
||||
* btrfs_find_next_key() can release our path and do another search
|
||||
* without COWing, this is because even with path->keep_locks = 1,
|
||||
* without COWing, this is because even with path->keep_locks == true,
|
||||
* btrfs_search_slot() / ctree.c:unlock_up() does not keeps a lock on a
|
||||
* node when path->slots[node_level - 1] does not point to the last
|
||||
* item or a slot beyond the last item (ctree.c:unlock_up()). Therefore
|
||||
|
||||
@@ -358,8 +358,8 @@ int btrfs_delalloc_reserve_metadata(struct btrfs_inode *inode, u64 num_bytes,
|
||||
noflush);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = btrfs_reserve_metadata_bytes(fs_info, block_rsv->space_info,
|
||||
meta_reserve, flush);
|
||||
ret = btrfs_reserve_metadata_bytes(block_rsv->space_info, meta_reserve,
|
||||
flush);
|
||||
if (ret) {
|
||||
btrfs_qgroup_free_meta_prealloc(root, qgroup_reserve);
|
||||
return ret;
|
||||
|
||||
+10
-16
@@ -668,7 +668,7 @@ static int btrfs_insert_delayed_item(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_key first_key;
|
||||
const u32 first_data_size = first_item->data_len;
|
||||
int total_size;
|
||||
char *ins_data = NULL;
|
||||
char AUTO_KFREE(ins_data);
|
||||
int ret;
|
||||
bool continuous_keys_only = false;
|
||||
|
||||
@@ -740,10 +740,8 @@ static int btrfs_insert_delayed_item(struct btrfs_trans_handle *trans,
|
||||
|
||||
ins_data = kmalloc_array(batch.nr,
|
||||
sizeof(u32) + sizeof(struct btrfs_key), GFP_NOFS);
|
||||
if (!ins_data) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if (!ins_data)
|
||||
return -ENOMEM;
|
||||
ins_sizes = (u32 *)ins_data;
|
||||
ins_keys = (struct btrfs_key *)(ins_data + batch.nr * sizeof(u32));
|
||||
batch.keys = ins_keys;
|
||||
@@ -759,7 +757,7 @@ static int btrfs_insert_delayed_item(struct btrfs_trans_handle *trans,
|
||||
|
||||
ret = btrfs_insert_empty_items(trans, root, path, &batch);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
list_for_each_entry(curr, &item_list, tree_list) {
|
||||
char *data_ptr;
|
||||
@@ -814,9 +812,8 @@ static int btrfs_insert_delayed_item(struct btrfs_trans_handle *trans,
|
||||
list_del(&curr->tree_list);
|
||||
btrfs_release_delayed_item(curr);
|
||||
}
|
||||
out:
|
||||
kfree(ins_data);
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btrfs_insert_delayed_items(struct btrfs_trans_handle *trans,
|
||||
@@ -2011,13 +2008,10 @@ int btrfs_delayed_delete_inode_ref(struct btrfs_inode *inode)
|
||||
* It is very rare.
|
||||
*/
|
||||
mutex_lock(&delayed_node->mutex);
|
||||
if (test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags))
|
||||
goto release_node;
|
||||
|
||||
set_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags);
|
||||
delayed_node->count++;
|
||||
atomic_inc(&fs_info->delayed_root->items);
|
||||
release_node:
|
||||
if (!test_and_set_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags)) {
|
||||
delayed_node->count++;
|
||||
atomic_inc(&fs_info->delayed_root->items);
|
||||
}
|
||||
mutex_unlock(&delayed_node->mutex);
|
||||
btrfs_release_delayed_node(delayed_node, &delayed_node_tracker);
|
||||
return 0;
|
||||
|
||||
+34
-11
@@ -228,7 +228,7 @@ int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info,
|
||||
if (!num_bytes)
|
||||
return 0;
|
||||
|
||||
ret = btrfs_reserve_metadata_bytes(fs_info, space_info, num_bytes, flush);
|
||||
ret = btrfs_reserve_metadata_bytes(space_info, num_bytes, flush);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -798,9 +798,13 @@ static void init_delayed_ref_head(struct btrfs_delayed_ref_head *head_ref,
|
||||
}
|
||||
|
||||
/*
|
||||
* helper function to actually insert a head node into the rbtree.
|
||||
* this does all the dirty work in terms of maintaining the correct
|
||||
* overall modification count.
|
||||
* Helper function to actually insert a head node into the xarray. This does all
|
||||
* the dirty work in terms of maintaining the correct overall modification
|
||||
* count.
|
||||
*
|
||||
* The caller is responsible for calling kfree() on @qrecord. More specifically,
|
||||
* if this function reports that it did not insert it as noted in
|
||||
* @qrecord_inserted_ret, then it's safe to call kfree() on it.
|
||||
*
|
||||
* Returns an error pointer in case of an error.
|
||||
*/
|
||||
@@ -814,7 +818,14 @@ add_delayed_ref_head(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_delayed_ref_head *existing;
|
||||
struct btrfs_delayed_ref_root *delayed_refs;
|
||||
const unsigned long index = (head_ref->bytenr >> fs_info->sectorsize_bits);
|
||||
bool qrecord_inserted = false;
|
||||
|
||||
/*
|
||||
* If 'qrecord_inserted_ret' is provided, then the first thing we need
|
||||
* to do is to initialize it to false just in case we have an exit
|
||||
* before trying to insert the record.
|
||||
*/
|
||||
if (qrecord_inserted_ret)
|
||||
*qrecord_inserted_ret = false;
|
||||
|
||||
delayed_refs = &trans->transaction->delayed_refs;
|
||||
lockdep_assert_held(&delayed_refs->lock);
|
||||
@@ -833,6 +844,12 @@ add_delayed_ref_head(struct btrfs_trans_handle *trans,
|
||||
|
||||
/* Record qgroup extent info if provided */
|
||||
if (qrecord) {
|
||||
/*
|
||||
* Setting 'qrecord' but not 'qrecord_inserted_ret' will likely
|
||||
* result in a memory leakage.
|
||||
*/
|
||||
ASSERT(qrecord_inserted_ret != NULL);
|
||||
|
||||
int ret;
|
||||
|
||||
ret = btrfs_qgroup_trace_extent_nolock(fs_info, delayed_refs, qrecord,
|
||||
@@ -840,12 +857,10 @@ add_delayed_ref_head(struct btrfs_trans_handle *trans,
|
||||
if (ret) {
|
||||
/* Clean up if insertion fails or item exists. */
|
||||
xa_release(&delayed_refs->dirty_extents, index);
|
||||
/* Caller responsible for freeing qrecord on error. */
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
kfree(qrecord);
|
||||
} else {
|
||||
qrecord_inserted = true;
|
||||
} else if (qrecord_inserted_ret) {
|
||||
*qrecord_inserted_ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -888,8 +903,6 @@ add_delayed_ref_head(struct btrfs_trans_handle *trans,
|
||||
delayed_refs->num_heads++;
|
||||
delayed_refs->num_heads_ready++;
|
||||
}
|
||||
if (qrecord_inserted_ret)
|
||||
*qrecord_inserted_ret = qrecord_inserted;
|
||||
|
||||
return head_ref;
|
||||
}
|
||||
@@ -1049,6 +1062,14 @@ static int add_delayed_ref(struct btrfs_trans_handle *trans,
|
||||
xa_release(&delayed_refs->head_refs, index);
|
||||
spin_unlock(&delayed_refs->lock);
|
||||
ret = PTR_ERR(new_head_ref);
|
||||
|
||||
/*
|
||||
* It's only safe to call kfree() on 'qrecord' if
|
||||
* add_delayed_ref_head() has _not_ inserted it for
|
||||
* tracing. Otherwise we need to handle this here.
|
||||
*/
|
||||
if (!qrecord_reserved || qrecord_inserted)
|
||||
goto free_head_ref;
|
||||
goto free_record;
|
||||
}
|
||||
head_ref = new_head_ref;
|
||||
@@ -1071,6 +1092,8 @@ static int add_delayed_ref(struct btrfs_trans_handle *trans,
|
||||
|
||||
if (qrecord_inserted)
|
||||
return btrfs_qgroup_trace_extent_post(trans, record, generic_ref->bytenr);
|
||||
|
||||
kfree(record);
|
||||
return 0;
|
||||
|
||||
free_record:
|
||||
|
||||
@@ -489,8 +489,8 @@ static int mark_block_group_to_copy(struct btrfs_fs_info *fs_info,
|
||||
}
|
||||
|
||||
path->reada = READA_FORWARD;
|
||||
path->search_commit_root = 1;
|
||||
path->skip_locking = 1;
|
||||
path->search_commit_root = true;
|
||||
path->skip_locking = true;
|
||||
|
||||
key.objectid = src_dev->devid;
|
||||
key.type = BTRFS_DEV_EXTENT_KEY;
|
||||
|
||||
+2
-2
@@ -9,6 +9,7 @@
|
||||
#include "transaction.h"
|
||||
#include "accessors.h"
|
||||
#include "dir-item.h"
|
||||
#include "delayed-inode.h"
|
||||
|
||||
/*
|
||||
* insert a name into a directory, doing overflow properly if there is a hash
|
||||
@@ -111,7 +112,7 @@ int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
|
||||
int ret = 0;
|
||||
int ret2 = 0;
|
||||
struct btrfs_root *root = dir->root;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct btrfs_dir_item *dir_item;
|
||||
struct extent_buffer *leaf;
|
||||
unsigned long name_ptr;
|
||||
@@ -163,7 +164,6 @@ second_insert:
|
||||
ret2 = btrfs_insert_delayed_dir_index(trans, name->name, name->len, dir,
|
||||
&disk_key, type, index);
|
||||
out_free:
|
||||
btrfs_free_path(path);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ret2)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user