mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
btrfs: remove the v1 space cache write path
Nothing writes out a v1 space cache any more. Remove the writers and their io_ctl helpers, along with create_free_space_inode() and btrfs_prealloc_file_range_trans(), whose only user was the cache inode creation. The io_list and io_ctl block group fields were only used by the writers, so remove them too. btrfs_truncate_free_space_cache() only needed the block group to wait for and clear in-flight cache IO, so drop that parameter. Assisted-by: LLM Signed-off-by: Tal Zussman <tz2294@columbia.edu> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
74c8f34811
commit
af8841bbe1
|
|
@ -1268,7 +1268,6 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
|
|||
|
||||
spin_lock(&trans->transaction->dirty_bgs_lock);
|
||||
WARN_ON(!list_empty(&block_group->dirty_list));
|
||||
WARN_ON(!list_empty(&block_group->io_list));
|
||||
spin_unlock(&trans->transaction->dirty_bgs_lock);
|
||||
|
||||
btrfs_remove_free_space_cache(block_group);
|
||||
|
|
@ -2454,7 +2453,6 @@ static struct btrfs_block_group *btrfs_create_block_group(
|
|||
INIT_LIST_HEAD(&cache->ro_list);
|
||||
INIT_LIST_HEAD(&cache->discard_list);
|
||||
INIT_LIST_HEAD(&cache->dirty_list);
|
||||
INIT_LIST_HEAD(&cache->io_list);
|
||||
INIT_LIST_HEAD(&cache->active_bg_list);
|
||||
btrfs_init_free_space_ctl(cache, cache->free_space_ctl);
|
||||
atomic_set(&cache->frozen, 0);
|
||||
|
|
@ -4338,7 +4336,6 @@ void btrfs_put_block_group_cache(struct btrfs_fs_info *info)
|
|||
block_group->inode = NULL;
|
||||
spin_unlock(&block_group->lock);
|
||||
|
||||
ASSERT(block_group->io_ctl.inode == NULL);
|
||||
iput(&inode->vfs_inode);
|
||||
} else {
|
||||
spin_unlock(&block_group->lock);
|
||||
|
|
@ -4475,7 +4472,6 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
|
|||
btrfs_remove_free_space_cache(block_group);
|
||||
ASSERT(block_group->cached != BTRFS_CACHE_STARTED);
|
||||
ASSERT(list_empty(&block_group->dirty_list));
|
||||
ASSERT(list_empty(&block_group->io_list));
|
||||
ASSERT(list_empty(&block_group->bg_list));
|
||||
ASSERT(refcount_read(&block_group->refs) == 1);
|
||||
ASSERT(block_group->swap_extents == 0);
|
||||
|
|
|
|||
|
|
@ -228,9 +228,6 @@ struct btrfs_block_group {
|
|||
|
||||
/* For dirty block groups */
|
||||
struct list_head dirty_list;
|
||||
struct list_head io_list;
|
||||
|
||||
struct btrfs_io_ctl io_ctl;
|
||||
|
||||
/*
|
||||
* Incremented when doing extent allocations and holding a read lock
|
||||
|
|
|
|||
|
|
@ -598,10 +598,6 @@ int btrfs_wait_on_delayed_iputs(struct btrfs_fs_info *fs_info);
|
|||
int btrfs_prealloc_file_range(struct inode *inode, int mode,
|
||||
u64 start, u64 num_bytes, u64 min_size,
|
||||
loff_t actual_len, u64 *alloc_hint);
|
||||
int btrfs_prealloc_file_range_trans(struct inode *inode,
|
||||
struct btrfs_trans_handle *trans, int mode,
|
||||
u64 start, u64 num_bytes, u64 min_size,
|
||||
loff_t actual_len, u64 *alloc_hint);
|
||||
int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct folio *locked_folio,
|
||||
u64 start, u64 end, struct writeback_control *wbc);
|
||||
void btrfs_queue_writepage_fixup(struct btrfs_inode *inode, struct folio *folio);
|
||||
|
|
|
|||
|
|
@ -164,78 +164,6 @@ struct inode *lookup_free_space_inode(struct btrfs_block_group *block_group,
|
|||
return inode;
|
||||
}
|
||||
|
||||
static int __create_free_space_inode(struct btrfs_root *root,
|
||||
struct btrfs_trans_handle *trans,
|
||||
struct btrfs_path *path,
|
||||
u64 ino, u64 offset)
|
||||
{
|
||||
struct btrfs_key key;
|
||||
struct btrfs_disk_key disk_key;
|
||||
struct btrfs_free_space_header *header;
|
||||
struct btrfs_inode_item *inode_item;
|
||||
struct extent_buffer *leaf;
|
||||
/* We inline CRCs for the free disk space cache */
|
||||
const u64 flags = BTRFS_INODE_NOCOMPRESS | BTRFS_INODE_PREALLOC |
|
||||
BTRFS_INODE_NODATASUM | BTRFS_INODE_NODATACOW;
|
||||
int ret;
|
||||
|
||||
ret = btrfs_insert_empty_inode(trans, root, path, ino);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
leaf = path->nodes[0];
|
||||
inode_item = btrfs_item_ptr(leaf, path->slots[0],
|
||||
struct btrfs_inode_item);
|
||||
btrfs_item_key(leaf, &disk_key, path->slots[0]);
|
||||
memzero_extent_buffer(leaf, (unsigned long)inode_item,
|
||||
sizeof(*inode_item));
|
||||
btrfs_set_inode_generation(leaf, inode_item, trans->transid);
|
||||
btrfs_set_inode_size(leaf, inode_item, 0);
|
||||
btrfs_set_inode_nbytes(leaf, inode_item, 0);
|
||||
btrfs_set_inode_uid(leaf, inode_item, 0);
|
||||
btrfs_set_inode_gid(leaf, inode_item, 0);
|
||||
btrfs_set_inode_mode(leaf, inode_item, S_IFREG | 0600);
|
||||
btrfs_set_inode_flags(leaf, inode_item, flags);
|
||||
btrfs_set_inode_nlink(leaf, inode_item, 1);
|
||||
btrfs_set_inode_transid(leaf, inode_item, trans->transid);
|
||||
btrfs_set_inode_block_group(leaf, inode_item, offset);
|
||||
btrfs_release_path(path);
|
||||
|
||||
key.objectid = BTRFS_FREE_SPACE_OBJECTID;
|
||||
key.type = 0;
|
||||
key.offset = offset;
|
||||
ret = btrfs_insert_empty_item(trans, root, path, &key,
|
||||
sizeof(struct btrfs_free_space_header));
|
||||
if (ret < 0) {
|
||||
btrfs_release_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
leaf = path->nodes[0];
|
||||
header = btrfs_item_ptr(leaf, path->slots[0],
|
||||
struct btrfs_free_space_header);
|
||||
memzero_extent_buffer(leaf, (unsigned long)header, sizeof(*header));
|
||||
btrfs_set_free_space_key(leaf, header, &disk_key);
|
||||
btrfs_release_path(path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int create_free_space_inode(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_block_group *block_group,
|
||||
struct btrfs_path *path)
|
||||
{
|
||||
int ret;
|
||||
u64 ino;
|
||||
|
||||
ret = btrfs_get_free_objectid(trans->fs_info->tree_root, &ino);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return __create_free_space_inode(trans->fs_info->tree_root, trans, path,
|
||||
ino, block_group->start);
|
||||
}
|
||||
|
||||
/*
|
||||
* inode is an optional sink: if it is NULL, btrfs_remove_free_space_inode
|
||||
* handles lookup, otherwise it takes ownership and iputs the inode.
|
||||
|
|
@ -302,7 +230,6 @@ int btrfs_remove_free_space_inode(struct btrfs_trans_handle *trans,
|
|||
}
|
||||
|
||||
int btrfs_truncate_free_space_cache(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_block_group *block_group,
|
||||
struct inode *vfs_inode)
|
||||
{
|
||||
struct btrfs_truncate_control control = {
|
||||
|
|
@ -316,33 +243,6 @@ int btrfs_truncate_free_space_cache(struct btrfs_trans_handle *trans,
|
|||
struct btrfs_root *root = inode->root;
|
||||
struct extent_state *cached_state = NULL;
|
||||
int ret = 0;
|
||||
bool locked = false;
|
||||
|
||||
if (block_group) {
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
locked = true;
|
||||
mutex_lock(&trans->transaction->cache_write_mutex);
|
||||
if (!list_empty(&block_group->io_list)) {
|
||||
list_del_init(&block_group->io_list);
|
||||
|
||||
btrfs_wait_cache_io(trans, block_group, path);
|
||||
btrfs_put_block_group(block_group);
|
||||
}
|
||||
|
||||
/*
|
||||
* now that we've truncated the cache away, its no longer
|
||||
* setup or written
|
||||
*/
|
||||
spin_lock(&block_group->lock);
|
||||
block_group->disk_cache_state = BTRFS_DC_CLEAR;
|
||||
spin_unlock(&block_group->lock);
|
||||
}
|
||||
|
||||
btrfs_i_size_write(inode, 0);
|
||||
truncate_pagecache(vfs_inode, 0);
|
||||
|
|
@ -366,8 +266,6 @@ int btrfs_truncate_free_space_cache(struct btrfs_trans_handle *trans,
|
|||
ret = btrfs_update_inode(trans, inode);
|
||||
|
||||
fail:
|
||||
if (locked)
|
||||
mutex_unlock(&trans->transaction->cache_write_mutex);
|
||||
if (ret)
|
||||
btrfs_abort_transaction(trans, ret);
|
||||
|
||||
|
|
@ -500,21 +398,6 @@ static int io_ctl_prepare_pages(struct btrfs_io_ctl *io_ctl, bool uptodate)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void io_ctl_set_generation(struct btrfs_io_ctl *io_ctl, u64 generation)
|
||||
{
|
||||
io_ctl_map_page(io_ctl, 1);
|
||||
|
||||
/*
|
||||
* Skip the csum areas. If we don't check crcs then we just have a
|
||||
* 64bit chunk at the front of the first page.
|
||||
*/
|
||||
io_ctl->cur += (sizeof(u32) * io_ctl->num_pages);
|
||||
io_ctl->size -= sizeof(u64) + (sizeof(u32) * io_ctl->num_pages);
|
||||
|
||||
put_unaligned_le64(generation, io_ctl->cur);
|
||||
io_ctl->cur += sizeof(u64);
|
||||
}
|
||||
|
||||
static int io_ctl_check_generation(struct btrfs_io_ctl *io_ctl, u64 generation)
|
||||
{
|
||||
u64 cache_gen;
|
||||
|
|
@ -538,23 +421,6 @@ static int io_ctl_check_generation(struct btrfs_io_ctl *io_ctl, u64 generation)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void io_ctl_set_crc(struct btrfs_io_ctl *io_ctl, int index)
|
||||
{
|
||||
u32 *tmp;
|
||||
u32 crc = ~(u32)0;
|
||||
unsigned offset = 0;
|
||||
|
||||
if (index == 0)
|
||||
offset = sizeof(u32) * io_ctl->num_pages;
|
||||
|
||||
crc = crc32c(crc, io_ctl->orig + offset, PAGE_SIZE - offset);
|
||||
btrfs_crc32c_final(crc, (u8 *)&crc);
|
||||
io_ctl_unmap_page(io_ctl);
|
||||
tmp = page_address(io_ctl->pages[0]);
|
||||
tmp += index;
|
||||
*tmp = crc;
|
||||
}
|
||||
|
||||
static int io_ctl_check_crc(struct btrfs_io_ctl *io_ctl, int index)
|
||||
{
|
||||
u32 *tmp, val;
|
||||
|
|
@ -584,76 +450,6 @@ static int io_ctl_check_crc(struct btrfs_io_ctl *io_ctl, int index)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int io_ctl_add_entry(struct btrfs_io_ctl *io_ctl, u64 offset, u64 bytes,
|
||||
void *bitmap)
|
||||
{
|
||||
struct btrfs_free_space_entry *entry;
|
||||
|
||||
if (!io_ctl->cur)
|
||||
return -ENOSPC;
|
||||
|
||||
entry = io_ctl->cur;
|
||||
put_unaligned_le64(offset, &entry->offset);
|
||||
put_unaligned_le64(bytes, &entry->bytes);
|
||||
entry->type = (bitmap) ? BTRFS_FREE_SPACE_BITMAP :
|
||||
BTRFS_FREE_SPACE_EXTENT;
|
||||
io_ctl->cur += sizeof(struct btrfs_free_space_entry);
|
||||
io_ctl->size -= sizeof(struct btrfs_free_space_entry);
|
||||
|
||||
if (io_ctl->size >= sizeof(struct btrfs_free_space_entry))
|
||||
return 0;
|
||||
|
||||
io_ctl_set_crc(io_ctl, io_ctl->index - 1);
|
||||
|
||||
/* No more pages to map */
|
||||
if (io_ctl->index >= io_ctl->num_pages)
|
||||
return 0;
|
||||
|
||||
/* map the next page */
|
||||
io_ctl_map_page(io_ctl, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int io_ctl_add_bitmap(struct btrfs_io_ctl *io_ctl, void *bitmap)
|
||||
{
|
||||
if (!io_ctl->cur)
|
||||
return -ENOSPC;
|
||||
|
||||
/*
|
||||
* If we aren't at the start of the current page, unmap this one and
|
||||
* map the next one if there is any left.
|
||||
*/
|
||||
if (io_ctl->cur != io_ctl->orig) {
|
||||
io_ctl_set_crc(io_ctl, io_ctl->index - 1);
|
||||
if (io_ctl->index >= io_ctl->num_pages)
|
||||
return -ENOSPC;
|
||||
io_ctl_map_page(io_ctl, 0);
|
||||
}
|
||||
|
||||
copy_page(io_ctl->cur, bitmap);
|
||||
io_ctl_set_crc(io_ctl, io_ctl->index - 1);
|
||||
if (io_ctl->index < io_ctl->num_pages)
|
||||
io_ctl_map_page(io_ctl, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void io_ctl_zero_remaining_pages(struct btrfs_io_ctl *io_ctl)
|
||||
{
|
||||
/*
|
||||
* If we're not on the boundary we know we've modified the page and we
|
||||
* need to crc the page.
|
||||
*/
|
||||
if (io_ctl->cur != io_ctl->orig)
|
||||
io_ctl_set_crc(io_ctl, io_ctl->index - 1);
|
||||
else
|
||||
io_ctl_unmap_page(io_ctl);
|
||||
|
||||
while (io_ctl->index < io_ctl->num_pages) {
|
||||
io_ctl_map_page(io_ctl, 1);
|
||||
io_ctl_set_crc(io_ctl, io_ctl->index - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int io_ctl_read_entry(struct btrfs_io_ctl *io_ctl,
|
||||
struct btrfs_free_space *entry, u8 *type)
|
||||
{
|
||||
|
|
@ -1075,490 +871,6 @@ int load_free_space_cache(struct btrfs_block_group *block_group)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static noinline_for_stack
|
||||
int write_cache_extent_entries(struct btrfs_io_ctl *io_ctl,
|
||||
struct btrfs_block_group *block_group,
|
||||
int *entries, int *bitmaps,
|
||||
struct list_head *bitmap_list)
|
||||
{
|
||||
int ret;
|
||||
struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
|
||||
struct btrfs_free_cluster *cluster = NULL;
|
||||
struct btrfs_free_cluster *cluster_locked = NULL;
|
||||
struct rb_node *node = rb_first(&ctl->free_space_offset);
|
||||
struct btrfs_trim_range *trim_entry;
|
||||
|
||||
/* Get the cluster for this block_group if it exists */
|
||||
if (!list_empty(&block_group->cluster_list)) {
|
||||
cluster = list_first_entry(&block_group->cluster_list,
|
||||
struct btrfs_free_cluster, block_group_list);
|
||||
}
|
||||
|
||||
if (!node && cluster) {
|
||||
cluster_locked = cluster;
|
||||
spin_lock(&cluster_locked->lock);
|
||||
node = rb_first(&cluster->root);
|
||||
cluster = NULL;
|
||||
}
|
||||
|
||||
/* Write out the extent entries */
|
||||
while (node) {
|
||||
struct btrfs_free_space *e;
|
||||
|
||||
e = rb_entry(node, struct btrfs_free_space, offset_index);
|
||||
*entries += 1;
|
||||
|
||||
ret = io_ctl_add_entry(io_ctl, e->offset, e->bytes,
|
||||
e->bitmap);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
if (e->bitmap) {
|
||||
list_add_tail(&e->list, bitmap_list);
|
||||
*bitmaps += 1;
|
||||
}
|
||||
node = rb_next(node);
|
||||
if (!node && cluster) {
|
||||
node = rb_first(&cluster->root);
|
||||
cluster_locked = cluster;
|
||||
spin_lock(&cluster_locked->lock);
|
||||
cluster = NULL;
|
||||
}
|
||||
}
|
||||
if (cluster_locked) {
|
||||
spin_unlock(&cluster_locked->lock);
|
||||
cluster_locked = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure we don't miss any range that was removed from our rbtree
|
||||
* because trimming is running. Otherwise after a umount+mount (or crash
|
||||
* after committing the transaction) we would leak free space and get
|
||||
* an inconsistent free space cache report from fsck.
|
||||
*/
|
||||
list_for_each_entry(trim_entry, &ctl->trimming_ranges, list) {
|
||||
ret = io_ctl_add_entry(io_ctl, trim_entry->start,
|
||||
trim_entry->bytes, NULL);
|
||||
if (ret)
|
||||
goto fail;
|
||||
*entries += 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
if (cluster_locked)
|
||||
spin_unlock(&cluster_locked->lock);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
static noinline_for_stack int
|
||||
update_cache_item(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct inode *inode,
|
||||
struct btrfs_path *path, u64 offset,
|
||||
int entries, int bitmaps)
|
||||
{
|
||||
struct btrfs_key key;
|
||||
struct btrfs_free_space_header *header;
|
||||
struct extent_buffer *leaf;
|
||||
int ret;
|
||||
|
||||
key.objectid = BTRFS_FREE_SPACE_OBJECTID;
|
||||
key.type = 0;
|
||||
key.offset = offset;
|
||||
|
||||
ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
|
||||
if (ret < 0) {
|
||||
btrfs_clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1,
|
||||
EXTENT_DELALLOC, NULL);
|
||||
return ret;
|
||||
}
|
||||
leaf = path->nodes[0];
|
||||
if (ret > 0) {
|
||||
struct btrfs_key found_key;
|
||||
ASSERT(path->slots[0]);
|
||||
path->slots[0]--;
|
||||
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
|
||||
if (found_key.objectid != BTRFS_FREE_SPACE_OBJECTID ||
|
||||
found_key.offset != offset) {
|
||||
btrfs_clear_extent_bit(&BTRFS_I(inode)->io_tree, 0,
|
||||
inode->i_size - 1, EXTENT_DELALLOC,
|
||||
NULL);
|
||||
btrfs_release_path(path);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
BTRFS_I(inode)->generation = trans->transid;
|
||||
header = btrfs_item_ptr(leaf, path->slots[0],
|
||||
struct btrfs_free_space_header);
|
||||
btrfs_set_free_space_entries(leaf, header, entries);
|
||||
btrfs_set_free_space_bitmaps(leaf, header, bitmaps);
|
||||
btrfs_set_free_space_generation(leaf, header, trans->transid);
|
||||
btrfs_release_path(path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static noinline_for_stack int write_pinned_extent_entries(
|
||||
struct btrfs_trans_handle *trans,
|
||||
struct btrfs_block_group *block_group,
|
||||
struct btrfs_io_ctl *io_ctl,
|
||||
int *entries)
|
||||
{
|
||||
u64 start, extent_start, extent_end, len;
|
||||
const u64 block_group_end = btrfs_block_group_end(block_group);
|
||||
struct extent_io_tree *unpin = NULL;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* We want to add any pinned extents to our free space cache
|
||||
* so we don't leak the space
|
||||
*
|
||||
* We shouldn't have switched the pinned extents yet so this is the
|
||||
* right one
|
||||
*/
|
||||
unpin = &trans->transaction->pinned_extents;
|
||||
|
||||
start = block_group->start;
|
||||
|
||||
while (start < block_group_end) {
|
||||
if (!btrfs_find_first_extent_bit(unpin, start,
|
||||
&extent_start, &extent_end,
|
||||
EXTENT_DIRTY, NULL))
|
||||
return 0;
|
||||
|
||||
/* This pinned extent is out of our range */
|
||||
if (extent_start >= block_group_end)
|
||||
return 0;
|
||||
|
||||
extent_start = max(extent_start, start);
|
||||
extent_end = min(block_group_end, extent_end + 1);
|
||||
len = extent_end - extent_start;
|
||||
|
||||
*entries += 1;
|
||||
ret = io_ctl_add_entry(io_ctl, extent_start, len, NULL);
|
||||
if (ret)
|
||||
return -ENOSPC;
|
||||
|
||||
start = extent_end;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static noinline_for_stack int
|
||||
write_bitmap_entries(struct btrfs_io_ctl *io_ctl, struct list_head *bitmap_list)
|
||||
{
|
||||
struct btrfs_free_space *entry, *next;
|
||||
int ret;
|
||||
|
||||
/* Write out the bitmaps */
|
||||
list_for_each_entry_safe(entry, next, bitmap_list, list) {
|
||||
ret = io_ctl_add_bitmap(io_ctl, entry->bitmap);
|
||||
if (ret)
|
||||
return -ENOSPC;
|
||||
list_del_init(&entry->list);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int flush_dirty_cache(struct inode *inode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = btrfs_wait_ordered_range(BTRFS_I(inode), 0, (u64)-1);
|
||||
if (ret)
|
||||
btrfs_clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1,
|
||||
EXTENT_DELALLOC, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void noinline_for_stack
|
||||
cleanup_bitmap_list(struct list_head *bitmap_list)
|
||||
{
|
||||
struct btrfs_free_space *entry, *next;
|
||||
|
||||
list_for_each_entry_safe(entry, next, bitmap_list, list)
|
||||
list_del_init(&entry->list);
|
||||
}
|
||||
|
||||
static void noinline_for_stack
|
||||
cleanup_write_cache_enospc(struct inode *inode,
|
||||
struct btrfs_io_ctl *io_ctl,
|
||||
struct extent_state **cached_state)
|
||||
{
|
||||
io_ctl_drop_pages(io_ctl);
|
||||
btrfs_unlock_extent(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
|
||||
cached_state);
|
||||
}
|
||||
|
||||
static int __btrfs_wait_cache_io(struct btrfs_root *root,
|
||||
struct btrfs_trans_handle *trans,
|
||||
struct btrfs_block_group *block_group,
|
||||
struct btrfs_io_ctl *io_ctl,
|
||||
struct btrfs_path *path, u64 offset)
|
||||
{
|
||||
int ret;
|
||||
struct inode *inode = io_ctl->inode;
|
||||
|
||||
if (!inode)
|
||||
return 0;
|
||||
|
||||
/* Flush the dirty pages in the cache file. */
|
||||
ret = flush_dirty_cache(inode);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* Update the cache item to tell everyone this cache file is valid. */
|
||||
ret = update_cache_item(trans, root, inode, path, offset,
|
||||
io_ctl->entries, io_ctl->bitmaps);
|
||||
out:
|
||||
if (ret) {
|
||||
invalidate_inode_pages2(inode->i_mapping);
|
||||
BTRFS_I(inode)->generation = 0;
|
||||
if (block_group)
|
||||
btrfs_debug(root->fs_info,
|
||||
"failed to write free space cache for block group %llu error %d",
|
||||
block_group->start, ret);
|
||||
}
|
||||
btrfs_update_inode(trans, BTRFS_I(inode));
|
||||
|
||||
if (block_group) {
|
||||
/* the dirty list is protected by the dirty_bgs_lock */
|
||||
spin_lock(&trans->transaction->dirty_bgs_lock);
|
||||
|
||||
/* the disk_cache_state is protected by the block group lock */
|
||||
spin_lock(&block_group->lock);
|
||||
|
||||
/*
|
||||
* only mark this as written if we didn't get put back on
|
||||
* the dirty list while waiting for IO. Otherwise our
|
||||
* cache state won't be right, and we won't get written again
|
||||
*/
|
||||
if (!ret && list_empty(&block_group->dirty_list))
|
||||
block_group->disk_cache_state = BTRFS_DC_WRITTEN;
|
||||
else if (ret)
|
||||
block_group->disk_cache_state = BTRFS_DC_ERROR;
|
||||
|
||||
spin_unlock(&block_group->lock);
|
||||
spin_unlock(&trans->transaction->dirty_bgs_lock);
|
||||
io_ctl->inode = NULL;
|
||||
iput(inode);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
int btrfs_wait_cache_io(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_block_group *block_group,
|
||||
struct btrfs_path *path)
|
||||
{
|
||||
return __btrfs_wait_cache_io(block_group->fs_info->tree_root, trans,
|
||||
block_group, &block_group->io_ctl,
|
||||
path, block_group->start);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out cached info to an inode.
|
||||
*
|
||||
* @inode: freespace inode we are writing out
|
||||
* @ctl: free space cache we are going to write out
|
||||
* @block_group: block_group for this cache if it belongs to a block_group
|
||||
* @io_ctl: holds context for the io
|
||||
* @trans: the trans handle
|
||||
*
|
||||
* This function writes out a free space cache struct to disk for quick recovery
|
||||
* on mount. This will return 0 if it was successful in writing the cache out,
|
||||
* or an errno if it was not.
|
||||
*/
|
||||
static int __btrfs_write_out_cache(struct inode *inode,
|
||||
struct btrfs_block_group *block_group,
|
||||
struct btrfs_trans_handle *trans)
|
||||
{
|
||||
struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
|
||||
struct btrfs_io_ctl *io_ctl = &block_group->io_ctl;
|
||||
struct extent_state *cached_state = NULL;
|
||||
LIST_HEAD(bitmap_list);
|
||||
int entries = 0;
|
||||
int bitmaps = 0;
|
||||
int ret;
|
||||
bool must_iput = false;
|
||||
int i_size;
|
||||
|
||||
if (!i_size_read(inode))
|
||||
return -EIO;
|
||||
|
||||
WARN_ON(io_ctl->pages);
|
||||
ret = io_ctl_init(io_ctl, inode, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (block_group->flags & BTRFS_BLOCK_GROUP_DATA) {
|
||||
down_write(&block_group->data_rwsem);
|
||||
spin_lock(&block_group->lock);
|
||||
if (block_group->delalloc_bytes) {
|
||||
block_group->disk_cache_state = BTRFS_DC_WRITTEN;
|
||||
spin_unlock(&block_group->lock);
|
||||
up_write(&block_group->data_rwsem);
|
||||
BTRFS_I(inode)->generation = 0;
|
||||
ret = 0;
|
||||
must_iput = true;
|
||||
goto out;
|
||||
}
|
||||
spin_unlock(&block_group->lock);
|
||||
}
|
||||
|
||||
/* Lock all pages first so we can lock the extent safely. */
|
||||
ret = io_ctl_prepare_pages(io_ctl, false);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
||||
btrfs_lock_extent(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
|
||||
&cached_state);
|
||||
|
||||
io_ctl_set_generation(io_ctl, trans->transid);
|
||||
|
||||
mutex_lock(&ctl->cache_writeout_mutex);
|
||||
/* Write out the extent entries in the free space cache */
|
||||
spin_lock(&ctl->tree_lock);
|
||||
ret = write_cache_extent_entries(io_ctl, block_group, &entries, &bitmaps,
|
||||
&bitmap_list);
|
||||
if (ret)
|
||||
goto out_nospc_locked;
|
||||
|
||||
/*
|
||||
* Some spaces that are freed in the current transaction are pinned,
|
||||
* they will be added into free space cache after the transaction is
|
||||
* committed, we shouldn't lose them.
|
||||
*
|
||||
* If this changes while we are working we'll get added back to
|
||||
* the dirty list and redo it. No locking needed
|
||||
*/
|
||||
ret = write_pinned_extent_entries(trans, block_group, io_ctl, &entries);
|
||||
if (ret)
|
||||
goto out_nospc_locked;
|
||||
|
||||
/*
|
||||
* At last, we write out all the bitmaps and keep cache_writeout_mutex
|
||||
* locked while doing it because a concurrent trim can be manipulating
|
||||
* or freeing the bitmap.
|
||||
*/
|
||||
ret = write_bitmap_entries(io_ctl, &bitmap_list);
|
||||
spin_unlock(&ctl->tree_lock);
|
||||
mutex_unlock(&ctl->cache_writeout_mutex);
|
||||
if (ret)
|
||||
goto out_nospc;
|
||||
|
||||
/* Zero out the rest of the pages just to make sure */
|
||||
io_ctl_zero_remaining_pages(io_ctl);
|
||||
|
||||
/* Everything is written out, now we dirty the pages in the file. */
|
||||
i_size = i_size_read(inode);
|
||||
for (int i = 0; i < round_up(i_size, PAGE_SIZE) / PAGE_SIZE; i++) {
|
||||
u64 dirty_start = i * PAGE_SIZE;
|
||||
u64 dirty_len = min_t(u64, dirty_start + PAGE_SIZE, i_size) - dirty_start;
|
||||
|
||||
ret = btrfs_dirty_folio(BTRFS_I(inode), page_folio(io_ctl->pages[i]),
|
||||
dirty_start, dirty_len, &cached_state, false);
|
||||
if (ret < 0)
|
||||
goto out_nospc;
|
||||
}
|
||||
|
||||
if (block_group->flags & BTRFS_BLOCK_GROUP_DATA)
|
||||
up_write(&block_group->data_rwsem);
|
||||
/*
|
||||
* Release the pages and unlock the extent, we will flush
|
||||
* them out later
|
||||
*/
|
||||
io_ctl_drop_pages(io_ctl);
|
||||
io_ctl_free(io_ctl);
|
||||
|
||||
btrfs_unlock_extent(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
|
||||
&cached_state);
|
||||
|
||||
/*
|
||||
* at this point the pages are under IO and we're happy,
|
||||
* The caller is responsible for waiting on them and updating
|
||||
* the cache and the inode
|
||||
*/
|
||||
io_ctl->entries = entries;
|
||||
io_ctl->bitmaps = bitmaps;
|
||||
|
||||
ret = btrfs_fdatawrite_range(BTRFS_I(inode), 0, (u64)-1);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
return 0;
|
||||
|
||||
out_nospc_locked:
|
||||
cleanup_bitmap_list(&bitmap_list);
|
||||
spin_unlock(&ctl->tree_lock);
|
||||
mutex_unlock(&ctl->cache_writeout_mutex);
|
||||
|
||||
out_nospc:
|
||||
cleanup_write_cache_enospc(inode, io_ctl, &cached_state);
|
||||
|
||||
out_unlock:
|
||||
if (block_group->flags & BTRFS_BLOCK_GROUP_DATA)
|
||||
up_write(&block_group->data_rwsem);
|
||||
|
||||
out:
|
||||
io_ctl->inode = NULL;
|
||||
io_ctl_free(io_ctl);
|
||||
if (ret) {
|
||||
invalidate_inode_pages2(inode->i_mapping);
|
||||
BTRFS_I(inode)->generation = 0;
|
||||
}
|
||||
btrfs_update_inode(trans, BTRFS_I(inode));
|
||||
if (must_iput)
|
||||
iput(inode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_write_out_cache(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_block_group *block_group,
|
||||
struct btrfs_path *path)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = trans->fs_info;
|
||||
struct inode *inode;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock(&block_group->lock);
|
||||
if (block_group->disk_cache_state < BTRFS_DC_SETUP) {
|
||||
spin_unlock(&block_group->lock);
|
||||
return 0;
|
||||
}
|
||||
spin_unlock(&block_group->lock);
|
||||
|
||||
inode = lookup_free_space_inode(block_group, path);
|
||||
if (IS_ERR(inode))
|
||||
return 0;
|
||||
|
||||
ret = __btrfs_write_out_cache(inode, block_group, trans);
|
||||
if (ret) {
|
||||
btrfs_debug(fs_info,
|
||||
"failed to write free space cache for block group %llu error %d",
|
||||
block_group->start, ret);
|
||||
spin_lock(&block_group->lock);
|
||||
block_group->disk_cache_state = BTRFS_DC_ERROR;
|
||||
spin_unlock(&block_group->lock);
|
||||
|
||||
block_group->io_ctl.inode = NULL;
|
||||
iput(inode);
|
||||
}
|
||||
|
||||
/*
|
||||
* if ret == 0 the caller is expected to call btrfs_wait_cache_io
|
||||
* to wait for IO and put the inode
|
||||
*/
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline unsigned long offset_to_bit(u64 bitmap_start, u32 unit,
|
||||
u64 offset)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -105,23 +105,13 @@ int __init btrfs_free_space_init(void);
|
|||
void __cold btrfs_free_space_exit(void);
|
||||
struct inode *lookup_free_space_inode(struct btrfs_block_group *block_group,
|
||||
struct btrfs_path *path);
|
||||
int create_free_space_inode(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_block_group *block_group,
|
||||
struct btrfs_path *path);
|
||||
int btrfs_remove_free_space_inode(struct btrfs_trans_handle *trans,
|
||||
struct inode *inode,
|
||||
struct btrfs_block_group *block_group);
|
||||
|
||||
int btrfs_truncate_free_space_cache(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_block_group *block_group,
|
||||
struct inode *inode);
|
||||
int load_free_space_cache(struct btrfs_block_group *block_group);
|
||||
int btrfs_wait_cache_io(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_block_group *block_group,
|
||||
struct btrfs_path *path);
|
||||
int btrfs_write_out_cache(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_block_group *block_group,
|
||||
struct btrfs_path *path);
|
||||
|
||||
void btrfs_init_free_space_ctl(struct btrfs_block_group *block_group,
|
||||
struct btrfs_free_space_ctl *ctl);
|
||||
|
|
|
|||
|
|
@ -9390,15 +9390,6 @@ int btrfs_prealloc_file_range(struct inode *inode, int mode,
|
|||
NULL);
|
||||
}
|
||||
|
||||
int btrfs_prealloc_file_range_trans(struct inode *inode,
|
||||
struct btrfs_trans_handle *trans, int mode,
|
||||
u64 start, u64 num_bytes, u64 min_size,
|
||||
loff_t actual_len, u64 *alloc_hint)
|
||||
{
|
||||
return __btrfs_prealloc_file_range(inode, mode, start, num_bytes,
|
||||
min_size, actual_len, alloc_hint, trans);
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: in case you are adding MAY_EXEC check for directories:
|
||||
* we are marking them with IOP_FASTPERM_MAY_EXEC, allowing path lookup to
|
||||
|
|
|
|||
|
|
@ -3356,7 +3356,7 @@ static int delete_block_group_cache(struct btrfs_block_group *block_group,
|
|||
goto out;
|
||||
}
|
||||
|
||||
ret = btrfs_truncate_free_space_cache(trans, block_group, inode);
|
||||
ret = btrfs_truncate_free_space_cache(trans, inode);
|
||||
|
||||
btrfs_end_transaction(trans);
|
||||
btrfs_btree_balance_dirty(fs_info);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user