mirror of
https://github.com/torvalds/linux.git
synced 2026-01-25 15:03:52 +08:00
Merge tag 'for-6.15-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
Pull btrfs updates from David Sterba:
"User visible changes:
- fall back to buffered write if direct io is done on a file that
requires checksums
- this avoids a problem with checksum mismatch errors, observed
e.g. on virtual images when writes to pages under writeback
cause the checksum mismatch reports
- this may lead to some performance degradation but currently the
recommended setup for VM images is to use the NOCOW file
attribute that also disables checksums
- fast/realtime zstd levels -15 to -1
- supported by mount options (compress=zstd:-5) and defrag ioctl
- improved speed, reduced compression ratio, check the commit for
sample measurements
- defrag ioctl extended to accept negative compression levels
- subpage mode
- remove warning when subpage mode is used, the feature is now
reasonably complete and tested
- in debug mode allow to create 2K b-tree nodes to allow testing
subpage on x86_64 with 4K pages too
Performance improvements:
- in send, better file path caching improves runtime (on sample load
by -30%)
- on s390x with hardware zlib support prepare the input buffer in a
better way to get the best results from the acceleration
- minor speed improvement in encoded read, avoid memory allocation in
synchronous mode
Core:
- enable stable writes on inodes, replacing manually waiting for
writeback and allowing to skip that on inodes without checksums
- add last checks and warnings for out-of-band dirty writes to pages,
requiring a fixup ("fixup worker"), this should not be necessary
since 5.8 where get_user_page() and pin_user_pages*() prevent this
- long history behind that, we'll be happy to remove the whole
infrastructure in the near future
- more folio API conversions and preparations for large folio support
- subpage cleanups and refactoring, split handling of data and
metadata to allow future support for large folios
- readpage works as block-by-block, no change for normal mode, this
is preparation for future subpage updates
- block group refcount fixes and hardening
- delayed iput fixes
- in zoned mode, fix zone activation on filesystem with missing
devices
Cleanups:
- inode parameter cleanups
- path auto-freeing updates
- code flow simplifications in send
- redundant parameter cleanups"
* tag 'for-6.15-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: (164 commits)
btrfs: zoned: fix zone finishing with missing devices
btrfs: zoned: fix zone activation with missing devices
btrfs: remove end_no_trans label from btrfs_log_inode_parent()
btrfs: simplify condition for logging new dentries at btrfs_log_inode_parent()
btrfs: remove redundant else statement from btrfs_log_inode_parent()
btrfs: use memcmp_extent_buffer() at replay_one_extent()
btrfs: update outdated comment for overwrite_item()
btrfs: use variables to store extent buffer and slot at overwrite_item()
btrfs: avoid unnecessary memory allocation and copy at overwrite_item()
btrfs: don't clobber ret in btrfs_validate_super()
btrfs: prepare btrfs_page_mkwrite() for large folios
btrfs: prepare extent_io.c for future large folio support
btrfs: prepare btrfs_launcher_folio() for large folios support
btrfs: replace PAGE_SIZE with folio_size for subpage.[ch]
btrfs: add a size parameter to btrfs_alloc_subpage()
btrfs: subpage: make btrfs_is_subpage() check against a folio
btrfs: add extra warning if delayed iput is added when it's not allowed
btrfs: avoid redundant path slot assignment in btrfs_search_forward()
btrfs: remove unnecessary btrfs_key local variable in btrfs_search_forward()
btrfs: simplify the return value handling in search_ioctl()
...
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/mm.h>
|
||||
#include <uapi/linux/btrfs_tree.h>
|
||||
#include "extent_io.h"
|
||||
|
||||
struct extent_buffer;
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#ifndef BTRFS_ACL_H
|
||||
#define BTRFS_ACL_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct posix_acl;
|
||||
struct inode;
|
||||
struct btrfs_trans_handle;
|
||||
|
||||
@@ -168,7 +168,7 @@ static inline void thresh_exec_hook(struct btrfs_workqueue *wq)
|
||||
{
|
||||
int new_current_active;
|
||||
long pending;
|
||||
int need_change = 0;
|
||||
bool need_change = false;
|
||||
|
||||
if (wq->thresh == NO_THRESHOLD)
|
||||
return;
|
||||
@@ -196,15 +196,14 @@ static inline void thresh_exec_hook(struct btrfs_workqueue *wq)
|
||||
new_current_active--;
|
||||
new_current_active = clamp_val(new_current_active, 1, wq->limit_active);
|
||||
if (new_current_active != wq->current_active) {
|
||||
need_change = 1;
|
||||
need_change = true;
|
||||
wq->current_active = new_current_active;
|
||||
}
|
||||
out:
|
||||
spin_unlock(&wq->thres_lock);
|
||||
|
||||
if (need_change) {
|
||||
if (need_change)
|
||||
workqueue_set_max_active(wq->normal_wq, wq->current_active);
|
||||
}
|
||||
}
|
||||
|
||||
static void run_ordered_work(struct btrfs_workqueue *wq,
|
||||
@@ -296,7 +295,7 @@ static void btrfs_work_helper(struct work_struct *normal_work)
|
||||
struct btrfs_work *work = container_of(normal_work, struct btrfs_work,
|
||||
normal_work);
|
||||
struct btrfs_workqueue *wq = work->wq;
|
||||
int need_order = 0;
|
||||
bool need_order = false;
|
||||
|
||||
/*
|
||||
* We should not touch things inside work in the following cases:
|
||||
@@ -307,7 +306,7 @@ static void btrfs_work_helper(struct work_struct *normal_work)
|
||||
* So we save the needed things here.
|
||||
*/
|
||||
if (work->ordered_func)
|
||||
need_order = 1;
|
||||
need_order = true;
|
||||
|
||||
trace_btrfs_work_sched(work);
|
||||
thresh_exec_hook(wq);
|
||||
|
||||
@@ -1399,11 +1399,11 @@ static int find_parent_nodes(struct btrfs_backref_walk_ctx *ctx,
|
||||
ASSERT(ctx->roots == NULL);
|
||||
|
||||
key.objectid = ctx->bytenr;
|
||||
key.offset = (u64)-1;
|
||||
if (btrfs_fs_incompat(ctx->fs_info, SKINNY_METADATA))
|
||||
key.type = BTRFS_METADATA_ITEM_KEY;
|
||||
else
|
||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
key.offset = (u64)-1;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
@@ -2206,11 +2206,11 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
|
||||
struct btrfs_extent_item *ei;
|
||||
struct btrfs_key key;
|
||||
|
||||
key.objectid = logical;
|
||||
if (btrfs_fs_incompat(fs_info, SKINNY_METADATA))
|
||||
key.type = BTRFS_METADATA_ITEM_KEY;
|
||||
else
|
||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
key.objectid = logical;
|
||||
key.offset = (u64)-1;
|
||||
|
||||
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
||||
|
||||
@@ -97,33 +97,17 @@ static struct btrfs_bio *btrfs_split_bio(struct btrfs_fs_info *fs_info,
|
||||
return bbio;
|
||||
}
|
||||
|
||||
/* Free a bio that was never submitted to the underlying device. */
|
||||
static void btrfs_cleanup_bio(struct btrfs_bio *bbio)
|
||||
{
|
||||
if (bbio_has_ordered_extent(bbio))
|
||||
btrfs_put_ordered_extent(bbio->ordered);
|
||||
bio_put(&bbio->bio);
|
||||
}
|
||||
|
||||
static void __btrfs_bio_end_io(struct btrfs_bio *bbio)
|
||||
{
|
||||
if (bbio_has_ordered_extent(bbio)) {
|
||||
struct btrfs_ordered_extent *ordered = bbio->ordered;
|
||||
|
||||
bbio->end_io(bbio);
|
||||
btrfs_put_ordered_extent(ordered);
|
||||
} else {
|
||||
bbio->end_io(bbio);
|
||||
}
|
||||
}
|
||||
|
||||
void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status)
|
||||
{
|
||||
bbio->bio.bi_status = status;
|
||||
if (bbio->bio.bi_pool == &btrfs_clone_bioset) {
|
||||
struct btrfs_bio *orig_bbio = bbio->private;
|
||||
|
||||
btrfs_cleanup_bio(bbio);
|
||||
/* Free bio that was never submitted to the underlying device. */
|
||||
if (bbio_has_ordered_extent(bbio))
|
||||
btrfs_put_ordered_extent(bbio->ordered);
|
||||
bio_put(&bbio->bio);
|
||||
|
||||
bbio = orig_bbio;
|
||||
}
|
||||
|
||||
@@ -138,7 +122,15 @@ void btrfs_bio_end_io(struct btrfs_bio *bbio, blk_status_t status)
|
||||
/* Load split bio's error which might be set above. */
|
||||
if (status == BLK_STS_OK)
|
||||
bbio->bio.bi_status = READ_ONCE(bbio->status);
|
||||
__btrfs_bio_end_io(bbio);
|
||||
|
||||
if (bbio_has_ordered_extent(bbio)) {
|
||||
struct btrfs_ordered_extent *ordered = bbio->ordered;
|
||||
|
||||
bbio->end_io(bbio);
|
||||
btrfs_put_ordered_extent(ordered);
|
||||
} else {
|
||||
bbio->end_io(bbio);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,7 +573,7 @@ static void run_one_async_done(struct btrfs_work *work, bool do_free)
|
||||
|
||||
/* If an error occurred we just want to clean up the bio and move on. */
|
||||
if (bio->bi_status) {
|
||||
btrfs_bio_end_io(async->bbio, async->bbio->bio.bi_status);
|
||||
btrfs_bio_end_io(async->bbio, bio->bi_status);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -191,21 +191,21 @@ static int btrfs_bg_start_cmp(const struct rb_node *new,
|
||||
/*
|
||||
* This adds the block group to the fs_info rb tree for the block group cache
|
||||
*/
|
||||
static int btrfs_add_block_group_cache(struct btrfs_fs_info *info,
|
||||
struct btrfs_block_group *block_group)
|
||||
static int btrfs_add_block_group_cache(struct btrfs_block_group *block_group)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = block_group->fs_info;
|
||||
struct rb_node *exist;
|
||||
int ret = 0;
|
||||
|
||||
ASSERT(block_group->length != 0);
|
||||
|
||||
write_lock(&info->block_group_cache_lock);
|
||||
write_lock(&fs_info->block_group_cache_lock);
|
||||
|
||||
exist = rb_find_add_cached(&block_group->cache_node,
|
||||
&info->block_group_cache_tree, btrfs_bg_start_cmp);
|
||||
&fs_info->block_group_cache_tree, btrfs_bg_start_cmp);
|
||||
if (exist)
|
||||
ret = -EEXIST;
|
||||
write_unlock(&info->block_group_cache_lock);
|
||||
write_unlock(&fs_info->block_group_cache_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -584,7 +584,7 @@ static int sample_block_group_extent_item(struct btrfs_caching_control *caching_
|
||||
struct btrfs_root *extent_root;
|
||||
u64 search_offset;
|
||||
u64 search_end = block_group->start + block_group->length;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct btrfs_key search_key;
|
||||
int ret = 0;
|
||||
|
||||
@@ -626,7 +626,6 @@ static int sample_block_group_extent_item(struct btrfs_caching_control *caching_
|
||||
|
||||
lockdep_assert_held(&caching_ctl->mutex);
|
||||
lockdep_assert_held_read(&fs_info->commit_root_sem);
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -738,8 +737,8 @@ static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl)
|
||||
path->reada = READA_FORWARD;
|
||||
|
||||
key.objectid = last;
|
||||
key.offset = 0;
|
||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
key.offset = 0;
|
||||
|
||||
next:
|
||||
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
||||
@@ -785,8 +784,8 @@ next:
|
||||
|
||||
if (key.objectid < last) {
|
||||
key.objectid = last;
|
||||
key.offset = 0;
|
||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
key.offset = 0;
|
||||
btrfs_release_path(path);
|
||||
goto next;
|
||||
}
|
||||
@@ -1456,6 +1455,32 @@ out:
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Link the block_group to a list via bg_list.
|
||||
*
|
||||
* @bg: The block_group to link to the list.
|
||||
* @list: The list to link it to.
|
||||
*
|
||||
* Use this rather than list_add_tail() directly to ensure proper respect
|
||||
* to locking and refcounting.
|
||||
*
|
||||
* Returns: true if the bg was linked with a refcount bump and false otherwise.
|
||||
*/
|
||||
static bool btrfs_link_bg_list(struct btrfs_block_group *bg, struct list_head *list)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = bg->fs_info;
|
||||
bool added = false;
|
||||
|
||||
spin_lock(&fs_info->unused_bgs_lock);
|
||||
if (list_empty(&bg->bg_list)) {
|
||||
btrfs_get_block_group(bg);
|
||||
list_add_tail(&bg->bg_list, list);
|
||||
added = true;
|
||||
}
|
||||
spin_unlock(&fs_info->unused_bgs_lock);
|
||||
return added;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the unused_bgs list and remove any that don't have any allocated
|
||||
* space inside of them.
|
||||
@@ -1571,8 +1596,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
|
||||
* drop under the "next" label for the
|
||||
* fs_info->unused_bgs list.
|
||||
*/
|
||||
btrfs_get_block_group(block_group);
|
||||
list_add_tail(&block_group->bg_list, &retry_list);
|
||||
btrfs_link_bg_list(block_group, &retry_list);
|
||||
|
||||
trace_btrfs_skip_unused_block_group(block_group);
|
||||
spin_unlock(&block_group->lock);
|
||||
@@ -1823,7 +1847,8 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
|
||||
list_sort(NULL, &fs_info->reclaim_bgs, reclaim_bgs_cmp);
|
||||
while (!list_empty(&fs_info->reclaim_bgs)) {
|
||||
u64 zone_unusable;
|
||||
u64 reclaimed;
|
||||
u64 used;
|
||||
u64 reserved;
|
||||
int ret = 0;
|
||||
|
||||
bg = list_first_entry(&fs_info->reclaim_bgs,
|
||||
@@ -1887,6 +1912,17 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
|
||||
up_write(&space_info->groups_sem);
|
||||
goto next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cache the zone_unusable value before turning the block group
|
||||
* to read only. As soon as the block group is read only it's
|
||||
* zone_unusable value gets moved to the block group's read-only
|
||||
* bytes and isn't available for calculations anymore. We also
|
||||
* cache it before unlocking the block group, to prevent races
|
||||
* (reports from KCSAN and such tools) with tasks updating it.
|
||||
*/
|
||||
zone_unusable = bg->zone_unusable;
|
||||
|
||||
spin_unlock(&bg->lock);
|
||||
spin_unlock(&space_info->lock);
|
||||
|
||||
@@ -1903,31 +1939,47 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
|
||||
goto next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cache the zone_unusable value before turning the block group
|
||||
* to read only. As soon as the blog group is read only it's
|
||||
* zone_unusable value gets moved to the block group's read-only
|
||||
* bytes and isn't available for calculations anymore.
|
||||
*/
|
||||
zone_unusable = bg->zone_unusable;
|
||||
ret = inc_block_group_ro(bg, 0);
|
||||
up_write(&space_info->groups_sem);
|
||||
if (ret < 0)
|
||||
goto next;
|
||||
|
||||
/*
|
||||
* The amount of bytes reclaimed corresponds to the sum of the
|
||||
* "used" and "reserved" counters. We have set the block group
|
||||
* to RO above, which prevents reservations from happening but
|
||||
* we may have existing reservations for which allocation has
|
||||
* not yet been done - btrfs_update_block_group() was not yet
|
||||
* called, which is where we will transfer a reserved extent's
|
||||
* size from the "reserved" counter to the "used" counter - this
|
||||
* happens when running delayed references. When we relocate the
|
||||
* chunk below, relocation first flushes dellaloc, waits for
|
||||
* ordered extent completion (which is where we create delayed
|
||||
* references for data extents) and commits the current
|
||||
* transaction (which runs delayed references), and only after
|
||||
* it does the actual work to move extents out of the block
|
||||
* group. So the reported amount of reclaimed bytes is
|
||||
* effectively the sum of the 'used' and 'reserved' counters.
|
||||
*/
|
||||
spin_lock(&bg->lock);
|
||||
used = bg->used;
|
||||
reserved = bg->reserved;
|
||||
spin_unlock(&bg->lock);
|
||||
|
||||
btrfs_info(fs_info,
|
||||
"reclaiming chunk %llu with %llu%% used %llu%% unusable",
|
||||
"reclaiming chunk %llu with %llu%% used %llu%% reserved %llu%% unusable",
|
||||
bg->start,
|
||||
div64_u64(bg->used * 100, bg->length),
|
||||
div64_u64(used * 100, bg->length),
|
||||
div64_u64(reserved * 100, bg->length),
|
||||
div64_u64(zone_unusable * 100, bg->length));
|
||||
trace_btrfs_reclaim_block_group(bg);
|
||||
reclaimed = bg->used;
|
||||
ret = btrfs_relocate_chunk(fs_info, bg->start);
|
||||
if (ret) {
|
||||
btrfs_dec_block_group_ro(bg);
|
||||
btrfs_err(fs_info, "error relocating chunk %llu",
|
||||
bg->start);
|
||||
reclaimed = 0;
|
||||
used = 0;
|
||||
reserved = 0;
|
||||
spin_lock(&space_info->lock);
|
||||
space_info->reclaim_errors++;
|
||||
if (READ_ONCE(space_info->periodic_reclaim))
|
||||
@@ -1936,24 +1988,13 @@ void btrfs_reclaim_bgs_work(struct work_struct *work)
|
||||
}
|
||||
spin_lock(&space_info->lock);
|
||||
space_info->reclaim_count++;
|
||||
space_info->reclaim_bytes += reclaimed;
|
||||
space_info->reclaim_bytes += used;
|
||||
space_info->reclaim_bytes += reserved;
|
||||
spin_unlock(&space_info->lock);
|
||||
|
||||
next:
|
||||
if (ret && !READ_ONCE(space_info->periodic_reclaim)) {
|
||||
/* Refcount held by the reclaim_bgs list after splice. */
|
||||
spin_lock(&fs_info->unused_bgs_lock);
|
||||
/*
|
||||
* This block group might be added to the unused list
|
||||
* during the above process. Move it back to the
|
||||
* reclaim list otherwise.
|
||||
*/
|
||||
if (list_empty(&bg->bg_list)) {
|
||||
btrfs_get_block_group(bg);
|
||||
list_add_tail(&bg->bg_list, &retry_list);
|
||||
}
|
||||
spin_unlock(&fs_info->unused_bgs_lock);
|
||||
}
|
||||
if (ret && !READ_ONCE(space_info->periodic_reclaim))
|
||||
btrfs_link_bg_list(bg, &retry_list);
|
||||
btrfs_put_block_group(bg);
|
||||
|
||||
mutex_unlock(&fs_info->reclaim_bgs_lock);
|
||||
@@ -1993,13 +2034,8 @@ void btrfs_mark_bg_to_reclaim(struct btrfs_block_group *bg)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = bg->fs_info;
|
||||
|
||||
spin_lock(&fs_info->unused_bgs_lock);
|
||||
if (list_empty(&bg->bg_list)) {
|
||||
btrfs_get_block_group(bg);
|
||||
if (btrfs_link_bg_list(bg, &fs_info->reclaim_bgs))
|
||||
trace_btrfs_add_reclaim_block_group(bg);
|
||||
list_add_tail(&bg->bg_list, &fs_info->reclaim_bgs);
|
||||
}
|
||||
spin_unlock(&fs_info->unused_bgs_lock);
|
||||
}
|
||||
|
||||
static int read_bg_from_eb(struct btrfs_fs_info *fs_info, const struct btrfs_key *key,
|
||||
@@ -2410,7 +2446,7 @@ static int read_one_block_group(struct btrfs_fs_info *info,
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = btrfs_add_block_group_cache(info, cache);
|
||||
ret = btrfs_add_block_group_cache(cache);
|
||||
if (ret) {
|
||||
btrfs_remove_free_space_cache(cache);
|
||||
goto error;
|
||||
@@ -2459,7 +2495,7 @@ static int fill_dummy_bgs(struct btrfs_fs_info *fs_info)
|
||||
bg->cached = BTRFS_CACHE_FINISHED;
|
||||
bg->used = map->chunk_len;
|
||||
bg->flags = map->type;
|
||||
ret = btrfs_add_block_group_cache(fs_info, bg);
|
||||
ret = btrfs_add_block_group_cache(bg);
|
||||
/*
|
||||
* We may have some valid block group cache added already, in
|
||||
* that case we skip to the next one.
|
||||
@@ -2509,8 +2545,8 @@ int btrfs_read_block_groups(struct btrfs_fs_info *info)
|
||||
return fill_dummy_bgs(info);
|
||||
|
||||
key.objectid = 0;
|
||||
key.offset = 0;
|
||||
key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
|
||||
key.offset = 0;
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
@@ -2641,7 +2677,7 @@ static int insert_dev_extent(struct btrfs_trans_handle *trans,
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = device->fs_info;
|
||||
struct btrfs_root *root = fs_info->dev_root;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct btrfs_dev_extent *extent;
|
||||
struct extent_buffer *leaf;
|
||||
struct btrfs_key key;
|
||||
@@ -2658,7 +2694,7 @@ static int insert_dev_extent(struct btrfs_trans_handle *trans,
|
||||
key.offset = start;
|
||||
ret = btrfs_insert_empty_item(trans, root, path, &key, sizeof(*extent));
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
leaf = path->nodes[0];
|
||||
extent = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dev_extent);
|
||||
@@ -2666,10 +2702,8 @@ static int insert_dev_extent(struct btrfs_trans_handle *trans,
|
||||
btrfs_set_dev_extent_chunk_objectid(leaf, extent,
|
||||
BTRFS_FIRST_CHUNK_TREE_OBJECTID);
|
||||
btrfs_set_dev_extent_chunk_offset(leaf, extent, chunk_offset);
|
||||
|
||||
btrfs_set_dev_extent_length(leaf, extent, num_bytes);
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2771,8 +2805,12 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans)
|
||||
/* Already aborted the transaction if it failed. */
|
||||
next:
|
||||
btrfs_dec_delayed_refs_rsv_bg_inserts(fs_info);
|
||||
|
||||
spin_lock(&fs_info->unused_bgs_lock);
|
||||
list_del_init(&block_group->bg_list);
|
||||
clear_bit(BLOCK_GROUP_FLAG_NEW, &block_group->runtime_flags);
|
||||
btrfs_put_block_group(block_group);
|
||||
spin_unlock(&fs_info->unused_bgs_lock);
|
||||
|
||||
/*
|
||||
* If the block group is still unused, add it to the list of
|
||||
@@ -2888,7 +2926,7 @@ struct btrfs_block_group *btrfs_make_block_group(struct btrfs_trans_handle *tran
|
||||
cache->space_info = btrfs_find_space_info(fs_info, cache->flags);
|
||||
ASSERT(cache->space_info);
|
||||
|
||||
ret = btrfs_add_block_group_cache(fs_info, cache);
|
||||
ret = btrfs_add_block_group_cache(cache);
|
||||
if (ret) {
|
||||
btrfs_remove_free_space_cache(cache);
|
||||
btrfs_put_block_group(cache);
|
||||
@@ -2910,7 +2948,7 @@ struct btrfs_block_group *btrfs_make_block_group(struct btrfs_trans_handle *tran
|
||||
}
|
||||
#endif
|
||||
|
||||
list_add_tail(&cache->bg_list, &trans->new_bgs);
|
||||
btrfs_link_bg_list(cache, &trans->new_bgs);
|
||||
btrfs_inc_delayed_refs_rsv_bg_inserts(fs_info);
|
||||
|
||||
set_avail_alloc_bits(fs_info, type);
|
||||
@@ -3306,7 +3344,7 @@ int btrfs_setup_space_cache(struct btrfs_trans_handle *trans)
|
||||
struct btrfs_fs_info *fs_info = trans->fs_info;
|
||||
struct btrfs_block_group *cache, *tmp;
|
||||
struct btrfs_transaction *cur_trans = trans->transaction;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
|
||||
if (list_empty(&cur_trans->dirty_bgs) ||
|
||||
!btrfs_test_opt(fs_info, SPACE_CACHE))
|
||||
@@ -3323,7 +3361,6 @@ int btrfs_setup_space_cache(struct btrfs_trans_handle *trans)
|
||||
cache_save_setup(cache, trans, path);
|
||||
}
|
||||
|
||||
btrfs_free_path(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3346,7 +3383,7 @@ int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans)
|
||||
struct btrfs_transaction *cur_trans = trans->transaction;
|
||||
int ret = 0;
|
||||
int should_put;
|
||||
struct btrfs_path *path = NULL;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
LIST_HEAD(dirty);
|
||||
struct list_head *io = &cur_trans->io_bgs;
|
||||
int loops = 0;
|
||||
@@ -3501,7 +3538,6 @@ out:
|
||||
btrfs_cleanup_dirty_bgs(cur_trans, fs_info);
|
||||
}
|
||||
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3512,7 +3548,7 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans)
|
||||
struct btrfs_transaction *cur_trans = trans->transaction;
|
||||
int ret = 0;
|
||||
int should_put;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct list_head *io = &cur_trans->io_bgs;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
@@ -3624,7 +3660,6 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans)
|
||||
btrfs_put_block_group(cache);
|
||||
}
|
||||
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -145,6 +145,7 @@ struct btrfs_inode {
|
||||
* different from prop_compress and takes precedence if set.
|
||||
*/
|
||||
u8 defrag_compress;
|
||||
s8 defrag_compress_level;
|
||||
|
||||
/*
|
||||
* Lock for counters and all fields used to determine if the inode is in
|
||||
@@ -516,6 +517,14 @@ static inline void btrfs_assert_inode_locked(struct btrfs_inode *inode)
|
||||
lockdep_assert_held(&inode->vfs_inode.i_rwsem);
|
||||
}
|
||||
|
||||
static inline void btrfs_update_inode_mapping_flags(struct btrfs_inode *inode)
|
||||
{
|
||||
if (inode->flags & BTRFS_INODE_NODATASUM)
|
||||
mapping_clear_stable_writes(inode->vfs_inode.i_mapping);
|
||||
else
|
||||
mapping_set_stable_writes(inode->vfs_inode.i_mapping);
|
||||
}
|
||||
|
||||
/* Array of bytes with variable length, hexadecimal format 0x1234 */
|
||||
#define CSUM_FMT "0x%*phN"
|
||||
#define CSUM_FMT_VALUE(size, bytes) size, bytes
|
||||
@@ -524,7 +533,7 @@ int btrfs_check_sector_csum(struct btrfs_fs_info *fs_info, struct page *page,
|
||||
u32 pgoff, u8 *csum, const u8 * const csum_expected);
|
||||
bool btrfs_data_csum_ok(struct btrfs_bio *bbio, struct btrfs_device *dev,
|
||||
u32 bio_offset, struct bio_vec *bv);
|
||||
noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
|
||||
noinline int can_nocow_extent(struct btrfs_inode *inode, u64 offset, u64 *len,
|
||||
struct btrfs_file_extent *file_extent,
|
||||
bool nowait);
|
||||
|
||||
@@ -584,9 +593,9 @@ void btrfs_free_inode(struct inode *inode);
|
||||
int btrfs_drop_inode(struct inode *inode);
|
||||
int __init btrfs_init_cachep(void);
|
||||
void __cold btrfs_destroy_cachep(void);
|
||||
struct inode *btrfs_iget_path(u64 ino, struct btrfs_root *root,
|
||||
struct btrfs_path *path);
|
||||
struct inode *btrfs_iget(u64 ino, struct btrfs_root *root);
|
||||
struct btrfs_inode *btrfs_iget_path(u64 ino, struct btrfs_root *root,
|
||||
struct btrfs_path *path);
|
||||
struct btrfs_inode *btrfs_iget(u64 ino, struct btrfs_root *root);
|
||||
struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
|
||||
struct folio *folio, u64 start, u64 len);
|
||||
int btrfs_update_inode(struct btrfs_trans_handle *trans,
|
||||
|
||||
@@ -740,7 +740,7 @@ static const struct btrfs_compress_op * const btrfs_compress_op[] = {
|
||||
&btrfs_zstd_compress,
|
||||
};
|
||||
|
||||
static struct list_head *alloc_workspace(int type, unsigned int level)
|
||||
static struct list_head *alloc_workspace(int type, int level)
|
||||
{
|
||||
switch (type) {
|
||||
case BTRFS_COMPRESS_NONE: return alloc_heuristic_ws();
|
||||
@@ -818,7 +818,7 @@ static void btrfs_cleanup_workspace_manager(int type)
|
||||
* Preallocation makes a forward progress guarantees and we do not return
|
||||
* errors.
|
||||
*/
|
||||
struct list_head *btrfs_get_workspace(int type, unsigned int level)
|
||||
struct list_head *btrfs_get_workspace(int type, int level)
|
||||
{
|
||||
struct workspace_manager *wsm;
|
||||
struct list_head *workspace;
|
||||
@@ -968,18 +968,28 @@ static void put_workspace(int type, struct list_head *ws)
|
||||
* Adjust @level according to the limits of the compression algorithm or
|
||||
* fallback to default
|
||||
*/
|
||||
static unsigned int btrfs_compress_set_level(int type, unsigned level)
|
||||
static int btrfs_compress_set_level(unsigned int type, int level)
|
||||
{
|
||||
const struct btrfs_compress_op *ops = btrfs_compress_op[type];
|
||||
|
||||
if (level == 0)
|
||||
level = ops->default_level;
|
||||
else
|
||||
level = min(level, ops->max_level);
|
||||
level = min(max(level, ops->min_level), ops->max_level);
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the @level is within the valid range for the given type.
|
||||
*/
|
||||
bool btrfs_compress_level_valid(unsigned int type, int level)
|
||||
{
|
||||
const struct btrfs_compress_op *ops = btrfs_compress_op[type];
|
||||
|
||||
return ops->min_level <= level && level <= ops->max_level;
|
||||
}
|
||||
|
||||
/* Wrapper around find_get_page(), with extra error message. */
|
||||
int btrfs_compress_filemap_get_folio(struct address_space *mapping, u64 start,
|
||||
struct folio **in_folio_ret)
|
||||
@@ -1023,12 +1033,10 @@ int btrfs_compress_filemap_get_folio(struct address_space *mapping, u64 start,
|
||||
* @total_out is an in/out parameter, must be set to the input length and will
|
||||
* be also used to return the total number of compressed bytes
|
||||
*/
|
||||
int btrfs_compress_folios(unsigned int type_level, struct address_space *mapping,
|
||||
int btrfs_compress_folios(unsigned int type, int level, struct address_space *mapping,
|
||||
u64 start, struct folio **folios, unsigned long *out_folios,
|
||||
unsigned long *total_in, unsigned long *total_out)
|
||||
{
|
||||
int type = btrfs_compress_type(type_level);
|
||||
int level = btrfs_compress_level(type_level);
|
||||
const unsigned long orig_len = *total_out;
|
||||
struct list_head *workspace;
|
||||
int ret;
|
||||
@@ -1590,18 +1598,19 @@ out:
|
||||
|
||||
/*
|
||||
* Convert the compression suffix (eg. after "zlib" starting with ":") to
|
||||
* level, unrecognized string will set the default level
|
||||
* level, unrecognized string will set the default level. Negative level
|
||||
* numbers are allowed.
|
||||
*/
|
||||
unsigned int btrfs_compress_str2level(unsigned int type, const char *str)
|
||||
int btrfs_compress_str2level(unsigned int type, const char *str)
|
||||
{
|
||||
unsigned int level = 0;
|
||||
int level = 0;
|
||||
int ret;
|
||||
|
||||
if (!type)
|
||||
return 0;
|
||||
|
||||
if (str[0] == ':') {
|
||||
ret = kstrtouint(str + 1, 10, &level);
|
||||
ret = kstrtoint(str + 1, 10, &level);
|
||||
if (ret)
|
||||
level = 0;
|
||||
}
|
||||
|
||||
@@ -72,16 +72,6 @@ struct compressed_bio {
|
||||
struct btrfs_bio bbio;
|
||||
};
|
||||
|
||||
static inline unsigned int btrfs_compress_type(unsigned int type_level)
|
||||
{
|
||||
return (type_level & 0xF);
|
||||
}
|
||||
|
||||
static inline unsigned int btrfs_compress_level(unsigned int type_level)
|
||||
{
|
||||
return ((type_level & 0xF0) >> 4);
|
||||
}
|
||||
|
||||
/* @range_end must be exclusive. */
|
||||
static inline u32 btrfs_calc_input_length(u64 range_end, u64 cur)
|
||||
{
|
||||
@@ -93,7 +83,8 @@ static inline u32 btrfs_calc_input_length(u64 range_end, u64 cur)
|
||||
int __init btrfs_init_compress(void);
|
||||
void __cold btrfs_exit_compress(void);
|
||||
|
||||
int btrfs_compress_folios(unsigned int type_level, struct address_space *mapping,
|
||||
bool btrfs_compress_level_valid(unsigned int type, int level);
|
||||
int btrfs_compress_folios(unsigned int type, int level, struct address_space *mapping,
|
||||
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,
|
||||
@@ -107,7 +98,7 @@ void btrfs_submit_compressed_write(struct btrfs_ordered_extent *ordered,
|
||||
bool writeback);
|
||||
void btrfs_submit_compressed_read(struct btrfs_bio *bbio);
|
||||
|
||||
unsigned int btrfs_compress_str2level(unsigned int type, const char *str);
|
||||
int btrfs_compress_str2level(unsigned int type, const char *str);
|
||||
|
||||
struct folio *btrfs_alloc_compr_folio(void);
|
||||
void btrfs_free_compr_folio(struct folio *folio);
|
||||
@@ -131,14 +122,15 @@ struct workspace_manager {
|
||||
wait_queue_head_t ws_wait;
|
||||
};
|
||||
|
||||
struct list_head *btrfs_get_workspace(int type, unsigned int level);
|
||||
struct list_head *btrfs_get_workspace(int type, int level);
|
||||
void btrfs_put_workspace(int type, struct list_head *ws);
|
||||
|
||||
struct btrfs_compress_op {
|
||||
struct workspace_manager *workspace_manager;
|
||||
/* Maximum level supported by the compression algorithm */
|
||||
unsigned int max_level;
|
||||
unsigned int default_level;
|
||||
int min_level;
|
||||
int max_level;
|
||||
int default_level;
|
||||
};
|
||||
|
||||
/* The heuristic workspaces are managed via the 0th workspace manager */
|
||||
@@ -187,9 +179,9 @@ int zstd_decompress(struct list_head *ws, const u8 *data_in,
|
||||
size_t destlen);
|
||||
void zstd_init_workspace_manager(void);
|
||||
void zstd_cleanup_workspace_manager(void);
|
||||
struct list_head *zstd_alloc_workspace(unsigned int level);
|
||||
struct list_head *zstd_alloc_workspace(int level);
|
||||
void zstd_free_workspace(struct list_head *ws);
|
||||
struct list_head *zstd_get_workspace(unsigned int level);
|
||||
struct list_head *zstd_get_workspace(int level);
|
||||
void zstd_put_workspace(struct list_head *ws);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4306,7 +4306,7 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
u32 data_size)
|
||||
{
|
||||
int ret = 0;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct extent_buffer *leaf;
|
||||
unsigned long ptr;
|
||||
|
||||
@@ -4320,7 +4320,6 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
write_extent_buffer(leaf, data, ptr, data_size);
|
||||
btrfs_mark_buffer_dirty(trans, leaf);
|
||||
}
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -4608,7 +4607,6 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
|
||||
u64 min_trans)
|
||||
{
|
||||
struct extent_buffer *cur;
|
||||
struct btrfs_key found_key;
|
||||
int slot;
|
||||
int sret;
|
||||
u32 nritems;
|
||||
@@ -4644,7 +4642,8 @@ again:
|
||||
goto find_next_key;
|
||||
ret = 0;
|
||||
path->slots[level] = slot;
|
||||
btrfs_item_key_to_cpu(cur, &found_key, slot);
|
||||
/* Save our key for returning back. */
|
||||
btrfs_item_key_to_cpu(cur, min_key, slot);
|
||||
goto out;
|
||||
}
|
||||
if (sret && slot > 0)
|
||||
@@ -4668,8 +4667,8 @@ find_next_key:
|
||||
* we didn't find a candidate key in this node, walk forward
|
||||
* and find another one
|
||||
*/
|
||||
path->slots[level] = slot;
|
||||
if (slot >= nritems) {
|
||||
path->slots[level] = slot;
|
||||
sret = btrfs_find_next_key(root, path, min_key, level,
|
||||
min_trans);
|
||||
if (sret == 0) {
|
||||
@@ -4679,11 +4678,10 @@ find_next_key:
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* save our key for returning back */
|
||||
btrfs_node_key_to_cpu(cur, &found_key, slot);
|
||||
path->slots[level] = slot;
|
||||
if (level == path->lowest_level) {
|
||||
ret = 0;
|
||||
/* Save our key for returning back. */
|
||||
btrfs_node_key_to_cpu(cur, min_key, slot);
|
||||
goto out;
|
||||
}
|
||||
cur = btrfs_read_node_slot(cur, slot);
|
||||
@@ -4700,10 +4698,8 @@ find_next_key:
|
||||
}
|
||||
out:
|
||||
path->keep_locks = keep_locks;
|
||||
if (ret == 0) {
|
||||
if (ret == 0)
|
||||
btrfs_unlock_up_safe(path, path->lowest_level + 1);
|
||||
memcpy(min_key, &found_key, sizeof(found_key));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef BTRFS_CTREE_H
|
||||
#define BTRFS_CTREE_H
|
||||
|
||||
#include "linux/cleanup.h"
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
@@ -225,7 +225,7 @@ static int btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info,
|
||||
struct file_ra_state *ra)
|
||||
{
|
||||
struct btrfs_root *inode_root;
|
||||
struct inode *inode;
|
||||
struct btrfs_inode *inode;
|
||||
struct btrfs_ioctl_defrag_range_args range;
|
||||
int ret = 0;
|
||||
u64 cur = 0;
|
||||
@@ -250,24 +250,24 @@ again:
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (cur >= i_size_read(inode)) {
|
||||
iput(inode);
|
||||
if (cur >= i_size_read(&inode->vfs_inode)) {
|
||||
iput(&inode->vfs_inode);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Do a chunk of defrag */
|
||||
clear_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags);
|
||||
clear_bit(BTRFS_INODE_IN_DEFRAG, &inode->runtime_flags);
|
||||
memset(&range, 0, sizeof(range));
|
||||
range.len = (u64)-1;
|
||||
range.start = cur;
|
||||
range.extent_thresh = defrag->extent_thresh;
|
||||
file_ra_state_init(ra, inode->i_mapping);
|
||||
file_ra_state_init(ra, inode->vfs_inode.i_mapping);
|
||||
|
||||
sb_start_write(fs_info->sb);
|
||||
ret = btrfs_defrag_file(inode, ra, &range, defrag->transid,
|
||||
BTRFS_DEFRAG_BATCH);
|
||||
BTRFS_DEFRAG_BATCH);
|
||||
sb_end_write(fs_info->sb);
|
||||
iput(inode);
|
||||
iput(&inode->vfs_inode);
|
||||
|
||||
if (ret < 0)
|
||||
goto cleanup;
|
||||
@@ -1352,17 +1352,18 @@ out:
|
||||
* (Mostly for autodefrag, which sets @max_to_defrag thus we may exit early without
|
||||
* defragging all the range).
|
||||
*/
|
||||
int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
|
||||
int btrfs_defrag_file(struct btrfs_inode *inode, struct file_ra_state *ra,
|
||||
struct btrfs_ioctl_defrag_range_args *range,
|
||||
u64 newer_than, unsigned long max_to_defrag)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||
unsigned long sectors_defragged = 0;
|
||||
u64 isize = i_size_read(inode);
|
||||
u64 isize = i_size_read(&inode->vfs_inode);
|
||||
u64 cur;
|
||||
u64 last_byte;
|
||||
bool do_compress = (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS);
|
||||
int compress_type = BTRFS_COMPRESS_ZLIB;
|
||||
int compress_level = 0;
|
||||
int ret = 0;
|
||||
u32 extent_thresh = range->extent_thresh;
|
||||
pgoff_t start_index;
|
||||
@@ -1376,10 +1377,21 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
|
||||
return -EINVAL;
|
||||
|
||||
if (do_compress) {
|
||||
if (range->compress_type >= BTRFS_NR_COMPRESS_TYPES)
|
||||
return -EINVAL;
|
||||
if (range->compress_type)
|
||||
compress_type = range->compress_type;
|
||||
if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL) {
|
||||
if (range->compress.type >= BTRFS_NR_COMPRESS_TYPES)
|
||||
return -EINVAL;
|
||||
if (range->compress.type) {
|
||||
compress_type = range->compress.type;
|
||||
compress_level = range->compress.level;
|
||||
if (!btrfs_compress_level_valid(compress_type, compress_level))
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
if (range->compress_type >= BTRFS_NR_COMPRESS_TYPES)
|
||||
return -EINVAL;
|
||||
if (range->compress_type)
|
||||
compress_type = range->compress_type;
|
||||
}
|
||||
}
|
||||
|
||||
if (extent_thresh == 0)
|
||||
@@ -1402,8 +1414,8 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
|
||||
* defrag range can be written sequentially.
|
||||
*/
|
||||
start_index = cur >> PAGE_SHIFT;
|
||||
if (start_index < inode->i_mapping->writeback_index)
|
||||
inode->i_mapping->writeback_index = start_index;
|
||||
if (start_index < inode->vfs_inode.i_mapping->writeback_index)
|
||||
inode->vfs_inode.i_mapping->writeback_index = start_index;
|
||||
|
||||
while (cur < last_byte) {
|
||||
const unsigned long prev_sectors_defragged = sectors_defragged;
|
||||
@@ -1420,27 +1432,29 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
|
||||
(SZ_256K >> PAGE_SHIFT)) << PAGE_SHIFT) - 1;
|
||||
cluster_end = min(cluster_end, last_byte);
|
||||
|
||||
btrfs_inode_lock(BTRFS_I(inode), 0);
|
||||
if (IS_SWAPFILE(inode)) {
|
||||
btrfs_inode_lock(inode, 0);
|
||||
if (IS_SWAPFILE(&inode->vfs_inode)) {
|
||||
ret = -ETXTBSY;
|
||||
btrfs_inode_unlock(BTRFS_I(inode), 0);
|
||||
btrfs_inode_unlock(inode, 0);
|
||||
break;
|
||||
}
|
||||
if (!(inode->i_sb->s_flags & SB_ACTIVE)) {
|
||||
btrfs_inode_unlock(BTRFS_I(inode), 0);
|
||||
if (!(inode->vfs_inode.i_sb->s_flags & SB_ACTIVE)) {
|
||||
btrfs_inode_unlock(inode, 0);
|
||||
break;
|
||||
}
|
||||
if (do_compress)
|
||||
BTRFS_I(inode)->defrag_compress = compress_type;
|
||||
ret = defrag_one_cluster(BTRFS_I(inode), ra, cur,
|
||||
if (do_compress) {
|
||||
inode->defrag_compress = compress_type;
|
||||
inode->defrag_compress_level = compress_level;
|
||||
}
|
||||
ret = defrag_one_cluster(inode, ra, cur,
|
||||
cluster_end + 1 - cur, extent_thresh,
|
||||
newer_than, do_compress, §ors_defragged,
|
||||
max_to_defrag, &last_scanned);
|
||||
|
||||
if (sectors_defragged > prev_sectors_defragged)
|
||||
balance_dirty_pages_ratelimited(inode->i_mapping);
|
||||
balance_dirty_pages_ratelimited(inode->vfs_inode.i_mapping);
|
||||
|
||||
btrfs_inode_unlock(BTRFS_I(inode), 0);
|
||||
btrfs_inode_unlock(inode, 0);
|
||||
if (ret < 0)
|
||||
break;
|
||||
cur = max(cluster_end + 1, last_scanned);
|
||||
@@ -1462,10 +1476,10 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
|
||||
* need to be written back immediately.
|
||||
*/
|
||||
if (range->flags & BTRFS_DEFRAG_RANGE_START_IO) {
|
||||
filemap_flush(inode->i_mapping);
|
||||
filemap_flush(inode->vfs_inode.i_mapping);
|
||||
if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
|
||||
&BTRFS_I(inode)->runtime_flags))
|
||||
filemap_flush(inode->i_mapping);
|
||||
&inode->runtime_flags))
|
||||
filemap_flush(inode->vfs_inode.i_mapping);
|
||||
}
|
||||
if (range->compress_type == BTRFS_COMPRESS_LZO)
|
||||
btrfs_set_fs_incompat(fs_info, COMPRESS_LZO);
|
||||
@@ -1474,9 +1488,9 @@ int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
|
||||
ret = sectors_defragged;
|
||||
}
|
||||
if (do_compress) {
|
||||
btrfs_inode_lock(BTRFS_I(inode), 0);
|
||||
BTRFS_I(inode)->defrag_compress = BTRFS_COMPRESS_NONE;
|
||||
btrfs_inode_unlock(BTRFS_I(inode), 0);
|
||||
btrfs_inode_lock(inode, 0);
|
||||
inode->defrag_compress = BTRFS_COMPRESS_NONE;
|
||||
btrfs_inode_unlock(inode, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/compiler_types.h>
|
||||
|
||||
struct inode;
|
||||
struct file_ra_state;
|
||||
struct btrfs_inode;
|
||||
struct btrfs_fs_info;
|
||||
struct btrfs_root;
|
||||
struct btrfs_trans_handle;
|
||||
struct btrfs_ioctl_defrag_range_args;
|
||||
|
||||
int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
|
||||
int btrfs_defrag_file(struct btrfs_inode *inode, struct file_ra_state *ra,
|
||||
struct btrfs_ioctl_defrag_range_args *range,
|
||||
u64 newer_than, unsigned long max_to_defrag);
|
||||
int __init btrfs_auto_defrag_init(void);
|
||||
|
||||
@@ -1211,7 +1211,7 @@ int btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_inode *inode)
|
||||
{
|
||||
struct btrfs_delayed_node *delayed_node = btrfs_get_delayed_node(inode);
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct btrfs_block_rsv *block_rsv;
|
||||
int ret;
|
||||
|
||||
@@ -1238,7 +1238,6 @@ int btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans,
|
||||
ret = __btrfs_commit_inode_delayed_items(trans, path, delayed_node);
|
||||
|
||||
btrfs_release_delayed_node(delayed_node);
|
||||
btrfs_free_path(path);
|
||||
trans->block_rsv = block_rsv;
|
||||
|
||||
return ret;
|
||||
@@ -1817,53 +1816,53 @@ int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
|
||||
|
||||
static void fill_stack_inode_item(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_inode_item *inode_item,
|
||||
struct inode *inode)
|
||||
struct btrfs_inode *inode)
|
||||
{
|
||||
struct inode *vfs_inode = &inode->vfs_inode;
|
||||
u64 flags;
|
||||
|
||||
btrfs_set_stack_inode_uid(inode_item, i_uid_read(inode));
|
||||
btrfs_set_stack_inode_gid(inode_item, i_gid_read(inode));
|
||||
btrfs_set_stack_inode_size(inode_item, BTRFS_I(inode)->disk_i_size);
|
||||
btrfs_set_stack_inode_mode(inode_item, inode->i_mode);
|
||||
btrfs_set_stack_inode_nlink(inode_item, inode->i_nlink);
|
||||
btrfs_set_stack_inode_nbytes(inode_item, inode_get_bytes(inode));
|
||||
btrfs_set_stack_inode_generation(inode_item,
|
||||
BTRFS_I(inode)->generation);
|
||||
btrfs_set_stack_inode_uid(inode_item, i_uid_read(vfs_inode));
|
||||
btrfs_set_stack_inode_gid(inode_item, i_gid_read(vfs_inode));
|
||||
btrfs_set_stack_inode_size(inode_item, inode->disk_i_size);
|
||||
btrfs_set_stack_inode_mode(inode_item, vfs_inode->i_mode);
|
||||
btrfs_set_stack_inode_nlink(inode_item, vfs_inode->i_nlink);
|
||||
btrfs_set_stack_inode_nbytes(inode_item, inode_get_bytes(vfs_inode));
|
||||
btrfs_set_stack_inode_generation(inode_item, inode->generation);
|
||||
btrfs_set_stack_inode_sequence(inode_item,
|
||||
inode_peek_iversion(inode));
|
||||
inode_peek_iversion(vfs_inode));
|
||||
btrfs_set_stack_inode_transid(inode_item, trans->transid);
|
||||
btrfs_set_stack_inode_rdev(inode_item, inode->i_rdev);
|
||||
flags = btrfs_inode_combine_flags(BTRFS_I(inode)->flags,
|
||||
BTRFS_I(inode)->ro_flags);
|
||||
btrfs_set_stack_inode_rdev(inode_item, vfs_inode->i_rdev);
|
||||
flags = btrfs_inode_combine_flags(inode->flags, inode->ro_flags);
|
||||
btrfs_set_stack_inode_flags(inode_item, flags);
|
||||
btrfs_set_stack_inode_block_group(inode_item, 0);
|
||||
|
||||
btrfs_set_stack_timespec_sec(&inode_item->atime,
|
||||
inode_get_atime_sec(inode));
|
||||
inode_get_atime_sec(vfs_inode));
|
||||
btrfs_set_stack_timespec_nsec(&inode_item->atime,
|
||||
inode_get_atime_nsec(inode));
|
||||
inode_get_atime_nsec(vfs_inode));
|
||||
|
||||
btrfs_set_stack_timespec_sec(&inode_item->mtime,
|
||||
inode_get_mtime_sec(inode));
|
||||
inode_get_mtime_sec(vfs_inode));
|
||||
btrfs_set_stack_timespec_nsec(&inode_item->mtime,
|
||||
inode_get_mtime_nsec(inode));
|
||||
inode_get_mtime_nsec(vfs_inode));
|
||||
|
||||
btrfs_set_stack_timespec_sec(&inode_item->ctime,
|
||||
inode_get_ctime_sec(inode));
|
||||
inode_get_ctime_sec(vfs_inode));
|
||||
btrfs_set_stack_timespec_nsec(&inode_item->ctime,
|
||||
inode_get_ctime_nsec(inode));
|
||||
inode_get_ctime_nsec(vfs_inode));
|
||||
|
||||
btrfs_set_stack_timespec_sec(&inode_item->otime, BTRFS_I(inode)->i_otime_sec);
|
||||
btrfs_set_stack_timespec_nsec(&inode_item->otime, BTRFS_I(inode)->i_otime_nsec);
|
||||
btrfs_set_stack_timespec_sec(&inode_item->otime, inode->i_otime_sec);
|
||||
btrfs_set_stack_timespec_nsec(&inode_item->otime, inode->i_otime_nsec);
|
||||
}
|
||||
|
||||
int btrfs_fill_inode(struct inode *inode, u32 *rdev)
|
||||
int btrfs_fill_inode(struct btrfs_inode *inode, u32 *rdev)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
|
||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||
struct btrfs_delayed_node *delayed_node;
|
||||
struct btrfs_inode_item *inode_item;
|
||||
struct inode *vfs_inode = &inode->vfs_inode;
|
||||
|
||||
delayed_node = btrfs_get_delayed_node(BTRFS_I(inode));
|
||||
delayed_node = btrfs_get_delayed_node(inode);
|
||||
if (!delayed_node)
|
||||
return -ENOENT;
|
||||
|
||||
@@ -1876,39 +1875,38 @@ int btrfs_fill_inode(struct inode *inode, u32 *rdev)
|
||||
|
||||
inode_item = &delayed_node->inode_item;
|
||||
|
||||
i_uid_write(inode, btrfs_stack_inode_uid(inode_item));
|
||||
i_gid_write(inode, btrfs_stack_inode_gid(inode_item));
|
||||
btrfs_i_size_write(BTRFS_I(inode), btrfs_stack_inode_size(inode_item));
|
||||
btrfs_inode_set_file_extent_range(BTRFS_I(inode), 0,
|
||||
round_up(i_size_read(inode), fs_info->sectorsize));
|
||||
inode->i_mode = btrfs_stack_inode_mode(inode_item);
|
||||
set_nlink(inode, btrfs_stack_inode_nlink(inode_item));
|
||||
inode_set_bytes(inode, btrfs_stack_inode_nbytes(inode_item));
|
||||
BTRFS_I(inode)->generation = btrfs_stack_inode_generation(inode_item);
|
||||
BTRFS_I(inode)->last_trans = btrfs_stack_inode_transid(inode_item);
|
||||
i_uid_write(vfs_inode, btrfs_stack_inode_uid(inode_item));
|
||||
i_gid_write(vfs_inode, btrfs_stack_inode_gid(inode_item));
|
||||
btrfs_i_size_write(inode, btrfs_stack_inode_size(inode_item));
|
||||
btrfs_inode_set_file_extent_range(inode, 0,
|
||||
round_up(i_size_read(vfs_inode), fs_info->sectorsize));
|
||||
vfs_inode->i_mode = btrfs_stack_inode_mode(inode_item);
|
||||
set_nlink(vfs_inode, btrfs_stack_inode_nlink(inode_item));
|
||||
inode_set_bytes(vfs_inode, btrfs_stack_inode_nbytes(inode_item));
|
||||
inode->generation = btrfs_stack_inode_generation(inode_item);
|
||||
inode->last_trans = btrfs_stack_inode_transid(inode_item);
|
||||
|
||||
inode_set_iversion_queried(inode,
|
||||
btrfs_stack_inode_sequence(inode_item));
|
||||
inode->i_rdev = 0;
|
||||
inode_set_iversion_queried(vfs_inode, btrfs_stack_inode_sequence(inode_item));
|
||||
vfs_inode->i_rdev = 0;
|
||||
*rdev = btrfs_stack_inode_rdev(inode_item);
|
||||
btrfs_inode_split_flags(btrfs_stack_inode_flags(inode_item),
|
||||
&BTRFS_I(inode)->flags, &BTRFS_I(inode)->ro_flags);
|
||||
&inode->flags, &inode->ro_flags);
|
||||
|
||||
inode_set_atime(inode, btrfs_stack_timespec_sec(&inode_item->atime),
|
||||
inode_set_atime(vfs_inode, btrfs_stack_timespec_sec(&inode_item->atime),
|
||||
btrfs_stack_timespec_nsec(&inode_item->atime));
|
||||
|
||||
inode_set_mtime(inode, btrfs_stack_timespec_sec(&inode_item->mtime),
|
||||
inode_set_mtime(vfs_inode, btrfs_stack_timespec_sec(&inode_item->mtime),
|
||||
btrfs_stack_timespec_nsec(&inode_item->mtime));
|
||||
|
||||
inode_set_ctime(inode, btrfs_stack_timespec_sec(&inode_item->ctime),
|
||||
inode_set_ctime(vfs_inode, btrfs_stack_timespec_sec(&inode_item->ctime),
|
||||
btrfs_stack_timespec_nsec(&inode_item->ctime));
|
||||
|
||||
BTRFS_I(inode)->i_otime_sec = btrfs_stack_timespec_sec(&inode_item->otime);
|
||||
BTRFS_I(inode)->i_otime_nsec = btrfs_stack_timespec_nsec(&inode_item->otime);
|
||||
inode->i_otime_sec = btrfs_stack_timespec_sec(&inode_item->otime);
|
||||
inode->i_otime_nsec = btrfs_stack_timespec_nsec(&inode_item->otime);
|
||||
|
||||
inode->i_generation = BTRFS_I(inode)->generation;
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
BTRFS_I(inode)->index_cnt = (u64)-1;
|
||||
vfs_inode->i_generation = inode->generation;
|
||||
if (S_ISDIR(vfs_inode->i_mode))
|
||||
inode->index_cnt = (u64)-1;
|
||||
|
||||
mutex_unlock(&delayed_node->mutex);
|
||||
btrfs_release_delayed_node(delayed_node);
|
||||
@@ -1928,8 +1926,7 @@ int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans,
|
||||
|
||||
mutex_lock(&delayed_node->mutex);
|
||||
if (test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
|
||||
fill_stack_inode_item(trans, &delayed_node->inode_item,
|
||||
&inode->vfs_inode);
|
||||
fill_stack_inode_item(trans, &delayed_node->inode_item, inode);
|
||||
goto release_node;
|
||||
}
|
||||
|
||||
@@ -1937,7 +1934,7 @@ int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans,
|
||||
if (ret)
|
||||
goto release_node;
|
||||
|
||||
fill_stack_inode_item(trans, &delayed_node->inode_item, &inode->vfs_inode);
|
||||
fill_stack_inode_item(trans, &delayed_node->inode_item, inode);
|
||||
set_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags);
|
||||
delayed_node->count++;
|
||||
atomic_inc(&root->fs_info->delayed_root->items);
|
||||
|
||||
@@ -133,7 +133,7 @@ int btrfs_commit_inode_delayed_inode(struct btrfs_inode *inode);
|
||||
|
||||
int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_inode *inode);
|
||||
int btrfs_fill_inode(struct inode *inode, u32 *rdev);
|
||||
int btrfs_fill_inode(struct btrfs_inode *inode, u32 *rdev);
|
||||
int btrfs_delayed_delete_inode_ref(struct btrfs_inode *inode);
|
||||
|
||||
/* Used for drop dead root */
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/slab.h>
|
||||
#include <uapi/linux/btrfs_tree.h>
|
||||
#include "fs.h"
|
||||
#include "messages.h"
|
||||
|
||||
struct btrfs_trans_handle;
|
||||
struct btrfs_fs_info;
|
||||
|
||||
@@ -76,7 +76,7 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info)
|
||||
struct extent_buffer *eb;
|
||||
int slot;
|
||||
int ret = 0;
|
||||
struct btrfs_path *path = NULL;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
int item_size;
|
||||
struct btrfs_dev_replace_item *ptr;
|
||||
u64 src_devid;
|
||||
@@ -85,10 +85,8 @@ int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info)
|
||||
return 0;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
key.objectid = 0;
|
||||
key.type = BTRFS_DEV_REPLACE_KEY;
|
||||
@@ -103,10 +101,8 @@ no_valid_dev_replace_entry_found:
|
||||
if (btrfs_find_device(fs_info->fs_devices, &args)) {
|
||||
btrfs_err(fs_info,
|
||||
"found replace target device without a valid replace item");
|
||||
ret = -EUCLEAN;
|
||||
goto out;
|
||||
return -EUCLEAN;
|
||||
}
|
||||
ret = 0;
|
||||
dev_replace->replace_state =
|
||||
BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED;
|
||||
dev_replace->cont_reading_from_srcdev_mode =
|
||||
@@ -123,7 +119,7 @@ no_valid_dev_replace_entry_found:
|
||||
dev_replace->tgtdev = NULL;
|
||||
dev_replace->is_valid = 0;
|
||||
dev_replace->item_needs_writeback = 0;
|
||||
goto out;
|
||||
return 0;
|
||||
}
|
||||
slot = path->slots[0];
|
||||
eb = path->nodes[0];
|
||||
@@ -226,8 +222,6 @@ no_valid_dev_replace_entry_found:
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -346,7 +340,7 @@ int btrfs_run_dev_replace(struct btrfs_trans_handle *trans)
|
||||
struct btrfs_fs_info *fs_info = trans->fs_info;
|
||||
int ret;
|
||||
struct btrfs_root *dev_root = fs_info->dev_root;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct btrfs_key key;
|
||||
struct extent_buffer *eb;
|
||||
struct btrfs_dev_replace_item *ptr;
|
||||
@@ -365,16 +359,15 @@ int btrfs_run_dev_replace(struct btrfs_trans_handle *trans)
|
||||
key.offset = 0;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = btrfs_search_slot(trans, dev_root, &key, path, -1, 1);
|
||||
if (ret < 0) {
|
||||
btrfs_warn(fs_info,
|
||||
"error %d while searching for dev_replace item!",
|
||||
ret);
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret == 0 &&
|
||||
@@ -395,7 +388,7 @@ int btrfs_run_dev_replace(struct btrfs_trans_handle *trans)
|
||||
btrfs_warn(fs_info,
|
||||
"delete too small dev_replace item failed %d!",
|
||||
ret);
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
ret = 1;
|
||||
}
|
||||
@@ -408,7 +401,7 @@ int btrfs_run_dev_replace(struct btrfs_trans_handle *trans)
|
||||
if (ret < 0) {
|
||||
btrfs_warn(fs_info,
|
||||
"insert dev_replace item failed %d!", ret);
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,8 +433,6 @@ int btrfs_run_dev_replace(struct btrfs_trans_handle *trans)
|
||||
dev_replace->cursor_right);
|
||||
dev_replace->item_needs_writeback = 0;
|
||||
up_write(&dev_replace->rwsem);
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
|
||||
int data_size;
|
||||
struct extent_buffer *leaf;
|
||||
int slot;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
@@ -251,20 +251,17 @@ int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
|
||||
if (IS_ERR(di)) {
|
||||
ret = PTR_ERR(di);
|
||||
/* Nothing found, we're safe */
|
||||
if (ret == -ENOENT) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
if (ret == -ENOENT)
|
||||
return 0;
|
||||
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* we found an item, look for our name in the item */
|
||||
if (di) {
|
||||
/* our exact name was found */
|
||||
ret = -EEXIST;
|
||||
goto out;
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
/* See if there is room in the item to insert this name. */
|
||||
@@ -273,14 +270,11 @@ int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
|
||||
slot = path->slots[0];
|
||||
if (data_size + btrfs_item_size(leaf, slot) +
|
||||
sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root->fs_info)) {
|
||||
ret = -EOVERFLOW;
|
||||
} else {
|
||||
/* plenty of insertion room */
|
||||
ret = 0;
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
|
||||
/* Plenty of insertion room. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -10,6 +10,7 @@ struct fscrypt_str;
|
||||
struct btrfs_fs_info;
|
||||
struct btrfs_key;
|
||||
struct btrfs_path;
|
||||
struct btrfs_inode;
|
||||
struct btrfs_root;
|
||||
struct btrfs_trans_handle;
|
||||
|
||||
|
||||
@@ -248,7 +248,8 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,
|
||||
len = min(len, em->len - (start - em->start));
|
||||
block_start = extent_map_block_start(em) + (start - em->start);
|
||||
|
||||
if (can_nocow_extent(inode, start, &len, &file_extent, false) == 1) {
|
||||
if (can_nocow_extent(BTRFS_I(inode), start, &len, &file_extent,
|
||||
false) == 1) {
|
||||
bg = btrfs_inc_nocow_writers(fs_info, block_start);
|
||||
if (bg)
|
||||
can_nocow = true;
|
||||
@@ -855,6 +856,22 @@ relock:
|
||||
btrfs_inode_unlock(BTRFS_I(inode), ilock_flags);
|
||||
goto buffered;
|
||||
}
|
||||
/*
|
||||
* We can't control the folios being passed in, applications can write
|
||||
* to them while a direct IO write is in progress. This means the
|
||||
* content might change after we calculated the data checksum.
|
||||
* Therefore we can end up storing a checksum that doesn't match the
|
||||
* persisted data.
|
||||
*
|
||||
* To be extra safe and avoid false data checksum mismatch, if the
|
||||
* inode requires data checksum, just fallback to buffered IO.
|
||||
* For buffered IO we have full control of page cache and can ensure
|
||||
* no one is modifying the content during writeback.
|
||||
*/
|
||||
if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
|
||||
btrfs_inode_unlock(BTRFS_I(inode), ilock_flags);
|
||||
goto buffered;
|
||||
}
|
||||
|
||||
/*
|
||||
* The iov_iter can be mapped to the same file range we are writing to.
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct kiocb;
|
||||
|
||||
int __init btrfs_init_dio(void);
|
||||
void __cold btrfs_destroy_dio(void);
|
||||
|
||||
|
||||
@@ -167,13 +167,7 @@ static bool remove_from_discard_list(struct btrfs_discard_ctl *discard_ctl,
|
||||
block_group->discard_eligible_time = 0;
|
||||
queued = !list_empty(&block_group->discard_list);
|
||||
list_del_init(&block_group->discard_list);
|
||||
/*
|
||||
* If the block group is currently running in the discard workfn, we
|
||||
* don't want to deref it, since it's still being used by the workfn.
|
||||
* The workfn will notice this case and deref the block group when it is
|
||||
* finished.
|
||||
*/
|
||||
if (queued && !running)
|
||||
if (queued)
|
||||
btrfs_put_block_group(block_group);
|
||||
|
||||
spin_unlock(&discard_ctl->lock);
|
||||
@@ -260,9 +254,10 @@ again:
|
||||
block_group->discard_cursor = block_group->start;
|
||||
block_group->discard_state = BTRFS_DISCARD_EXTENTS;
|
||||
}
|
||||
discard_ctl->block_group = block_group;
|
||||
}
|
||||
if (block_group) {
|
||||
btrfs_get_block_group(block_group);
|
||||
discard_ctl->block_group = block_group;
|
||||
*discard_state = block_group->discard_state;
|
||||
*discard_index = block_group->discard_index;
|
||||
}
|
||||
@@ -493,9 +488,20 @@ static void btrfs_discard_workfn(struct work_struct *work)
|
||||
|
||||
block_group = peek_discard_list(discard_ctl, &discard_state,
|
||||
&discard_index, now);
|
||||
if (!block_group || !btrfs_run_discard_work(discard_ctl))
|
||||
if (!block_group)
|
||||
return;
|
||||
if (!btrfs_run_discard_work(discard_ctl)) {
|
||||
spin_lock(&discard_ctl->lock);
|
||||
btrfs_put_block_group(block_group);
|
||||
discard_ctl->block_group = NULL;
|
||||
spin_unlock(&discard_ctl->lock);
|
||||
return;
|
||||
}
|
||||
if (now < block_group->discard_eligible_time) {
|
||||
spin_lock(&discard_ctl->lock);
|
||||
btrfs_put_block_group(block_group);
|
||||
discard_ctl->block_group = NULL;
|
||||
spin_unlock(&discard_ctl->lock);
|
||||
btrfs_discard_schedule_work(discard_ctl, false);
|
||||
return;
|
||||
}
|
||||
@@ -547,15 +553,7 @@ static void btrfs_discard_workfn(struct work_struct *work)
|
||||
spin_lock(&discard_ctl->lock);
|
||||
discard_ctl->prev_discard = trimmed;
|
||||
discard_ctl->prev_discard_time = now;
|
||||
/*
|
||||
* If the block group was removed from the discard list while it was
|
||||
* running in this workfn, then we didn't deref it, since this function
|
||||
* still owned that reference. But we set the discard_ctl->block_group
|
||||
* back to NULL, so we can use that condition to know that now we need
|
||||
* to deref the block_group.
|
||||
*/
|
||||
if (discard_ctl->block_group == NULL)
|
||||
btrfs_put_block_group(block_group);
|
||||
btrfs_put_block_group(block_group);
|
||||
discard_ctl->block_group = NULL;
|
||||
__btrfs_discard_schedule_work(discard_ctl, now, false);
|
||||
spin_unlock(&discard_ctl->lock);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#ifndef BTRFS_DISCARD_H
|
||||
#define BTRFS_DISCARD_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
struct btrfs_fs_info;
|
||||
|
||||
@@ -182,13 +182,12 @@ static int btrfs_repair_eb_io_failure(const struct extent_buffer *eb,
|
||||
int mirror_num)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = eb->fs_info;
|
||||
int num_folios = num_extent_folios(eb);
|
||||
int ret = 0;
|
||||
|
||||
if (sb_rdonly(fs_info->sb))
|
||||
return -EROFS;
|
||||
|
||||
for (int i = 0; i < num_folios; i++) {
|
||||
for (int i = 0; i < num_extent_folios(eb); i++) {
|
||||
struct folio *folio = eb->folios[i];
|
||||
u64 start = max_t(u64, eb->start, folio_pos(folio));
|
||||
u64 end = min_t(u64, eb->start + eb->len,
|
||||
@@ -284,8 +283,7 @@ blk_status_t btree_csum_one_bio(struct btrfs_bio *bbio)
|
||||
|
||||
if (WARN_ON_ONCE(found_start != eb->start))
|
||||
return BLK_STS_IOERR;
|
||||
if (WARN_ON(!btrfs_folio_test_uptodate(fs_info, eb->folios[0],
|
||||
eb->start, eb->len)))
|
||||
if (WARN_ON(!btrfs_meta_folio_test_uptodate(eb->folios[0], eb)))
|
||||
return BLK_STS_IOERR;
|
||||
|
||||
ASSERT(memcmp_extent_buffer(eb, fs_info->fs_devices->metadata_uuid,
|
||||
@@ -1089,21 +1087,22 @@ struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root,
|
||||
const struct btrfs_key *key)
|
||||
{
|
||||
struct btrfs_root *root;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
root = read_tree_root_path(tree_root, path, key);
|
||||
btrfs_free_path(path);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize subvolume root in-memory structure
|
||||
* Initialize subvolume root in-memory structure.
|
||||
*
|
||||
* @anon_dev: anonymous device to attach to the root, if zero, allocate new
|
||||
*
|
||||
* In case of failure the caller is responsible to call btrfs_free_fs_root()
|
||||
*/
|
||||
static int btrfs_init_fs_root(struct btrfs_root *root, dev_t anon_dev)
|
||||
{
|
||||
@@ -1127,7 +1126,7 @@ static int btrfs_init_fs_root(struct btrfs_root *root, dev_t anon_dev)
|
||||
if (!anon_dev) {
|
||||
ret = get_anon_bdev(&root->anon_dev);
|
||||
if (ret)
|
||||
goto fail;
|
||||
return ret;
|
||||
} else {
|
||||
root->anon_dev = anon_dev;
|
||||
}
|
||||
@@ -1137,7 +1136,7 @@ static int btrfs_init_fs_root(struct btrfs_root *root, dev_t anon_dev)
|
||||
ret = btrfs_init_root_free_objectid(root);
|
||||
if (ret) {
|
||||
mutex_unlock(&root->objectid_mutex);
|
||||
goto fail;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ASSERT(root->free_objectid <= BTRFS_LAST_FREE_OBJECTID);
|
||||
@@ -1145,9 +1144,6 @@ static int btrfs_init_fs_root(struct btrfs_root *root, dev_t anon_dev)
|
||||
mutex_unlock(&root->objectid_mutex);
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
/* The caller is responsible to call btrfs_free_fs_root */
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
|
||||
@@ -2200,8 +2196,8 @@ static int load_global_roots_objectid(struct btrfs_root *tree_root,
|
||||
|
||||
static int load_global_roots(struct btrfs_root *tree_root)
|
||||
{
|
||||
struct btrfs_path *path;
|
||||
int ret = 0;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
int ret;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
@@ -2210,18 +2206,17 @@ static int load_global_roots(struct btrfs_root *tree_root)
|
||||
ret = load_global_roots_objectid(tree_root, path,
|
||||
BTRFS_EXTENT_TREE_OBJECTID, "extent");
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
ret = load_global_roots_objectid(tree_root, path,
|
||||
BTRFS_CSUM_TREE_OBJECTID, "csum");
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
if (!btrfs_fs_compat_ro(tree_root->fs_info, FREE_SPACE_TREE))
|
||||
goto out;
|
||||
return ret;
|
||||
ret = load_global_roots_objectid(tree_root, path,
|
||||
BTRFS_FREE_SPACE_TREE_OBJECTID,
|
||||
"free space");
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2447,21 +2442,27 @@ int btrfs_validate_super(const struct btrfs_fs_info *fs_info,
|
||||
* Check sectorsize and nodesize first, other check will need it.
|
||||
* Check all possible sectorsize(4K, 8K, 16K, 32K, 64K) here.
|
||||
*/
|
||||
if (!is_power_of_2(sectorsize) || sectorsize < 4096 ||
|
||||
if (!is_power_of_2(sectorsize) || sectorsize < BTRFS_MIN_BLOCKSIZE ||
|
||||
sectorsize > BTRFS_MAX_METADATA_BLOCKSIZE) {
|
||||
btrfs_err(fs_info, "invalid sectorsize %llu", sectorsize);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* We only support at most two sectorsizes: 4K and PAGE_SIZE.
|
||||
* We only support at most 3 sectorsizes: 4K, PAGE_SIZE, MIN_BLOCKSIZE.
|
||||
*
|
||||
* For 4K page sized systems with non-debug builds, all 3 matches (4K).
|
||||
* For 4K page sized systems with debug builds, there are two block sizes
|
||||
* supported. (4K and 2K)
|
||||
*
|
||||
* We can support 16K sectorsize with 64K page size without problem,
|
||||
* but such sectorsize/pagesize combination doesn't make much sense.
|
||||
* 4K will be our future standard, PAGE_SIZE is supported from the very
|
||||
* beginning.
|
||||
*/
|
||||
if (sectorsize > PAGE_SIZE || (sectorsize != SZ_4K && sectorsize != PAGE_SIZE)) {
|
||||
if (sectorsize > PAGE_SIZE || (sectorsize != SZ_4K &&
|
||||
sectorsize != PAGE_SIZE &&
|
||||
sectorsize != BTRFS_MIN_BLOCKSIZE)) {
|
||||
btrfs_err(fs_info,
|
||||
"sectorsize %llu not yet supported for page size %lu",
|
||||
sectorsize, PAGE_SIZE);
|
||||
@@ -2561,6 +2562,9 @@ int btrfs_validate_super(const struct btrfs_fs_info *fs_info,
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = validate_sys_chunk_array(fs_info, sb);
|
||||
|
||||
/*
|
||||
@@ -3390,7 +3394,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
|
||||
fs_info->nodesize = nodesize;
|
||||
fs_info->sectorsize = sectorsize;
|
||||
fs_info->sectorsize_bits = ilog2(sectorsize);
|
||||
fs_info->sectors_per_page = (PAGE_SIZE >> fs_info->sectorsize_bits);
|
||||
fs_info->csums_per_leaf = BTRFS_MAX_ITEM_SIZE(fs_info) / fs_info->csum_size;
|
||||
fs_info->stripesize = stripesize;
|
||||
fs_info->fs_devices->fs_info = fs_info;
|
||||
@@ -3416,11 +3419,6 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
|
||||
*/
|
||||
fs_info->max_inline = min_t(u64, fs_info->max_inline, fs_info->sectorsize);
|
||||
|
||||
if (sectorsize < PAGE_SIZE)
|
||||
btrfs_warn(fs_info,
|
||||
"read-write for sector size %u with page size %lu is experimental",
|
||||
sectorsize, PAGE_SIZE);
|
||||
|
||||
ret = btrfs_init_workqueues(fs_info);
|
||||
if (ret)
|
||||
goto fail_sb_buffer;
|
||||
@@ -4325,6 +4323,14 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
|
||||
/* clear out the rbtree of defraggable inodes */
|
||||
btrfs_cleanup_defrag_inodes(fs_info);
|
||||
|
||||
/*
|
||||
* Handle the error fs first, as it will flush and wait for all ordered
|
||||
* extents. This will generate delayed iputs, thus we want to handle
|
||||
* it first.
|
||||
*/
|
||||
if (unlikely(BTRFS_FS_ERROR(fs_info)))
|
||||
btrfs_error_commit_super(fs_info);
|
||||
|
||||
/*
|
||||
* Wait for any fixup workers to complete.
|
||||
* If we don't wait for them here and they are still running by the time
|
||||
@@ -4345,6 +4351,31 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
|
||||
*/
|
||||
btrfs_flush_workqueue(fs_info->delalloc_workers);
|
||||
|
||||
/*
|
||||
* We can have ordered extents getting their last reference dropped from
|
||||
* the fs_info->workers queue because for async writes for data bios we
|
||||
* queue a work for that queue, at btrfs_wq_submit_bio(), that runs
|
||||
* run_one_async_done() which calls btrfs_bio_end_io() in case the bio
|
||||
* has an error, and that later function can do the final
|
||||
* btrfs_put_ordered_extent() on the ordered extent attached to the bio,
|
||||
* which adds a delayed iput for the inode. So we must flush the queue
|
||||
* so that we don't have delayed iputs after committing the current
|
||||
* transaction below and stopping the cleaner and transaction kthreads.
|
||||
*/
|
||||
btrfs_flush_workqueue(fs_info->workers);
|
||||
|
||||
/*
|
||||
* When finishing a compressed write bio we schedule a work queue item
|
||||
* to finish an ordered extent - btrfs_finish_compressed_write_work()
|
||||
* calls btrfs_finish_ordered_extent() which in turns does a call to
|
||||
* btrfs_queue_ordered_fn(), and that queues the ordered extent
|
||||
* completion either in the endio_write_workers work queue or in the
|
||||
* fs_info->endio_freespace_worker work queue. We flush those queues
|
||||
* below, so before we flush them we must flush this queue for the
|
||||
* workers of compressed writes.
|
||||
*/
|
||||
flush_workqueue(fs_info->compressed_write_workers);
|
||||
|
||||
/*
|
||||
* After we parked the cleaner kthread, ordered extents may have
|
||||
* completed and created new delayed iputs. If one of the async reclaim
|
||||
@@ -4369,6 +4400,8 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
|
||||
/* Ordered extents for free space inodes. */
|
||||
btrfs_flush_workqueue(fs_info->endio_freespace_worker);
|
||||
btrfs_run_delayed_iputs(fs_info);
|
||||
/* There should be no more workload to generate new delayed iputs. */
|
||||
set_bit(BTRFS_FS_STATE_NO_DELAYED_IPUT, &fs_info->fs_state);
|
||||
|
||||
cancel_work_sync(&fs_info->async_reclaim_work);
|
||||
cancel_work_sync(&fs_info->async_data_reclaim_work);
|
||||
@@ -4403,9 +4436,6 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
|
||||
btrfs_err(fs_info, "commit super ret %d", ret);
|
||||
}
|
||||
|
||||
if (BTRFS_FS_ERROR(fs_info))
|
||||
btrfs_error_commit_super(fs_info);
|
||||
|
||||
kthread_stop(fs_info->transaction_kthread);
|
||||
kthread_stop(fs_info->cleaner_kthread);
|
||||
|
||||
@@ -4528,10 +4558,6 @@ static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info)
|
||||
/* cleanup FS via transaction */
|
||||
btrfs_cleanup_transaction(fs_info);
|
||||
|
||||
mutex_lock(&fs_info->cleaner_mutex);
|
||||
btrfs_run_delayed_iputs(fs_info);
|
||||
mutex_unlock(&fs_info->cleaner_mutex);
|
||||
|
||||
down_write(&fs_info->cleanup_work_sem);
|
||||
up_write(&fs_info->cleanup_work_sem);
|
||||
}
|
||||
@@ -4902,7 +4928,7 @@ static int btrfs_cleanup_transaction(struct btrfs_fs_info *fs_info)
|
||||
|
||||
int btrfs_init_root_free_objectid(struct btrfs_root *root)
|
||||
{
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
int ret;
|
||||
struct extent_buffer *l;
|
||||
struct btrfs_key search_key;
|
||||
@@ -4918,14 +4944,13 @@ int btrfs_init_root_free_objectid(struct btrfs_root *root)
|
||||
search_key.offset = (u64)-1;
|
||||
ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
return ret;
|
||||
if (ret == 0) {
|
||||
/*
|
||||
* Key with offset -1 found, there would have to exist a root
|
||||
* with such id, but this is out of valid range.
|
||||
*/
|
||||
ret = -EUCLEAN;
|
||||
goto error;
|
||||
return -EUCLEAN;
|
||||
}
|
||||
if (path->slots[0] > 0) {
|
||||
slot = path->slots[0] - 1;
|
||||
@@ -4936,10 +4961,8 @@ int btrfs_init_root_free_objectid(struct btrfs_root *root)
|
||||
} else {
|
||||
root->free_objectid = BTRFS_FIRST_FREE_OBJECTID;
|
||||
}
|
||||
ret = 0;
|
||||
error:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_get_free_objectid(struct btrfs_root *root, u64 *objectid)
|
||||
|
||||
@@ -75,7 +75,7 @@ struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = btrfs_sb(sb);
|
||||
struct btrfs_root *root;
|
||||
struct inode *inode;
|
||||
struct btrfs_inode *inode;
|
||||
|
||||
if (objectid < BTRFS_FIRST_FREE_OBJECTID)
|
||||
return ERR_PTR(-ESTALE);
|
||||
@@ -89,12 +89,12 @@ struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
|
||||
if (IS_ERR(inode))
|
||||
return ERR_CAST(inode);
|
||||
|
||||
if (generation != 0 && generation != inode->i_generation) {
|
||||
iput(inode);
|
||||
if (generation != 0 && generation != inode->vfs_inode.i_generation) {
|
||||
iput(&inode->vfs_inode);
|
||||
return ERR_PTR(-ESTALE);
|
||||
}
|
||||
|
||||
return d_obtain_alias(inode);
|
||||
return d_obtain_alias(&inode->vfs_inode);
|
||||
}
|
||||
|
||||
static struct dentry *btrfs_fh_to_parent(struct super_block *sb, struct fid *fh,
|
||||
@@ -145,9 +145,10 @@ static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh,
|
||||
|
||||
struct dentry *btrfs_get_parent(struct dentry *child)
|
||||
{
|
||||
struct inode *dir = d_inode(child);
|
||||
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
|
||||
struct btrfs_root *root = BTRFS_I(dir)->root;
|
||||
struct btrfs_inode *dir = BTRFS_I(d_inode(child));
|
||||
struct btrfs_inode *inode;
|
||||
struct btrfs_root *root = dir->root;
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
struct btrfs_path *path;
|
||||
struct extent_buffer *leaf;
|
||||
struct btrfs_root_ref *ref;
|
||||
@@ -159,13 +160,13 @@ struct dentry *btrfs_get_parent(struct dentry *child)
|
||||
if (!path)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (btrfs_ino(BTRFS_I(dir)) == BTRFS_FIRST_FREE_OBJECTID) {
|
||||
if (btrfs_ino(dir) == BTRFS_FIRST_FREE_OBJECTID) {
|
||||
key.objectid = btrfs_root_id(root);
|
||||
key.type = BTRFS_ROOT_BACKREF_KEY;
|
||||
key.offset = (u64)-1;
|
||||
root = fs_info->tree_root;
|
||||
} else {
|
||||
key.objectid = btrfs_ino(BTRFS_I(dir));
|
||||
key.objectid = btrfs_ino(dir);
|
||||
key.type = BTRFS_INODE_REF_KEY;
|
||||
key.offset = (u64)-1;
|
||||
}
|
||||
@@ -210,7 +211,11 @@ struct dentry *btrfs_get_parent(struct dentry *child)
|
||||
found_key.offset, 0);
|
||||
}
|
||||
|
||||
return d_obtain_alias(btrfs_iget(key.objectid, root));
|
||||
inode = btrfs_iget(key.objectid, root);
|
||||
if (IS_ERR(inode))
|
||||
return ERR_CAST(inode);
|
||||
|
||||
return d_obtain_alias(&inode->vfs_inode);
|
||||
fail:
|
||||
btrfs_free_path(path);
|
||||
return ERR_PTR(ret);
|
||||
@@ -219,11 +224,11 @@ fail:
|
||||
static int btrfs_get_name(struct dentry *parent, char *name,
|
||||
struct dentry *child)
|
||||
{
|
||||
struct inode *inode = d_inode(child);
|
||||
struct inode *dir = d_inode(parent);
|
||||
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||
struct btrfs_path *path;
|
||||
struct btrfs_root *root = BTRFS_I(dir)->root;
|
||||
struct btrfs_inode *inode = BTRFS_I(d_inode(child));
|
||||
struct btrfs_inode *dir = BTRFS_I(d_inode(parent));
|
||||
struct btrfs_root *root = dir->root;
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct btrfs_inode_ref *iref;
|
||||
struct btrfs_root_ref *rref;
|
||||
struct extent_buffer *leaf;
|
||||
@@ -233,37 +238,34 @@ static int btrfs_get_name(struct dentry *parent, char *name,
|
||||
int ret;
|
||||
u64 ino;
|
||||
|
||||
if (!S_ISDIR(dir->i_mode))
|
||||
if (!S_ISDIR(dir->vfs_inode.i_mode))
|
||||
return -EINVAL;
|
||||
|
||||
ino = btrfs_ino(BTRFS_I(inode));
|
||||
ino = btrfs_ino(inode);
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ino == BTRFS_FIRST_FREE_OBJECTID) {
|
||||
key.objectid = btrfs_root_id(BTRFS_I(inode)->root);
|
||||
key.objectid = btrfs_root_id(inode->root);
|
||||
key.type = BTRFS_ROOT_BACKREF_KEY;
|
||||
key.offset = (u64)-1;
|
||||
root = fs_info->tree_root;
|
||||
} else {
|
||||
key.objectid = ino;
|
||||
key.offset = btrfs_ino(BTRFS_I(dir));
|
||||
key.type = BTRFS_INODE_REF_KEY;
|
||||
key.offset = btrfs_ino(dir);
|
||||
}
|
||||
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
if (ret < 0) {
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
} else if (ret > 0) {
|
||||
if (ino == BTRFS_FIRST_FREE_OBJECTID) {
|
||||
if (ino == BTRFS_FIRST_FREE_OBJECTID)
|
||||
path->slots[0]--;
|
||||
} else {
|
||||
btrfs_free_path(path);
|
||||
else
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
leaf = path->nodes[0];
|
||||
|
||||
@@ -280,7 +282,6 @@ static int btrfs_get_name(struct dentry *parent, char *name,
|
||||
}
|
||||
|
||||
read_extent_buffer(leaf, name, name_ptr, name_len);
|
||||
btrfs_free_path(path);
|
||||
|
||||
/*
|
||||
* have to add the null termination to make sure that reconnect_path
|
||||
|
||||
@@ -346,10 +346,10 @@ static inline struct extent_state *tree_search(struct extent_io_tree *tree, u64
|
||||
return tree_search_for_insert(tree, offset, NULL, NULL);
|
||||
}
|
||||
|
||||
static void extent_io_tree_panic(const struct extent_io_tree *tree,
|
||||
const struct extent_state *state,
|
||||
const char *opname,
|
||||
int err)
|
||||
static void __cold extent_io_tree_panic(const struct extent_io_tree *tree,
|
||||
const struct extent_state *state,
|
||||
const char *opname,
|
||||
int err)
|
||||
{
|
||||
btrfs_panic(extent_io_tree_to_fs_info(tree), err,
|
||||
"extent io tree error on %s state start %llu end %llu",
|
||||
|
||||
@@ -70,20 +70,17 @@ static int block_group_bits(struct btrfs_block_group *cache, u64 bits)
|
||||
int btrfs_lookup_data_extent(struct btrfs_fs_info *fs_info, u64 start, u64 len)
|
||||
{
|
||||
struct btrfs_root *root = btrfs_extent_root(fs_info, start);
|
||||
int ret;
|
||||
struct btrfs_key key;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
key.objectid = start;
|
||||
key.offset = len;
|
||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
key.offset = len;
|
||||
return btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -103,7 +100,7 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *extent_root;
|
||||
struct btrfs_delayed_ref_head *head;
|
||||
struct btrfs_delayed_ref_root *delayed_refs;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct btrfs_key key;
|
||||
u64 num_refs;
|
||||
u64 extent_flags;
|
||||
@@ -125,16 +122,16 @@ int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans,
|
||||
|
||||
search_again:
|
||||
key.objectid = bytenr;
|
||||
key.offset = offset;
|
||||
if (metadata)
|
||||
key.type = BTRFS_METADATA_ITEM_KEY;
|
||||
else
|
||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
key.offset = offset;
|
||||
|
||||
extent_root = btrfs_extent_root(fs_info, bytenr);
|
||||
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
||||
if (ret < 0)
|
||||
goto out_free;
|
||||
return ret;
|
||||
|
||||
if (ret > 0 && key.type == BTRFS_METADATA_ITEM_KEY) {
|
||||
if (path->slots[0]) {
|
||||
@@ -159,7 +156,7 @@ search_again:
|
||||
"unexpected extent item size, has %u expect >= %zu",
|
||||
item_size, sizeof(*ei));
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out_free;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
|
||||
@@ -170,7 +167,7 @@ search_again:
|
||||
"unexpected zero reference count for extent item (%llu %u %llu)",
|
||||
key.objectid, key.type, key.offset);
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out_free;
|
||||
return ret;
|
||||
}
|
||||
extent_flags = btrfs_extent_flags(leaf, ei);
|
||||
owner = btrfs_get_extent_owner_root(fs_info, leaf, path->slots[0]);
|
||||
@@ -216,8 +213,7 @@ search_again:
|
||||
*flags = extent_flags;
|
||||
if (owning_root)
|
||||
*owning_root = owner;
|
||||
out_free:
|
||||
btrfs_free_path(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1487,7 +1483,7 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_delayed_ref_node *node,
|
||||
struct btrfs_delayed_extent_op *extent_op)
|
||||
{
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct extent_buffer *leaf;
|
||||
struct btrfs_extent_item *item;
|
||||
struct btrfs_key key;
|
||||
@@ -1508,7 +1504,7 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
||||
node->parent, node->ref_root, owner,
|
||||
offset, refs_to_add, extent_op);
|
||||
if ((ret < 0 && ret != -EAGAIN) || !ret)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Ok we had -EAGAIN which means we didn't have space to insert and
|
||||
@@ -1533,8 +1529,7 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
||||
|
||||
if (ret)
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1631,7 +1626,7 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_fs_info *fs_info = trans->fs_info;
|
||||
struct btrfs_root *root;
|
||||
struct btrfs_key key;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct btrfs_extent_item *ei;
|
||||
struct extent_buffer *leaf;
|
||||
u32 item_size;
|
||||
@@ -1662,7 +1657,7 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans,
|
||||
again:
|
||||
ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
return ret;
|
||||
} else if (ret > 0) {
|
||||
if (metadata) {
|
||||
if (path->slots[0] > 0) {
|
||||
@@ -1679,8 +1674,8 @@ again:
|
||||
metadata = 0;
|
||||
|
||||
key.objectid = head->bytenr;
|
||||
key.offset = head->num_bytes;
|
||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
key.offset = head->num_bytes;
|
||||
goto again;
|
||||
}
|
||||
} else {
|
||||
@@ -1688,7 +1683,7 @@ again:
|
||||
btrfs_err(fs_info,
|
||||
"missing extent item for extent %llu num_bytes %llu level %d",
|
||||
head->bytenr, head->num_bytes, head->level);
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1701,13 +1696,12 @@ again:
|
||||
"unexpected extent item size, has %u expect >= %zu",
|
||||
item_size, sizeof(*ei));
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
|
||||
__run_delayed_extent_op(extent_op, leaf, ei);
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2348,8 +2342,8 @@ static noinline int check_committed_ref(struct btrfs_inode *inode,
|
||||
int ret;
|
||||
|
||||
key.objectid = bytenr;
|
||||
key.offset = (u64)-1;
|
||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
key.offset = (u64)-1;
|
||||
|
||||
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
||||
if (ret < 0)
|
||||
@@ -2874,7 +2868,15 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
|
||||
block_group->length,
|
||||
&trimmed);
|
||||
|
||||
/*
|
||||
* Not strictly necessary to lock, as the block_group should be
|
||||
* read-only from btrfs_delete_unused_bgs().
|
||||
*/
|
||||
ASSERT(block_group->ro);
|
||||
spin_lock(&fs_info->unused_bgs_lock);
|
||||
list_del_init(&block_group->bg_list);
|
||||
spin_unlock(&fs_info->unused_bgs_lock);
|
||||
|
||||
btrfs_unfreeze_block_group(block_group);
|
||||
btrfs_put_block_group(block_group);
|
||||
|
||||
@@ -5465,7 +5467,7 @@ static int check_ref_exists(struct btrfs_trans_handle *trans,
|
||||
{
|
||||
struct btrfs_delayed_ref_root *delayed_refs;
|
||||
struct btrfs_delayed_ref_head *head;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct btrfs_extent_inline_ref *iref;
|
||||
int ret;
|
||||
bool exists = false;
|
||||
@@ -5482,7 +5484,6 @@ again:
|
||||
* If we get 0 then we found our reference, return 1, else
|
||||
* return the error if it's not -ENOENT;
|
||||
*/
|
||||
btrfs_free_path(path);
|
||||
return (ret < 0 ) ? ret : 1;
|
||||
}
|
||||
|
||||
@@ -5517,7 +5518,6 @@ again:
|
||||
mutex_unlock(&head->mutex);
|
||||
out:
|
||||
spin_unlock(&delayed_refs->lock);
|
||||
btrfs_free_path(path);
|
||||
return exists ? 1 : 0;
|
||||
}
|
||||
|
||||
@@ -6285,7 +6285,7 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
|
||||
struct extent_buffer *parent)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct walk_control *wc;
|
||||
int level;
|
||||
int parent_level;
|
||||
@@ -6298,10 +6298,8 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
|
||||
return -ENOMEM;
|
||||
|
||||
wc = kzalloc(sizeof(*wc), GFP_NOFS);
|
||||
if (!wc) {
|
||||
btrfs_free_path(path);
|
||||
if (!wc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
btrfs_assert_tree_write_locked(parent);
|
||||
parent_level = btrfs_header_level(parent);
|
||||
@@ -6338,7 +6336,6 @@ int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
|
||||
kfree(wc);
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#define BTRFS_EXTENT_TREE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include "misc.h"
|
||||
#include "block-group.h"
|
||||
#include "locking.h"
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -252,8 +252,6 @@ void clear_folio_extent_mapped(struct folio *folio);
|
||||
|
||||
struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
|
||||
u64 start, u64 owner_root, int level);
|
||||
struct extent_buffer *__alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
|
||||
u64 start, unsigned long len);
|
||||
struct extent_buffer *alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
|
||||
u64 start);
|
||||
struct extent_buffer *btrfs_clone_extent_buffer(const struct extent_buffer *src);
|
||||
@@ -276,7 +274,8 @@ void btrfs_readahead_tree_block(struct btrfs_fs_info *fs_info,
|
||||
u64 bytenr, u64 owner_root, u64 gen, int level);
|
||||
void btrfs_readahead_node_child(struct extent_buffer *node, int slot);
|
||||
|
||||
static inline int num_extent_pages(const struct extent_buffer *eb)
|
||||
/* Note: this can be used in for loops without caching the value in a variable. */
|
||||
static inline int __pure num_extent_pages(const struct extent_buffer *eb)
|
||||
{
|
||||
/*
|
||||
* For sectorsize == PAGE_SIZE case, since nodesize is always aligned to
|
||||
@@ -294,8 +293,10 @@ static inline int num_extent_pages(const struct extent_buffer *eb)
|
||||
* As we can have either one large folio covering the whole eb
|
||||
* (either nodesize <= PAGE_SIZE, or high order folio), or multiple
|
||||
* single-paged folios.
|
||||
*
|
||||
* Note: this can be used in for loops without caching the value in a variable.
|
||||
*/
|
||||
static inline int num_extent_folios(const struct extent_buffer *eb)
|
||||
static inline int __pure num_extent_folios(const struct extent_buffer *eb)
|
||||
{
|
||||
if (folio_order(eb->folios[0]))
|
||||
return 1;
|
||||
|
||||
@@ -163,20 +163,21 @@ int btrfs_insert_hole_extent(struct btrfs_trans_handle *trans,
|
||||
int ret = 0;
|
||||
struct btrfs_file_extent_item *item;
|
||||
struct btrfs_key file_key;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct extent_buffer *leaf;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
file_key.objectid = objectid;
|
||||
file_key.offset = pos;
|
||||
file_key.type = BTRFS_EXTENT_DATA_KEY;
|
||||
file_key.offset = pos;
|
||||
|
||||
ret = btrfs_insert_empty_item(trans, root, path, &file_key,
|
||||
sizeof(*item));
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return ret;
|
||||
leaf = path->nodes[0];
|
||||
item = btrfs_item_ptr(leaf, path->slots[0],
|
||||
struct btrfs_file_extent_item);
|
||||
@@ -190,8 +191,7 @@ int btrfs_insert_hole_extent(struct btrfs_trans_handle *trans,
|
||||
btrfs_set_file_extent_compression(leaf, item, 0);
|
||||
btrfs_set_file_extent_encryption(leaf, item, 0);
|
||||
btrfs_set_file_extent_other_encoding(leaf, item, 0);
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -212,8 +212,8 @@ btrfs_lookup_csum(struct btrfs_trans_handle *trans,
|
||||
int csums_in_item;
|
||||
|
||||
file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
|
||||
file_key.offset = bytenr;
|
||||
file_key.type = BTRFS_EXTENT_CSUM_KEY;
|
||||
file_key.offset = bytenr;
|
||||
ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
@@ -259,8 +259,8 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
|
||||
int cow = mod != 0;
|
||||
|
||||
file_key.objectid = objectid;
|
||||
file_key.offset = offset;
|
||||
file_key.type = BTRFS_EXTENT_DATA_KEY;
|
||||
file_key.offset = offset;
|
||||
|
||||
return btrfs_search_slot(trans, root, &file_key, path, ins_len, cow);
|
||||
}
|
||||
@@ -341,7 +341,7 @@ blk_status_t btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
|
||||
struct btrfs_inode *inode = bbio->inode;
|
||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||
struct bio *bio = &bbio->bio;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
const u32 sectorsize = fs_info->sectorsize;
|
||||
const u32 csum_size = fs_info->csum_size;
|
||||
u32 orig_len = bio->bi_iter.bi_size;
|
||||
@@ -373,10 +373,8 @@ blk_status_t btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
|
||||
|
||||
if (nblocks * csum_size > BTRFS_BIO_INLINE_CSUM_SIZE) {
|
||||
bbio->csum = kmalloc_array(nblocks, csum_size, GFP_NOFS);
|
||||
if (!bbio->csum) {
|
||||
btrfs_free_path(path);
|
||||
if (!bbio->csum)
|
||||
return BLK_STS_RESOURCE;
|
||||
}
|
||||
} else {
|
||||
bbio->csum = bbio->csum_inline;
|
||||
}
|
||||
@@ -444,7 +442,6 @@ blk_status_t btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
|
||||
bio_offset += count * sectorsize;
|
||||
}
|
||||
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -484,8 +481,8 @@ int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end,
|
||||
path->nowait = nowait;
|
||||
|
||||
key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
|
||||
key.offset = start;
|
||||
key.type = BTRFS_EXTENT_CSUM_KEY;
|
||||
key.offset = start;
|
||||
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
if (ret < 0)
|
||||
@@ -874,7 +871,7 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 bytenr, u64 len)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = trans->fs_info;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct btrfs_key key;
|
||||
u64 end_byte = bytenr + len;
|
||||
u64 csum_end;
|
||||
@@ -892,8 +889,8 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
|
||||
|
||||
while (1) {
|
||||
key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
|
||||
key.offset = end_byte - 1;
|
||||
key.type = BTRFS_EXTENT_CSUM_KEY;
|
||||
key.offset = end_byte - 1;
|
||||
|
||||
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
||||
if (ret > 0) {
|
||||
@@ -1010,7 +1007,6 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
btrfs_release_path(path);
|
||||
}
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1074,8 +1070,8 @@ again:
|
||||
found_next = 0;
|
||||
bytenr = sums->logical + total_bytes;
|
||||
file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
|
||||
file_key.offset = bytenr;
|
||||
file_key.type = BTRFS_EXTENT_CSUM_KEY;
|
||||
file_key.offset = bytenr;
|
||||
|
||||
item = btrfs_lookup_csum(trans, root, path, bytenr, 1);
|
||||
if (!IS_ERR(item)) {
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
#ifndef BTRFS_FILE_ITEM_H
|
||||
#define BTRFS_FILE_ITEM_H
|
||||
|
||||
#include <linux/blk_types.h>
|
||||
#include <linux/list.h>
|
||||
#include <uapi/linux/btrfs_tree.h>
|
||||
#include "ctree.h"
|
||||
#include "accessors.h"
|
||||
|
||||
struct extent_map;
|
||||
|
||||
@@ -804,14 +804,15 @@ static int prepare_uptodate_folio(struct inode *inode, struct folio *folio, u64
|
||||
{
|
||||
u64 clamp_start = max_t(u64, pos, folio_pos(folio));
|
||||
u64 clamp_end = min_t(u64, pos + len, folio_pos(folio) + folio_size(folio));
|
||||
const u32 blocksize = inode_to_fs_info(inode)->sectorsize;
|
||||
int ret = 0;
|
||||
|
||||
if (folio_test_uptodate(folio))
|
||||
return 0;
|
||||
|
||||
if (!force_uptodate &&
|
||||
IS_ALIGNED(clamp_start, PAGE_SIZE) &&
|
||||
IS_ALIGNED(clamp_end, PAGE_SIZE))
|
||||
IS_ALIGNED(clamp_start, blocksize) &&
|
||||
IS_ALIGNED(clamp_end, blocksize))
|
||||
return 0;
|
||||
|
||||
ret = btrfs_read_folio(NULL, folio);
|
||||
@@ -874,7 +875,6 @@ again:
|
||||
ret = PTR_ERR(folio);
|
||||
return ret;
|
||||
}
|
||||
folio_wait_writeback(folio);
|
||||
/* Only support page sized folio yet. */
|
||||
ASSERT(folio_order(folio) == 0);
|
||||
ret = set_folio_extent_mapped(folio);
|
||||
@@ -1014,8 +1014,7 @@ int btrfs_check_nocow_lock(struct btrfs_inode *inode, loff_t pos,
|
||||
btrfs_lock_and_flush_ordered_range(inode, lockstart, lockend,
|
||||
&cached_state);
|
||||
}
|
||||
ret = can_nocow_extent(&inode->vfs_inode, lockstart, &num_bytes,
|
||||
NULL, nowait);
|
||||
ret = can_nocow_extent(inode, lockstart, &num_bytes, NULL, nowait);
|
||||
if (ret <= 0)
|
||||
btrfs_drew_write_unlock(&root->snapshot_lock);
|
||||
else
|
||||
@@ -1783,6 +1782,7 @@ static vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf)
|
||||
struct extent_changeset *data_reserved = NULL;
|
||||
unsigned long zero_start;
|
||||
loff_t size;
|
||||
size_t fsize = folio_size(folio);
|
||||
vm_fault_t ret;
|
||||
int ret2;
|
||||
int reserved = 0;
|
||||
@@ -1793,7 +1793,7 @@ static vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf)
|
||||
|
||||
ASSERT(folio_order(folio) == 0);
|
||||
|
||||
reserved_space = PAGE_SIZE;
|
||||
reserved_space = fsize;
|
||||
|
||||
sb_start_pagefault(inode->i_sb);
|
||||
page_start = folio_pos(folio);
|
||||
@@ -1847,7 +1847,7 @@ again:
|
||||
* We can't set the delalloc bits if there are pending ordered
|
||||
* extents. Drop our locks and wait for them to finish.
|
||||
*/
|
||||
ordered = btrfs_lookup_ordered_range(BTRFS_I(inode), page_start, PAGE_SIZE);
|
||||
ordered = btrfs_lookup_ordered_range(BTRFS_I(inode), page_start, fsize);
|
||||
if (ordered) {
|
||||
unlock_extent(io_tree, page_start, page_end, &cached_state);
|
||||
folio_unlock(folio);
|
||||
@@ -1859,11 +1859,11 @@ again:
|
||||
|
||||
if (folio->index == ((size - 1) >> PAGE_SHIFT)) {
|
||||
reserved_space = round_up(size - page_start, fs_info->sectorsize);
|
||||
if (reserved_space < PAGE_SIZE) {
|
||||
if (reserved_space < fsize) {
|
||||
end = page_start + reserved_space - 1;
|
||||
btrfs_delalloc_release_space(BTRFS_I(inode),
|
||||
data_reserved, page_start,
|
||||
PAGE_SIZE - reserved_space, true);
|
||||
fsize - reserved_space, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1890,12 +1890,12 @@ again:
|
||||
if (page_start + folio_size(folio) > size)
|
||||
zero_start = offset_in_folio(folio, size);
|
||||
else
|
||||
zero_start = PAGE_SIZE;
|
||||
zero_start = fsize;
|
||||
|
||||
if (zero_start != PAGE_SIZE)
|
||||
if (zero_start != fsize)
|
||||
folio_zero_range(folio, zero_start, folio_size(folio) - zero_start);
|
||||
|
||||
btrfs_folio_clear_checked(fs_info, folio, page_start, PAGE_SIZE);
|
||||
btrfs_folio_clear_checked(fs_info, folio, page_start, fsize);
|
||||
btrfs_folio_set_dirty(fs_info, folio, page_start, end + 1 - page_start);
|
||||
btrfs_folio_set_uptodate(fs_info, folio, page_start, end + 1 - page_start);
|
||||
|
||||
@@ -1904,7 +1904,7 @@ again:
|
||||
unlock_extent(io_tree, page_start, page_end, &cached_state);
|
||||
up_read(&BTRFS_I(inode)->i_mmap_lock);
|
||||
|
||||
btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE);
|
||||
btrfs_delalloc_release_extents(BTRFS_I(inode), fsize);
|
||||
sb_end_pagefault(inode->i_sb);
|
||||
extent_changeset_free(data_reserved);
|
||||
return VM_FAULT_LOCKED;
|
||||
@@ -1913,7 +1913,7 @@ out_unlock:
|
||||
folio_unlock(folio);
|
||||
up_read(&BTRFS_I(inode)->i_mmap_lock);
|
||||
out:
|
||||
btrfs_delalloc_release_extents(BTRFS_I(inode), PAGE_SIZE);
|
||||
btrfs_delalloc_release_extents(BTRFS_I(inode), fsize);
|
||||
btrfs_delalloc_release_space(BTRFS_I(inode), data_reserved, page_start,
|
||||
reserved_space, (ret != 0));
|
||||
out_noreserve:
|
||||
|
||||
@@ -9,6 +9,8 @@ struct file;
|
||||
struct extent_state;
|
||||
struct kiocb;
|
||||
struct iov_iter;
|
||||
struct inode;
|
||||
struct folio;
|
||||
struct page;
|
||||
struct btrfs_ioctl_encoded_io_args;
|
||||
struct btrfs_drop_extents_args;
|
||||
|
||||
@@ -88,13 +88,13 @@ static struct inode *__lookup_free_space_inode(struct btrfs_root *root,
|
||||
struct btrfs_disk_key disk_key;
|
||||
struct btrfs_free_space_header *header;
|
||||
struct extent_buffer *leaf;
|
||||
struct inode *inode = NULL;
|
||||
struct btrfs_inode *inode;
|
||||
unsigned nofs_flag;
|
||||
int ret;
|
||||
|
||||
key.objectid = BTRFS_FREE_SPACE_OBJECTID;
|
||||
key.offset = offset;
|
||||
key.type = 0;
|
||||
key.offset = offset;
|
||||
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
if (ret < 0)
|
||||
@@ -120,13 +120,13 @@ static struct inode *__lookup_free_space_inode(struct btrfs_root *root,
|
||||
btrfs_release_path(path);
|
||||
memalloc_nofs_restore(nofs_flag);
|
||||
if (IS_ERR(inode))
|
||||
return inode;
|
||||
return ERR_CAST(inode);
|
||||
|
||||
mapping_set_gfp_mask(inode->i_mapping,
|
||||
mapping_gfp_constraint(inode->i_mapping,
|
||||
mapping_set_gfp_mask(inode->vfs_inode.i_mapping,
|
||||
mapping_gfp_constraint(inode->vfs_inode.i_mapping,
|
||||
~(__GFP_FS | __GFP_HIGHMEM)));
|
||||
|
||||
return inode;
|
||||
return &inode->vfs_inode;
|
||||
}
|
||||
|
||||
struct inode *lookup_free_space_inode(struct btrfs_block_group *block_group,
|
||||
@@ -201,8 +201,8 @@ static int __create_free_space_inode(struct btrfs_root *root,
|
||||
btrfs_release_path(path);
|
||||
|
||||
key.objectid = BTRFS_FREE_SPACE_OBJECTID;
|
||||
key.offset = offset;
|
||||
key.type = 0;
|
||||
key.offset = offset;
|
||||
ret = btrfs_insert_empty_item(trans, root, path, &key,
|
||||
sizeof(struct btrfs_free_space_header));
|
||||
if (ret < 0) {
|
||||
@@ -244,7 +244,7 @@ int btrfs_remove_free_space_inode(struct btrfs_trans_handle *trans,
|
||||
struct inode *inode,
|
||||
struct btrfs_block_group *block_group)
|
||||
{
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct btrfs_key key;
|
||||
int ret = 0;
|
||||
|
||||
@@ -257,12 +257,12 @@ int btrfs_remove_free_space_inode(struct btrfs_trans_handle *trans,
|
||||
if (IS_ERR(inode)) {
|
||||
if (PTR_ERR(inode) != -ENOENT)
|
||||
ret = PTR_ERR(inode);
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
ret = btrfs_orphan_add(trans, BTRFS_I(inode));
|
||||
if (ret) {
|
||||
btrfs_add_delayed_iput(BTRFS_I(inode));
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
clear_nlink(inode);
|
||||
/* One for the block groups ref */
|
||||
@@ -285,12 +285,9 @@ int btrfs_remove_free_space_inode(struct btrfs_trans_handle *trans,
|
||||
if (ret) {
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
goto out;
|
||||
return ret;
|
||||
}
|
||||
ret = btrfs_del_item(trans, trans->fs_info->tree_root, path);
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
return btrfs_del_item(trans, trans->fs_info->tree_root, path);
|
||||
}
|
||||
|
||||
int btrfs_truncate_free_space_cache(struct btrfs_trans_handle *trans,
|
||||
@@ -447,7 +444,7 @@ static void io_ctl_drop_pages(struct btrfs_io_ctl *io_ctl)
|
||||
|
||||
static int io_ctl_prepare_pages(struct btrfs_io_ctl *io_ctl, bool uptodate)
|
||||
{
|
||||
struct page *page;
|
||||
struct folio *folio;
|
||||
struct inode *inode = io_ctl->inode;
|
||||
gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping);
|
||||
int i;
|
||||
@@ -455,31 +452,33 @@ static int io_ctl_prepare_pages(struct btrfs_io_ctl *io_ctl, bool uptodate)
|
||||
for (i = 0; i < io_ctl->num_pages; i++) {
|
||||
int ret;
|
||||
|
||||
page = find_or_create_page(inode->i_mapping, i, mask);
|
||||
if (!page) {
|
||||
folio = __filemap_get_folio(inode->i_mapping, i,
|
||||
FGP_LOCK | FGP_ACCESSED | FGP_CREAT,
|
||||
mask);
|
||||
if (IS_ERR(folio)) {
|
||||
io_ctl_drop_pages(io_ctl);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = set_folio_extent_mapped(page_folio(page));
|
||||
ret = set_folio_extent_mapped(folio);
|
||||
if (ret < 0) {
|
||||
unlock_page(page);
|
||||
put_page(page);
|
||||
folio_unlock(folio);
|
||||
folio_put(folio);
|
||||
io_ctl_drop_pages(io_ctl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
io_ctl->pages[i] = page;
|
||||
if (uptodate && !PageUptodate(page)) {
|
||||
btrfs_read_folio(NULL, page_folio(page));
|
||||
lock_page(page);
|
||||
if (page->mapping != inode->i_mapping) {
|
||||
io_ctl->pages[i] = &folio->page;
|
||||
if (uptodate && !folio_test_uptodate(folio)) {
|
||||
btrfs_read_folio(NULL, folio);
|
||||
folio_lock(folio);
|
||||
if (folio->mapping != inode->i_mapping) {
|
||||
btrfs_err(BTRFS_I(inode)->root->fs_info,
|
||||
"free space cache page truncated");
|
||||
io_ctl_drop_pages(io_ctl);
|
||||
return -EIO;
|
||||
}
|
||||
if (!PageUptodate(page)) {
|
||||
if (!folio_test_uptodate(folio)) {
|
||||
btrfs_err(BTRFS_I(inode)->root->fs_info,
|
||||
"error reading free space cache");
|
||||
io_ctl_drop_pages(io_ctl);
|
||||
@@ -753,8 +752,8 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
|
||||
return 0;
|
||||
|
||||
key.objectid = BTRFS_FREE_SPACE_OBJECTID;
|
||||
key.offset = offset;
|
||||
key.type = 0;
|
||||
key.offset = offset;
|
||||
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
if (ret < 0)
|
||||
@@ -1156,8 +1155,8 @@ update_cache_item(struct btrfs_trans_handle *trans,
|
||||
int ret;
|
||||
|
||||
key.objectid = BTRFS_FREE_SPACE_OBJECTID;
|
||||
key.offset = offset;
|
||||
key.type = 0;
|
||||
key.offset = offset;
|
||||
|
||||
ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
|
||||
if (ret < 0) {
|
||||
|
||||
@@ -1062,7 +1062,8 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_block_group *block_group)
|
||||
{
|
||||
struct btrfs_root *extent_root;
|
||||
struct btrfs_path *path, *path2;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
BTRFS_PATH_AUTO_FREE(path2);
|
||||
struct btrfs_key key;
|
||||
u64 start, end;
|
||||
int ret;
|
||||
@@ -1070,17 +1071,16 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
path->reada = READA_FORWARD;
|
||||
|
||||
path2 = btrfs_alloc_path();
|
||||
if (!path2) {
|
||||
btrfs_free_path(path);
|
||||
if (!path2)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
path->reada = READA_FORWARD;
|
||||
|
||||
ret = add_new_free_space_info(trans, block_group, path2);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
mutex_lock(&block_group->free_space_lock);
|
||||
|
||||
@@ -1146,9 +1146,7 @@ static int populate_free_space_tree(struct btrfs_trans_handle *trans,
|
||||
ret = 0;
|
||||
out_locked:
|
||||
mutex_unlock(&block_group->free_space_lock);
|
||||
out:
|
||||
btrfs_free_path(path2);
|
||||
btrfs_free_path(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1217,7 +1215,7 @@ out_clear:
|
||||
static int clear_free_space_tree(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
struct btrfs_key key;
|
||||
int nr;
|
||||
int ret;
|
||||
@@ -1233,7 +1231,7 @@ static int clear_free_space_tree(struct btrfs_trans_handle *trans,
|
||||
while (1) {
|
||||
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
nr = btrfs_header_nritems(path->nodes[0]);
|
||||
if (!nr)
|
||||
@@ -1242,15 +1240,12 @@ static int clear_free_space_tree(struct btrfs_trans_handle *trans,
|
||||
path->slots[0] = 0;
|
||||
ret = btrfs_del_items(trans, root, path, 0, nr);
|
||||
if (ret)
|
||||
goto out;
|
||||
return ret;
|
||||
|
||||
btrfs_release_path(path);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_delete_free_space_tree(struct btrfs_fs_info *fs_info)
|
||||
@@ -1638,9 +1633,8 @@ int load_free_space_tree(struct btrfs_caching_control *caching_ctl)
|
||||
{
|
||||
struct btrfs_block_group *block_group;
|
||||
struct btrfs_free_space_info *info;
|
||||
struct btrfs_path *path;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
u32 extent_count, flags;
|
||||
int ret;
|
||||
|
||||
block_group = caching_ctl->block_group;
|
||||
|
||||
@@ -1657,10 +1651,9 @@ int load_free_space_tree(struct btrfs_caching_control *caching_ctl)
|
||||
path->reada = READA_FORWARD;
|
||||
|
||||
info = search_free_space_info(NULL, block_group, path, 0);
|
||||
if (IS_ERR(info)) {
|
||||
ret = PTR_ERR(info);
|
||||
goto out;
|
||||
}
|
||||
if (IS_ERR(info))
|
||||
return PTR_ERR(info);
|
||||
|
||||
extent_count = btrfs_free_space_extent_count(path->nodes[0], info);
|
||||
flags = btrfs_free_space_flags(path->nodes[0], info);
|
||||
|
||||
@@ -1670,11 +1663,7 @@ int load_free_space_tree(struct btrfs_caching_control *caching_ctl)
|
||||
* there.
|
||||
*/
|
||||
if (flags & BTRFS_FREE_SPACE_USING_BITMAPS)
|
||||
ret = load_free_space_bitmaps(caching_ctl, path, extent_count);
|
||||
return load_free_space_bitmaps(caching_ctl, path, extent_count);
|
||||
else
|
||||
ret = load_free_space_extents(caching_ctl, path, extent_count);
|
||||
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
return load_free_space_extents(caching_ctl, path, extent_count);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include "messages.h"
|
||||
#include "ctree.h"
|
||||
#include "fs.h"
|
||||
#include "accessors.h"
|
||||
#include "volumes.h"
|
||||
|
||||
@@ -47,6 +47,18 @@ struct btrfs_subpage_info;
|
||||
struct btrfs_stripe_hash_table;
|
||||
struct btrfs_space_info;
|
||||
|
||||
/*
|
||||
* Minimum data and metadata block size.
|
||||
*
|
||||
* Normally it's 4K, but for testing subpage block size on 4K page systems, we
|
||||
* allow DEBUG builds to accept 2K page size.
|
||||
*/
|
||||
#ifdef CONFIG_BTRFS_DEBUG
|
||||
#define BTRFS_MIN_BLOCKSIZE (SZ_2K)
|
||||
#else
|
||||
#define BTRFS_MIN_BLOCKSIZE (SZ_4K)
|
||||
#endif
|
||||
|
||||
#define BTRFS_MAX_EXTENT_SIZE SZ_128M
|
||||
|
||||
#define BTRFS_OLDEST_GENERATION 0ULL
|
||||
@@ -105,6 +117,9 @@ enum {
|
||||
/* Indicates there was an error cleaning up a log tree. */
|
||||
BTRFS_FS_STATE_LOG_CLEANUP_ERROR,
|
||||
|
||||
/* No more delayed iput can be queued. */
|
||||
BTRFS_FS_STATE_NO_DELAYED_IPUT,
|
||||
|
||||
BTRFS_FS_STATE_COUNT
|
||||
};
|
||||
|
||||
@@ -485,8 +500,8 @@ struct btrfs_fs_info {
|
||||
u64 last_trans_log_full_commit;
|
||||
unsigned long long mount_opt;
|
||||
|
||||
unsigned long compress_type:4;
|
||||
unsigned int compress_level;
|
||||
int compress_type;
|
||||
int compress_level;
|
||||
u32 commit_interval;
|
||||
/*
|
||||
* It is a suggestive number, the read side is safe even it gets a
|
||||
@@ -709,7 +724,6 @@ struct btrfs_fs_info {
|
||||
* running.
|
||||
*/
|
||||
refcount_t scrub_workers_refcnt;
|
||||
u32 sectors_per_page;
|
||||
struct workqueue_struct *scrub_workers;
|
||||
|
||||
struct btrfs_discard_ctl discard_ctl;
|
||||
@@ -981,6 +995,12 @@ static inline u32 count_max_extents(const struct btrfs_fs_info *fs_info, u64 siz
|
||||
return div_u64(size + fs_info->max_extent_size - 1, fs_info->max_extent_size);
|
||||
}
|
||||
|
||||
static inline unsigned int btrfs_blocks_per_folio(const struct btrfs_fs_info *fs_info,
|
||||
const struct folio *folio)
|
||||
{
|
||||
return folio_size(folio) >> fs_info->sectorsize_bits;
|
||||
}
|
||||
|
||||
bool btrfs_exclop_start(struct btrfs_fs_info *fs_info,
|
||||
enum btrfs_exclusive_operation type);
|
||||
bool btrfs_exclop_start_try_lock(struct btrfs_fs_info *fs_info,
|
||||
|
||||
@@ -191,8 +191,8 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
|
||||
int del_len = name->len + sizeof(*ref);
|
||||
|
||||
key.objectid = inode_objectid;
|
||||
key.offset = ref_objectid;
|
||||
key.type = BTRFS_INODE_REF_KEY;
|
||||
key.offset = ref_objectid;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
@@ -317,8 +317,8 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
|
||||
int ins_len = name->len + sizeof(*ref);
|
||||
|
||||
key.objectid = inode_objectid;
|
||||
key.offset = ref_objectid;
|
||||
key.type = BTRFS_INODE_REF_KEY;
|
||||
key.offset = ref_objectid;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
@@ -493,8 +493,8 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
|
||||
path->reada = READA_BACK;
|
||||
|
||||
key.objectid = control->ino;
|
||||
key.offset = (u64)-1;
|
||||
key.type = (u8)-1;
|
||||
key.offset = (u64)-1;
|
||||
|
||||
search_again:
|
||||
/*
|
||||
|
||||
587
fs/btrfs/inode.c
587
fs/btrfs/inode.c
File diff suppressed because it is too large
Load Diff
217
fs/btrfs/ioctl.c
217
fs/btrfs/ioctl.c
@@ -118,8 +118,8 @@ struct btrfs_ioctl_encoded_io_args_32 {
|
||||
#endif
|
||||
|
||||
/* Mask out flags that are inappropriate for the given type of inode. */
|
||||
static unsigned int btrfs_mask_fsflags_for_type(struct inode *inode,
|
||||
unsigned int flags)
|
||||
static unsigned int btrfs_mask_fsflags_for_type(const struct inode *inode,
|
||||
unsigned int flags)
|
||||
{
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
return flags;
|
||||
@@ -133,11 +133,11 @@ static unsigned int btrfs_mask_fsflags_for_type(struct inode *inode,
|
||||
* Export internal inode flags to the format expected by the FS_IOC_GETFLAGS
|
||||
* ioctl.
|
||||
*/
|
||||
static unsigned int btrfs_inode_flags_to_fsflags(struct btrfs_inode *binode)
|
||||
static unsigned int btrfs_inode_flags_to_fsflags(const struct btrfs_inode *inode)
|
||||
{
|
||||
unsigned int iflags = 0;
|
||||
u32 flags = binode->flags;
|
||||
u32 ro_flags = binode->ro_flags;
|
||||
u32 flags = inode->flags;
|
||||
u32 ro_flags = inode->ro_flags;
|
||||
|
||||
if (flags & BTRFS_INODE_SYNC)
|
||||
iflags |= FS_SYNC_FL;
|
||||
@@ -167,25 +167,24 @@ static unsigned int btrfs_inode_flags_to_fsflags(struct btrfs_inode *binode)
|
||||
/*
|
||||
* Update inode->i_flags based on the btrfs internal flags.
|
||||
*/
|
||||
void btrfs_sync_inode_flags_to_i_flags(struct inode *inode)
|
||||
void btrfs_sync_inode_flags_to_i_flags(struct btrfs_inode *inode)
|
||||
{
|
||||
struct btrfs_inode *binode = BTRFS_I(inode);
|
||||
unsigned int new_fl = 0;
|
||||
|
||||
if (binode->flags & BTRFS_INODE_SYNC)
|
||||
if (inode->flags & BTRFS_INODE_SYNC)
|
||||
new_fl |= S_SYNC;
|
||||
if (binode->flags & BTRFS_INODE_IMMUTABLE)
|
||||
if (inode->flags & BTRFS_INODE_IMMUTABLE)
|
||||
new_fl |= S_IMMUTABLE;
|
||||
if (binode->flags & BTRFS_INODE_APPEND)
|
||||
if (inode->flags & BTRFS_INODE_APPEND)
|
||||
new_fl |= S_APPEND;
|
||||
if (binode->flags & BTRFS_INODE_NOATIME)
|
||||
if (inode->flags & BTRFS_INODE_NOATIME)
|
||||
new_fl |= S_NOATIME;
|
||||
if (binode->flags & BTRFS_INODE_DIRSYNC)
|
||||
if (inode->flags & BTRFS_INODE_DIRSYNC)
|
||||
new_fl |= S_DIRSYNC;
|
||||
if (binode->ro_flags & BTRFS_INODE_RO_VERITY)
|
||||
if (inode->ro_flags & BTRFS_INODE_RO_VERITY)
|
||||
new_fl |= S_VERITY;
|
||||
|
||||
set_mask_bits(&inode->i_flags,
|
||||
set_mask_bits(&inode->vfs_inode.i_flags,
|
||||
S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME | S_DIRSYNC |
|
||||
S_VERITY, new_fl);
|
||||
}
|
||||
@@ -219,7 +218,7 @@ static int check_fsflags(unsigned int old_flags, unsigned int flags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_fsflags_compatible(struct btrfs_fs_info *fs_info,
|
||||
static int check_fsflags_compatible(const struct btrfs_fs_info *fs_info,
|
||||
unsigned int flags)
|
||||
{
|
||||
if (btrfs_is_zoned(fs_info) && (flags & FS_NOCOW_FL))
|
||||
@@ -248,24 +247,23 @@ static int btrfs_check_ioctl_vol_args2_subvol_name(const struct btrfs_ioctl_vol_
|
||||
*/
|
||||
int btrfs_fileattr_get(struct dentry *dentry, struct fileattr *fa)
|
||||
{
|
||||
struct btrfs_inode *binode = BTRFS_I(d_inode(dentry));
|
||||
const struct btrfs_inode *inode = BTRFS_I(d_inode(dentry));
|
||||
|
||||
fileattr_fill_flags(fa, btrfs_inode_flags_to_fsflags(binode));
|
||||
fileattr_fill_flags(fa, btrfs_inode_flags_to_fsflags(inode));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_fileattr_set(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, struct fileattr *fa)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||
struct btrfs_inode *binode = BTRFS_I(inode);
|
||||
struct btrfs_root *root = binode->root;
|
||||
struct btrfs_inode *inode = BTRFS_I(d_inode(dentry));
|
||||
struct btrfs_root *root = inode->root;
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
struct btrfs_trans_handle *trans;
|
||||
unsigned int fsflags, old_fsflags;
|
||||
int ret;
|
||||
const char *comp = NULL;
|
||||
u32 binode_flags;
|
||||
u32 inode_flags;
|
||||
|
||||
if (btrfs_root_readonly(root))
|
||||
return -EROFS;
|
||||
@@ -273,8 +271,8 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
|
||||
if (fileattr_has_fsx(fa))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
fsflags = btrfs_mask_fsflags_for_type(inode, fa->flags);
|
||||
old_fsflags = btrfs_inode_flags_to_fsflags(binode);
|
||||
fsflags = btrfs_mask_fsflags_for_type(&inode->vfs_inode, fa->flags);
|
||||
old_fsflags = btrfs_inode_flags_to_fsflags(inode);
|
||||
ret = check_fsflags(old_fsflags, fsflags);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -283,27 +281,27 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
binode_flags = binode->flags;
|
||||
inode_flags = inode->flags;
|
||||
if (fsflags & FS_SYNC_FL)
|
||||
binode_flags |= BTRFS_INODE_SYNC;
|
||||
inode_flags |= BTRFS_INODE_SYNC;
|
||||
else
|
||||
binode_flags &= ~BTRFS_INODE_SYNC;
|
||||
inode_flags &= ~BTRFS_INODE_SYNC;
|
||||
if (fsflags & FS_IMMUTABLE_FL)
|
||||
binode_flags |= BTRFS_INODE_IMMUTABLE;
|
||||
inode_flags |= BTRFS_INODE_IMMUTABLE;
|
||||
else
|
||||
binode_flags &= ~BTRFS_INODE_IMMUTABLE;
|
||||
inode_flags &= ~BTRFS_INODE_IMMUTABLE;
|
||||
if (fsflags & FS_APPEND_FL)
|
||||
binode_flags |= BTRFS_INODE_APPEND;
|
||||
inode_flags |= BTRFS_INODE_APPEND;
|
||||
else
|
||||
binode_flags &= ~BTRFS_INODE_APPEND;
|
||||
inode_flags &= ~BTRFS_INODE_APPEND;
|
||||
if (fsflags & FS_NODUMP_FL)
|
||||
binode_flags |= BTRFS_INODE_NODUMP;
|
||||
inode_flags |= BTRFS_INODE_NODUMP;
|
||||
else
|
||||
binode_flags &= ~BTRFS_INODE_NODUMP;
|
||||
inode_flags &= ~BTRFS_INODE_NODUMP;
|
||||
if (fsflags & FS_NOATIME_FL)
|
||||
binode_flags |= BTRFS_INODE_NOATIME;
|
||||
inode_flags |= BTRFS_INODE_NOATIME;
|
||||
else
|
||||
binode_flags &= ~BTRFS_INODE_NOATIME;
|
||||
inode_flags &= ~BTRFS_INODE_NOATIME;
|
||||
|
||||
/* If coming from FS_IOC_FSSETXATTR then skip unconverted flags */
|
||||
if (!fa->flags_valid) {
|
||||
@@ -315,32 +313,32 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
|
||||
}
|
||||
|
||||
if (fsflags & FS_DIRSYNC_FL)
|
||||
binode_flags |= BTRFS_INODE_DIRSYNC;
|
||||
inode_flags |= BTRFS_INODE_DIRSYNC;
|
||||
else
|
||||
binode_flags &= ~BTRFS_INODE_DIRSYNC;
|
||||
inode_flags &= ~BTRFS_INODE_DIRSYNC;
|
||||
if (fsflags & FS_NOCOW_FL) {
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
if (S_ISREG(inode->vfs_inode.i_mode)) {
|
||||
/*
|
||||
* It's safe to turn csums off here, no extents exist.
|
||||
* Otherwise we want the flag to reflect the real COW
|
||||
* status of the file and will not set it.
|
||||
*/
|
||||
if (inode->i_size == 0)
|
||||
binode_flags |= BTRFS_INODE_NODATACOW |
|
||||
BTRFS_INODE_NODATASUM;
|
||||
if (inode->vfs_inode.i_size == 0)
|
||||
inode_flags |= BTRFS_INODE_NODATACOW |
|
||||
BTRFS_INODE_NODATASUM;
|
||||
} else {
|
||||
binode_flags |= BTRFS_INODE_NODATACOW;
|
||||
inode_flags |= BTRFS_INODE_NODATACOW;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Revert back under same assumptions as above
|
||||
*/
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
if (inode->i_size == 0)
|
||||
binode_flags &= ~(BTRFS_INODE_NODATACOW |
|
||||
BTRFS_INODE_NODATASUM);
|
||||
if (S_ISREG(inode->vfs_inode.i_mode)) {
|
||||
if (inode->vfs_inode.i_size == 0)
|
||||
inode_flags &= ~(BTRFS_INODE_NODATACOW |
|
||||
BTRFS_INODE_NODATASUM);
|
||||
} else {
|
||||
binode_flags &= ~BTRFS_INODE_NODATACOW;
|
||||
inode_flags &= ~BTRFS_INODE_NODATACOW;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,21 +348,21 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
|
||||
* things smaller.
|
||||
*/
|
||||
if (fsflags & FS_NOCOMP_FL) {
|
||||
binode_flags &= ~BTRFS_INODE_COMPRESS;
|
||||
binode_flags |= BTRFS_INODE_NOCOMPRESS;
|
||||
inode_flags &= ~BTRFS_INODE_COMPRESS;
|
||||
inode_flags |= BTRFS_INODE_NOCOMPRESS;
|
||||
} else if (fsflags & FS_COMPR_FL) {
|
||||
|
||||
if (IS_SWAPFILE(inode))
|
||||
if (IS_SWAPFILE(&inode->vfs_inode))
|
||||
return -ETXTBSY;
|
||||
|
||||
binode_flags |= BTRFS_INODE_COMPRESS;
|
||||
binode_flags &= ~BTRFS_INODE_NOCOMPRESS;
|
||||
inode_flags |= BTRFS_INODE_COMPRESS;
|
||||
inode_flags &= ~BTRFS_INODE_NOCOMPRESS;
|
||||
|
||||
comp = btrfs_compress_type2str(fs_info->compress_type);
|
||||
if (!comp || comp[0] == 0)
|
||||
comp = btrfs_compress_type2str(BTRFS_COMPRESS_ZLIB);
|
||||
} else {
|
||||
binode_flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS);
|
||||
inode_flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -376,15 +374,14 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
|
||||
return PTR_ERR(trans);
|
||||
|
||||
if (comp) {
|
||||
ret = btrfs_set_prop(trans, BTRFS_I(inode), "btrfs.compression",
|
||||
ret = btrfs_set_prop(trans, inode, "btrfs.compression",
|
||||
comp, strlen(comp), 0);
|
||||
if (ret) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out_end_trans;
|
||||
}
|
||||
} else {
|
||||
ret = btrfs_set_prop(trans, BTRFS_I(inode), "btrfs.compression",
|
||||
NULL, 0, 0);
|
||||
ret = btrfs_set_prop(trans, inode, "btrfs.compression", NULL, 0, 0);
|
||||
if (ret && ret != -ENODATA) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto out_end_trans;
|
||||
@@ -392,18 +389,19 @@ int btrfs_fileattr_set(struct mnt_idmap *idmap,
|
||||
}
|
||||
|
||||
update_flags:
|
||||
binode->flags = binode_flags;
|
||||
inode->flags = inode_flags;
|
||||
btrfs_update_inode_mapping_flags(inode);
|
||||
btrfs_sync_inode_flags_to_i_flags(inode);
|
||||
inode_inc_iversion(inode);
|
||||
inode_set_ctime_current(inode);
|
||||
ret = btrfs_update_inode(trans, BTRFS_I(inode));
|
||||
inode_inc_iversion(&inode->vfs_inode);
|
||||
inode_set_ctime_current(&inode->vfs_inode);
|
||||
ret = btrfs_update_inode(trans, inode);
|
||||
|
||||
out_end_trans:
|
||||
btrfs_end_transaction(trans);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int btrfs_ioctl_getversion(struct inode *inode, int __user *arg)
|
||||
static int btrfs_ioctl_getversion(const struct inode *inode, int __user *arg)
|
||||
{
|
||||
return put_user(inode->i_generation, arg);
|
||||
}
|
||||
@@ -475,7 +473,7 @@ static noinline int btrfs_ioctl_fitrim(struct btrfs_fs_info *fs_info,
|
||||
* Calculate the number of transaction items to reserve for creating a subvolume
|
||||
* or snapshot, not including the inode, directory entries, or parent directory.
|
||||
*/
|
||||
static unsigned int create_subvol_num_items(struct btrfs_qgroup_inherit *inherit)
|
||||
static unsigned int create_subvol_num_items(const struct btrfs_qgroup_inherit *inherit)
|
||||
{
|
||||
/*
|
||||
* 1 to add root block
|
||||
@@ -617,8 +615,8 @@ static noinline int create_subvol(struct mnt_idmap *idmap,
|
||||
btrfs_set_root_dirid(root_item, BTRFS_FIRST_FREE_OBJECTID);
|
||||
|
||||
key.objectid = objectid;
|
||||
key.offset = 0;
|
||||
key.type = BTRFS_ROOT_ITEM_KEY;
|
||||
key.offset = 0;
|
||||
ret = btrfs_insert_root(trans, fs_info->tree_root, &key,
|
||||
root_item);
|
||||
if (ret) {
|
||||
@@ -878,7 +876,7 @@ static int btrfs_may_delete(struct mnt_idmap *idmap,
|
||||
|
||||
/* copy of may_create in fs/namei.c() */
|
||||
static inline int btrfs_may_create(struct mnt_idmap *idmap,
|
||||
struct inode *dir, struct dentry *child)
|
||||
struct inode *dir, const struct dentry *child)
|
||||
{
|
||||
if (d_really_is_positive(child))
|
||||
return -EEXIST;
|
||||
@@ -1033,17 +1031,14 @@ static noinline int btrfs_ioctl_resize(struct file *file,
|
||||
void __user *arg)
|
||||
{
|
||||
BTRFS_DEV_LOOKUP_ARGS(args);
|
||||
struct inode *inode = file_inode(file);
|
||||
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||
struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
u64 new_size;
|
||||
u64 old_size;
|
||||
u64 devid = 1;
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
struct btrfs_ioctl_vol_args *vol_args;
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_device *device = NULL;
|
||||
char *sizestr;
|
||||
char *retptr;
|
||||
char *devstr = NULL;
|
||||
int ret = 0;
|
||||
int mod = 0;
|
||||
@@ -1111,6 +1106,8 @@ static noinline int btrfs_ioctl_resize(struct file *file,
|
||||
if (!strcmp(sizestr, "max"))
|
||||
new_size = bdev_nr_bytes(device->bdev);
|
||||
else {
|
||||
char *retptr;
|
||||
|
||||
if (sizestr[0] == '-') {
|
||||
mod = -1;
|
||||
sizestr++;
|
||||
@@ -1158,6 +1155,8 @@ static noinline int btrfs_ioctl_resize(struct file *file,
|
||||
new_size = round_down(new_size, fs_info->sectorsize);
|
||||
|
||||
if (new_size > old_size) {
|
||||
struct btrfs_trans_handle *trans;
|
||||
|
||||
trans = btrfs_start_transaction(root, 0);
|
||||
if (IS_ERR(trans)) {
|
||||
ret = PTR_ERR(trans);
|
||||
@@ -1336,15 +1335,15 @@ free_args:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static noinline int btrfs_ioctl_subvol_getflags(struct inode *inode,
|
||||
static noinline int btrfs_ioctl_subvol_getflags(struct btrfs_inode *inode,
|
||||
void __user *arg)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
struct btrfs_root *root = inode->root;
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
int ret = 0;
|
||||
u64 flags = 0;
|
||||
|
||||
if (btrfs_ino(BTRFS_I(inode)) != BTRFS_FIRST_FREE_OBJECTID)
|
||||
if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID)
|
||||
return -EINVAL;
|
||||
|
||||
down_read(&fs_info->subvol_sem);
|
||||
@@ -1447,8 +1446,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static noinline int key_in_sk(struct btrfs_key *key,
|
||||
struct btrfs_ioctl_search_key *sk)
|
||||
static noinline int key_in_sk(const struct btrfs_key *key,
|
||||
const struct btrfs_ioctl_search_key *sk)
|
||||
{
|
||||
struct btrfs_key test;
|
||||
int ret;
|
||||
@@ -1473,7 +1472,7 @@ static noinline int key_in_sk(struct btrfs_key *key,
|
||||
|
||||
static noinline int copy_to_sk(struct btrfs_path *path,
|
||||
struct btrfs_key *key,
|
||||
struct btrfs_ioctl_search_key *sk,
|
||||
const struct btrfs_ioctl_search_key *sk,
|
||||
u64 *buf_size,
|
||||
char __user *ubuf,
|
||||
unsigned long *sk_offset,
|
||||
@@ -1530,8 +1529,8 @@ static noinline int copy_to_sk(struct btrfs_path *path,
|
||||
}
|
||||
|
||||
sh.objectid = key->objectid;
|
||||
sh.offset = key->offset;
|
||||
sh.type = key->type;
|
||||
sh.offset = key->offset;
|
||||
sh.len = item_len;
|
||||
sh.transid = found_transid;
|
||||
|
||||
@@ -1604,13 +1603,12 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static noinline int search_ioctl(struct inode *inode,
|
||||
static noinline int search_ioctl(struct btrfs_root *root,
|
||||
struct btrfs_ioctl_search_key *sk,
|
||||
u64 *buf_size,
|
||||
char __user *ubuf)
|
||||
{
|
||||
struct btrfs_fs_info *info = inode_to_fs_info(inode);
|
||||
struct btrfs_root *root;
|
||||
struct btrfs_fs_info *info = root->fs_info;
|
||||
struct btrfs_key key;
|
||||
struct btrfs_path *path;
|
||||
int ret;
|
||||
@@ -1627,9 +1625,10 @@ static noinline int search_ioctl(struct inode *inode,
|
||||
return -ENOMEM;
|
||||
|
||||
if (sk->tree_id == 0) {
|
||||
/* search the root of the inode that was passed */
|
||||
root = btrfs_grab_root(BTRFS_I(inode)->root);
|
||||
/* Search the root that we got passed. */
|
||||
root = btrfs_grab_root(root);
|
||||
} else {
|
||||
/* Look up the root from the arguments. */
|
||||
root = btrfs_get_fs_root(info, sk->tree_id, true);
|
||||
if (IS_ERR(root)) {
|
||||
btrfs_free_path(path);
|
||||
@@ -1642,21 +1641,19 @@ static noinline int search_ioctl(struct inode *inode,
|
||||
key.offset = sk->min_offset;
|
||||
|
||||
while (1) {
|
||||
ret = -EFAULT;
|
||||
/*
|
||||
* Ensure that the whole user buffer is faulted in at sub-page
|
||||
* granularity, otherwise the loop may live-lock.
|
||||
*/
|
||||
if (fault_in_subpage_writeable(ubuf + sk_offset,
|
||||
*buf_size - sk_offset))
|
||||
if (fault_in_subpage_writeable(ubuf + sk_offset, *buf_size - sk_offset)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = btrfs_search_forward(root, &key, path, sk->min_transid);
|
||||
if (ret != 0) {
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
goto err;
|
||||
}
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
ret = copy_to_sk(path, &key, sk, buf_size, ubuf,
|
||||
&sk_offset, &num_found);
|
||||
btrfs_release_path(path);
|
||||
@@ -1664,16 +1661,17 @@ static noinline int search_ioctl(struct inode *inode,
|
||||
break;
|
||||
|
||||
}
|
||||
/* Normalize return values from btrfs_search_forward() and copy_to_sk(). */
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
err:
|
||||
|
||||
sk->nr_items = num_found;
|
||||
btrfs_put_root(root);
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static noinline int btrfs_ioctl_tree_search(struct inode *inode,
|
||||
static noinline int btrfs_ioctl_tree_search(struct btrfs_root *root,
|
||||
void __user *argp)
|
||||
{
|
||||
struct btrfs_ioctl_search_args __user *uargs = argp;
|
||||
@@ -1689,7 +1687,7 @@ static noinline int btrfs_ioctl_tree_search(struct inode *inode,
|
||||
|
||||
buf_size = sizeof(uargs->buf);
|
||||
|
||||
ret = search_ioctl(inode, &sk, &buf_size, uargs->buf);
|
||||
ret = search_ioctl(root, &sk, &buf_size, uargs->buf);
|
||||
|
||||
/*
|
||||
* In the origin implementation an overflow is handled by returning a
|
||||
@@ -1703,7 +1701,7 @@ static noinline int btrfs_ioctl_tree_search(struct inode *inode,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static noinline int btrfs_ioctl_tree_search_v2(struct inode *inode,
|
||||
static noinline int btrfs_ioctl_tree_search_v2(struct btrfs_root *root,
|
||||
void __user *argp)
|
||||
{
|
||||
struct btrfs_ioctl_search_args_v2 __user *uarg = argp;
|
||||
@@ -1725,7 +1723,7 @@ static noinline int btrfs_ioctl_tree_search_v2(struct inode *inode,
|
||||
if (buf_size > buf_limit)
|
||||
buf_size = buf_limit;
|
||||
|
||||
ret = search_ioctl(inode, &args.key, &buf_size,
|
||||
ret = search_ioctl(root, &args.key, &buf_size,
|
||||
(char __user *)(&uarg->buf[0]));
|
||||
if (ret == 0 && copy_to_user(&uarg->key, &args.key, sizeof(args.key)))
|
||||
ret = -EFAULT;
|
||||
@@ -1833,7 +1831,6 @@ static int btrfs_search_path_in_tree_user(struct mnt_idmap *idmap,
|
||||
struct btrfs_path *path;
|
||||
struct btrfs_key key, key2;
|
||||
struct extent_buffer *leaf;
|
||||
struct inode *temp_inode;
|
||||
char *ptr;
|
||||
int slot;
|
||||
int len;
|
||||
@@ -1861,6 +1858,8 @@ static int btrfs_search_path_in_tree_user(struct mnt_idmap *idmap,
|
||||
key.type = BTRFS_INODE_REF_KEY;
|
||||
key.offset = (u64)-1;
|
||||
while (1) {
|
||||
struct btrfs_inode *temp_inode;
|
||||
|
||||
ret = btrfs_search_backwards(root, &key, path);
|
||||
if (ret < 0)
|
||||
goto out_put;
|
||||
@@ -1915,9 +1914,9 @@ static int btrfs_search_path_in_tree_user(struct mnt_idmap *idmap,
|
||||
ret = PTR_ERR(temp_inode);
|
||||
goto out_put;
|
||||
}
|
||||
ret = inode_permission(idmap, temp_inode,
|
||||
ret = inode_permission(idmap, &temp_inode->vfs_inode,
|
||||
MAY_READ | MAY_EXEC);
|
||||
iput(temp_inode);
|
||||
iput(&temp_inode->vfs_inode);
|
||||
if (ret) {
|
||||
ret = -EACCES;
|
||||
goto out_put;
|
||||
@@ -2571,7 +2570,7 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
|
||||
/* the rest are all set to zero by kzalloc */
|
||||
range.len = (u64)-1;
|
||||
}
|
||||
ret = btrfs_defrag_file(file_inode(file), &file->f_ra,
|
||||
ret = btrfs_defrag_file(BTRFS_I(file_inode(file)), &file->f_ra,
|
||||
&range, BTRFS_OLDEST_GENERATION, 0);
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
@@ -2763,7 +2762,7 @@ out_free:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long btrfs_ioctl_fs_info(struct btrfs_fs_info *fs_info,
|
||||
static long btrfs_ioctl_fs_info(const struct btrfs_fs_info *fs_info,
|
||||
void __user *arg)
|
||||
{
|
||||
struct btrfs_ioctl_fs_info_args *fi_args;
|
||||
@@ -2817,7 +2816,7 @@ static long btrfs_ioctl_fs_info(struct btrfs_fs_info *fs_info,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long btrfs_ioctl_dev_info(struct btrfs_fs_info *fs_info,
|
||||
static long btrfs_ioctl_dev_info(const struct btrfs_fs_info *fs_info,
|
||||
void __user *arg)
|
||||
{
|
||||
BTRFS_DEV_LOOKUP_ARGS(args);
|
||||
@@ -4248,7 +4247,7 @@ static int btrfs_ioctl_get_features(struct btrfs_fs_info *fs_info,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_feature_bits(struct btrfs_fs_info *fs_info,
|
||||
static int check_feature_bits(const struct btrfs_fs_info *fs_info,
|
||||
enum btrfs_feature_set set,
|
||||
u64 change_mask, u64 flags, u64 supported_flags,
|
||||
u64 safe_set, u64 safe_clear)
|
||||
@@ -4384,7 +4383,7 @@ out_drop_write:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _btrfs_ioctl_send(struct btrfs_inode *inode, void __user *argp, bool compat)
|
||||
static int _btrfs_ioctl_send(struct btrfs_root *root, void __user *argp, bool compat)
|
||||
{
|
||||
struct btrfs_ioctl_send_args *arg;
|
||||
int ret;
|
||||
@@ -4415,7 +4414,7 @@ static int _btrfs_ioctl_send(struct btrfs_inode *inode, void __user *argp, bool
|
||||
if (IS_ERR(arg))
|
||||
return PTR_ERR(arg);
|
||||
}
|
||||
ret = btrfs_ioctl_send(inode, arg);
|
||||
ret = btrfs_ioctl_send(root, arg);
|
||||
kfree(arg);
|
||||
return ret;
|
||||
}
|
||||
@@ -5242,7 +5241,7 @@ long btrfs_ioctl(struct file *file, unsigned int
|
||||
case BTRFS_IOC_SNAP_DESTROY_V2:
|
||||
return btrfs_ioctl_snap_destroy(file, argp, true);
|
||||
case BTRFS_IOC_SUBVOL_GETFLAGS:
|
||||
return btrfs_ioctl_subvol_getflags(inode, argp);
|
||||
return btrfs_ioctl_subvol_getflags(BTRFS_I(inode), argp);
|
||||
case BTRFS_IOC_SUBVOL_SETFLAGS:
|
||||
return btrfs_ioctl_subvol_setflags(file, argp);
|
||||
case BTRFS_IOC_DEFAULT_SUBVOL:
|
||||
@@ -5264,9 +5263,9 @@ long btrfs_ioctl(struct file *file, unsigned int
|
||||
case BTRFS_IOC_DEV_INFO:
|
||||
return btrfs_ioctl_dev_info(fs_info, argp);
|
||||
case BTRFS_IOC_TREE_SEARCH:
|
||||
return btrfs_ioctl_tree_search(inode, argp);
|
||||
return btrfs_ioctl_tree_search(root, argp);
|
||||
case BTRFS_IOC_TREE_SEARCH_V2:
|
||||
return btrfs_ioctl_tree_search_v2(inode, argp);
|
||||
return btrfs_ioctl_tree_search_v2(root, argp);
|
||||
case BTRFS_IOC_INO_LOOKUP:
|
||||
return btrfs_ioctl_ino_lookup(root, argp);
|
||||
case BTRFS_IOC_INO_PATHS:
|
||||
@@ -5314,10 +5313,10 @@ long btrfs_ioctl(struct file *file, unsigned int
|
||||
return btrfs_ioctl_set_received_subvol_32(file, argp);
|
||||
#endif
|
||||
case BTRFS_IOC_SEND:
|
||||
return _btrfs_ioctl_send(BTRFS_I(inode), argp, false);
|
||||
return _btrfs_ioctl_send(root, argp, false);
|
||||
#if defined(CONFIG_64BIT) && defined(CONFIG_COMPAT)
|
||||
case BTRFS_IOC_SEND_32:
|
||||
return _btrfs_ioctl_send(BTRFS_I(inode), argp, true);
|
||||
return _btrfs_ioctl_send(root, argp, true);
|
||||
#endif
|
||||
case BTRFS_IOC_GET_DEV_STATS:
|
||||
return btrfs_ioctl_get_dev_stats(fs_info, argp);
|
||||
|
||||
@@ -9,6 +9,8 @@ struct file;
|
||||
struct dentry;
|
||||
struct mnt_idmap;
|
||||
struct fileattr;
|
||||
struct io_uring_cmd;
|
||||
struct btrfs_inode;
|
||||
struct btrfs_fs_info;
|
||||
struct btrfs_ioctl_balance_args;
|
||||
|
||||
@@ -18,7 +20,7 @@ int btrfs_fileattr_get(struct dentry *dentry, struct fileattr *fa);
|
||||
int btrfs_fileattr_set(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, struct fileattr *fa);
|
||||
int btrfs_ioctl_get_supported_features(void __user *arg);
|
||||
void btrfs_sync_inode_flags_to_i_flags(struct inode *inode);
|
||||
void btrfs_sync_inode_flags_to_i_flags(struct btrfs_inode *inode);
|
||||
void btrfs_update_ioctl_balance_args(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_ioctl_balance_args *bargs);
|
||||
int btrfs_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags);
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <linux/page-flags.h>
|
||||
#include <asm/bug.h>
|
||||
#include <trace/events/btrfs.h>
|
||||
#include "misc.h"
|
||||
#include "ctree.h"
|
||||
#include "extent_io.h"
|
||||
#include "locking.h"
|
||||
|
||||
@@ -842,10 +842,12 @@ void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, u64 nr,
|
||||
/*
|
||||
* Start IO and wait for a given ordered extent to finish.
|
||||
*
|
||||
* Wait on page writeback for all the pages in the extent and the IO completion
|
||||
* code to insert metadata into the btree corresponding to the extent.
|
||||
* Wait on page writeback for all the pages in the extent but not in
|
||||
* [@nowriteback_start, @nowriteback_start + @nowriteback_len) and the
|
||||
* IO completion code to insert metadata into the btree corresponding to the extent.
|
||||
*/
|
||||
void btrfs_start_ordered_extent(struct btrfs_ordered_extent *entry)
|
||||
void btrfs_start_ordered_extent_nowriteback(struct btrfs_ordered_extent *entry,
|
||||
u64 nowriteback_start, u32 nowriteback_len)
|
||||
{
|
||||
u64 start = entry->file_offset;
|
||||
u64 end = start + entry->num_bytes - 1;
|
||||
@@ -865,8 +867,19 @@ void btrfs_start_ordered_extent(struct btrfs_ordered_extent *entry)
|
||||
* start IO on any dirty ones so the wait doesn't stall waiting
|
||||
* for the flusher thread to find them
|
||||
*/
|
||||
if (!test_bit(BTRFS_ORDERED_DIRECT, &entry->flags))
|
||||
filemap_fdatawrite_range(inode->vfs_inode.i_mapping, start, end);
|
||||
if (!test_bit(BTRFS_ORDERED_DIRECT, &entry->flags)) {
|
||||
if (!nowriteback_len) {
|
||||
filemap_fdatawrite_range(inode->vfs_inode.i_mapping, start, end);
|
||||
} else {
|
||||
if (start < nowriteback_start)
|
||||
filemap_fdatawrite_range(inode->vfs_inode.i_mapping, start,
|
||||
nowriteback_start - 1);
|
||||
if (nowriteback_start + nowriteback_len < end)
|
||||
filemap_fdatawrite_range(inode->vfs_inode.i_mapping,
|
||||
nowriteback_start + nowriteback_len,
|
||||
end);
|
||||
}
|
||||
}
|
||||
|
||||
if (!freespace_inode)
|
||||
btrfs_might_wait_for_event(inode->root->fs_info, btrfs_ordered_extent);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
struct inode;
|
||||
struct page;
|
||||
struct extent_state;
|
||||
struct btrfs_block_group;
|
||||
struct btrfs_inode;
|
||||
struct btrfs_root;
|
||||
struct btrfs_fs_info;
|
||||
@@ -191,7 +192,13 @@ void btrfs_add_ordered_sum(struct btrfs_ordered_extent *entry,
|
||||
struct btrfs_ordered_sum *sum);
|
||||
struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct btrfs_inode *inode,
|
||||
u64 file_offset);
|
||||
void btrfs_start_ordered_extent(struct btrfs_ordered_extent *entry);
|
||||
void btrfs_start_ordered_extent_nowriteback(struct btrfs_ordered_extent *entry,
|
||||
u64 nowriteback_start, u32 nowriteback_len);
|
||||
static inline void btrfs_start_ordered_extent(struct btrfs_ordered_extent *entry)
|
||||
{
|
||||
return btrfs_start_ordered_extent_nowriteback(entry, 0, 0);
|
||||
}
|
||||
|
||||
int btrfs_wait_ordered_range(struct btrfs_inode *inode, u64 start, u64 len);
|
||||
struct btrfs_ordered_extent *
|
||||
btrfs_lookup_first_ordered_extent(struct btrfs_inode *inode, u64 file_offset);
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#ifndef BTRFS_PRINT_TREE_H
|
||||
#define BTRFS_PRINT_TREE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* Buffer size to contain tree name and possibly additional data (offset) */
|
||||
#define BTRFS_ROOT_NAME_BUF_LEN 48
|
||||
|
||||
|
||||
@@ -26,8 +26,8 @@ struct prop_handler {
|
||||
const char *xattr_name;
|
||||
int (*validate)(const struct btrfs_inode *inode, const char *value,
|
||||
size_t len);
|
||||
int (*apply)(struct inode *inode, const char *value, size_t len);
|
||||
const char *(*extract)(const struct inode *inode);
|
||||
int (*apply)(struct btrfs_inode *inode, const char *value, size_t len);
|
||||
const char *(*extract)(const struct btrfs_inode *inode);
|
||||
bool (*ignore)(const struct btrfs_inode *inode);
|
||||
int inheritable;
|
||||
};
|
||||
@@ -121,7 +121,7 @@ int btrfs_set_prop(struct btrfs_trans_handle *trans, struct btrfs_inode *inode,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = handler->apply(&inode->vfs_inode, NULL, 0);
|
||||
ret = handler->apply(inode, NULL, 0);
|
||||
ASSERT(ret == 0);
|
||||
|
||||
return ret;
|
||||
@@ -131,7 +131,7 @@ int btrfs_set_prop(struct btrfs_trans_handle *trans, struct btrfs_inode *inode,
|
||||
value_len, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = handler->apply(&inode->vfs_inode, value, value_len);
|
||||
ret = handler->apply(inode, value, value_len);
|
||||
if (ret) {
|
||||
btrfs_setxattr(trans, &inode->vfs_inode, handler->xattr_name, NULL,
|
||||
0, flags);
|
||||
@@ -263,7 +263,7 @@ static void inode_prop_iterator(void *ctx,
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
int ret;
|
||||
|
||||
ret = handler->apply(inode, value, len);
|
||||
ret = handler->apply(BTRFS_I(inode), value, len);
|
||||
if (unlikely(ret))
|
||||
btrfs_warn(root->fs_info,
|
||||
"error applying prop %s to ino %llu (root %llu): %d",
|
||||
@@ -273,12 +273,13 @@ static void inode_prop_iterator(void *ctx,
|
||||
set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
|
||||
}
|
||||
|
||||
int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path)
|
||||
int btrfs_load_inode_props(struct btrfs_inode *inode, struct btrfs_path *path)
|
||||
{
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
u64 ino = btrfs_ino(BTRFS_I(inode));
|
||||
struct btrfs_root *root = inode->root;
|
||||
u64 ino = btrfs_ino(inode);
|
||||
|
||||
return iterate_object_props(root, path, ino, inode_prop_iterator, inode);
|
||||
return iterate_object_props(root, path, ino, inode_prop_iterator,
|
||||
&inode->vfs_inode);
|
||||
}
|
||||
|
||||
static int prop_compression_validate(const struct btrfs_inode *inode,
|
||||
@@ -300,26 +301,26 @@ static int prop_compression_validate(const struct btrfs_inode *inode,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int prop_compression_apply(struct inode *inode, const char *value,
|
||||
static int prop_compression_apply(struct btrfs_inode *inode, const char *value,
|
||||
size_t len)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = inode_to_fs_info(inode);
|
||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||
int type;
|
||||
|
||||
/* Reset to defaults */
|
||||
if (len == 0) {
|
||||
BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
|
||||
BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
|
||||
BTRFS_I(inode)->prop_compress = BTRFS_COMPRESS_NONE;
|
||||
inode->flags &= ~BTRFS_INODE_COMPRESS;
|
||||
inode->flags &= ~BTRFS_INODE_NOCOMPRESS;
|
||||
inode->prop_compress = BTRFS_COMPRESS_NONE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set NOCOMPRESS flag */
|
||||
if ((len == 2 && strncmp("no", value, 2) == 0) ||
|
||||
(len == 4 && strncmp("none", value, 4) == 0)) {
|
||||
BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
|
||||
BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
|
||||
BTRFS_I(inode)->prop_compress = BTRFS_COMPRESS_NONE;
|
||||
inode->flags |= BTRFS_INODE_NOCOMPRESS;
|
||||
inode->flags &= ~BTRFS_INODE_COMPRESS;
|
||||
inode->prop_compress = BTRFS_COMPRESS_NONE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -336,9 +337,9 @@ static int prop_compression_apply(struct inode *inode, const char *value,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
|
||||
BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS;
|
||||
BTRFS_I(inode)->prop_compress = type;
|
||||
inode->flags &= ~BTRFS_INODE_NOCOMPRESS;
|
||||
inode->flags |= BTRFS_INODE_COMPRESS;
|
||||
inode->prop_compress = type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -359,13 +360,13 @@ static bool prop_compression_ignore(const struct btrfs_inode *inode)
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char *prop_compression_extract(const struct inode *inode)
|
||||
static const char *prop_compression_extract(const struct btrfs_inode *inode)
|
||||
{
|
||||
switch (BTRFS_I(inode)->prop_compress) {
|
||||
switch (inode->prop_compress) {
|
||||
case BTRFS_COMPRESS_ZLIB:
|
||||
case BTRFS_COMPRESS_LZO:
|
||||
case BTRFS_COMPRESS_ZSTD:
|
||||
return btrfs_compress_type2str(BTRFS_I(inode)->prop_compress);
|
||||
return btrfs_compress_type2str(inode->prop_compress);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -385,16 +386,16 @@ static struct prop_handler prop_handlers[] = {
|
||||
};
|
||||
|
||||
int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
|
||||
struct inode *inode, const struct inode *parent)
|
||||
struct btrfs_inode *inode,
|
||||
const struct btrfs_inode *parent)
|
||||
{
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
struct btrfs_root *root = inode->root;
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
int ret;
|
||||
int i;
|
||||
bool need_reserve = false;
|
||||
|
||||
if (!test_bit(BTRFS_INODE_HAS_PROPS,
|
||||
&BTRFS_I(parent)->runtime_flags))
|
||||
if (!test_bit(BTRFS_INODE_HAS_PROPS, &parent->runtime_flags))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) {
|
||||
@@ -405,7 +406,7 @@ int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
|
||||
if (!h->inheritable)
|
||||
continue;
|
||||
|
||||
if (h->ignore(BTRFS_I(inode)))
|
||||
if (h->ignore(inode))
|
||||
continue;
|
||||
|
||||
value = h->extract(parent);
|
||||
@@ -416,7 +417,7 @@ int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
|
||||
* This is not strictly necessary as the property should be
|
||||
* valid, but in case it isn't, don't propagate it further.
|
||||
*/
|
||||
ret = h->validate(BTRFS_I(inode), value, strlen(value));
|
||||
ret = h->validate(inode, value, strlen(value));
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
@@ -436,16 +437,15 @@ int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = btrfs_setxattr(trans, inode, h->xattr_name, value,
|
||||
ret = btrfs_setxattr(trans, &inode->vfs_inode, h->xattr_name, value,
|
||||
strlen(value), 0);
|
||||
if (!ret) {
|
||||
ret = h->apply(inode, value, strlen(value));
|
||||
if (ret)
|
||||
btrfs_setxattr(trans, inode, h->xattr_name,
|
||||
btrfs_setxattr(trans, &inode->vfs_inode, h->xattr_name,
|
||||
NULL, 0, 0);
|
||||
else
|
||||
set_bit(BTRFS_INODE_HAS_PROPS,
|
||||
&BTRFS_I(inode)->runtime_flags);
|
||||
set_bit(BTRFS_INODE_HAS_PROPS, &inode->runtime_flags);
|
||||
}
|
||||
|
||||
if (need_reserve) {
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
#ifndef BTRFS_PROPS_H
|
||||
#define BTRFS_PROPS_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/compiler_types.h>
|
||||
|
||||
struct inode;
|
||||
struct btrfs_inode;
|
||||
struct btrfs_path;
|
||||
struct btrfs_trans_handle;
|
||||
@@ -22,10 +22,10 @@ int btrfs_validate_prop(const struct btrfs_inode *inode, const char *name,
|
||||
const char *value, size_t value_len);
|
||||
bool btrfs_ignore_prop(const struct btrfs_inode *inode, const char *name);
|
||||
|
||||
int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path);
|
||||
int btrfs_load_inode_props(struct btrfs_inode *inode, struct btrfs_path *path);
|
||||
|
||||
int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
|
||||
struct inode *inode,
|
||||
const struct inode *dir);
|
||||
struct btrfs_inode *inode,
|
||||
const struct btrfs_inode *dir);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -956,8 +956,8 @@ static int btrfs_clean_quota_tree(struct btrfs_trans_handle *trans,
|
||||
return -ENOMEM;
|
||||
|
||||
key.objectid = 0;
|
||||
key.offset = 0;
|
||||
key.type = 0;
|
||||
key.offset = 0;
|
||||
|
||||
while (1) {
|
||||
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
||||
|
||||
@@ -22,6 +22,9 @@ struct btrfs_ioctl_quota_ctl_args;
|
||||
struct btrfs_trans_handle;
|
||||
struct btrfs_delayed_ref_root;
|
||||
struct btrfs_inode;
|
||||
struct btrfs_transaction;
|
||||
struct btrfs_block_group;
|
||||
struct btrfs_qgroup_swapped_blocks;
|
||||
|
||||
/*
|
||||
* Btrfs qgroup overview
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <uapi/linux/btrfs_tree.h>
|
||||
#include "fs.h"
|
||||
#include "accessors.h"
|
||||
|
||||
#define BTRFS_RST_SUPP_BLOCK_GROUP_MASK (BTRFS_BLOCK_GROUP_DUP | \
|
||||
BTRFS_BLOCK_GROUP_RAID1_MASK | \
|
||||
|
||||
@@ -165,7 +165,7 @@ out:
|
||||
* the source inode to destination inode when possible. When not possible we
|
||||
* copy the inline extent's data into the respective page of the inode.
|
||||
*/
|
||||
static int clone_copy_inline_extent(struct inode *dst,
|
||||
static int clone_copy_inline_extent(struct btrfs_inode *inode,
|
||||
struct btrfs_path *path,
|
||||
struct btrfs_key *new_key,
|
||||
const u64 drop_start,
|
||||
@@ -175,8 +175,8 @@ static int clone_copy_inline_extent(struct inode *dst,
|
||||
char *inline_data,
|
||||
struct btrfs_trans_handle **trans_out)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = inode_to_fs_info(dst);
|
||||
struct btrfs_root *root = BTRFS_I(dst)->root;
|
||||
struct btrfs_root *root = inode->root;
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
const u64 aligned_end = ALIGN(new_key->offset + datal,
|
||||
fs_info->sectorsize);
|
||||
struct btrfs_trans_handle *trans = NULL;
|
||||
@@ -185,12 +185,12 @@ static int clone_copy_inline_extent(struct inode *dst,
|
||||
struct btrfs_key key;
|
||||
|
||||
if (new_key->offset > 0) {
|
||||
ret = copy_inline_to_page(BTRFS_I(dst), new_key->offset,
|
||||
ret = copy_inline_to_page(inode, new_key->offset,
|
||||
inline_data, size, datal, comp_type);
|
||||
goto out;
|
||||
}
|
||||
|
||||
key.objectid = btrfs_ino(BTRFS_I(dst));
|
||||
key.objectid = btrfs_ino(inode);
|
||||
key.type = BTRFS_EXTENT_DATA_KEY;
|
||||
key.offset = 0;
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
@@ -205,7 +205,7 @@ static int clone_copy_inline_extent(struct inode *dst,
|
||||
goto copy_inline_extent;
|
||||
}
|
||||
btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
|
||||
if (key.objectid == btrfs_ino(BTRFS_I(dst)) &&
|
||||
if (key.objectid == btrfs_ino(inode) &&
|
||||
key.type == BTRFS_EXTENT_DATA_KEY) {
|
||||
/*
|
||||
* There's an implicit hole at file offset 0, copy the
|
||||
@@ -214,7 +214,7 @@ static int clone_copy_inline_extent(struct inode *dst,
|
||||
ASSERT(key.offset > 0);
|
||||
goto copy_to_page;
|
||||
}
|
||||
} else if (i_size_read(dst) <= datal) {
|
||||
} else if (i_size_read(&inode->vfs_inode) <= datal) {
|
||||
struct btrfs_file_extent_item *ei;
|
||||
|
||||
ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
|
||||
@@ -236,7 +236,7 @@ copy_inline_extent:
|
||||
* We have no extent items, or we have an extent at offset 0 which may
|
||||
* or may not be inlined. All these cases are dealt the same way.
|
||||
*/
|
||||
if (i_size_read(dst) > datal) {
|
||||
if (i_size_read(&inode->vfs_inode) > datal) {
|
||||
/*
|
||||
* At the destination offset 0 we have either a hole, a regular
|
||||
* extent or an inline extent larger then the one we want to
|
||||
@@ -270,7 +270,7 @@ copy_inline_extent:
|
||||
drop_args.start = drop_start;
|
||||
drop_args.end = aligned_end;
|
||||
drop_args.drop_cache = true;
|
||||
ret = btrfs_drop_extents(trans, root, BTRFS_I(dst), &drop_args);
|
||||
ret = btrfs_drop_extents(trans, root, inode, &drop_args);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = btrfs_insert_empty_item(trans, root, path, new_key, size);
|
||||
@@ -281,9 +281,9 @@ copy_inline_extent:
|
||||
btrfs_item_ptr_offset(path->nodes[0],
|
||||
path->slots[0]),
|
||||
size);
|
||||
btrfs_update_inode_bytes(BTRFS_I(dst), datal, drop_args.bytes_found);
|
||||
btrfs_set_inode_full_sync(BTRFS_I(dst));
|
||||
ret = btrfs_inode_set_file_extent_range(BTRFS_I(dst), 0, aligned_end);
|
||||
btrfs_update_inode_bytes(inode, datal, drop_args.bytes_found);
|
||||
btrfs_set_inode_full_sync(inode);
|
||||
ret = btrfs_inode_set_file_extent_range(inode, 0, aligned_end);
|
||||
out:
|
||||
if (!ret && !trans) {
|
||||
/*
|
||||
@@ -318,7 +318,7 @@ copy_to_page:
|
||||
*/
|
||||
btrfs_release_path(path);
|
||||
|
||||
ret = copy_inline_to_page(BTRFS_I(dst), new_key->offset,
|
||||
ret = copy_inline_to_page(inode, new_key->offset,
|
||||
inline_data, size, datal, comp_type);
|
||||
goto out;
|
||||
}
|
||||
@@ -526,7 +526,7 @@ process_slot:
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = clone_copy_inline_extent(inode, path, &new_key,
|
||||
ret = clone_copy_inline_extent(BTRFS_I(inode), path, &new_key,
|
||||
drop_start, datal, size,
|
||||
comp, buf, &trans);
|
||||
if (ret)
|
||||
@@ -617,26 +617,26 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void btrfs_double_mmap_lock(struct inode *inode1, struct inode *inode2)
|
||||
static void btrfs_double_mmap_lock(struct btrfs_inode *inode1, struct btrfs_inode *inode2)
|
||||
{
|
||||
if (inode1 < inode2)
|
||||
swap(inode1, inode2);
|
||||
down_write(&BTRFS_I(inode1)->i_mmap_lock);
|
||||
down_write_nested(&BTRFS_I(inode2)->i_mmap_lock, SINGLE_DEPTH_NESTING);
|
||||
down_write(&inode1->i_mmap_lock);
|
||||
down_write_nested(&inode2->i_mmap_lock, SINGLE_DEPTH_NESTING);
|
||||
}
|
||||
|
||||
static void btrfs_double_mmap_unlock(struct inode *inode1, struct inode *inode2)
|
||||
static void btrfs_double_mmap_unlock(struct btrfs_inode *inode1, struct btrfs_inode *inode2)
|
||||
{
|
||||
up_write(&BTRFS_I(inode1)->i_mmap_lock);
|
||||
up_write(&BTRFS_I(inode2)->i_mmap_lock);
|
||||
up_write(&inode1->i_mmap_lock);
|
||||
up_write(&inode2->i_mmap_lock);
|
||||
}
|
||||
|
||||
static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 len,
|
||||
struct inode *dst, u64 dst_loff)
|
||||
static int btrfs_extent_same_range(struct btrfs_inode *src, u64 loff, u64 len,
|
||||
struct btrfs_inode *dst, u64 dst_loff)
|
||||
{
|
||||
const u64 end = dst_loff + len - 1;
|
||||
struct extent_state *cached_state = NULL;
|
||||
struct btrfs_fs_info *fs_info = BTRFS_I(src)->root->fs_info;
|
||||
struct btrfs_fs_info *fs_info = src->root->fs_info;
|
||||
const u64 bs = fs_info->sectorsize;
|
||||
int ret;
|
||||
|
||||
@@ -646,9 +646,10 @@ static int btrfs_extent_same_range(struct inode *src, u64 loff, u64 len,
|
||||
* because we have already locked the inode's i_mmap_lock in exclusive
|
||||
* mode.
|
||||
*/
|
||||
lock_extent(&BTRFS_I(dst)->io_tree, dst_loff, end, &cached_state);
|
||||
ret = btrfs_clone(src, dst, loff, len, ALIGN(len, bs), dst_loff, 1);
|
||||
unlock_extent(&BTRFS_I(dst)->io_tree, dst_loff, end, &cached_state);
|
||||
lock_extent(&dst->io_tree, dst_loff, end, &cached_state);
|
||||
ret = btrfs_clone(&src->vfs_inode, &dst->vfs_inode, loff, len,
|
||||
ALIGN(len, bs), dst_loff, 1);
|
||||
unlock_extent(&dst->io_tree, dst_loff, end, &cached_state);
|
||||
|
||||
btrfs_btree_balance_dirty(fs_info);
|
||||
|
||||
@@ -678,8 +679,8 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen,
|
||||
chunk_count = div_u64(olen, BTRFS_MAX_DEDUPE_LEN);
|
||||
|
||||
for (i = 0; i < chunk_count; i++) {
|
||||
ret = btrfs_extent_same_range(src, loff, BTRFS_MAX_DEDUPE_LEN,
|
||||
dst, dst_loff);
|
||||
ret = btrfs_extent_same_range(BTRFS_I(src), loff, BTRFS_MAX_DEDUPE_LEN,
|
||||
BTRFS_I(dst), dst_loff);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@@ -688,7 +689,8 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen,
|
||||
}
|
||||
|
||||
if (tail_len > 0)
|
||||
ret = btrfs_extent_same_range(src, loff, tail_len, dst, dst_loff);
|
||||
ret = btrfs_extent_same_range(BTRFS_I(src), loff, tail_len,
|
||||
BTRFS_I(dst), dst_loff);
|
||||
out:
|
||||
spin_lock(&root_dst->root_item_lock);
|
||||
root_dst->dedupe_in_progress--;
|
||||
@@ -775,24 +777,24 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
||||
struct file *file_out, loff_t pos_out,
|
||||
loff_t *len, unsigned int remap_flags)
|
||||
{
|
||||
struct inode *inode_in = file_inode(file_in);
|
||||
struct inode *inode_out = file_inode(file_out);
|
||||
u64 bs = BTRFS_I(inode_out)->root->fs_info->sectorsize;
|
||||
struct btrfs_inode *inode_in = BTRFS_I(file_inode(file_in));
|
||||
struct btrfs_inode *inode_out = BTRFS_I(file_inode(file_out));
|
||||
u64 bs = inode_out->root->fs_info->sectorsize;
|
||||
u64 wb_len;
|
||||
int ret;
|
||||
|
||||
if (!(remap_flags & REMAP_FILE_DEDUP)) {
|
||||
struct btrfs_root *root_out = BTRFS_I(inode_out)->root;
|
||||
struct btrfs_root *root_out = inode_out->root;
|
||||
|
||||
if (btrfs_root_readonly(root_out))
|
||||
return -EROFS;
|
||||
|
||||
ASSERT(inode_in->i_sb == inode_out->i_sb);
|
||||
ASSERT(inode_in->vfs_inode.i_sb == inode_out->vfs_inode.i_sb);
|
||||
}
|
||||
|
||||
/* Don't make the dst file partly checksummed */
|
||||
if ((BTRFS_I(inode_in)->flags & BTRFS_INODE_NODATASUM) !=
|
||||
(BTRFS_I(inode_out)->flags & BTRFS_INODE_NODATASUM)) {
|
||||
if ((inode_in->flags & BTRFS_INODE_NODATASUM) !=
|
||||
(inode_out->flags & BTRFS_INODE_NODATASUM)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -811,7 +813,7 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
||||
* to complete so that new file extent items are in the fs tree.
|
||||
*/
|
||||
if (*len == 0 && !(remap_flags & REMAP_FILE_DEDUP))
|
||||
wb_len = ALIGN(inode_in->i_size, bs) - ALIGN_DOWN(pos_in, bs);
|
||||
wb_len = ALIGN(inode_in->vfs_inode.i_size, bs) - ALIGN_DOWN(pos_in, bs);
|
||||
else
|
||||
wb_len = ALIGN(*len, bs);
|
||||
|
||||
@@ -832,16 +834,14 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in,
|
||||
* Also we don't need to check ASYNC_EXTENT, as async extent will be
|
||||
* CoWed anyway, not affecting nocow part.
|
||||
*/
|
||||
ret = filemap_flush(inode_in->i_mapping);
|
||||
ret = filemap_flush(inode_in->vfs_inode.i_mapping);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = btrfs_wait_ordered_range(BTRFS_I(inode_in), ALIGN_DOWN(pos_in, bs),
|
||||
wb_len);
|
||||
ret = btrfs_wait_ordered_range(inode_in, ALIGN_DOWN(pos_in, bs), wb_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = btrfs_wait_ordered_range(BTRFS_I(inode_out), ALIGN_DOWN(pos_out, bs),
|
||||
wb_len);
|
||||
ret = btrfs_wait_ordered_range(inode_out, ALIGN_DOWN(pos_out, bs), wb_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -863,8 +863,8 @@ loff_t btrfs_remap_file_range(struct file *src_file, loff_t off,
|
||||
struct file *dst_file, loff_t destoff, loff_t len,
|
||||
unsigned int remap_flags)
|
||||
{
|
||||
struct inode *src_inode = file_inode(src_file);
|
||||
struct inode *dst_inode = file_inode(dst_file);
|
||||
struct btrfs_inode *src_inode = BTRFS_I(file_inode(src_file));
|
||||
struct btrfs_inode *dst_inode = BTRFS_I(file_inode(dst_file));
|
||||
bool same_inode = dst_inode == src_inode;
|
||||
int ret;
|
||||
|
||||
@@ -872,9 +872,9 @@ loff_t btrfs_remap_file_range(struct file *src_file, loff_t off,
|
||||
return -EINVAL;
|
||||
|
||||
if (same_inode) {
|
||||
btrfs_inode_lock(BTRFS_I(src_inode), BTRFS_ILOCK_MMAP);
|
||||
btrfs_inode_lock(src_inode, BTRFS_ILOCK_MMAP);
|
||||
} else {
|
||||
lock_two_nondirectories(src_inode, dst_inode);
|
||||
lock_two_nondirectories(&src_inode->vfs_inode, &dst_inode->vfs_inode);
|
||||
btrfs_double_mmap_lock(src_inode, dst_inode);
|
||||
}
|
||||
|
||||
@@ -884,16 +884,18 @@ loff_t btrfs_remap_file_range(struct file *src_file, loff_t off,
|
||||
goto out_unlock;
|
||||
|
||||
if (remap_flags & REMAP_FILE_DEDUP)
|
||||
ret = btrfs_extent_same(src_inode, off, len, dst_inode, destoff);
|
||||
ret = btrfs_extent_same(&src_inode->vfs_inode, off, len,
|
||||
&dst_inode->vfs_inode, destoff);
|
||||
else
|
||||
ret = btrfs_clone_files(dst_file, src_file, off, len, destoff);
|
||||
|
||||
out_unlock:
|
||||
if (same_inode) {
|
||||
btrfs_inode_unlock(BTRFS_I(src_inode), BTRFS_ILOCK_MMAP);
|
||||
btrfs_inode_unlock(src_inode, BTRFS_ILOCK_MMAP);
|
||||
} else {
|
||||
btrfs_double_mmap_unlock(src_inode, dst_inode);
|
||||
unlock_two_nondirectories(src_inode, dst_inode);
|
||||
unlock_two_nondirectories(&src_inode->vfs_inode,
|
||||
&dst_inode->vfs_inode);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -3239,21 +3239,23 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int delete_block_group_cache(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_block_group *block_group,
|
||||
static int delete_block_group_cache(struct btrfs_block_group *block_group,
|
||||
struct inode *inode,
|
||||
u64 ino)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = block_group->fs_info;
|
||||
struct btrfs_root *root = fs_info->tree_root;
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_inode *btrfs_inode;
|
||||
int ret = 0;
|
||||
|
||||
if (inode)
|
||||
goto truncate;
|
||||
|
||||
inode = btrfs_iget(ino, root);
|
||||
if (IS_ERR(inode))
|
||||
btrfs_inode = btrfs_iget(ino, root);
|
||||
if (IS_ERR(btrfs_inode))
|
||||
return -ENOENT;
|
||||
inode = &btrfs_inode->vfs_inode;
|
||||
|
||||
truncate:
|
||||
ret = btrfs_check_trunc_cache_free_space(fs_info,
|
||||
@@ -3313,8 +3315,7 @@ static int delete_v1_space_cache(struct extent_buffer *leaf,
|
||||
}
|
||||
if (!found)
|
||||
return -ENOENT;
|
||||
ret = delete_block_group_cache(leaf->fs_info, block_group, NULL,
|
||||
space_cache_ino);
|
||||
ret = delete_block_group_cache(block_group, NULL, space_cache_ino);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3761,10 +3762,10 @@ out:
|
||||
* the inode is in data relocation tree and its link count is 0
|
||||
*/
|
||||
static noinline_for_stack struct inode *create_reloc_inode(
|
||||
struct btrfs_fs_info *fs_info,
|
||||
const struct btrfs_block_group *group)
|
||||
{
|
||||
struct inode *inode = NULL;
|
||||
struct btrfs_fs_info *fs_info = group->fs_info;
|
||||
struct btrfs_inode *inode = NULL;
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_root *root;
|
||||
u64 objectid;
|
||||
@@ -3792,18 +3793,19 @@ static noinline_for_stack struct inode *create_reloc_inode(
|
||||
inode = NULL;
|
||||
goto out;
|
||||
}
|
||||
BTRFS_I(inode)->reloc_block_group_start = group->start;
|
||||
inode->reloc_block_group_start = group->start;
|
||||
|
||||
ret = btrfs_orphan_add(trans, BTRFS_I(inode));
|
||||
ret = btrfs_orphan_add(trans, inode);
|
||||
out:
|
||||
btrfs_put_root(root);
|
||||
btrfs_end_transaction(trans);
|
||||
btrfs_btree_balance_dirty(fs_info);
|
||||
if (ret) {
|
||||
iput(inode);
|
||||
if (inode)
|
||||
iput(&inode->vfs_inode);
|
||||
inode = ERR_PTR(ret);
|
||||
}
|
||||
return inode;
|
||||
return &inode->vfs_inode;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3977,7 +3979,7 @@ int btrfs_relocate_block_group(struct btrfs_fs_info *fs_info, u64 group_start)
|
||||
btrfs_free_path(path);
|
||||
|
||||
if (!IS_ERR(inode))
|
||||
ret = delete_block_group_cache(fs_info, rc->block_group, inode, 0);
|
||||
ret = delete_block_group_cache(rc->block_group, inode, 0);
|
||||
else
|
||||
ret = PTR_ERR(inode);
|
||||
|
||||
@@ -3986,7 +3988,7 @@ int btrfs_relocate_block_group(struct btrfs_fs_info *fs_info, u64 group_start)
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc->data_inode = create_reloc_inode(fs_info, rc->block_group);
|
||||
rc->data_inode = create_reloc_inode(rc->block_group);
|
||||
if (IS_ERR(rc->data_inode)) {
|
||||
err = PTR_ERR(rc->data_inode);
|
||||
rc->data_inode = NULL;
|
||||
|
||||
@@ -1380,11 +1380,11 @@ static int find_first_extent_item(struct btrfs_root *extent_root,
|
||||
if (path->nodes[0])
|
||||
goto search_forward;
|
||||
|
||||
key.objectid = search_start;
|
||||
if (btrfs_fs_incompat(fs_info, SKINNY_METADATA))
|
||||
key.type = BTRFS_METADATA_ITEM_KEY;
|
||||
else
|
||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
key.objectid = search_start;
|
||||
key.offset = (u64)-1;
|
||||
|
||||
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
||||
@@ -2497,8 +2497,8 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
|
||||
path->skip_locking = 1;
|
||||
|
||||
key.objectid = scrub_dev->devid;
|
||||
key.offset = 0ull;
|
||||
key.type = BTRFS_DEV_EXTENT_KEY;
|
||||
key.offset = 0ull;
|
||||
|
||||
while (1) {
|
||||
u64 dev_extent_len;
|
||||
|
||||
544
fs/btrfs/send.c
544
fs/btrfs/send.c
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/align.h>
|
||||
|
||||
struct btrfs_inode;
|
||||
struct btrfs_root;
|
||||
struct btrfs_ioctl_send_args;
|
||||
|
||||
#define BTRFS_SEND_STREAM_MAGIC "btrfs-stream"
|
||||
@@ -182,6 +182,6 @@ enum {
|
||||
__BTRFS_SEND_A_MAX = 35,
|
||||
};
|
||||
|
||||
long btrfs_ioctl_send(struct btrfs_inode *inode, const struct btrfs_ioctl_send_args *arg);
|
||||
long btrfs_ioctl_send(struct btrfs_root *send_root, const struct btrfs_ioctl_send_args *arg);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include "linux/spinlock.h"
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/minmax.h>
|
||||
#include "misc.h"
|
||||
#include "ctree.h"
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include "messages.h"
|
||||
#include "ctree.h"
|
||||
#include "subpage.h"
|
||||
#include "btrfs_inode.h"
|
||||
|
||||
/*
|
||||
* Subpage (sectorsize < PAGE_SIZE) support overview:
|
||||
* Subpage (block size < folio size) support overview:
|
||||
*
|
||||
* Limitations:
|
||||
*
|
||||
@@ -64,35 +63,14 @@
|
||||
* This means a slightly higher tree locking latency.
|
||||
*/
|
||||
|
||||
#if PAGE_SIZE > SZ_4K
|
||||
bool btrfs_is_subpage(const struct btrfs_fs_info *fs_info, struct address_space *mapping)
|
||||
{
|
||||
if (fs_info->sectorsize >= PAGE_SIZE)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Only data pages (either through DIO or compression) can have no
|
||||
* mapping. And if page->mapping->host is data inode, it's subpage.
|
||||
* As we have ruled our sectorsize >= PAGE_SIZE case already.
|
||||
*/
|
||||
if (!mapping || !mapping->host || is_data_inode(BTRFS_I(mapping->host)))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Now the only remaining case is metadata, which we only go subpage
|
||||
* routine if nodesize < PAGE_SIZE.
|
||||
*/
|
||||
if (fs_info->nodesize < PAGE_SIZE)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio, enum btrfs_subpage_type type)
|
||||
{
|
||||
struct btrfs_subpage *subpage;
|
||||
|
||||
/* For metadata we don't support large folio yet. */
|
||||
ASSERT(!folio_test_large(folio));
|
||||
|
||||
/*
|
||||
* We have cases like a dummy extent buffer page, which is not mapped
|
||||
* and doesn't need to be locked.
|
||||
@@ -101,10 +79,14 @@ int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info,
|
||||
ASSERT(folio_test_locked(folio));
|
||||
|
||||
/* Either not subpage, or the folio already has private attached. */
|
||||
if (!btrfs_is_subpage(fs_info, folio->mapping) || folio_test_private(folio))
|
||||
if (folio_test_private(folio))
|
||||
return 0;
|
||||
if (type == BTRFS_SUBPAGE_METADATA && !btrfs_meta_is_subpage(fs_info))
|
||||
return 0;
|
||||
if (type == BTRFS_SUBPAGE_DATA && !btrfs_is_subpage(fs_info, folio))
|
||||
return 0;
|
||||
|
||||
subpage = btrfs_alloc_subpage(fs_info, type);
|
||||
subpage = btrfs_alloc_subpage(fs_info, folio_size(folio), type);
|
||||
if (IS_ERR(subpage))
|
||||
return PTR_ERR(subpage);
|
||||
|
||||
@@ -112,12 +94,17 @@ int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info, struct folio *folio)
|
||||
void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info, struct folio *folio,
|
||||
enum btrfs_subpage_type type)
|
||||
{
|
||||
struct btrfs_subpage *subpage;
|
||||
|
||||
/* Either not subpage, or the folio already has private attached. */
|
||||
if (!btrfs_is_subpage(fs_info, folio->mapping) || !folio_test_private(folio))
|
||||
if (!folio_test_private(folio))
|
||||
return;
|
||||
if (type == BTRFS_SUBPAGE_METADATA && !btrfs_meta_is_subpage(fs_info))
|
||||
return;
|
||||
if (type == BTRFS_SUBPAGE_DATA && !btrfs_is_subpage(fs_info, folio))
|
||||
return;
|
||||
|
||||
subpage = folio_detach_private(folio);
|
||||
@@ -126,15 +113,16 @@ void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info, struct folio *fol
|
||||
}
|
||||
|
||||
struct btrfs_subpage *btrfs_alloc_subpage(const struct btrfs_fs_info *fs_info,
|
||||
enum btrfs_subpage_type type)
|
||||
size_t fsize, enum btrfs_subpage_type type)
|
||||
{
|
||||
struct btrfs_subpage *ret;
|
||||
unsigned int real_size;
|
||||
|
||||
ASSERT(fs_info->sectorsize < PAGE_SIZE);
|
||||
ASSERT(fs_info->sectorsize < fsize);
|
||||
|
||||
real_size = struct_size(ret, bitmaps,
|
||||
BITS_TO_LONGS(btrfs_bitmap_nr_max * fs_info->sectors_per_page));
|
||||
BITS_TO_LONGS(btrfs_bitmap_nr_max *
|
||||
(fsize >> fs_info->sectorsize_bits)));
|
||||
ret = kzalloc(real_size, GFP_NOFS);
|
||||
if (!ret)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
@@ -165,7 +153,7 @@ void btrfs_folio_inc_eb_refs(const struct btrfs_fs_info *fs_info, struct folio *
|
||||
{
|
||||
struct btrfs_subpage *subpage;
|
||||
|
||||
if (!btrfs_is_subpage(fs_info, folio->mapping))
|
||||
if (!btrfs_meta_is_subpage(fs_info))
|
||||
return;
|
||||
|
||||
ASSERT(folio_test_private(folio) && folio->mapping);
|
||||
@@ -179,7 +167,7 @@ void btrfs_folio_dec_eb_refs(const struct btrfs_fs_info *fs_info, struct folio *
|
||||
{
|
||||
struct btrfs_subpage *subpage;
|
||||
|
||||
if (!btrfs_is_subpage(fs_info, folio->mapping))
|
||||
if (!btrfs_meta_is_subpage(fs_info))
|
||||
return;
|
||||
|
||||
ASSERT(folio_test_private(folio) && folio->mapping);
|
||||
@@ -206,16 +194,18 @@ static void btrfs_subpage_assert(const struct btrfs_fs_info *fs_info,
|
||||
*/
|
||||
if (folio->mapping)
|
||||
ASSERT(folio_pos(folio) <= start &&
|
||||
start + len <= folio_pos(folio) + PAGE_SIZE);
|
||||
start + len <= folio_pos(folio) + folio_size(folio));
|
||||
}
|
||||
|
||||
#define subpage_calc_start_bit(fs_info, folio, name, start, len) \
|
||||
({ \
|
||||
unsigned int __start_bit; \
|
||||
unsigned int __start_bit; \
|
||||
const unsigned int blocks_per_folio = \
|
||||
btrfs_blocks_per_folio(fs_info, folio); \
|
||||
\
|
||||
btrfs_subpage_assert(fs_info, folio, start, len); \
|
||||
__start_bit = offset_in_page(start) >> fs_info->sectorsize_bits; \
|
||||
__start_bit += fs_info->sectors_per_page * btrfs_bitmap_nr_##name; \
|
||||
__start_bit += blocks_per_folio * btrfs_bitmap_nr_##name; \
|
||||
__start_bit; \
|
||||
})
|
||||
|
||||
@@ -233,7 +223,7 @@ static void btrfs_subpage_clamp_range(struct folio *folio, u64 *start, u32 *len)
|
||||
if (folio_pos(folio) >= orig_start + orig_len)
|
||||
*len = 0;
|
||||
else
|
||||
*len = min_t(u64, folio_pos(folio) + PAGE_SIZE,
|
||||
*len = min_t(u64, folio_pos(folio) + folio_size(folio),
|
||||
orig_start + orig_len) - *start;
|
||||
}
|
||||
|
||||
@@ -296,7 +286,7 @@ void btrfs_folio_end_lock(const struct btrfs_fs_info *fs_info,
|
||||
|
||||
ASSERT(folio_test_locked(folio));
|
||||
|
||||
if (unlikely(!fs_info) || !btrfs_is_subpage(fs_info, folio->mapping)) {
|
||||
if (unlikely(!fs_info) || !btrfs_is_subpage(fs_info, folio)) {
|
||||
folio_unlock(folio);
|
||||
return;
|
||||
}
|
||||
@@ -323,13 +313,14 @@ void btrfs_folio_end_lock_bitmap(const struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio, unsigned long bitmap)
|
||||
{
|
||||
struct btrfs_subpage *subpage = folio_get_private(folio);
|
||||
const int start_bit = fs_info->sectors_per_page * btrfs_bitmap_nr_locked;
|
||||
const unsigned int blocks_per_folio = btrfs_blocks_per_folio(fs_info, folio);
|
||||
const int start_bit = blocks_per_folio * btrfs_bitmap_nr_locked;
|
||||
unsigned long flags;
|
||||
bool last = false;
|
||||
int cleared = 0;
|
||||
int bit;
|
||||
|
||||
if (!btrfs_is_subpage(fs_info, folio->mapping)) {
|
||||
if (!btrfs_is_subpage(fs_info, folio)) {
|
||||
folio_unlock(folio);
|
||||
return;
|
||||
}
|
||||
@@ -341,7 +332,7 @@ void btrfs_folio_end_lock_bitmap(const struct btrfs_fs_info *fs_info,
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&subpage->lock, flags);
|
||||
for_each_set_bit(bit, &bitmap, fs_info->sectors_per_page) {
|
||||
for_each_set_bit(bit, &bitmap, blocks_per_folio) {
|
||||
if (test_and_clear_bit(bit + start_bit, subpage->bitmaps))
|
||||
cleared++;
|
||||
}
|
||||
@@ -352,15 +343,27 @@ void btrfs_folio_end_lock_bitmap(const struct btrfs_fs_info *fs_info,
|
||||
folio_unlock(folio);
|
||||
}
|
||||
|
||||
#define subpage_test_bitmap_all_set(fs_info, subpage, name) \
|
||||
#define subpage_test_bitmap_all_set(fs_info, folio, name) \
|
||||
({ \
|
||||
struct btrfs_subpage *subpage = folio_get_private(folio); \
|
||||
const unsigned int blocks_per_folio = \
|
||||
btrfs_blocks_per_folio(fs_info, folio); \
|
||||
\
|
||||
bitmap_test_range_all_set(subpage->bitmaps, \
|
||||
fs_info->sectors_per_page * btrfs_bitmap_nr_##name, \
|
||||
fs_info->sectors_per_page)
|
||||
blocks_per_folio * btrfs_bitmap_nr_##name, \
|
||||
blocks_per_folio); \
|
||||
})
|
||||
|
||||
#define subpage_test_bitmap_all_zero(fs_info, subpage, name) \
|
||||
#define subpage_test_bitmap_all_zero(fs_info, folio, name) \
|
||||
({ \
|
||||
struct btrfs_subpage *subpage = folio_get_private(folio); \
|
||||
const unsigned int blocks_per_folio = \
|
||||
btrfs_blocks_per_folio(fs_info, folio); \
|
||||
\
|
||||
bitmap_test_range_all_zero(subpage->bitmaps, \
|
||||
fs_info->sectors_per_page * btrfs_bitmap_nr_##name, \
|
||||
fs_info->sectors_per_page)
|
||||
blocks_per_folio * btrfs_bitmap_nr_##name, \
|
||||
blocks_per_folio); \
|
||||
})
|
||||
|
||||
void btrfs_subpage_set_uptodate(const struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio, u64 start, u32 len)
|
||||
@@ -372,7 +375,7 @@ void btrfs_subpage_set_uptodate(const struct btrfs_fs_info *fs_info,
|
||||
|
||||
spin_lock_irqsave(&subpage->lock, flags);
|
||||
bitmap_set(subpage->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
|
||||
if (subpage_test_bitmap_all_set(fs_info, subpage, uptodate))
|
||||
if (subpage_test_bitmap_all_set(fs_info, folio, uptodate))
|
||||
folio_mark_uptodate(folio);
|
||||
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||
}
|
||||
@@ -426,7 +429,7 @@ bool btrfs_subpage_clear_and_test_dirty(const struct btrfs_fs_info *fs_info,
|
||||
|
||||
spin_lock_irqsave(&subpage->lock, flags);
|
||||
bitmap_clear(subpage->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
|
||||
if (subpage_test_bitmap_all_zero(fs_info, subpage, dirty))
|
||||
if (subpage_test_bitmap_all_zero(fs_info, folio, dirty))
|
||||
last = true;
|
||||
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||
return last;
|
||||
@@ -467,7 +470,7 @@ void btrfs_subpage_clear_writeback(const struct btrfs_fs_info *fs_info,
|
||||
|
||||
spin_lock_irqsave(&subpage->lock, flags);
|
||||
bitmap_clear(subpage->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
|
||||
if (subpage_test_bitmap_all_zero(fs_info, subpage, writeback)) {
|
||||
if (subpage_test_bitmap_all_zero(fs_info, folio, writeback)) {
|
||||
ASSERT(folio_test_writeback(folio));
|
||||
folio_end_writeback(folio);
|
||||
}
|
||||
@@ -498,7 +501,7 @@ void btrfs_subpage_clear_ordered(const struct btrfs_fs_info *fs_info,
|
||||
|
||||
spin_lock_irqsave(&subpage->lock, flags);
|
||||
bitmap_clear(subpage->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
|
||||
if (subpage_test_bitmap_all_zero(fs_info, subpage, ordered))
|
||||
if (subpage_test_bitmap_all_zero(fs_info, folio, ordered))
|
||||
folio_clear_ordered(folio);
|
||||
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||
}
|
||||
@@ -513,7 +516,7 @@ void btrfs_subpage_set_checked(const struct btrfs_fs_info *fs_info,
|
||||
|
||||
spin_lock_irqsave(&subpage->lock, flags);
|
||||
bitmap_set(subpage->bitmaps, start_bit, len >> fs_info->sectorsize_bits);
|
||||
if (subpage_test_bitmap_all_set(fs_info, subpage, checked))
|
||||
if (subpage_test_bitmap_all_set(fs_info, folio, checked))
|
||||
folio_set_checked(folio);
|
||||
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||
}
|
||||
@@ -569,7 +572,7 @@ void btrfs_folio_set_##name(const struct btrfs_fs_info *fs_info, \
|
||||
struct folio *folio, u64 start, u32 len) \
|
||||
{ \
|
||||
if (unlikely(!fs_info) || \
|
||||
!btrfs_is_subpage(fs_info, folio->mapping)) { \
|
||||
!btrfs_is_subpage(fs_info, folio)) { \
|
||||
folio_set_func(folio); \
|
||||
return; \
|
||||
} \
|
||||
@@ -579,7 +582,7 @@ void btrfs_folio_clear_##name(const struct btrfs_fs_info *fs_info, \
|
||||
struct folio *folio, u64 start, u32 len) \
|
||||
{ \
|
||||
if (unlikely(!fs_info) || \
|
||||
!btrfs_is_subpage(fs_info, folio->mapping)) { \
|
||||
!btrfs_is_subpage(fs_info, folio)) { \
|
||||
folio_clear_func(folio); \
|
||||
return; \
|
||||
} \
|
||||
@@ -589,7 +592,7 @@ bool btrfs_folio_test_##name(const struct btrfs_fs_info *fs_info, \
|
||||
struct folio *folio, u64 start, u32 len) \
|
||||
{ \
|
||||
if (unlikely(!fs_info) || \
|
||||
!btrfs_is_subpage(fs_info, folio->mapping)) \
|
||||
!btrfs_is_subpage(fs_info, folio)) \
|
||||
return folio_test_func(folio); \
|
||||
return btrfs_subpage_test_##name(fs_info, folio, start, len); \
|
||||
} \
|
||||
@@ -597,7 +600,7 @@ void btrfs_folio_clamp_set_##name(const struct btrfs_fs_info *fs_info, \
|
||||
struct folio *folio, u64 start, u32 len) \
|
||||
{ \
|
||||
if (unlikely(!fs_info) || \
|
||||
!btrfs_is_subpage(fs_info, folio->mapping)) { \
|
||||
!btrfs_is_subpage(fs_info, folio)) { \
|
||||
folio_set_func(folio); \
|
||||
return; \
|
||||
} \
|
||||
@@ -608,7 +611,7 @@ void btrfs_folio_clamp_clear_##name(const struct btrfs_fs_info *fs_info, \
|
||||
struct folio *folio, u64 start, u32 len) \
|
||||
{ \
|
||||
if (unlikely(!fs_info) || \
|
||||
!btrfs_is_subpage(fs_info, folio->mapping)) { \
|
||||
!btrfs_is_subpage(fs_info, folio)) { \
|
||||
folio_clear_func(folio); \
|
||||
return; \
|
||||
} \
|
||||
@@ -619,10 +622,32 @@ bool btrfs_folio_clamp_test_##name(const struct btrfs_fs_info *fs_info, \
|
||||
struct folio *folio, u64 start, u32 len) \
|
||||
{ \
|
||||
if (unlikely(!fs_info) || \
|
||||
!btrfs_is_subpage(fs_info, folio->mapping)) \
|
||||
!btrfs_is_subpage(fs_info, folio)) \
|
||||
return folio_test_func(folio); \
|
||||
btrfs_subpage_clamp_range(folio, &start, &len); \
|
||||
return btrfs_subpage_test_##name(fs_info, folio, start, len); \
|
||||
} \
|
||||
void btrfs_meta_folio_set_##name(struct folio *folio, const struct extent_buffer *eb) \
|
||||
{ \
|
||||
if (!btrfs_meta_is_subpage(eb->fs_info)) { \
|
||||
folio_set_func(folio); \
|
||||
return; \
|
||||
} \
|
||||
btrfs_subpage_set_##name(eb->fs_info, folio, eb->start, eb->len); \
|
||||
} \
|
||||
void btrfs_meta_folio_clear_##name(struct folio *folio, const struct extent_buffer *eb) \
|
||||
{ \
|
||||
if (!btrfs_meta_is_subpage(eb->fs_info)) { \
|
||||
folio_clear_func(folio); \
|
||||
return; \
|
||||
} \
|
||||
btrfs_subpage_clear_##name(eb->fs_info, folio, eb->start, eb->len); \
|
||||
} \
|
||||
bool btrfs_meta_folio_test_##name(struct folio *folio, const struct extent_buffer *eb) \
|
||||
{ \
|
||||
if (!btrfs_meta_is_subpage(eb->fs_info)) \
|
||||
return folio_test_func(folio); \
|
||||
return btrfs_subpage_test_##name(eb->fs_info, folio, eb->start, eb->len); \
|
||||
}
|
||||
IMPLEMENT_BTRFS_PAGE_OPS(uptodate, folio_mark_uptodate, folio_clear_uptodate,
|
||||
folio_test_uptodate);
|
||||
@@ -635,26 +660,29 @@ IMPLEMENT_BTRFS_PAGE_OPS(ordered, folio_set_ordered, folio_clear_ordered,
|
||||
IMPLEMENT_BTRFS_PAGE_OPS(checked, folio_set_checked, folio_clear_checked,
|
||||
folio_test_checked);
|
||||
|
||||
#define GET_SUBPAGE_BITMAP(subpage, fs_info, name, dst) \
|
||||
#define GET_SUBPAGE_BITMAP(fs_info, folio, name, dst) \
|
||||
{ \
|
||||
const int sectors_per_page = fs_info->sectors_per_page; \
|
||||
const unsigned int blocks_per_folio = \
|
||||
btrfs_blocks_per_folio(fs_info, folio); \
|
||||
const struct btrfs_subpage *subpage = folio_get_private(folio); \
|
||||
\
|
||||
ASSERT(sectors_per_page < BITS_PER_LONG); \
|
||||
ASSERT(blocks_per_folio < BITS_PER_LONG); \
|
||||
*dst = bitmap_read(subpage->bitmaps, \
|
||||
sectors_per_page * btrfs_bitmap_nr_##name, \
|
||||
sectors_per_page); \
|
||||
blocks_per_folio * btrfs_bitmap_nr_##name, \
|
||||
blocks_per_folio); \
|
||||
}
|
||||
|
||||
#define SUBPAGE_DUMP_BITMAP(fs_info, folio, name, start, len) \
|
||||
{ \
|
||||
const struct btrfs_subpage *subpage = folio_get_private(folio); \
|
||||
unsigned long bitmap; \
|
||||
const unsigned int blocks_per_folio = \
|
||||
btrfs_blocks_per_folio(fs_info, folio); \
|
||||
\
|
||||
GET_SUBPAGE_BITMAP(subpage, fs_info, name, &bitmap); \
|
||||
GET_SUBPAGE_BITMAP(fs_info, folio, name, &bitmap); \
|
||||
btrfs_warn(fs_info, \
|
||||
"dumpping bitmap start=%llu len=%u folio=%llu " #name "_bitmap=%*pbl", \
|
||||
start, len, folio_pos(folio), \
|
||||
fs_info->sectors_per_page, &bitmap); \
|
||||
blocks_per_folio, &bitmap); \
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -672,7 +700,7 @@ void btrfs_folio_assert_not_dirty(const struct btrfs_fs_info *fs_info,
|
||||
if (!IS_ENABLED(CONFIG_BTRFS_ASSERT))
|
||||
return;
|
||||
|
||||
if (!btrfs_is_subpage(fs_info, folio->mapping)) {
|
||||
if (!btrfs_is_subpage(fs_info, folio)) {
|
||||
ASSERT(!folio_test_dirty(folio));
|
||||
return;
|
||||
}
|
||||
@@ -707,7 +735,7 @@ void btrfs_folio_set_lock(const struct btrfs_fs_info *fs_info,
|
||||
int ret;
|
||||
|
||||
ASSERT(folio_test_locked(folio));
|
||||
if (unlikely(!fs_info) || !btrfs_is_subpage(fs_info, folio->mapping))
|
||||
if (unlikely(!fs_info) || !btrfs_is_subpage(fs_info, folio))
|
||||
return;
|
||||
|
||||
subpage = folio_get_private(folio);
|
||||
@@ -721,15 +749,37 @@ void btrfs_folio_set_lock(const struct btrfs_fs_info *fs_info,
|
||||
}
|
||||
bitmap_set(subpage->bitmaps, start_bit, nbits);
|
||||
ret = atomic_add_return(nbits, &subpage->nr_locked);
|
||||
ASSERT(ret <= fs_info->sectors_per_page);
|
||||
ASSERT(ret <= btrfs_blocks_per_folio(fs_info, folio));
|
||||
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the dirty flag for the folio.
|
||||
*
|
||||
* If the affected folio is no longer dirty, return true. Otherwise return false.
|
||||
*/
|
||||
bool btrfs_meta_folio_clear_and_test_dirty(struct folio *folio, const struct extent_buffer *eb)
|
||||
{
|
||||
bool last;
|
||||
|
||||
if (!btrfs_meta_is_subpage(eb->fs_info)) {
|
||||
folio_clear_dirty_for_io(folio);
|
||||
return true;
|
||||
}
|
||||
|
||||
last = btrfs_subpage_clear_and_test_dirty(eb->fs_info, folio, eb->start, eb->len);
|
||||
if (last) {
|
||||
folio_clear_dirty_for_io(folio);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void __cold btrfs_subpage_dump_bitmap(const struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio, u64 start, u32 len)
|
||||
{
|
||||
struct btrfs_subpage *subpage;
|
||||
const u32 sectors_per_page = fs_info->sectors_per_page;
|
||||
const unsigned int blocks_per_folio = btrfs_blocks_per_folio(fs_info, folio);
|
||||
unsigned long uptodate_bitmap;
|
||||
unsigned long dirty_bitmap;
|
||||
unsigned long writeback_bitmap;
|
||||
@@ -739,28 +789,28 @@ void __cold btrfs_subpage_dump_bitmap(const struct btrfs_fs_info *fs_info,
|
||||
unsigned long flags;
|
||||
|
||||
ASSERT(folio_test_private(folio) && folio_get_private(folio));
|
||||
ASSERT(sectors_per_page > 1);
|
||||
ASSERT(blocks_per_folio > 1);
|
||||
subpage = folio_get_private(folio);
|
||||
|
||||
spin_lock_irqsave(&subpage->lock, flags);
|
||||
GET_SUBPAGE_BITMAP(subpage, fs_info, uptodate, &uptodate_bitmap);
|
||||
GET_SUBPAGE_BITMAP(subpage, fs_info, dirty, &dirty_bitmap);
|
||||
GET_SUBPAGE_BITMAP(subpage, fs_info, writeback, &writeback_bitmap);
|
||||
GET_SUBPAGE_BITMAP(subpage, fs_info, ordered, &ordered_bitmap);
|
||||
GET_SUBPAGE_BITMAP(subpage, fs_info, checked, &checked_bitmap);
|
||||
GET_SUBPAGE_BITMAP(subpage, fs_info, locked, &locked_bitmap);
|
||||
GET_SUBPAGE_BITMAP(fs_info, folio, uptodate, &uptodate_bitmap);
|
||||
GET_SUBPAGE_BITMAP(fs_info, folio, dirty, &dirty_bitmap);
|
||||
GET_SUBPAGE_BITMAP(fs_info, folio, writeback, &writeback_bitmap);
|
||||
GET_SUBPAGE_BITMAP(fs_info, folio, ordered, &ordered_bitmap);
|
||||
GET_SUBPAGE_BITMAP(fs_info, folio, checked, &checked_bitmap);
|
||||
GET_SUBPAGE_BITMAP(fs_info, folio, locked, &locked_bitmap);
|
||||
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||
|
||||
dump_page(folio_page(folio, 0), "btrfs subpage dump");
|
||||
btrfs_warn(fs_info,
|
||||
"start=%llu len=%u page=%llu, bitmaps uptodate=%*pbl dirty=%*pbl locked=%*pbl writeback=%*pbl ordered=%*pbl checked=%*pbl",
|
||||
start, len, folio_pos(folio),
|
||||
sectors_per_page, &uptodate_bitmap,
|
||||
sectors_per_page, &dirty_bitmap,
|
||||
sectors_per_page, &locked_bitmap,
|
||||
sectors_per_page, &writeback_bitmap,
|
||||
sectors_per_page, &ordered_bitmap,
|
||||
sectors_per_page, &checked_bitmap);
|
||||
blocks_per_folio, &uptodate_bitmap,
|
||||
blocks_per_folio, &dirty_bitmap,
|
||||
blocks_per_folio, &locked_bitmap,
|
||||
blocks_per_folio, &writeback_bitmap,
|
||||
blocks_per_folio, &ordered_bitmap,
|
||||
blocks_per_folio, &checked_bitmap);
|
||||
}
|
||||
|
||||
void btrfs_get_subpage_dirty_bitmap(struct btrfs_fs_info *fs_info,
|
||||
@@ -771,10 +821,10 @@ void btrfs_get_subpage_dirty_bitmap(struct btrfs_fs_info *fs_info,
|
||||
unsigned long flags;
|
||||
|
||||
ASSERT(folio_test_private(folio) && folio_get_private(folio));
|
||||
ASSERT(fs_info->sectors_per_page > 1);
|
||||
ASSERT(btrfs_blocks_per_folio(fs_info, folio) > 1);
|
||||
subpage = folio_get_private(folio);
|
||||
|
||||
spin_lock_irqsave(&subpage->lock, flags);
|
||||
GET_SUBPAGE_BITMAP(subpage, fs_info, dirty, ret_bitmap);
|
||||
GET_SUBPAGE_BITMAP(fs_info, folio, dirty, ret_bitmap);
|
||||
spin_unlock_irqrestore(&subpage->lock, flags);
|
||||
}
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/sizes.h>
|
||||
#include "btrfs_inode.h"
|
||||
#include "fs.h"
|
||||
|
||||
struct address_space;
|
||||
struct folio;
|
||||
struct btrfs_fs_info;
|
||||
|
||||
/*
|
||||
* Extra info for subpapge bitmap.
|
||||
@@ -69,23 +70,49 @@ enum btrfs_subpage_type {
|
||||
BTRFS_SUBPAGE_DATA,
|
||||
};
|
||||
|
||||
#if PAGE_SIZE > SZ_4K
|
||||
bool btrfs_is_subpage(const struct btrfs_fs_info *fs_info, struct address_space *mapping);
|
||||
#else
|
||||
static inline bool btrfs_is_subpage(const struct btrfs_fs_info *fs_info,
|
||||
struct address_space *mapping)
|
||||
#if PAGE_SIZE > BTRFS_MIN_BLOCKSIZE
|
||||
/*
|
||||
* Subpage support for metadata is more complex, as we can have dummy extent
|
||||
* buffers, where folios have no mapping to determine the owning inode.
|
||||
*
|
||||
* Thankfully we only need to check if node size is smaller than page size.
|
||||
* Even with larger folio support, we will only allocate a folio as large as
|
||||
* node size.
|
||||
* Thus if nodesize < PAGE_SIZE, we know metadata needs need to subpage routine.
|
||||
*/
|
||||
static inline bool btrfs_meta_is_subpage(const struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
return fs_info->nodesize < PAGE_SIZE;
|
||||
}
|
||||
static inline bool btrfs_is_subpage(const struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio)
|
||||
{
|
||||
if (folio->mapping && folio->mapping->host)
|
||||
ASSERT(is_data_inode(BTRFS_I(folio->mapping->host)));
|
||||
return fs_info->sectorsize < folio_size(folio);
|
||||
}
|
||||
#else
|
||||
static inline bool btrfs_meta_is_subpage(const struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline bool btrfs_is_subpage(const struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio)
|
||||
{
|
||||
if (folio->mapping && folio->mapping->host)
|
||||
ASSERT(is_data_inode(BTRFS_I(folio->mapping->host)));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio, enum btrfs_subpage_type type);
|
||||
void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info, struct folio *folio);
|
||||
void btrfs_detach_subpage(const struct btrfs_fs_info *fs_info, struct folio *folio,
|
||||
enum btrfs_subpage_type type);
|
||||
|
||||
/* Allocate additional data where page represents more than one sector */
|
||||
struct btrfs_subpage *btrfs_alloc_subpage(const struct btrfs_fs_info *fs_info,
|
||||
enum btrfs_subpage_type type);
|
||||
size_t fsize, enum btrfs_subpage_type type);
|
||||
void btrfs_free_subpage(struct btrfs_subpage *subpage);
|
||||
|
||||
void btrfs_folio_inc_eb_refs(const struct btrfs_fs_info *fs_info, struct folio *folio);
|
||||
@@ -110,6 +137,13 @@ void btrfs_folio_end_lock_bitmap(const struct btrfs_fs_info *fs_info,
|
||||
* btrfs_folio_clamp_*() are similar to btrfs_folio_*(), except the range doesn't
|
||||
* need to be inside the page. Those functions will truncate the range
|
||||
* automatically.
|
||||
*
|
||||
* Both btrfs_folio_*() and btrfs_folio_clamp_*() are for data folios.
|
||||
*
|
||||
* For metadata, one should use btrfs_meta_folio_*() helpers instead, and there
|
||||
* is no clamp version for metadata helpers, as we either go subpage
|
||||
* (nodesize < PAGE_SIZE) or go regular folio helpers (nodesize >= PAGE_SIZE,
|
||||
* and our folio is never larger than nodesize).
|
||||
*/
|
||||
#define DECLARE_BTRFS_SUBPAGE_OPS(name) \
|
||||
void btrfs_subpage_set_##name(const struct btrfs_fs_info *fs_info, \
|
||||
@@ -129,7 +163,10 @@ void btrfs_folio_clamp_set_##name(const struct btrfs_fs_info *fs_info, \
|
||||
void btrfs_folio_clamp_clear_##name(const struct btrfs_fs_info *fs_info, \
|
||||
struct folio *folio, u64 start, u32 len); \
|
||||
bool btrfs_folio_clamp_test_##name(const struct btrfs_fs_info *fs_info, \
|
||||
struct folio *folio, u64 start, u32 len);
|
||||
struct folio *folio, u64 start, u32 len); \
|
||||
void btrfs_meta_folio_set_##name(struct folio *folio, const struct extent_buffer *eb); \
|
||||
void btrfs_meta_folio_clear_##name(struct folio *folio, const struct extent_buffer *eb); \
|
||||
bool btrfs_meta_folio_test_##name(struct folio *folio, const struct extent_buffer *eb);
|
||||
|
||||
DECLARE_BTRFS_SUBPAGE_OPS(uptodate);
|
||||
DECLARE_BTRFS_SUBPAGE_OPS(dirty);
|
||||
@@ -155,6 +192,7 @@ bool btrfs_subpage_clear_and_test_dirty(const struct btrfs_fs_info *fs_info,
|
||||
|
||||
void btrfs_folio_assert_not_dirty(const struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio, u64 start, u32 len);
|
||||
bool btrfs_meta_folio_clear_and_test_dirty(struct folio *folio, const struct extent_buffer *eb);
|
||||
void btrfs_get_subpage_dirty_bitmap(struct btrfs_fs_info *fs_info,
|
||||
struct folio *folio,
|
||||
unsigned long *ret_bitmap);
|
||||
|
||||
@@ -84,7 +84,7 @@ struct btrfs_fs_context {
|
||||
u32 thread_pool_size;
|
||||
unsigned long long mount_opt;
|
||||
unsigned long compress_type:4;
|
||||
unsigned int compress_level;
|
||||
int compress_level;
|
||||
refcount_t refs;
|
||||
};
|
||||
|
||||
@@ -947,7 +947,7 @@ static int get_default_subvol_objectid(struct btrfs_fs_info *fs_info, u64 *objec
|
||||
static int btrfs_fill_super(struct super_block *sb,
|
||||
struct btrfs_fs_devices *fs_devices)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct btrfs_inode *inode;
|
||||
struct btrfs_fs_info *fs_info = btrfs_sb(sb);
|
||||
int err;
|
||||
|
||||
@@ -982,7 +982,7 @@ static int btrfs_fill_super(struct super_block *sb,
|
||||
goto fail_close;
|
||||
}
|
||||
|
||||
sb->s_root = d_make_root(inode);
|
||||
sb->s_root = d_make_root(&inode->vfs_inode);
|
||||
if (!sb->s_root) {
|
||||
err = -ENOMEM;
|
||||
goto fail_close;
|
||||
|
||||
@@ -411,7 +411,8 @@ static ssize_t supported_sectorsizes_show(struct kobject *kobj,
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
|
||||
/* An artificial limit to only support 4K and PAGE_SIZE */
|
||||
if (BTRFS_MIN_BLOCKSIZE != SZ_4K && BTRFS_MIN_BLOCKSIZE != PAGE_SIZE)
|
||||
ret += sysfs_emit_at(buf, ret, "%u ", BTRFS_MIN_BLOCKSIZE);
|
||||
if (PAGE_SIZE > SZ_4K)
|
||||
ret += sysfs_emit_at(buf, ret, "%u ", SZ_4K);
|
||||
ret += sysfs_emit_at(buf, ret, "%lu\n", PAGE_SIZE);
|
||||
@@ -1342,17 +1343,18 @@ int btrfs_read_policy_to_enum(const char *str, s64 *value_ret)
|
||||
/* Separate value from input in policy:value format. */
|
||||
value_str = strchr(param, ':');
|
||||
if (value_str) {
|
||||
int ret;
|
||||
char *retptr;
|
||||
|
||||
*value_str = 0;
|
||||
value_str++;
|
||||
if (!value_ret)
|
||||
return -EINVAL;
|
||||
ret = kstrtos64(value_str, 10, value_ret);
|
||||
if (ret)
|
||||
|
||||
*value_ret = memparse(value_str, &retptr);
|
||||
/* There could be any trailing typos after the value. */
|
||||
retptr = skip_spaces(retptr);
|
||||
if (*retptr != 0 || *value_ret <= 0)
|
||||
return -EINVAL;
|
||||
if (*value_ret < 0)
|
||||
return -ERANGE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <linux/compiler_types.h>
|
||||
#include <linux/kobject.h>
|
||||
|
||||
struct block_device;
|
||||
struct btrfs_fs_info;
|
||||
struct btrfs_device;
|
||||
struct btrfs_fs_devices;
|
||||
|
||||
@@ -525,7 +525,7 @@ static int test_eb_bitmaps(u32 sectorsize, u32 nodesize)
|
||||
goto out;
|
||||
}
|
||||
|
||||
eb = __alloc_dummy_extent_buffer(fs_info, 0, nodesize);
|
||||
eb = alloc_dummy_extent_buffer(fs_info, 0);
|
||||
if (!eb) {
|
||||
test_std_err(TEST_ALLOC_ROOT);
|
||||
ret = -ENOMEM;
|
||||
@@ -542,7 +542,7 @@ static int test_eb_bitmaps(u32 sectorsize, u32 nodesize)
|
||||
* Test again for case where the tree block is sectorsize aligned but
|
||||
* not nodesize aligned.
|
||||
*/
|
||||
eb = __alloc_dummy_extent_buffer(fs_info, sectorsize, nodesize);
|
||||
eb = alloc_dummy_extent_buffer(fs_info, sectorsize);
|
||||
if (!eb) {
|
||||
test_std_err(TEST_ALLOC_ROOT);
|
||||
ret = -ENOMEM;
|
||||
@@ -730,7 +730,7 @@ static int test_eb_mem_ops(u32 sectorsize, u32 nodesize)
|
||||
goto out;
|
||||
}
|
||||
|
||||
eb = __alloc_dummy_extent_buffer(fs_info, SZ_1M, nodesize);
|
||||
eb = alloc_dummy_extent_buffer(fs_info, SZ_1M);
|
||||
if (!eb) {
|
||||
test_std_err(TEST_ALLOC_EXTENT_BUFFER);
|
||||
ret = -ENOMEM;
|
||||
|
||||
@@ -1045,6 +1045,7 @@ static int test_rmap_block(struct btrfs_fs_info *fs_info,
|
||||
ret = btrfs_add_chunk_map(fs_info, map);
|
||||
if (ret) {
|
||||
test_err("error adding chunk map to mapping tree");
|
||||
btrfs_free_chunk_map(map);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
|
||||
@@ -160,7 +160,13 @@ void btrfs_put_transaction(struct btrfs_transaction *transaction)
|
||||
cache = list_first_entry(&transaction->deleted_bgs,
|
||||
struct btrfs_block_group,
|
||||
bg_list);
|
||||
/*
|
||||
* Not strictly necessary to lock, as no other task will be using a
|
||||
* block_group on the deleted_bgs list during a transaction abort.
|
||||
*/
|
||||
spin_lock(&transaction->fs_info->unused_bgs_lock);
|
||||
list_del_init(&cache->bg_list);
|
||||
spin_unlock(&transaction->fs_info->unused_bgs_lock);
|
||||
btrfs_unfreeze_block_group(cache);
|
||||
btrfs_put_block_group(cache);
|
||||
}
|
||||
@@ -1635,7 +1641,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root = pending->root;
|
||||
struct btrfs_root *parent_root;
|
||||
struct btrfs_block_rsv *rsv;
|
||||
struct inode *parent_inode = &pending->dir->vfs_inode;
|
||||
struct btrfs_inode *parent_inode = pending->dir;
|
||||
struct btrfs_path *path;
|
||||
struct btrfs_dir_item *dir_item;
|
||||
struct extent_buffer *tmp;
|
||||
@@ -1661,7 +1667,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
||||
* filesystem.
|
||||
*/
|
||||
nofs_flags = memalloc_nofs_save();
|
||||
pending->error = fscrypt_setup_filename(parent_inode,
|
||||
pending->error = fscrypt_setup_filename(&parent_inode->vfs_inode,
|
||||
&pending->dentry->d_name, 0,
|
||||
&fname);
|
||||
memalloc_nofs_restore(nofs_flags);
|
||||
@@ -1690,8 +1696,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
|
||||
key.objectid = objectid;
|
||||
key.offset = (u64)-1;
|
||||
key.type = BTRFS_ROOT_ITEM_KEY;
|
||||
key.offset = (u64)-1;
|
||||
|
||||
rsv = trans->block_rsv;
|
||||
trans->block_rsv = &pending->block_rsv;
|
||||
@@ -1699,16 +1705,16 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
||||
trace_btrfs_space_reservation(fs_info, "transaction",
|
||||
trans->transid,
|
||||
trans->bytes_reserved, 1);
|
||||
parent_root = BTRFS_I(parent_inode)->root;
|
||||
parent_root = parent_inode->root;
|
||||
ret = record_root_in_trans(trans, parent_root, 0);
|
||||
if (ret)
|
||||
goto fail;
|
||||
cur_time = current_time(parent_inode);
|
||||
cur_time = current_time(&parent_inode->vfs_inode);
|
||||
|
||||
/*
|
||||
* insert the directory item
|
||||
*/
|
||||
ret = btrfs_set_inode_index(BTRFS_I(parent_inode), &index);
|
||||
ret = btrfs_set_inode_index(parent_inode, &index);
|
||||
if (ret) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto fail;
|
||||
@@ -1716,7 +1722,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
||||
|
||||
/* check if there is a file/dir which has the same name. */
|
||||
dir_item = btrfs_lookup_dir_item(NULL, parent_root, path,
|
||||
btrfs_ino(BTRFS_I(parent_inode)),
|
||||
btrfs_ino(parent_inode),
|
||||
&fname.disk_name, 0);
|
||||
if (dir_item != NULL && !IS_ERR(dir_item)) {
|
||||
pending->error = -EEXIST;
|
||||
@@ -1817,7 +1823,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
||||
*/
|
||||
ret = btrfs_add_root_ref(trans, objectid,
|
||||
btrfs_root_id(parent_root),
|
||||
btrfs_ino(BTRFS_I(parent_inode)), index,
|
||||
btrfs_ino(parent_inode), index,
|
||||
&fname.disk_name);
|
||||
if (ret) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
@@ -1855,18 +1861,18 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
||||
goto fail;
|
||||
|
||||
ret = btrfs_insert_dir_item(trans, &fname.disk_name,
|
||||
BTRFS_I(parent_inode), &key, BTRFS_FT_DIR,
|
||||
parent_inode, &key, BTRFS_FT_DIR,
|
||||
index);
|
||||
if (ret) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
btrfs_i_size_write(BTRFS_I(parent_inode), parent_inode->i_size +
|
||||
btrfs_i_size_write(parent_inode, parent_inode->vfs_inode.i_size +
|
||||
fname.disk_name.len * 2);
|
||||
inode_set_mtime_to_ts(parent_inode,
|
||||
inode_set_ctime_current(parent_inode));
|
||||
ret = btrfs_update_inode_fallback(trans, BTRFS_I(parent_inode));
|
||||
inode_set_mtime_to_ts(&parent_inode->vfs_inode,
|
||||
inode_set_ctime_current(&parent_inode->vfs_inode));
|
||||
ret = btrfs_update_inode_fallback(trans, parent_inode);
|
||||
if (ret) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
goto fail;
|
||||
@@ -2096,7 +2102,14 @@ static void btrfs_cleanup_pending_block_groups(struct btrfs_trans_handle *trans)
|
||||
|
||||
list_for_each_entry_safe(block_group, tmp, &trans->new_bgs, bg_list) {
|
||||
btrfs_dec_delayed_refs_rsv_bg_inserts(fs_info);
|
||||
/*
|
||||
* Not strictly necessary to lock, as no other task will be using a
|
||||
* block_group on the new_bgs list during a transaction abort.
|
||||
*/
|
||||
spin_lock(&fs_info->unused_bgs_lock);
|
||||
list_del_init(&block_group->bg_list);
|
||||
btrfs_put_block_group(block_group);
|
||||
spin_unlock(&fs_info->unused_bgs_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -138,10 +138,10 @@ static void wait_log_commit(struct btrfs_root *root, int transid);
|
||||
* and once to do all the other items.
|
||||
*/
|
||||
|
||||
static struct inode *btrfs_iget_logging(u64 objectid, struct btrfs_root *root)
|
||||
static struct btrfs_inode *btrfs_iget_logging(u64 objectid, struct btrfs_root *root)
|
||||
{
|
||||
unsigned int nofs_flag;
|
||||
struct inode *inode;
|
||||
struct btrfs_inode *inode;
|
||||
|
||||
/*
|
||||
* We're holding a transaction handle whether we are logging or
|
||||
@@ -376,12 +376,12 @@ static int process_one_buffer(struct btrfs_root *log,
|
||||
}
|
||||
|
||||
/*
|
||||
* Item overwrite used by replay and tree logging. eb, slot and key all refer
|
||||
* to the src data we are copying out.
|
||||
* Item overwrite used by log replay. The given eb, slot and key all refer to
|
||||
* the source data we are copying out.
|
||||
*
|
||||
* root is the tree we are copying into, and path is a scratch
|
||||
* path for use in this function (it should be released on entry and
|
||||
* will be released on exit).
|
||||
* The given root is for the tree we are copying into, and path is a scratch
|
||||
* path for use in this function (it should be released on entry and will be
|
||||
* released on exit).
|
||||
*
|
||||
* If the key is already in the destination tree the existing item is
|
||||
* overwritten. If the existing item isn't big enough, it is extended.
|
||||
@@ -401,6 +401,8 @@ static int overwrite_item(struct btrfs_trans_handle *trans,
|
||||
int save_old_i_size = 0;
|
||||
unsigned long src_ptr;
|
||||
unsigned long dst_ptr;
|
||||
struct extent_buffer *dst_eb;
|
||||
int dst_slot;
|
||||
bool inode_item = key->type == BTRFS_INODE_ITEM_KEY;
|
||||
|
||||
/*
|
||||
@@ -420,11 +422,13 @@ static int overwrite_item(struct btrfs_trans_handle *trans,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dst_eb = path->nodes[0];
|
||||
dst_slot = path->slots[0];
|
||||
|
||||
if (ret == 0) {
|
||||
char *src_copy;
|
||||
char *dst_copy;
|
||||
u32 dst_size = btrfs_item_size(path->nodes[0],
|
||||
path->slots[0]);
|
||||
const u32 dst_size = btrfs_item_size(dst_eb, dst_slot);
|
||||
|
||||
if (dst_size != item_size)
|
||||
goto insert;
|
||||
|
||||
@@ -432,23 +436,16 @@ static int overwrite_item(struct btrfs_trans_handle *trans,
|
||||
btrfs_release_path(path);
|
||||
return 0;
|
||||
}
|
||||
dst_copy = kmalloc(item_size, GFP_NOFS);
|
||||
src_copy = kmalloc(item_size, GFP_NOFS);
|
||||
if (!dst_copy || !src_copy) {
|
||||
if (!src_copy) {
|
||||
btrfs_release_path(path);
|
||||
kfree(dst_copy);
|
||||
kfree(src_copy);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
read_extent_buffer(eb, src_copy, src_ptr, item_size);
|
||||
dst_ptr = btrfs_item_ptr_offset(dst_eb, dst_slot);
|
||||
ret = memcmp_extent_buffer(dst_eb, src_copy, dst_ptr, item_size);
|
||||
|
||||
dst_ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]);
|
||||
read_extent_buffer(path->nodes[0], dst_copy, dst_ptr,
|
||||
item_size);
|
||||
ret = memcmp(dst_copy, src_copy, item_size);
|
||||
|
||||
kfree(dst_copy);
|
||||
kfree(src_copy);
|
||||
/*
|
||||
* they have the same contents, just return, this saves
|
||||
@@ -470,9 +467,9 @@ static int overwrite_item(struct btrfs_trans_handle *trans,
|
||||
u64 nbytes;
|
||||
u32 mode;
|
||||
|
||||
item = btrfs_item_ptr(path->nodes[0], path->slots[0],
|
||||
item = btrfs_item_ptr(dst_eb, dst_slot,
|
||||
struct btrfs_inode_item);
|
||||
nbytes = btrfs_inode_nbytes(path->nodes[0], item);
|
||||
nbytes = btrfs_inode_nbytes(dst_eb, item);
|
||||
item = btrfs_item_ptr(eb, slot,
|
||||
struct btrfs_inode_item);
|
||||
btrfs_set_inode_nbytes(eb, item, nbytes);
|
||||
@@ -514,11 +511,13 @@ insert:
|
||||
key, item_size);
|
||||
path->skip_release_on_error = 0;
|
||||
|
||||
dst_eb = path->nodes[0];
|
||||
dst_slot = path->slots[0];
|
||||
|
||||
/* make sure any existing item is the correct size */
|
||||
if (ret == -EEXIST || ret == -EOVERFLOW) {
|
||||
u32 found_size;
|
||||
found_size = btrfs_item_size(path->nodes[0],
|
||||
path->slots[0]);
|
||||
const u32 found_size = btrfs_item_size(dst_eb, dst_slot);
|
||||
|
||||
if (found_size > item_size)
|
||||
btrfs_truncate_item(trans, path, item_size, 1);
|
||||
else if (found_size < item_size)
|
||||
@@ -526,8 +525,7 @@ insert:
|
||||
} else if (ret) {
|
||||
return ret;
|
||||
}
|
||||
dst_ptr = btrfs_item_ptr_offset(path->nodes[0],
|
||||
path->slots[0]);
|
||||
dst_ptr = btrfs_item_ptr_offset(dst_eb, dst_slot);
|
||||
|
||||
/* don't overwrite an existing inode if the generation number
|
||||
* was logged as zero. This is done when the tree logging code
|
||||
@@ -546,7 +544,6 @@ insert:
|
||||
dst_item = (struct btrfs_inode_item *)dst_ptr;
|
||||
|
||||
if (btrfs_inode_generation(eb, src_item) == 0) {
|
||||
struct extent_buffer *dst_eb = path->nodes[0];
|
||||
const u64 ino_size = btrfs_inode_size(eb, src_item);
|
||||
|
||||
/*
|
||||
@@ -564,30 +561,28 @@ insert:
|
||||
}
|
||||
|
||||
if (S_ISDIR(btrfs_inode_mode(eb, src_item)) &&
|
||||
S_ISDIR(btrfs_inode_mode(path->nodes[0], dst_item))) {
|
||||
S_ISDIR(btrfs_inode_mode(dst_eb, dst_item))) {
|
||||
save_old_i_size = 1;
|
||||
saved_i_size = btrfs_inode_size(path->nodes[0],
|
||||
dst_item);
|
||||
saved_i_size = btrfs_inode_size(dst_eb, dst_item);
|
||||
}
|
||||
}
|
||||
|
||||
copy_extent_buffer(path->nodes[0], eb, dst_ptr,
|
||||
src_ptr, item_size);
|
||||
copy_extent_buffer(dst_eb, eb, dst_ptr, src_ptr, item_size);
|
||||
|
||||
if (save_old_i_size) {
|
||||
struct btrfs_inode_item *dst_item;
|
||||
|
||||
dst_item = (struct btrfs_inode_item *)dst_ptr;
|
||||
btrfs_set_inode_size(path->nodes[0], dst_item, saved_i_size);
|
||||
btrfs_set_inode_size(dst_eb, dst_item, saved_i_size);
|
||||
}
|
||||
|
||||
/* make sure the generation is filled in */
|
||||
if (key->type == BTRFS_INODE_ITEM_KEY) {
|
||||
struct btrfs_inode_item *dst_item;
|
||||
|
||||
dst_item = (struct btrfs_inode_item *)dst_ptr;
|
||||
if (btrfs_inode_generation(path->nodes[0], dst_item) == 0) {
|
||||
btrfs_set_inode_generation(path->nodes[0], dst_item,
|
||||
trans->transid);
|
||||
}
|
||||
if (btrfs_inode_generation(dst_eb, dst_item) == 0)
|
||||
btrfs_set_inode_generation(dst_eb, dst_item, trans->transid);
|
||||
}
|
||||
no_copy:
|
||||
btrfs_release_path(path);
|
||||
@@ -613,14 +608,14 @@ static int read_alloc_one_name(struct extent_buffer *eb, void *start, int len,
|
||||
* simple helper to read an inode off the disk from a given root
|
||||
* This can only be called for subvolume roots and not for the log
|
||||
*/
|
||||
static noinline struct inode *read_one_inode(struct btrfs_root *root,
|
||||
u64 objectid)
|
||||
static noinline struct btrfs_inode *read_one_inode(struct btrfs_root *root,
|
||||
u64 objectid)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct btrfs_inode *inode;
|
||||
|
||||
inode = btrfs_iget_logging(objectid, root);
|
||||
if (IS_ERR(inode))
|
||||
inode = NULL;
|
||||
return NULL;
|
||||
return inode;
|
||||
}
|
||||
|
||||
@@ -649,7 +644,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
|
||||
u64 start = key->offset;
|
||||
u64 nbytes = 0;
|
||||
struct btrfs_file_extent_item *item;
|
||||
struct inode *inode = NULL;
|
||||
struct btrfs_inode *inode = NULL;
|
||||
unsigned long size;
|
||||
int ret = 0;
|
||||
|
||||
@@ -688,31 +683,23 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
|
||||
* file. This must be done before the btrfs_drop_extents run
|
||||
* so we don't try to drop this extent.
|
||||
*/
|
||||
ret = btrfs_lookup_file_extent(trans, root, path,
|
||||
btrfs_ino(BTRFS_I(inode)), start, 0);
|
||||
ret = btrfs_lookup_file_extent(trans, root, path, btrfs_ino(inode), start, 0);
|
||||
|
||||
if (ret == 0 &&
|
||||
(found_type == BTRFS_FILE_EXTENT_REG ||
|
||||
found_type == BTRFS_FILE_EXTENT_PREALLOC)) {
|
||||
struct btrfs_file_extent_item cmp1;
|
||||
struct btrfs_file_extent_item cmp2;
|
||||
struct btrfs_file_extent_item *existing;
|
||||
struct extent_buffer *leaf;
|
||||
struct btrfs_file_extent_item existing;
|
||||
unsigned long ptr;
|
||||
|
||||
leaf = path->nodes[0];
|
||||
existing = btrfs_item_ptr(leaf, path->slots[0],
|
||||
struct btrfs_file_extent_item);
|
||||
|
||||
read_extent_buffer(eb, &cmp1, (unsigned long)item,
|
||||
sizeof(cmp1));
|
||||
read_extent_buffer(leaf, &cmp2, (unsigned long)existing,
|
||||
sizeof(cmp2));
|
||||
ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]);
|
||||
read_extent_buffer(path->nodes[0], &existing, ptr, sizeof(existing));
|
||||
|
||||
/*
|
||||
* we already have a pointer to this exact extent,
|
||||
* we don't have to do anything
|
||||
*/
|
||||
if (memcmp(&cmp1, &cmp2, sizeof(cmp1)) == 0) {
|
||||
if (memcmp_extent_buffer(eb, &existing, (unsigned long)item,
|
||||
sizeof(existing)) == 0) {
|
||||
btrfs_release_path(path);
|
||||
goto out;
|
||||
}
|
||||
@@ -723,7 +710,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
|
||||
drop_args.start = start;
|
||||
drop_args.end = extent_end;
|
||||
drop_args.drop_cache = true;
|
||||
ret = btrfs_drop_extents(trans, root, BTRFS_I(inode), &drop_args);
|
||||
ret = btrfs_drop_extents(trans, root, inode, &drop_args);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@@ -747,8 +734,8 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
|
||||
(unsigned long)item, sizeof(*item));
|
||||
|
||||
ins.objectid = btrfs_file_extent_disk_bytenr(eb, item);
|
||||
ins.offset = btrfs_file_extent_disk_num_bytes(eb, item);
|
||||
ins.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
ins.offset = btrfs_file_extent_disk_num_bytes(eb, item);
|
||||
offset = key->offset - btrfs_file_extent_offset(eb, item);
|
||||
|
||||
/*
|
||||
@@ -901,16 +888,15 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = btrfs_inode_set_file_extent_range(BTRFS_I(inode), start,
|
||||
extent_end - start);
|
||||
ret = btrfs_inode_set_file_extent_range(inode, start, extent_end - start);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
update_inode:
|
||||
btrfs_update_inode_bytes(BTRFS_I(inode), nbytes, drop_args.bytes_found);
|
||||
ret = btrfs_update_inode(trans, BTRFS_I(inode));
|
||||
btrfs_update_inode_bytes(inode, nbytes, drop_args.bytes_found);
|
||||
ret = btrfs_update_inode(trans, inode);
|
||||
out:
|
||||
iput(inode);
|
||||
iput(&inode->vfs_inode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -947,7 +933,7 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_dir_item *di)
|
||||
{
|
||||
struct btrfs_root *root = dir->root;
|
||||
struct inode *inode;
|
||||
struct btrfs_inode *inode;
|
||||
struct fscrypt_str name;
|
||||
struct extent_buffer *leaf;
|
||||
struct btrfs_key location;
|
||||
@@ -972,10 +958,10 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = unlink_inode_for_log_replay(trans, dir, BTRFS_I(inode), &name);
|
||||
ret = unlink_inode_for_log_replay(trans, dir, inode, &name);
|
||||
out:
|
||||
kfree(name.name);
|
||||
iput(inode);
|
||||
iput(&inode->vfs_inode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1148,7 +1134,7 @@ again:
|
||||
u32 item_size;
|
||||
u32 cur_offset = 0;
|
||||
unsigned long base;
|
||||
struct inode *victim_parent;
|
||||
struct btrfs_inode *victim_parent;
|
||||
|
||||
leaf = path->nodes[0];
|
||||
|
||||
@@ -1188,10 +1174,10 @@ again:
|
||||
btrfs_release_path(path);
|
||||
|
||||
ret = unlink_inode_for_log_replay(trans,
|
||||
BTRFS_I(victim_parent),
|
||||
victim_parent,
|
||||
inode, &victim_name);
|
||||
}
|
||||
iput(victim_parent);
|
||||
iput(&victim_parent->vfs_inode);
|
||||
kfree(victim_name.name);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1325,7 +1311,7 @@ again:
|
||||
ret = !!btrfs_find_name_in_backref(log_eb, log_slot, &name);
|
||||
|
||||
if (!ret) {
|
||||
struct inode *dir;
|
||||
struct btrfs_inode *dir;
|
||||
|
||||
btrfs_release_path(path);
|
||||
dir = read_one_inode(root, parent_id);
|
||||
@@ -1334,10 +1320,9 @@ again:
|
||||
kfree(name.name);
|
||||
goto out;
|
||||
}
|
||||
ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir),
|
||||
inode, &name);
|
||||
ret = unlink_inode_for_log_replay(trans, dir, inode, &name);
|
||||
kfree(name.name);
|
||||
iput(dir);
|
||||
iput(&dir->vfs_inode);
|
||||
if (ret)
|
||||
goto out;
|
||||
goto again;
|
||||
@@ -1369,8 +1354,8 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
|
||||
struct extent_buffer *eb, int slot,
|
||||
struct btrfs_key *key)
|
||||
{
|
||||
struct inode *dir = NULL;
|
||||
struct inode *inode = NULL;
|
||||
struct btrfs_inode *dir = NULL;
|
||||
struct btrfs_inode *inode = NULL;
|
||||
unsigned long ref_ptr;
|
||||
unsigned long ref_end;
|
||||
struct fscrypt_str name = { 0 };
|
||||
@@ -1435,8 +1420,8 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = inode_in_dir(root, path, btrfs_ino(BTRFS_I(dir)),
|
||||
btrfs_ino(BTRFS_I(inode)), ref_index, &name);
|
||||
ret = inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode),
|
||||
ref_index, &name);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
} else if (ret == 0) {
|
||||
@@ -1447,8 +1432,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
|
||||
* overwrite any existing back reference, and we don't
|
||||
* want to create dangling pointers in the directory.
|
||||
*/
|
||||
ret = __add_inode_ref(trans, root, path, log,
|
||||
BTRFS_I(dir), BTRFS_I(inode),
|
||||
ret = __add_inode_ref(trans, root, path, log, dir, inode,
|
||||
inode_objectid, parent_objectid,
|
||||
ref_index, &name);
|
||||
if (ret) {
|
||||
@@ -1458,12 +1442,11 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
|
||||
/* insert our name */
|
||||
ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
|
||||
&name, 0, ref_index);
|
||||
ret = btrfs_add_link(trans, dir, inode, &name, 0, ref_index);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = btrfs_update_inode(trans, BTRFS_I(inode));
|
||||
ret = btrfs_update_inode(trans, inode);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
@@ -1473,7 +1456,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
|
||||
kfree(name.name);
|
||||
name.name = NULL;
|
||||
if (log_ref_ver) {
|
||||
iput(dir);
|
||||
iput(&dir->vfs_inode);
|
||||
dir = NULL;
|
||||
}
|
||||
}
|
||||
@@ -1486,8 +1469,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
|
||||
* dir index entries exist for a name but there is no inode reference
|
||||
* item with the same name.
|
||||
*/
|
||||
ret = unlink_old_inode_refs(trans, root, path, BTRFS_I(inode), eb, slot,
|
||||
key);
|
||||
ret = unlink_old_inode_refs(trans, root, path, inode, eb, slot, key);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@@ -1496,8 +1478,10 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
|
||||
out:
|
||||
btrfs_release_path(path);
|
||||
kfree(name.name);
|
||||
iput(dir);
|
||||
iput(inode);
|
||||
if (dir)
|
||||
iput(&dir->vfs_inode);
|
||||
if (inode)
|
||||
iput(&inode->vfs_inode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1611,25 +1595,25 @@ process_slot:
|
||||
* will free the inode.
|
||||
*/
|
||||
static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
|
||||
struct inode *inode)
|
||||
struct btrfs_inode *inode)
|
||||
{
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
struct btrfs_root *root = inode->root;
|
||||
struct btrfs_path *path;
|
||||
int ret;
|
||||
u64 nlink = 0;
|
||||
u64 ino = btrfs_ino(BTRFS_I(inode));
|
||||
const u64 ino = btrfs_ino(inode);
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = count_inode_refs(BTRFS_I(inode), path);
|
||||
ret = count_inode_refs(inode, path);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
nlink = ret;
|
||||
|
||||
ret = count_inode_extrefs(BTRFS_I(inode), path);
|
||||
ret = count_inode_extrefs(inode, path);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
@@ -1637,17 +1621,17 @@ static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans,
|
||||
|
||||
ret = 0;
|
||||
|
||||
if (nlink != inode->i_nlink) {
|
||||
set_nlink(inode, nlink);
|
||||
ret = btrfs_update_inode(trans, BTRFS_I(inode));
|
||||
if (nlink != inode->vfs_inode.i_nlink) {
|
||||
set_nlink(&inode->vfs_inode, nlink);
|
||||
ret = btrfs_update_inode(trans, inode);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
BTRFS_I(inode)->index_cnt = (u64)-1;
|
||||
if (S_ISDIR(inode->vfs_inode.i_mode))
|
||||
inode->index_cnt = (u64)-1;
|
||||
|
||||
if (inode->i_nlink == 0) {
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
if (inode->vfs_inode.i_nlink == 0) {
|
||||
if (S_ISDIR(inode->vfs_inode.i_mode)) {
|
||||
ret = replay_dir_deletes(trans, root, NULL, path,
|
||||
ino, 1);
|
||||
if (ret)
|
||||
@@ -1669,12 +1653,13 @@ static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans,
|
||||
{
|
||||
int ret;
|
||||
struct btrfs_key key;
|
||||
struct inode *inode;
|
||||
|
||||
key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID;
|
||||
key.type = BTRFS_ORPHAN_ITEM_KEY;
|
||||
key.offset = (u64)-1;
|
||||
while (1) {
|
||||
struct btrfs_inode *inode;
|
||||
|
||||
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
||||
if (ret < 0)
|
||||
break;
|
||||
@@ -1703,7 +1688,7 @@ static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
|
||||
ret = fixup_inode_link_count(trans, inode);
|
||||
iput(inode);
|
||||
iput(&inode->vfs_inode);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
@@ -1731,12 +1716,14 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans,
|
||||
{
|
||||
struct btrfs_key key;
|
||||
int ret = 0;
|
||||
struct inode *inode;
|
||||
struct btrfs_inode *inode;
|
||||
struct inode *vfs_inode;
|
||||
|
||||
inode = read_one_inode(root, objectid);
|
||||
if (!inode)
|
||||
return -EIO;
|
||||
|
||||
vfs_inode = &inode->vfs_inode;
|
||||
key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID;
|
||||
key.type = BTRFS_ORPHAN_ITEM_KEY;
|
||||
key.offset = objectid;
|
||||
@@ -1745,15 +1732,15 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans,
|
||||
|
||||
btrfs_release_path(path);
|
||||
if (ret == 0) {
|
||||
if (!inode->i_nlink)
|
||||
set_nlink(inode, 1);
|
||||
if (!vfs_inode->i_nlink)
|
||||
set_nlink(vfs_inode, 1);
|
||||
else
|
||||
inc_nlink(inode);
|
||||
ret = btrfs_update_inode(trans, BTRFS_I(inode));
|
||||
inc_nlink(vfs_inode);
|
||||
ret = btrfs_update_inode(trans, inode);
|
||||
} else if (ret == -EEXIST) {
|
||||
ret = 0;
|
||||
}
|
||||
iput(inode);
|
||||
iput(vfs_inode);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1769,8 +1756,8 @@ static noinline int insert_one_name(struct btrfs_trans_handle *trans,
|
||||
const struct fscrypt_str *name,
|
||||
struct btrfs_key *location)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct inode *dir;
|
||||
struct btrfs_inode *inode;
|
||||
struct btrfs_inode *dir;
|
||||
int ret;
|
||||
|
||||
inode = read_one_inode(root, location->objectid);
|
||||
@@ -1779,17 +1766,16 @@ static noinline int insert_one_name(struct btrfs_trans_handle *trans,
|
||||
|
||||
dir = read_one_inode(root, dirid);
|
||||
if (!dir) {
|
||||
iput(inode);
|
||||
iput(&inode->vfs_inode);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), name,
|
||||
1, index);
|
||||
ret = btrfs_add_link(trans, dir, inode, name, 1, index);
|
||||
|
||||
/* FIXME, put inode into FIXUP list */
|
||||
|
||||
iput(inode);
|
||||
iput(dir);
|
||||
iput(&inode->vfs_inode);
|
||||
iput(&dir->vfs_inode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1851,7 +1837,7 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
|
||||
bool index_dst_matches = false;
|
||||
struct btrfs_key log_key;
|
||||
struct btrfs_key search_key;
|
||||
struct inode *dir;
|
||||
struct btrfs_inode *dir;
|
||||
u8 log_flags;
|
||||
bool exists;
|
||||
int ret;
|
||||
@@ -1881,9 +1867,8 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
|
||||
ret = PTR_ERR(dir_dst_di);
|
||||
goto out;
|
||||
} else if (dir_dst_di) {
|
||||
ret = delete_conflicting_dir_entry(trans, BTRFS_I(dir), path,
|
||||
dir_dst_di, &log_key,
|
||||
log_flags, exists);
|
||||
ret = delete_conflicting_dir_entry(trans, dir, path, dir_dst_di,
|
||||
&log_key, log_flags, exists);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
dir_dst_matches = (ret == 1);
|
||||
@@ -1898,9 +1883,8 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
|
||||
ret = PTR_ERR(index_dst_di);
|
||||
goto out;
|
||||
} else if (index_dst_di) {
|
||||
ret = delete_conflicting_dir_entry(trans, BTRFS_I(dir), path,
|
||||
index_dst_di, &log_key,
|
||||
log_flags, exists);
|
||||
ret = delete_conflicting_dir_entry(trans, dir, path, index_dst_di,
|
||||
&log_key, log_flags, exists);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
index_dst_matches = (ret == 1);
|
||||
@@ -1955,11 +1939,11 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
|
||||
|
||||
out:
|
||||
if (!ret && update_size) {
|
||||
btrfs_i_size_write(BTRFS_I(dir), dir->i_size + name.len * 2);
|
||||
ret = btrfs_update_inode(trans, BTRFS_I(dir));
|
||||
btrfs_i_size_write(dir, dir->vfs_inode.i_size + name.len * 2);
|
||||
ret = btrfs_update_inode(trans, dir);
|
||||
}
|
||||
kfree(name.name);
|
||||
iput(dir);
|
||||
iput(&dir->vfs_inode);
|
||||
if (!ret && name_added)
|
||||
ret = 1;
|
||||
return ret;
|
||||
@@ -2116,16 +2100,16 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *log,
|
||||
struct btrfs_path *path,
|
||||
struct btrfs_path *log_path,
|
||||
struct inode *dir,
|
||||
struct btrfs_inode *dir,
|
||||
struct btrfs_key *dir_key)
|
||||
{
|
||||
struct btrfs_root *root = BTRFS_I(dir)->root;
|
||||
struct btrfs_root *root = dir->root;
|
||||
int ret;
|
||||
struct extent_buffer *eb;
|
||||
int slot;
|
||||
struct btrfs_dir_item *di;
|
||||
struct fscrypt_str name = { 0 };
|
||||
struct inode *inode = NULL;
|
||||
struct btrfs_inode *inode = NULL;
|
||||
struct btrfs_key location;
|
||||
|
||||
/*
|
||||
@@ -2172,9 +2156,8 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
inc_nlink(inode);
|
||||
ret = unlink_inode_for_log_replay(trans, BTRFS_I(dir), BTRFS_I(inode),
|
||||
&name);
|
||||
inc_nlink(&inode->vfs_inode);
|
||||
ret = unlink_inode_for_log_replay(trans, dir, inode, &name);
|
||||
/*
|
||||
* Unlike dir item keys, dir index keys can only have one name (entry) in
|
||||
* them, as there are no key collisions since each key has a unique offset
|
||||
@@ -2184,7 +2167,8 @@ out:
|
||||
btrfs_release_path(path);
|
||||
btrfs_release_path(log_path);
|
||||
kfree(name.name);
|
||||
iput(inode);
|
||||
if (inode)
|
||||
iput(&inode->vfs_inode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2308,7 +2292,7 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_key dir_key;
|
||||
struct btrfs_key found_key;
|
||||
struct btrfs_path *log_path;
|
||||
struct inode *dir;
|
||||
struct btrfs_inode *dir;
|
||||
|
||||
dir_key.objectid = dirid;
|
||||
dir_key.type = BTRFS_DIR_INDEX_KEY;
|
||||
@@ -2385,7 +2369,7 @@ static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans,
|
||||
out:
|
||||
btrfs_release_path(path);
|
||||
btrfs_free_path(log_path);
|
||||
iput(dir);
|
||||
iput(&dir->vfs_inode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2479,7 +2463,7 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
|
||||
*/
|
||||
if (S_ISREG(mode)) {
|
||||
struct btrfs_drop_extents_args drop_args = { 0 };
|
||||
struct inode *inode;
|
||||
struct btrfs_inode *inode;
|
||||
u64 from;
|
||||
|
||||
inode = read_one_inode(root, key.objectid);
|
||||
@@ -2487,22 +2471,20 @@ static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb,
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
from = ALIGN(i_size_read(inode),
|
||||
from = ALIGN(i_size_read(&inode->vfs_inode),
|
||||
root->fs_info->sectorsize);
|
||||
drop_args.start = from;
|
||||
drop_args.end = (u64)-1;
|
||||
drop_args.drop_cache = true;
|
||||
ret = btrfs_drop_extents(wc->trans, root,
|
||||
BTRFS_I(inode),
|
||||
ret = btrfs_drop_extents(wc->trans, root, inode,
|
||||
&drop_args);
|
||||
if (!ret) {
|
||||
inode_sub_bytes(inode,
|
||||
inode_sub_bytes(&inode->vfs_inode,
|
||||
drop_args.bytes_found);
|
||||
/* Update the inode's nbytes. */
|
||||
ret = btrfs_update_inode(wc->trans,
|
||||
BTRFS_I(inode));
|
||||
ret = btrfs_update_inode(wc->trans, inode);
|
||||
}
|
||||
iput(inode);
|
||||
iput(&inode->vfs_inode);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
@@ -3560,8 +3542,8 @@ static noinline int insert_dir_log_key(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_dir_log_item *item;
|
||||
|
||||
key.objectid = dirid;
|
||||
key.offset = first_offset;
|
||||
key.type = BTRFS_DIR_LOG_INDEX_KEY;
|
||||
key.offset = first_offset;
|
||||
ret = btrfs_insert_empty_item(trans, log, path, &key, sizeof(*item));
|
||||
/*
|
||||
* -EEXIST is fine and can happen sporadically when we are logging a
|
||||
@@ -5481,7 +5463,6 @@ static int log_new_dir_dentries(struct btrfs_trans_handle *trans,
|
||||
ihold(&curr_inode->vfs_inode);
|
||||
|
||||
while (true) {
|
||||
struct inode *vfs_inode;
|
||||
struct btrfs_key key;
|
||||
struct btrfs_key found_key;
|
||||
u64 next_index;
|
||||
@@ -5497,7 +5478,7 @@ again:
|
||||
struct extent_buffer *leaf = path->nodes[0];
|
||||
struct btrfs_dir_item *di;
|
||||
struct btrfs_key di_key;
|
||||
struct inode *di_inode;
|
||||
struct btrfs_inode *di_inode;
|
||||
int log_mode = LOG_INODE_EXISTS;
|
||||
int type;
|
||||
|
||||
@@ -5524,17 +5505,16 @@ again:
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!need_log_inode(trans, BTRFS_I(di_inode))) {
|
||||
btrfs_add_delayed_iput(BTRFS_I(di_inode));
|
||||
if (!need_log_inode(trans, di_inode)) {
|
||||
btrfs_add_delayed_iput(di_inode);
|
||||
break;
|
||||
}
|
||||
|
||||
ctx->log_new_dentries = false;
|
||||
if (type == BTRFS_FT_DIR)
|
||||
log_mode = LOG_INODE_ALL;
|
||||
ret = btrfs_log_inode(trans, BTRFS_I(di_inode),
|
||||
log_mode, ctx);
|
||||
btrfs_add_delayed_iput(BTRFS_I(di_inode));
|
||||
ret = btrfs_log_inode(trans, di_inode, log_mode, ctx);
|
||||
btrfs_add_delayed_iput(di_inode);
|
||||
if (ret)
|
||||
goto out;
|
||||
if (ctx->log_new_dentries) {
|
||||
@@ -5576,14 +5556,13 @@ again:
|
||||
kfree(dir_elem);
|
||||
|
||||
btrfs_add_delayed_iput(curr_inode);
|
||||
curr_inode = NULL;
|
||||
|
||||
vfs_inode = btrfs_iget_logging(ino, root);
|
||||
if (IS_ERR(vfs_inode)) {
|
||||
ret = PTR_ERR(vfs_inode);
|
||||
curr_inode = btrfs_iget_logging(ino, root);
|
||||
if (IS_ERR(curr_inode)) {
|
||||
ret = PTR_ERR(curr_inode);
|
||||
curr_inode = NULL;
|
||||
break;
|
||||
}
|
||||
curr_inode = BTRFS_I(vfs_inode);
|
||||
}
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
@@ -5661,7 +5640,7 @@ static int add_conflicting_inode(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_log_ctx *ctx)
|
||||
{
|
||||
struct btrfs_ino_list *ino_elem;
|
||||
struct inode *inode;
|
||||
struct btrfs_inode *inode;
|
||||
|
||||
/*
|
||||
* It's rare to have a lot of conflicting inodes, in practice it is not
|
||||
@@ -5752,12 +5731,12 @@ static int add_conflicting_inode(struct btrfs_trans_handle *trans,
|
||||
* inode in LOG_INODE_EXISTS mode and rename operations update the log,
|
||||
* so that the log ends up with the new name and without the old name.
|
||||
*/
|
||||
if (!need_log_inode(trans, BTRFS_I(inode))) {
|
||||
btrfs_add_delayed_iput(BTRFS_I(inode));
|
||||
if (!need_log_inode(trans, inode)) {
|
||||
btrfs_add_delayed_iput(inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
btrfs_add_delayed_iput(BTRFS_I(inode));
|
||||
btrfs_add_delayed_iput(inode);
|
||||
|
||||
ino_elem = kmalloc(sizeof(*ino_elem), GFP_NOFS);
|
||||
if (!ino_elem)
|
||||
@@ -5793,7 +5772,7 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
|
||||
*/
|
||||
while (!list_empty(&ctx->conflict_inodes)) {
|
||||
struct btrfs_ino_list *curr;
|
||||
struct inode *inode;
|
||||
struct btrfs_inode *inode;
|
||||
u64 ino;
|
||||
u64 parent;
|
||||
|
||||
@@ -5829,9 +5808,8 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
|
||||
* dir index key range logged for the directory. So we
|
||||
* must make sure the deletion is recorded.
|
||||
*/
|
||||
ret = btrfs_log_inode(trans, BTRFS_I(inode),
|
||||
LOG_INODE_ALL, ctx);
|
||||
btrfs_add_delayed_iput(BTRFS_I(inode));
|
||||
ret = btrfs_log_inode(trans, inode, LOG_INODE_ALL, ctx);
|
||||
btrfs_add_delayed_iput(inode);
|
||||
if (ret)
|
||||
break;
|
||||
continue;
|
||||
@@ -5847,8 +5825,8 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
|
||||
* it again because if some other task logged the inode after
|
||||
* that, we can avoid doing it again.
|
||||
*/
|
||||
if (!need_log_inode(trans, BTRFS_I(inode))) {
|
||||
btrfs_add_delayed_iput(BTRFS_I(inode));
|
||||
if (!need_log_inode(trans, inode)) {
|
||||
btrfs_add_delayed_iput(inode);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -5859,8 +5837,8 @@ static int log_conflicting_inodes(struct btrfs_trans_handle *trans,
|
||||
* well because during a rename we pin the log and update the
|
||||
* log with the new name before we unpin it.
|
||||
*/
|
||||
ret = btrfs_log_inode(trans, BTRFS_I(inode), LOG_INODE_EXISTS, ctx);
|
||||
btrfs_add_delayed_iput(BTRFS_I(inode));
|
||||
ret = btrfs_log_inode(trans, inode, LOG_INODE_EXISTS, ctx);
|
||||
btrfs_add_delayed_iput(inode);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
@@ -6351,7 +6329,7 @@ static int log_new_delayed_dentries(struct btrfs_trans_handle *trans,
|
||||
|
||||
list_for_each_entry(item, delayed_ins_list, log_list) {
|
||||
struct btrfs_dir_item *dir_item;
|
||||
struct inode *di_inode;
|
||||
struct btrfs_inode *di_inode;
|
||||
struct btrfs_key key;
|
||||
int log_mode = LOG_INODE_EXISTS;
|
||||
|
||||
@@ -6367,8 +6345,8 @@ static int log_new_delayed_dentries(struct btrfs_trans_handle *trans,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!need_log_inode(trans, BTRFS_I(di_inode))) {
|
||||
btrfs_add_delayed_iput(BTRFS_I(di_inode));
|
||||
if (!need_log_inode(trans, di_inode)) {
|
||||
btrfs_add_delayed_iput(di_inode);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -6376,12 +6354,12 @@ static int log_new_delayed_dentries(struct btrfs_trans_handle *trans,
|
||||
log_mode = LOG_INODE_ALL;
|
||||
|
||||
ctx->log_new_dentries = false;
|
||||
ret = btrfs_log_inode(trans, BTRFS_I(di_inode), log_mode, ctx);
|
||||
ret = btrfs_log_inode(trans, di_inode, log_mode, ctx);
|
||||
|
||||
if (!ret && ctx->log_new_dentries)
|
||||
ret = log_new_dir_dentries(trans, BTRFS_I(di_inode), ctx);
|
||||
ret = log_new_dir_dentries(trans, di_inode, ctx);
|
||||
|
||||
btrfs_add_delayed_iput(BTRFS_I(di_inode));
|
||||
btrfs_add_delayed_iput(di_inode);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
@@ -6789,7 +6767,7 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans,
|
||||
ptr = btrfs_item_ptr_offset(leaf, slot);
|
||||
while (cur_offset < item_size) {
|
||||
struct btrfs_key inode_key;
|
||||
struct inode *dir_inode;
|
||||
struct btrfs_inode *dir_inode;
|
||||
|
||||
inode_key.type = BTRFS_INODE_ITEM_KEY;
|
||||
inode_key.offset = 0;
|
||||
@@ -6838,18 +6816,16 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!need_log_inode(trans, BTRFS_I(dir_inode))) {
|
||||
btrfs_add_delayed_iput(BTRFS_I(dir_inode));
|
||||
if (!need_log_inode(trans, dir_inode)) {
|
||||
btrfs_add_delayed_iput(dir_inode);
|
||||
continue;
|
||||
}
|
||||
|
||||
ctx->log_new_dentries = false;
|
||||
ret = btrfs_log_inode(trans, BTRFS_I(dir_inode),
|
||||
LOG_INODE_ALL, ctx);
|
||||
ret = btrfs_log_inode(trans, dir_inode, LOG_INODE_ALL, ctx);
|
||||
if (!ret && ctx->log_new_dentries)
|
||||
ret = log_new_dir_dentries(trans,
|
||||
BTRFS_I(dir_inode), ctx);
|
||||
btrfs_add_delayed_iput(BTRFS_I(dir_inode));
|
||||
ret = log_new_dir_dentries(trans, dir_inode, ctx);
|
||||
btrfs_add_delayed_iput(dir_inode);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
@@ -6874,7 +6850,7 @@ static int log_new_ancestors(struct btrfs_trans_handle *trans,
|
||||
struct extent_buffer *leaf;
|
||||
int slot;
|
||||
struct btrfs_key search_key;
|
||||
struct inode *inode;
|
||||
struct btrfs_inode *inode;
|
||||
u64 ino;
|
||||
int ret = 0;
|
||||
|
||||
@@ -6889,11 +6865,10 @@ static int log_new_ancestors(struct btrfs_trans_handle *trans,
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
if (BTRFS_I(inode)->generation >= trans->transid &&
|
||||
need_log_inode(trans, BTRFS_I(inode)))
|
||||
ret = btrfs_log_inode(trans, BTRFS_I(inode),
|
||||
LOG_INODE_EXISTS, ctx);
|
||||
btrfs_add_delayed_iput(BTRFS_I(inode));
|
||||
if (inode->generation >= trans->transid &&
|
||||
need_log_inode(trans, inode))
|
||||
ret = btrfs_log_inode(trans, inode, LOG_INODE_EXISTS, ctx);
|
||||
btrfs_add_delayed_iput(inode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -7061,26 +7036,20 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root = inode->root;
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
int ret = 0;
|
||||
bool log_dentries = false;
|
||||
bool log_dentries;
|
||||
|
||||
if (btrfs_test_opt(fs_info, NOTREELOG)) {
|
||||
ret = BTRFS_LOG_FORCE_COMMIT;
|
||||
goto end_no_trans;
|
||||
}
|
||||
if (btrfs_test_opt(fs_info, NOTREELOG))
|
||||
return BTRFS_LOG_FORCE_COMMIT;
|
||||
|
||||
if (btrfs_root_refs(&root->root_item) == 0) {
|
||||
ret = BTRFS_LOG_FORCE_COMMIT;
|
||||
goto end_no_trans;
|
||||
}
|
||||
if (btrfs_root_refs(&root->root_item) == 0)
|
||||
return BTRFS_LOG_FORCE_COMMIT;
|
||||
|
||||
/*
|
||||
* If we're logging an inode from a subvolume created in the current
|
||||
* transaction we must force a commit since the root is not persisted.
|
||||
*/
|
||||
if (btrfs_root_generation(&root->root_item) == trans->transid) {
|
||||
ret = BTRFS_LOG_FORCE_COMMIT;
|
||||
goto end_no_trans;
|
||||
}
|
||||
if (btrfs_root_generation(&root->root_item) == trans->transid)
|
||||
return BTRFS_LOG_FORCE_COMMIT;
|
||||
|
||||
/*
|
||||
* Skip already logged inodes or inodes corresponding to tmpfiles
|
||||
@@ -7089,14 +7058,12 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
|
||||
*/
|
||||
if ((btrfs_inode_in_log(inode, trans->transid) &&
|
||||
list_empty(&ctx->ordered_extents)) ||
|
||||
inode->vfs_inode.i_nlink == 0) {
|
||||
ret = BTRFS_NO_LOG_SYNC;
|
||||
goto end_no_trans;
|
||||
}
|
||||
inode->vfs_inode.i_nlink == 0)
|
||||
return BTRFS_NO_LOG_SYNC;
|
||||
|
||||
ret = start_log_trans(trans, root, ctx);
|
||||
if (ret)
|
||||
goto end_no_trans;
|
||||
return ret;
|
||||
|
||||
ret = btrfs_log_inode(trans, inode, inode_only, ctx);
|
||||
if (ret)
|
||||
@@ -7115,8 +7082,11 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
|
||||
goto end_trans;
|
||||
}
|
||||
|
||||
if (S_ISDIR(inode->vfs_inode.i_mode) && ctx->log_new_dentries)
|
||||
log_dentries = true;
|
||||
/*
|
||||
* Track if we need to log dentries because ctx->log_new_dentries can
|
||||
* be modified in the call chains below.
|
||||
*/
|
||||
log_dentries = ctx->log_new_dentries;
|
||||
|
||||
/*
|
||||
* On unlink we must make sure all our current and old parent directory
|
||||
@@ -7171,8 +7141,6 @@ static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
|
||||
|
||||
if (log_dentries)
|
||||
ret = log_new_dir_dentries(trans, inode, ctx);
|
||||
else
|
||||
ret = 0;
|
||||
end_trans:
|
||||
if (ret < 0) {
|
||||
btrfs_set_log_full_commit(trans);
|
||||
@@ -7182,7 +7150,7 @@ end_trans:
|
||||
if (ret)
|
||||
btrfs_remove_log_ctx(root, ctx);
|
||||
btrfs_end_log_trans(root);
|
||||
end_no_trans:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -7247,8 +7215,8 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
|
||||
|
||||
again:
|
||||
key.objectid = BTRFS_TREE_LOG_OBJECTID;
|
||||
key.offset = (u64)-1;
|
||||
key.type = BTRFS_ROOT_ITEM_KEY;
|
||||
key.offset = (u64)-1;
|
||||
|
||||
while (1) {
|
||||
ret = btrfs_search_slot(NULL, log_root_tree, &key, path, 0, 0);
|
||||
|
||||
@@ -485,7 +485,7 @@ static int rollback_verity(struct btrfs_inode *inode)
|
||||
goto out;
|
||||
}
|
||||
inode->ro_flags &= ~BTRFS_INODE_RO_VERITY;
|
||||
btrfs_sync_inode_flags_to_i_flags(&inode->vfs_inode);
|
||||
btrfs_sync_inode_flags_to_i_flags(inode);
|
||||
ret = btrfs_update_inode(trans, inode);
|
||||
if (ret) {
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
@@ -552,7 +552,7 @@ static int finish_verity(struct btrfs_inode *inode, const void *desc,
|
||||
goto out;
|
||||
}
|
||||
inode->ro_flags |= BTRFS_INODE_RO_VERITY;
|
||||
btrfs_sync_inode_flags_to_i_flags(&inode->vfs_inode);
|
||||
btrfs_sync_inode_flags_to_i_flags(inode);
|
||||
ret = btrfs_update_inode(trans, inode);
|
||||
if (ret)
|
||||
goto end_trans;
|
||||
|
||||
@@ -1798,8 +1798,8 @@ again:
|
||||
path->skip_locking = 1;
|
||||
|
||||
key.objectid = device->devid;
|
||||
key.offset = search_start;
|
||||
key.type = BTRFS_DEV_EXTENT_KEY;
|
||||
key.offset = search_start;
|
||||
|
||||
ret = btrfs_search_backwards(root, &key, path);
|
||||
if (ret < 0)
|
||||
@@ -1918,8 +1918,8 @@ static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
|
||||
return -ENOMEM;
|
||||
|
||||
key.objectid = device->devid;
|
||||
key.offset = start;
|
||||
key.type = BTRFS_DEV_EXTENT_KEY;
|
||||
key.offset = start;
|
||||
again:
|
||||
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
||||
if (ret > 0) {
|
||||
@@ -2721,8 +2721,8 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans)
|
||||
return -ENOMEM;
|
||||
|
||||
key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
|
||||
key.offset = 0;
|
||||
key.type = BTRFS_DEV_ITEM_KEY;
|
||||
key.offset = 0;
|
||||
|
||||
while (1) {
|
||||
btrfs_reserve_chunk_metadata(trans, false);
|
||||
@@ -3119,8 +3119,8 @@ static int btrfs_free_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset)
|
||||
return -ENOMEM;
|
||||
|
||||
key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
|
||||
key.offset = chunk_offset;
|
||||
key.type = BTRFS_CHUNK_ITEM_KEY;
|
||||
key.offset = chunk_offset;
|
||||
|
||||
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
||||
if (ret < 0)
|
||||
@@ -3577,8 +3577,8 @@ static int btrfs_relocate_sys_chunks(struct btrfs_fs_info *fs_info)
|
||||
|
||||
again:
|
||||
key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
|
||||
key.offset = (u64)-1;
|
||||
key.type = BTRFS_CHUNK_ITEM_KEY;
|
||||
key.offset = (u64)-1;
|
||||
|
||||
while (1) {
|
||||
mutex_lock(&fs_info->reclaim_bgs_lock);
|
||||
@@ -4184,8 +4184,8 @@ again:
|
||||
bctl->sys.limit = limit_sys;
|
||||
}
|
||||
key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
|
||||
key.offset = (u64)-1;
|
||||
key.type = BTRFS_CHUNK_ITEM_KEY;
|
||||
key.offset = (u64)-1;
|
||||
|
||||
while (1) {
|
||||
if ((!counting && atomic_read(&fs_info->balance_pause_req)) ||
|
||||
@@ -5001,8 +5001,8 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
|
||||
|
||||
again:
|
||||
key.objectid = device->devid;
|
||||
key.offset = (u64)-1;
|
||||
key.type = BTRFS_DEV_EXTENT_KEY;
|
||||
key.offset = (u64)-1;
|
||||
|
||||
do {
|
||||
mutex_lock(&fs_info->reclaim_bgs_lock);
|
||||
@@ -7539,8 +7539,8 @@ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info)
|
||||
* item - BTRFS_FIRST_CHUNK_TREE_OBJECTID).
|
||||
*/
|
||||
key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
|
||||
key.offset = 0;
|
||||
key.type = 0;
|
||||
key.offset = 0;
|
||||
btrfs_for_each_slot(root, &key, &found_key, path, iter_ret) {
|
||||
struct extent_buffer *node = path->nodes[1];
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define BTRFS_VOLUMES_H
|
||||
|
||||
#include <linux/blk_types.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/sort.h>
|
||||
@@ -18,14 +19,17 @@
|
||||
#include <linux/completion.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <uapi/linux/btrfs.h>
|
||||
#include <uapi/linux/btrfs_tree.h>
|
||||
#include "messages.h"
|
||||
#include "rcu-string.h"
|
||||
#include "extent-io-tree.h"
|
||||
|
||||
struct block_device;
|
||||
struct bdev_handle;
|
||||
struct btrfs_fs_info;
|
||||
struct btrfs_block_group;
|
||||
struct btrfs_trans_handle;
|
||||
struct btrfs_transaction;
|
||||
struct btrfs_zoned_device_info;
|
||||
|
||||
#define BTRFS_MAX_DATA_CHUNK_SIZE (10ULL * SZ_1G)
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#ifndef BTRFS_XATTR_H
|
||||
#define BTRFS_XATTR_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct dentry;
|
||||
struct inode;
|
||||
struct qstr;
|
||||
|
||||
@@ -94,6 +94,47 @@ fail:
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper for S390x with hardware zlib compression support.
|
||||
*
|
||||
* That hardware acceleration requires a buffer size larger than a single page
|
||||
* to get ideal performance, thus we need to do the memory copy rather than
|
||||
* use the page cache directly as input buffer.
|
||||
*/
|
||||
static int copy_data_into_buffer(struct address_space *mapping,
|
||||
struct workspace *workspace, u64 filepos,
|
||||
unsigned long length)
|
||||
{
|
||||
u64 cur = filepos;
|
||||
|
||||
/* It's only for hardware accelerated zlib code. */
|
||||
ASSERT(zlib_deflate_dfltcc_enabled());
|
||||
|
||||
while (cur < filepos + length) {
|
||||
struct folio *folio;
|
||||
void *data_in;
|
||||
unsigned int offset;
|
||||
unsigned long copy_length;
|
||||
int ret;
|
||||
|
||||
ret = btrfs_compress_filemap_get_folio(mapping, cur, &folio);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
/* No large folio support yet. */
|
||||
ASSERT(!folio_test_large(folio));
|
||||
|
||||
offset = offset_in_folio(folio, cur);
|
||||
copy_length = min(folio_size(folio) - offset,
|
||||
filepos + length - cur);
|
||||
|
||||
data_in = kmap_local_folio(folio, offset);
|
||||
memcpy(workspace->buf + cur - filepos, data_in, copy_length);
|
||||
kunmap_local(data_in);
|
||||
cur += copy_length;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zlib_compress_folios(struct list_head *ws, struct address_space *mapping,
|
||||
u64 start, struct folio **folios, unsigned long *out_folios,
|
||||
unsigned long *total_in, unsigned long *total_out)
|
||||
@@ -105,8 +146,6 @@ int zlib_compress_folios(struct list_head *ws, struct address_space *mapping,
|
||||
int nr_folios = 0;
|
||||
struct folio *in_folio = NULL;
|
||||
struct folio *out_folio = NULL;
|
||||
unsigned long bytes_left;
|
||||
unsigned int in_buf_folios;
|
||||
unsigned long len = *total_out;
|
||||
unsigned long nr_dest_folios = *out_folios;
|
||||
const unsigned long max_out = nr_dest_folios * PAGE_SIZE;
|
||||
@@ -150,34 +189,21 @@ int zlib_compress_folios(struct list_head *ws, struct address_space *mapping,
|
||||
* the workspace buffer if required.
|
||||
*/
|
||||
if (workspace->strm.avail_in == 0) {
|
||||
bytes_left = len - workspace->strm.total_in;
|
||||
in_buf_folios = min(DIV_ROUND_UP(bytes_left, PAGE_SIZE),
|
||||
workspace->buf_size / PAGE_SIZE);
|
||||
if (in_buf_folios > 1) {
|
||||
int i;
|
||||
unsigned long bytes_left = len - workspace->strm.total_in;
|
||||
unsigned int copy_length = min(bytes_left, workspace->buf_size);
|
||||
|
||||
/* S390 hardware acceleration path, not subpage. */
|
||||
ASSERT(!btrfs_is_subpage(
|
||||
inode_to_fs_info(mapping->host),
|
||||
mapping));
|
||||
for (i = 0; i < in_buf_folios; i++) {
|
||||
if (data_in) {
|
||||
kunmap_local(data_in);
|
||||
folio_put(in_folio);
|
||||
data_in = NULL;
|
||||
}
|
||||
ret = btrfs_compress_filemap_get_folio(mapping,
|
||||
start, &in_folio);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
data_in = kmap_local_folio(in_folio, 0);
|
||||
copy_page(workspace->buf + i * PAGE_SIZE,
|
||||
data_in);
|
||||
start += PAGE_SIZE;
|
||||
}
|
||||
/*
|
||||
* This can only happen when hardware zlib compression is
|
||||
* enabled.
|
||||
*/
|
||||
if (copy_length > PAGE_SIZE) {
|
||||
ret = copy_data_into_buffer(mapping, workspace,
|
||||
start, copy_length);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
start += copy_length;
|
||||
workspace->strm.next_in = workspace->buf;
|
||||
workspace->strm.avail_in = min(bytes_left,
|
||||
in_buf_folios << PAGE_SHIFT);
|
||||
workspace->strm.avail_in = copy_length;
|
||||
} else {
|
||||
unsigned int pg_off;
|
||||
unsigned int cur_len;
|
||||
@@ -463,6 +489,7 @@ out:
|
||||
|
||||
const struct btrfs_compress_op btrfs_zlib_compress = {
|
||||
.workspace_manager = &wsm,
|
||||
.min_level = 1,
|
||||
.max_level = 9,
|
||||
.default_level = BTRFS_ZLIB_DEFAULT_LEVEL,
|
||||
};
|
||||
|
||||
@@ -2111,6 +2111,9 @@ bool btrfs_zone_activate(struct btrfs_block_group *block_group)
|
||||
physical = map->stripes[i].physical;
|
||||
zinfo = device->zone_info;
|
||||
|
||||
if (!device->bdev)
|
||||
continue;
|
||||
|
||||
if (zinfo->max_active_zones == 0)
|
||||
continue;
|
||||
|
||||
@@ -2272,6 +2275,9 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
|
||||
struct btrfs_zoned_device_info *zinfo = device->zone_info;
|
||||
unsigned int nofs_flags;
|
||||
|
||||
if (!device->bdev)
|
||||
continue;
|
||||
|
||||
if (zinfo->max_active_zones == 0)
|
||||
continue;
|
||||
|
||||
@@ -2325,6 +2331,9 @@ bool btrfs_can_activate_zone(struct btrfs_fs_devices *fs_devices, u64 flags)
|
||||
if (!btrfs_is_zoned(fs_info))
|
||||
return true;
|
||||
|
||||
if (test_bit(BTRFS_FS_NEED_ZONE_FINISH, &fs_info->flags))
|
||||
return false;
|
||||
|
||||
/* Check if there is a device with active zones left */
|
||||
mutex_lock(&fs_info->chunk_mutex);
|
||||
spin_lock(&fs_info->zone_active_bgs_lock);
|
||||
|
||||
@@ -26,11 +26,12 @@
|
||||
#define ZSTD_BTRFS_MAX_WINDOWLOG 17
|
||||
#define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG)
|
||||
#define ZSTD_BTRFS_DEFAULT_LEVEL 3
|
||||
#define ZSTD_BTRFS_MIN_LEVEL -15
|
||||
#define ZSTD_BTRFS_MAX_LEVEL 15
|
||||
/* 307s to avoid pathologically clashing with transaction commit */
|
||||
#define ZSTD_BTRFS_RECLAIM_JIFFIES (307 * HZ)
|
||||
|
||||
static zstd_parameters zstd_get_btrfs_parameters(unsigned int level,
|
||||
static zstd_parameters zstd_get_btrfs_parameters(int level,
|
||||
size_t src_len)
|
||||
{
|
||||
zstd_parameters params = zstd_get_params(level, src_len);
|
||||
@@ -45,13 +46,14 @@ struct workspace {
|
||||
void *mem;
|
||||
size_t size;
|
||||
char *buf;
|
||||
unsigned int level;
|
||||
unsigned int req_level;
|
||||
int level;
|
||||
int req_level;
|
||||
unsigned long last_used; /* jiffies */
|
||||
struct list_head list;
|
||||
struct list_head lru_list;
|
||||
zstd_in_buffer in_buf;
|
||||
zstd_out_buffer out_buf;
|
||||
zstd_parameters params;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -93,8 +95,10 @@ static inline struct workspace *list_to_workspace(struct list_head *list)
|
||||
return container_of(list, struct workspace, list);
|
||||
}
|
||||
|
||||
void zstd_free_workspace(struct list_head *ws);
|
||||
struct list_head *zstd_alloc_workspace(unsigned int level);
|
||||
static inline int clip_level(int level)
|
||||
{
|
||||
return max(0, level - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Timer callback to free unused workspaces.
|
||||
@@ -123,7 +127,7 @@ static void zstd_reclaim_timer_fn(struct timer_list *timer)
|
||||
list_for_each_prev_safe(pos, next, &wsm.lru_list) {
|
||||
struct workspace *victim = container_of(pos, struct workspace,
|
||||
lru_list);
|
||||
unsigned int level;
|
||||
int level;
|
||||
|
||||
if (time_after(victim->last_used, reclaim_threshold))
|
||||
break;
|
||||
@@ -137,8 +141,8 @@ static void zstd_reclaim_timer_fn(struct timer_list *timer)
|
||||
list_del(&victim->list);
|
||||
zstd_free_workspace(&victim->list);
|
||||
|
||||
if (list_empty(&wsm.idle_ws[level - 1]))
|
||||
clear_bit(level - 1, &wsm.active_map);
|
||||
if (list_empty(&wsm.idle_ws[level]))
|
||||
clear_bit(level, &wsm.active_map);
|
||||
|
||||
}
|
||||
|
||||
@@ -160,9 +164,11 @@ static void zstd_reclaim_timer_fn(struct timer_list *timer)
|
||||
static void zstd_calc_ws_mem_sizes(void)
|
||||
{
|
||||
size_t max_size = 0;
|
||||
unsigned int level;
|
||||
int level;
|
||||
|
||||
for (level = 1; level <= ZSTD_BTRFS_MAX_LEVEL; level++) {
|
||||
for (level = ZSTD_BTRFS_MIN_LEVEL; level <= ZSTD_BTRFS_MAX_LEVEL; level++) {
|
||||
if (level == 0)
|
||||
continue;
|
||||
zstd_parameters params =
|
||||
zstd_get_btrfs_parameters(level, ZSTD_BTRFS_MAX_INPUT);
|
||||
size_t level_size =
|
||||
@@ -171,7 +177,8 @@ static void zstd_calc_ws_mem_sizes(void)
|
||||
zstd_dstream_workspace_bound(ZSTD_BTRFS_MAX_INPUT));
|
||||
|
||||
max_size = max_t(size_t, max_size, level_size);
|
||||
zstd_ws_mem_sizes[level - 1] = max_size;
|
||||
/* Use level 1 workspace size for all the fast mode negative levels. */
|
||||
zstd_ws_mem_sizes[clip_level(level)] = max_size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,11 +240,11 @@ void zstd_cleanup_workspace_manager(void)
|
||||
* offer the opportunity to reclaim the workspace in favor of allocating an
|
||||
* appropriately sized one in the future.
|
||||
*/
|
||||
static struct list_head *zstd_find_workspace(unsigned int level)
|
||||
static struct list_head *zstd_find_workspace(int level)
|
||||
{
|
||||
struct list_head *ws;
|
||||
struct workspace *workspace;
|
||||
int i = level - 1;
|
||||
int i = clip_level(level);
|
||||
|
||||
spin_lock_bh(&wsm.lock);
|
||||
for_each_set_bit_from(i, &wsm.active_map, ZSTD_BTRFS_MAX_LEVEL) {
|
||||
@@ -247,7 +254,7 @@ static struct list_head *zstd_find_workspace(unsigned int level)
|
||||
list_del_init(ws);
|
||||
/* keep its place if it's a lower level using this */
|
||||
workspace->req_level = level;
|
||||
if (level == workspace->level)
|
||||
if (clip_level(level) == workspace->level)
|
||||
list_del(&workspace->lru_list);
|
||||
if (list_empty(&wsm.idle_ws[i]))
|
||||
clear_bit(i, &wsm.active_map);
|
||||
@@ -270,7 +277,7 @@ static struct list_head *zstd_find_workspace(unsigned int level)
|
||||
* attempt to allocate a new workspace. If we fail to allocate one due to
|
||||
* memory pressure, go to sleep waiting for the max level workspace to free up.
|
||||
*/
|
||||
struct list_head *zstd_get_workspace(unsigned int level)
|
||||
struct list_head *zstd_get_workspace(int level)
|
||||
{
|
||||
struct list_head *ws;
|
||||
unsigned int nofs_flag;
|
||||
@@ -319,7 +326,7 @@ void zstd_put_workspace(struct list_head *ws)
|
||||
spin_lock_bh(&wsm.lock);
|
||||
|
||||
/* A node is only taken off the lru if we are the corresponding level */
|
||||
if (workspace->req_level == workspace->level) {
|
||||
if (clip_level(workspace->req_level) == workspace->level) {
|
||||
/* Hide a max level workspace from reclaim */
|
||||
if (list_empty(&wsm.idle_ws[ZSTD_BTRFS_MAX_LEVEL - 1])) {
|
||||
INIT_LIST_HEAD(&workspace->lru_list);
|
||||
@@ -332,13 +339,13 @@ void zstd_put_workspace(struct list_head *ws)
|
||||
}
|
||||
}
|
||||
|
||||
set_bit(workspace->level - 1, &wsm.active_map);
|
||||
list_add(&workspace->list, &wsm.idle_ws[workspace->level - 1]);
|
||||
set_bit(workspace->level, &wsm.active_map);
|
||||
list_add(&workspace->list, &wsm.idle_ws[workspace->level]);
|
||||
workspace->req_level = 0;
|
||||
|
||||
spin_unlock_bh(&wsm.lock);
|
||||
|
||||
if (workspace->level == ZSTD_BTRFS_MAX_LEVEL)
|
||||
if (workspace->level == clip_level(ZSTD_BTRFS_MAX_LEVEL))
|
||||
cond_wake_up(&wsm.wait);
|
||||
}
|
||||
|
||||
@@ -351,7 +358,7 @@ void zstd_free_workspace(struct list_head *ws)
|
||||
kfree(workspace);
|
||||
}
|
||||
|
||||
struct list_head *zstd_alloc_workspace(unsigned int level)
|
||||
struct list_head *zstd_alloc_workspace(int level)
|
||||
{
|
||||
struct workspace *workspace;
|
||||
|
||||
@@ -359,8 +366,9 @@ struct list_head *zstd_alloc_workspace(unsigned int level)
|
||||
if (!workspace)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
workspace->size = zstd_ws_mem_sizes[level - 1];
|
||||
workspace->level = level;
|
||||
/* Use level 1 workspace size for all the fast mode negative levels. */
|
||||
workspace->size = zstd_ws_mem_sizes[clip_level(level)];
|
||||
workspace->level = clip_level(level);
|
||||
workspace->req_level = level;
|
||||
workspace->last_used = jiffies;
|
||||
workspace->mem = kvmalloc(workspace->size, GFP_KERNEL | __GFP_NOWARN);
|
||||
@@ -393,17 +401,15 @@ int zstd_compress_folios(struct list_head *ws, struct address_space *mapping,
|
||||
const unsigned long nr_dest_folios = *out_folios;
|
||||
const u64 orig_end = start + len;
|
||||
unsigned long max_out = nr_dest_folios * PAGE_SIZE;
|
||||
unsigned int pg_off;
|
||||
unsigned int cur_len;
|
||||
zstd_parameters params = zstd_get_btrfs_parameters(workspace->req_level,
|
||||
len);
|
||||
|
||||
workspace->params = zstd_get_btrfs_parameters(workspace->req_level, len);
|
||||
*out_folios = 0;
|
||||
*total_out = 0;
|
||||
*total_in = 0;
|
||||
|
||||
/* Initialize the stream */
|
||||
stream = zstd_init_cstream(¶ms, len, workspace->mem,
|
||||
stream = zstd_init_cstream(&workspace->params, len, workspace->mem,
|
||||
workspace->size);
|
||||
if (unlikely(!stream)) {
|
||||
struct btrfs_inode *inode = BTRFS_I(mapping->host);
|
||||
@@ -420,9 +426,8 @@ int zstd_compress_folios(struct list_head *ws, struct address_space *mapping,
|
||||
ret = btrfs_compress_filemap_get_folio(mapping, start, &in_folio);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
pg_off = offset_in_page(start);
|
||||
cur_len = btrfs_calc_input_length(orig_end, start);
|
||||
workspace->in_buf.src = kmap_local_folio(in_folio, pg_off);
|
||||
workspace->in_buf.src = kmap_local_folio(in_folio, offset_in_page(start));
|
||||
workspace->in_buf.pos = 0;
|
||||
workspace->in_buf.size = cur_len;
|
||||
|
||||
@@ -506,9 +511,9 @@ int zstd_compress_folios(struct list_head *ws, struct address_space *mapping,
|
||||
ret = btrfs_compress_filemap_get_folio(mapping, start, &in_folio);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
pg_off = offset_in_page(start);
|
||||
cur_len = btrfs_calc_input_length(orig_end, start);
|
||||
workspace->in_buf.src = kmap_local_folio(in_folio, pg_off);
|
||||
workspace->in_buf.src = kmap_local_folio(in_folio,
|
||||
offset_in_page(start));
|
||||
workspace->in_buf.pos = 0;
|
||||
workspace->in_buf.size = cur_len;
|
||||
}
|
||||
@@ -717,6 +722,7 @@ finish:
|
||||
const struct btrfs_compress_op btrfs_zstd_compress = {
|
||||
/* ZSTD uses own workspace manager */
|
||||
.workspace_manager = NULL,
|
||||
.min_level = ZSTD_BTRFS_MIN_LEVEL,
|
||||
.max_level = ZSTD_BTRFS_MAX_LEVEL,
|
||||
.default_level = ZSTD_BTRFS_DEFAULT_LEVEL,
|
||||
};
|
||||
|
||||
@@ -615,7 +615,9 @@ struct btrfs_ioctl_clone_range_args {
|
||||
*/
|
||||
#define BTRFS_DEFRAG_RANGE_COMPRESS 1
|
||||
#define BTRFS_DEFRAG_RANGE_START_IO 2
|
||||
#define BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL 4
|
||||
#define BTRFS_DEFRAG_RANGE_FLAGS_SUPP (BTRFS_DEFRAG_RANGE_COMPRESS | \
|
||||
BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL | \
|
||||
BTRFS_DEFRAG_RANGE_START_IO)
|
||||
|
||||
struct btrfs_ioctl_defrag_range_args {
|
||||
@@ -640,10 +642,18 @@ struct btrfs_ioctl_defrag_range_args {
|
||||
|
||||
/*
|
||||
* which compression method to use if turning on compression
|
||||
* for this defrag operation. If unspecified, zlib will
|
||||
* be used
|
||||
* for this defrag operation. If unspecified, zlib will be
|
||||
* used. If compression level is also being specified, set the
|
||||
* BTRFS_DEFRAG_RANGE_COMPRESS_LEVEL flag and fill the compress
|
||||
* member structure instead of the compress_type field.
|
||||
*/
|
||||
__u32 compress_type;
|
||||
union {
|
||||
__u32 compress_type;
|
||||
struct {
|
||||
__u8 type;
|
||||
__s8 level;
|
||||
} compress;
|
||||
};
|
||||
|
||||
/* spare for later */
|
||||
__u32 unused[4];
|
||||
|
||||
Reference in New Issue
Block a user