Commit a3d1f54d authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-6.10-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux

Pull btrfs updates from David Sterba:
 "This update brings a few minor performance improvements, otherwise
  there's a lot of refactoring, cleanups and other sort of not user
  visible changes.

  Performance improvements:

   - inline b-tree locking functions, improvement in metadata-heavy
     changes

   - relax locking on a range that's being reflinked, allows read
     operations to run in parallel

   - speed up NOCOW write checks (throughput +9% on a sample test)

   - extent locking ranges have been reduced in several places, namely
     around delayed ref processing

  Core:

   - more page to folio conversions:
      - relocation
      - send
      - compression
      - inline extent handling
      - super block write and wait

   - extent_map structure optimizations:
      - reduced structure size
      - code simplifications
      - add shrinker for allocated objects, the numbers can go high and
        could exhaust memory on smaller systems (reported) as they may
        not get an opportunity to be freed fast enough

   - extent locking optimizations:
      - reduce locking ranges where it does not seem to be necessary and
        are safe due to other means of synchronization
      - potential improvements due to lower contention,
        allocation/freeing and state management operations of extent
        state tracking structures

   - delayed ref cleanups and simplifications

   - updated trace points

   - improved error handling, warnings and assertions

   - cleanups and refactoring, unification of error handling paths"

* tag 'for-6.10-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: (122 commits)
  btrfs: qgroup: fix initialization of auto inherit array
  btrfs: count super block write errors in device instead of tracking folio error state
  btrfs: use the folio iterator in btrfs_end_super_write()
  btrfs: convert super block writes to folio in write_dev_supers()
  btrfs: convert super block writes to folio in wait_dev_supers()
  bio: Export bio_add_folio_nofail to modules
  btrfs: remove duplicate included header from fs.h
  btrfs: add a cached state to extent_clear_unlock_delalloc
  btrfs: push extent lock down in submit_one_async_extent
  btrfs: push lock_extent down in cow_file_range()
  btrfs: move can_cow_file_range_inline() outside of the extent lock
  btrfs: push lock_extent into cow_file_range_inline
  btrfs: push extent lock into cow_file_range
  btrfs: push extent lock into run_delalloc_cow
  btrfs: remove unlock_extent from run_delalloc_compressed
  btrfs: push extent lock down in run_delalloc_nocow
  btrfs: adjust while loop condition in run_delalloc_nocow
  btrfs: push extent lock into run_delalloc_nocow
  btrfs: push the extent lock into btrfs_run_delalloc_range
  btrfs: lock extent when doing inline extent in compression
  ...
parents 47e9bff7 0e39c9e5
...@@ -1136,6 +1136,7 @@ void bio_add_folio_nofail(struct bio *bio, struct folio *folio, size_t len, ...@@ -1136,6 +1136,7 @@ void bio_add_folio_nofail(struct bio *bio, struct folio *folio, size_t len,
WARN_ON_ONCE(off > UINT_MAX); WARN_ON_ONCE(off > UINT_MAX);
__bio_add_page(bio, &folio->page, len, off); __bio_add_page(bio, &folio->page, len, off);
} }
EXPORT_SYMBOL_GPL(bio_add_folio_nofail);
/** /**
* bio_add_folio - Attempt to add part of a folio to a bio. * bio_add_folio - Attempt to add part of a folio to a bio.
......
...@@ -261,7 +261,7 @@ static void update_share_count(struct share_check *sc, int oldcount, ...@@ -261,7 +261,7 @@ static void update_share_count(struct share_check *sc, int oldcount,
else if (oldcount < 1 && newcount > 0) else if (oldcount < 1 && newcount > 0)
sc->share_count++; sc->share_count++;
if (newref->root_id == sc->root->root_key.objectid && if (newref->root_id == btrfs_root_id(sc->root) &&
newref->wanted_disk_byte == sc->data_bytenr && newref->wanted_disk_byte == sc->data_bytenr &&
newref->key_for_search.objectid == sc->inum) newref->key_for_search.objectid == sc->inum)
sc->self_ref_count += newref->count; sc->self_ref_count += newref->count;
...@@ -769,7 +769,7 @@ static int resolve_indirect_refs(struct btrfs_backref_walk_ctx *ctx, ...@@ -769,7 +769,7 @@ static int resolve_indirect_refs(struct btrfs_backref_walk_ctx *ctx,
continue; continue;
} }
if (sc && ref->root_id != sc->root->root_key.objectid) { if (sc && ref->root_id != btrfs_root_id(sc->root)) {
free_pref(ref); free_pref(ref);
ret = BACKREF_FOUND_SHARED; ret = BACKREF_FOUND_SHARED;
goto out; goto out;
...@@ -919,40 +919,38 @@ static int add_delayed_refs(const struct btrfs_fs_info *fs_info, ...@@ -919,40 +919,38 @@ static int add_delayed_refs(const struct btrfs_fs_info *fs_info,
switch (node->type) { switch (node->type) {
case BTRFS_TREE_BLOCK_REF_KEY: { case BTRFS_TREE_BLOCK_REF_KEY: {
/* NORMAL INDIRECT METADATA backref */ /* NORMAL INDIRECT METADATA backref */
struct btrfs_delayed_tree_ref *ref;
struct btrfs_key *key_ptr = NULL; struct btrfs_key *key_ptr = NULL;
/* The owner of a tree block ref is the level. */
int level = btrfs_delayed_ref_owner(node);
if (head->extent_op && head->extent_op->update_key) { if (head->extent_op && head->extent_op->update_key) {
btrfs_disk_key_to_cpu(&key, &head->extent_op->key); btrfs_disk_key_to_cpu(&key, &head->extent_op->key);
key_ptr = &key; key_ptr = &key;
} }
ref = btrfs_delayed_node_to_tree_ref(node); ret = add_indirect_ref(fs_info, preftrees, node->ref_root,
ret = add_indirect_ref(fs_info, preftrees, ref->root, key_ptr, level + 1, node->bytenr,
key_ptr, ref->level + 1, count, sc, GFP_ATOMIC);
node->bytenr, count, sc,
GFP_ATOMIC);
break; break;
} }
case BTRFS_SHARED_BLOCK_REF_KEY: { case BTRFS_SHARED_BLOCK_REF_KEY: {
/* SHARED DIRECT METADATA backref */ /*
struct btrfs_delayed_tree_ref *ref; * SHARED DIRECT METADATA backref
*
ref = btrfs_delayed_node_to_tree_ref(node); * The owner of a tree block ref is the level.
*/
int level = btrfs_delayed_ref_owner(node);
ret = add_direct_ref(fs_info, preftrees, ref->level + 1, ret = add_direct_ref(fs_info, preftrees, level + 1,
ref->parent, node->bytenr, count, node->parent, node->bytenr, count,
sc, GFP_ATOMIC); sc, GFP_ATOMIC);
break; break;
} }
case BTRFS_EXTENT_DATA_REF_KEY: { case BTRFS_EXTENT_DATA_REF_KEY: {
/* NORMAL INDIRECT DATA backref */ /* NORMAL INDIRECT DATA backref */
struct btrfs_delayed_data_ref *ref; key.objectid = btrfs_delayed_ref_owner(node);
ref = btrfs_delayed_node_to_data_ref(node);
key.objectid = ref->objectid;
key.type = BTRFS_EXTENT_DATA_KEY; key.type = BTRFS_EXTENT_DATA_KEY;
key.offset = ref->offset; key.offset = btrfs_delayed_ref_offset(node);
/* /*
* If we have a share check context and a reference for * If we have a share check context and a reference for
...@@ -972,18 +970,14 @@ static int add_delayed_refs(const struct btrfs_fs_info *fs_info, ...@@ -972,18 +970,14 @@ static int add_delayed_refs(const struct btrfs_fs_info *fs_info,
if (sc && count < 0) if (sc && count < 0)
sc->have_delayed_delete_refs = true; sc->have_delayed_delete_refs = true;
ret = add_indirect_ref(fs_info, preftrees, ref->root, ret = add_indirect_ref(fs_info, preftrees, node->ref_root,
&key, 0, node->bytenr, count, sc, &key, 0, node->bytenr, count, sc,
GFP_ATOMIC); GFP_ATOMIC);
break; break;
} }
case BTRFS_SHARED_DATA_REF_KEY: { case BTRFS_SHARED_DATA_REF_KEY: {
/* SHARED DIRECT FULL backref */ /* SHARED DIRECT FULL backref */
struct btrfs_delayed_data_ref *ref; ret = add_direct_ref(fs_info, preftrees, 0, node->parent,
ref = btrfs_delayed_node_to_data_ref(node);
ret = add_direct_ref(fs_info, preftrees, 0, ref->parent,
node->bytenr, count, sc, node->bytenr, count, sc,
GFP_ATOMIC); GFP_ATOMIC);
break; break;
...@@ -2629,7 +2623,7 @@ static int iterate_inode_refs(u64 inum, struct inode_fs_paths *ipath) ...@@ -2629,7 +2623,7 @@ static int iterate_inode_refs(u64 inum, struct inode_fs_paths *ipath)
btrfs_debug(fs_root->fs_info, btrfs_debug(fs_root->fs_info,
"following ref at offset %u for inode %llu in tree %llu", "following ref at offset %u for inode %llu in tree %llu",
cur, found_key.objectid, cur, found_key.objectid,
fs_root->root_key.objectid); btrfs_root_id(fs_root));
ret = inode_to_path(parent, name_len, ret = inode_to_path(parent, name_len,
(unsigned long)(iref + 1), eb, ipath); (unsigned long)(iref + 1), eb, ipath);
if (ret) if (ret)
...@@ -3361,7 +3355,7 @@ static int handle_indirect_tree_backref(struct btrfs_trans_handle *trans, ...@@ -3361,7 +3355,7 @@ static int handle_indirect_tree_backref(struct btrfs_trans_handle *trans,
if (btrfs_node_blockptr(eb, path->slots[level]) != cur->bytenr) { if (btrfs_node_blockptr(eb, path->slots[level]) != cur->bytenr) {
btrfs_err(fs_info, btrfs_err(fs_info,
"couldn't find block (%llu) (level %d) in tree (%llu) with key (%llu %u %llu)", "couldn't find block (%llu) (level %d) in tree (%llu) with key (%llu %u %llu)",
cur->bytenr, level - 1, root->root_key.objectid, cur->bytenr, level - 1, btrfs_root_id(root),
tree_key->objectid, tree_key->type, tree_key->offset); tree_key->objectid, tree_key->type, tree_key->offset);
btrfs_put_root(root); btrfs_put_root(root);
ret = -ENOENT; ret = -ENOENT;
......
...@@ -341,9 +341,9 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info) ...@@ -341,9 +341,9 @@ void btrfs_update_global_block_rsv(struct btrfs_fs_info *fs_info)
read_lock(&fs_info->global_root_lock); read_lock(&fs_info->global_root_lock);
rbtree_postorder_for_each_entry_safe(root, tmp, &fs_info->global_root_tree, rbtree_postorder_for_each_entry_safe(root, tmp, &fs_info->global_root_tree,
rb_node) { rb_node) {
if (root->root_key.objectid == BTRFS_EXTENT_TREE_OBJECTID || if (btrfs_root_id(root) == BTRFS_EXTENT_TREE_OBJECTID ||
root->root_key.objectid == BTRFS_CSUM_TREE_OBJECTID || btrfs_root_id(root) == BTRFS_CSUM_TREE_OBJECTID ||
root->root_key.objectid == BTRFS_FREE_SPACE_TREE_OBJECTID) { btrfs_root_id(root) == BTRFS_FREE_SPACE_TREE_OBJECTID) {
num_bytes += btrfs_root_used(&root->root_item); num_bytes += btrfs_root_used(&root->root_item);
min_items++; min_items++;
} }
...@@ -406,7 +406,7 @@ void btrfs_init_root_block_rsv(struct btrfs_root *root) ...@@ -406,7 +406,7 @@ void btrfs_init_root_block_rsv(struct btrfs_root *root)
{ {
struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_fs_info *fs_info = root->fs_info;
switch (root->root_key.objectid) { switch (btrfs_root_id(root)) {
case BTRFS_CSUM_TREE_OBJECTID: case BTRFS_CSUM_TREE_OBJECTID:
case BTRFS_EXTENT_TREE_OBJECTID: case BTRFS_EXTENT_TREE_OBJECTID:
case BTRFS_FREE_SPACE_TREE_OBJECTID: case BTRFS_FREE_SPACE_TREE_OBJECTID:
...@@ -468,8 +468,7 @@ static struct btrfs_block_rsv *get_block_rsv( ...@@ -468,8 +468,7 @@ static struct btrfs_block_rsv *get_block_rsv(
if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state) || if (test_bit(BTRFS_ROOT_SHAREABLE, &root->state) ||
(root == fs_info->uuid_root) || (root == fs_info->uuid_root) ||
(trans->adding_csums && (trans->adding_csums && btrfs_root_id(root) == BTRFS_CSUM_TREE_OBJECTID))
root->root_key.objectid == BTRFS_CSUM_TREE_OBJECTID))
block_rsv = trans->block_rsv; block_rsv = trans->block_rsv;
if (!block_rsv) if (!block_rsv)
......
...@@ -381,9 +381,11 @@ static inline void btrfs_set_inode_last_sub_trans(struct btrfs_inode *inode) ...@@ -381,9 +381,11 @@ static inline void btrfs_set_inode_last_sub_trans(struct btrfs_inode *inode)
} }
/* /*
* Should be called while holding the inode's VFS lock in exclusive mode or in a * Should be called while holding the inode's VFS lock in exclusive mode, or
* context where no one else can access the inode concurrently (during inode * while holding the inode's mmap lock (struct btrfs_inode::i_mmap_lock) in
* creation or when loading an inode from disk). * either shared or exclusive mode, or in a context where no one else can access
* the inode concurrently (during inode creation or when loading an inode from
* disk).
*/ */
static inline void btrfs_set_inode_full_sync(struct btrfs_inode *inode) static inline void btrfs_set_inode_full_sync(struct btrfs_inode *inode)
{ {
...@@ -496,7 +498,6 @@ void btrfs_merge_delalloc_extent(struct btrfs_inode *inode, struct extent_state ...@@ -496,7 +498,6 @@ void btrfs_merge_delalloc_extent(struct btrfs_inode *inode, struct extent_state
void btrfs_split_delalloc_extent(struct btrfs_inode *inode, void btrfs_split_delalloc_extent(struct btrfs_inode *inode,
struct extent_state *orig, u64 split); struct extent_state *orig, u64 split);
void btrfs_set_range_writeback(struct btrfs_inode *inode, u64 start, u64 end); void btrfs_set_range_writeback(struct btrfs_inode *inode, u64 start, u64 end);
vm_fault_t btrfs_page_mkwrite(struct vm_fault *vmf);
void btrfs_evict_inode(struct inode *inode); void btrfs_evict_inode(struct inode *inode);
struct inode *btrfs_alloc_inode(struct super_block *sb); struct inode *btrfs_alloc_inode(struct super_block *sb);
void btrfs_destroy_inode(struct inode *inode); void btrfs_destroy_inode(struct inode *inode);
...@@ -544,6 +545,7 @@ ssize_t btrfs_dio_read(struct kiocb *iocb, struct iov_iter *iter, ...@@ -544,6 +545,7 @@ ssize_t btrfs_dio_read(struct kiocb *iocb, struct iov_iter *iter,
size_t done_before); size_t done_before);
struct iomap_dio *btrfs_dio_write(struct kiocb *iocb, struct iov_iter *iter, struct iomap_dio *btrfs_dio_write(struct kiocb *iocb, struct iov_iter *iter,
size_t done_before); size_t done_before);
struct btrfs_inode *btrfs_find_first_inode(struct btrfs_root *root, u64 min_ino);
extern const struct dentry_operations btrfs_dentry_operations; extern const struct dentry_operations btrfs_dentry_operations;
......
...@@ -90,20 +90,20 @@ bool btrfs_compress_is_valid_type(const char *str, size_t len) ...@@ -90,20 +90,20 @@ bool btrfs_compress_is_valid_type(const char *str, size_t len)
} }
static int compression_compress_pages(int type, struct list_head *ws, static int compression_compress_pages(int type, struct list_head *ws,
struct address_space *mapping, u64 start, struct page **pages, struct address_space *mapping, u64 start,
unsigned long *out_pages, unsigned long *total_in, struct folio **folios, unsigned long *out_folios,
unsigned long *total_out) unsigned long *total_in, unsigned long *total_out)
{ {
switch (type) { switch (type) {
case BTRFS_COMPRESS_ZLIB: case BTRFS_COMPRESS_ZLIB:
return zlib_compress_pages(ws, mapping, start, pages, return zlib_compress_folios(ws, mapping, start, folios,
out_pages, total_in, total_out); out_folios, total_in, total_out);
case BTRFS_COMPRESS_LZO: case BTRFS_COMPRESS_LZO:
return lzo_compress_pages(ws, mapping, start, pages, return lzo_compress_folios(ws, mapping, start, folios,
out_pages, total_in, total_out); out_folios, total_in, total_out);
case BTRFS_COMPRESS_ZSTD: case BTRFS_COMPRESS_ZSTD:
return zstd_compress_pages(ws, mapping, start, pages, return zstd_compress_folios(ws, mapping, start, folios,
out_pages, total_in, total_out); out_folios, total_in, total_out);
case BTRFS_COMPRESS_NONE: case BTRFS_COMPRESS_NONE:
default: default:
/* /*
...@@ -115,7 +115,7 @@ static int compression_compress_pages(int type, struct list_head *ws, ...@@ -115,7 +115,7 @@ static int compression_compress_pages(int type, struct list_head *ws,
* Not a big deal, just need to inform caller that we * Not a big deal, just need to inform caller that we
* haven't allocated any pages yet. * haven't allocated any pages yet.
*/ */
*out_pages = 0; *out_folios = 0;
return -E2BIG; return -E2BIG;
} }
} }
...@@ -158,11 +158,11 @@ static int compression_decompress(int type, struct list_head *ws, ...@@ -158,11 +158,11 @@ static int compression_decompress(int type, struct list_head *ws,
} }
} }
static void btrfs_free_compressed_pages(struct compressed_bio *cb) static void btrfs_free_compressed_folios(struct compressed_bio *cb)
{ {
for (unsigned int i = 0; i < cb->nr_pages; i++) for (unsigned int i = 0; i < cb->nr_folios; i++)
btrfs_free_compr_page(cb->compressed_pages[i]); btrfs_free_compr_folio(cb->compressed_folios[i]);
kfree(cb->compressed_pages); kfree(cb->compressed_folios);
} }
static int btrfs_decompress_bio(struct compressed_bio *cb); static int btrfs_decompress_bio(struct compressed_bio *cb);
...@@ -223,25 +223,25 @@ static unsigned long btrfs_compr_pool_scan(struct shrinker *sh, struct shrink_co ...@@ -223,25 +223,25 @@ static unsigned long btrfs_compr_pool_scan(struct shrinker *sh, struct shrink_co
/* /*
* Common wrappers for page allocation from compression wrappers * Common wrappers for page allocation from compression wrappers
*/ */
struct page *btrfs_alloc_compr_page(void) struct folio *btrfs_alloc_compr_folio(void)
{ {
struct page *page = NULL; struct folio *folio = NULL;
spin_lock(&compr_pool.lock); spin_lock(&compr_pool.lock);
if (compr_pool.count > 0) { if (compr_pool.count > 0) {
page = list_first_entry(&compr_pool.list, struct page, lru); folio = list_first_entry(&compr_pool.list, struct folio, lru);
list_del_init(&page->lru); list_del_init(&folio->lru);
compr_pool.count--; compr_pool.count--;
} }
spin_unlock(&compr_pool.lock); spin_unlock(&compr_pool.lock);
if (page) if (folio)
return page; return folio;
return alloc_page(GFP_NOFS); return folio_alloc(GFP_NOFS, 0);
} }
void btrfs_free_compr_page(struct page *page) void btrfs_free_compr_folio(struct folio *folio)
{ {
bool do_free = false; bool do_free = false;
...@@ -249,7 +249,7 @@ void btrfs_free_compr_page(struct page *page) ...@@ -249,7 +249,7 @@ void btrfs_free_compr_page(struct page *page)
if (compr_pool.count > compr_pool.thresh) { if (compr_pool.count > compr_pool.thresh) {
do_free = true; do_free = true;
} else { } else {
list_add(&page->lru, &compr_pool.list); list_add(&folio->lru, &compr_pool.list);
compr_pool.count++; compr_pool.count++;
} }
spin_unlock(&compr_pool.lock); spin_unlock(&compr_pool.lock);
...@@ -257,8 +257,8 @@ void btrfs_free_compr_page(struct page *page) ...@@ -257,8 +257,8 @@ void btrfs_free_compr_page(struct page *page)
if (!do_free) if (!do_free)
return; return;
ASSERT(page_ref_count(page) == 1); ASSERT(folio_ref_count(folio) == 1);
put_page(page); folio_put(folio);
} }
static void end_bbio_comprssed_read(struct btrfs_bio *bbio) static void end_bbio_comprssed_read(struct btrfs_bio *bbio)
...@@ -269,7 +269,7 @@ static void end_bbio_comprssed_read(struct btrfs_bio *bbio) ...@@ -269,7 +269,7 @@ static void end_bbio_comprssed_read(struct btrfs_bio *bbio)
if (!status) if (!status)
status = errno_to_blk_status(btrfs_decompress_bio(cb)); status = errno_to_blk_status(btrfs_decompress_bio(cb));
btrfs_free_compressed_pages(cb); btrfs_free_compressed_folios(cb);
btrfs_bio_end_io(cb->orig_bbio, status); btrfs_bio_end_io(cb->orig_bbio, status);
bio_put(&bbio->bio); bio_put(&bbio->bio);
} }
...@@ -323,7 +323,7 @@ static void btrfs_finish_compressed_write_work(struct work_struct *work) ...@@ -323,7 +323,7 @@ static void btrfs_finish_compressed_write_work(struct work_struct *work)
end_compressed_writeback(cb); end_compressed_writeback(cb);
/* Note, our inode could be gone now */ /* Note, our inode could be gone now */
btrfs_free_compressed_pages(cb); btrfs_free_compressed_folios(cb);
bio_put(&cb->bbio.bio); bio_put(&cb->bbio.bio);
} }
...@@ -342,17 +342,19 @@ static void end_bbio_comprssed_write(struct btrfs_bio *bbio) ...@@ -342,17 +342,19 @@ static void end_bbio_comprssed_write(struct btrfs_bio *bbio)
queue_work(fs_info->compressed_write_workers, &cb->write_end_work); queue_work(fs_info->compressed_write_workers, &cb->write_end_work);
} }
static void btrfs_add_compressed_bio_pages(struct compressed_bio *cb) static void btrfs_add_compressed_bio_folios(struct compressed_bio *cb)
{ {
struct bio *bio = &cb->bbio.bio; struct bio *bio = &cb->bbio.bio;
u32 offset = 0; u32 offset = 0;
while (offset < cb->compressed_len) { while (offset < cb->compressed_len) {
int ret;
u32 len = min_t(u32, cb->compressed_len - offset, PAGE_SIZE); u32 len = min_t(u32, cb->compressed_len - offset, PAGE_SIZE);
/* Maximum compressed extent is smaller than bio size limit. */ /* Maximum compressed extent is smaller than bio size limit. */
__bio_add_page(bio, cb->compressed_pages[offset >> PAGE_SHIFT], ret = bio_add_folio(bio, cb->compressed_folios[offset >> PAGE_SHIFT],
len, 0); len, 0);
ASSERT(ret);
offset += len; offset += len;
} }
} }
...@@ -367,8 +369,8 @@ static void btrfs_add_compressed_bio_pages(struct compressed_bio *cb) ...@@ -367,8 +369,8 @@ static void btrfs_add_compressed_bio_pages(struct compressed_bio *cb)
* the end io hooks. * the end io hooks.
*/ */
void btrfs_submit_compressed_write(struct btrfs_ordered_extent *ordered, void btrfs_submit_compressed_write(struct btrfs_ordered_extent *ordered,
struct page **compressed_pages, struct folio **compressed_folios,
unsigned int nr_pages, unsigned int nr_folios,
blk_opf_t write_flags, blk_opf_t write_flags,
bool writeback) bool writeback)
{ {
...@@ -384,14 +386,14 @@ void btrfs_submit_compressed_write(struct btrfs_ordered_extent *ordered, ...@@ -384,14 +386,14 @@ void btrfs_submit_compressed_write(struct btrfs_ordered_extent *ordered,
end_bbio_comprssed_write); end_bbio_comprssed_write);
cb->start = ordered->file_offset; cb->start = ordered->file_offset;
cb->len = ordered->num_bytes; cb->len = ordered->num_bytes;
cb->compressed_pages = compressed_pages; cb->compressed_folios = compressed_folios;
cb->compressed_len = ordered->disk_num_bytes; cb->compressed_len = ordered->disk_num_bytes;
cb->writeback = writeback; cb->writeback = writeback;
INIT_WORK(&cb->write_end_work, btrfs_finish_compressed_write_work); INIT_WORK(&cb->write_end_work, btrfs_finish_compressed_write_work);
cb->nr_pages = nr_pages; cb->nr_folios = nr_folios;
cb->bbio.bio.bi_iter.bi_sector = ordered->disk_bytenr >> SECTOR_SHIFT; cb->bbio.bio.bi_iter.bi_sector = ordered->disk_bytenr >> SECTOR_SHIFT;
cb->bbio.ordered = ordered; cb->bbio.ordered = ordered;
btrfs_add_compressed_bio_pages(cb); btrfs_add_compressed_bio_folios(cb);
btrfs_submit_bio(&cb->bbio, 0); btrfs_submit_bio(&cb->bbio, 0);
} }
...@@ -599,14 +601,14 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio) ...@@ -599,14 +601,14 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio)
free_extent_map(em); free_extent_map(em);
cb->nr_pages = DIV_ROUND_UP(compressed_len, PAGE_SIZE); cb->nr_folios = DIV_ROUND_UP(compressed_len, PAGE_SIZE);
cb->compressed_pages = kcalloc(cb->nr_pages, sizeof(struct page *), GFP_NOFS); cb->compressed_folios = kcalloc(cb->nr_folios, sizeof(struct page *), GFP_NOFS);
if (!cb->compressed_pages) { if (!cb->compressed_folios) {
ret = BLK_STS_RESOURCE; ret = BLK_STS_RESOURCE;
goto out_free_bio; goto out_free_bio;
} }
ret2 = btrfs_alloc_page_array(cb->nr_pages, cb->compressed_pages, 0); ret2 = btrfs_alloc_folio_array(cb->nr_folios, cb->compressed_folios, 0);
if (ret2) { if (ret2) {
ret = BLK_STS_RESOURCE; ret = BLK_STS_RESOURCE;
goto out_free_compressed_pages; goto out_free_compressed_pages;
...@@ -618,7 +620,7 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio) ...@@ -618,7 +620,7 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio)
/* include any pages we added in add_ra-bio_pages */ /* include any pages we added in add_ra-bio_pages */
cb->len = bbio->bio.bi_iter.bi_size; cb->len = bbio->bio.bi_iter.bi_size;
cb->bbio.bio.bi_iter.bi_sector = bbio->bio.bi_iter.bi_sector; cb->bbio.bio.bi_iter.bi_sector = bbio->bio.bi_iter.bi_sector;
btrfs_add_compressed_bio_pages(cb); btrfs_add_compressed_bio_folios(cb);
if (memstall) if (memstall)
psi_memstall_leave(&pflags); psi_memstall_leave(&pflags);
...@@ -627,7 +629,7 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio) ...@@ -627,7 +629,7 @@ void btrfs_submit_compressed_read(struct btrfs_bio *bbio)
return; return;
out_free_compressed_pages: out_free_compressed_pages:
kfree(cb->compressed_pages); kfree(cb->compressed_folios);
out_free_bio: out_free_bio:
bio_put(&cb->bbio.bio); bio_put(&cb->bbio.bio);
out: out:
...@@ -974,6 +976,29 @@ static unsigned int btrfs_compress_set_level(int type, unsigned level) ...@@ -974,6 +976,29 @@ static unsigned int btrfs_compress_set_level(int type, unsigned level)
return level; return 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)
{
struct folio *in_folio;
/*
* The compressed write path should have the folio locked already, thus
* we only need to grab one reference.
*/
in_folio = filemap_get_folio(mapping, start >> PAGE_SHIFT);
if (IS_ERR(in_folio)) {
struct btrfs_inode *inode = BTRFS_I(mapping->host);
btrfs_crit(inode->root->fs_info,
"failed to get page cache, root %lld ino %llu file offset %llu",
btrfs_root_id(inode->root), btrfs_ino(inode), start);
return -ENOENT;
}
*in_folio_ret = in_folio;
return 0;
}
/* /*
* Given an address space and start and length, compress the bytes into @pages * Given an address space and start and length, compress the bytes into @pages
* that are allocated on demand. * that are allocated on demand.
...@@ -994,11 +1019,9 @@ static unsigned int btrfs_compress_set_level(int type, unsigned level) ...@@ -994,11 +1019,9 @@ static unsigned int btrfs_compress_set_level(int type, unsigned level)
* @total_out is an in/out parameter, must be set to the input length and will * @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 * be also used to return the total number of compressed bytes
*/ */
int btrfs_compress_pages(unsigned int type_level, struct address_space *mapping, int btrfs_compress_folios(unsigned int type_level, struct address_space *mapping,
u64 start, struct page **pages, u64 start, struct folio **folios, unsigned long *out_folios,
unsigned long *out_pages, unsigned long *total_in, unsigned long *total_out)
unsigned long *total_in,
unsigned long *total_out)
{ {
int type = btrfs_compress_type(type_level); int type = btrfs_compress_type(type_level);
int level = btrfs_compress_level(type_level); int level = btrfs_compress_level(type_level);
...@@ -1007,8 +1030,8 @@ int btrfs_compress_pages(unsigned int type_level, struct address_space *mapping, ...@@ -1007,8 +1030,8 @@ int btrfs_compress_pages(unsigned int type_level, struct address_space *mapping,
level = btrfs_compress_set_level(type, level); level = btrfs_compress_set_level(type, level);
workspace = get_workspace(type, level); workspace = get_workspace(type, level);
ret = compression_compress_pages(type, workspace, mapping, start, pages, ret = compression_compress_pages(type, workspace, mapping, start, folios,
out_pages, total_in, total_out); out_folios, total_in, total_out);
put_workspace(type, workspace); put_workspace(type, workspace);
return ret; return ret;
} }
......
...@@ -41,11 +41,11 @@ static_assert((BTRFS_MAX_COMPRESSED % PAGE_SIZE) == 0); ...@@ -41,11 +41,11 @@ static_assert((BTRFS_MAX_COMPRESSED % PAGE_SIZE) == 0);
#define BTRFS_ZLIB_DEFAULT_LEVEL 3 #define BTRFS_ZLIB_DEFAULT_LEVEL 3
struct compressed_bio { struct compressed_bio {
/* Number of compressed pages in the array */ /* Number of compressed folios in the array. */
unsigned int nr_pages; unsigned int nr_folios;
/* the pages with the compressed data on them */ /* The folios with the compressed data on them. */
struct page **compressed_pages; struct folio **compressed_folios;
/* starting offset in the inode for our pages */ /* starting offset in the inode for our pages */
u64 start; u64 start;
...@@ -85,27 +85,24 @@ static inline unsigned int btrfs_compress_level(unsigned int type_level) ...@@ -85,27 +85,24 @@ static inline unsigned int btrfs_compress_level(unsigned int type_level)
int __init btrfs_init_compress(void); int __init btrfs_init_compress(void);
void __cold btrfs_exit_compress(void); void __cold btrfs_exit_compress(void);
int btrfs_compress_pages(unsigned int type_level, struct address_space *mapping, int btrfs_compress_folios(unsigned int type_level, struct address_space *mapping,
u64 start, struct page **pages, u64 start, struct folio **folios, unsigned long *out_folios,
unsigned long *out_pages, unsigned long *total_in, unsigned long *total_out);
unsigned long *total_in,
unsigned long *total_out);
int btrfs_decompress(int type, const u8 *data_in, struct page *dest_page, int btrfs_decompress(int type, const u8 *data_in, struct page *dest_page,
unsigned long start_byte, size_t srclen, size_t destlen); unsigned long start_byte, size_t srclen, size_t destlen);
int btrfs_decompress_buf2page(const char *buf, u32 buf_len, int btrfs_decompress_buf2page(const char *buf, u32 buf_len,
struct compressed_bio *cb, u32 decompressed); struct compressed_bio *cb, u32 decompressed);
void btrfs_submit_compressed_write(struct btrfs_ordered_extent *ordered, void btrfs_submit_compressed_write(struct btrfs_ordered_extent *ordered,
struct page **compressed_pages, struct folio **compressed_folios,
unsigned int nr_pages, unsigned int nr_folios, blk_opf_t write_flags,
blk_opf_t write_flags, bool writeback);
bool writeback);
void btrfs_submit_compressed_read(struct btrfs_bio *bbio); void btrfs_submit_compressed_read(struct btrfs_bio *bbio);
unsigned int btrfs_compress_str2level(unsigned int type, const char *str); unsigned int btrfs_compress_str2level(unsigned int type, const char *str);
struct page *btrfs_alloc_compr_page(void); struct folio *btrfs_alloc_compr_folio(void);
void btrfs_free_compr_page(struct page *page); void btrfs_free_compr_folio(struct folio *folio);
enum btrfs_compression_type { enum btrfs_compression_type {
BTRFS_COMPRESS_NONE = 0, BTRFS_COMPRESS_NONE = 0,
...@@ -149,8 +146,11 @@ bool btrfs_compress_is_valid_type(const char *str, size_t len); ...@@ -149,8 +146,11 @@ bool btrfs_compress_is_valid_type(const char *str, size_t len);
int btrfs_compress_heuristic(struct inode *inode, u64 start, u64 end); int btrfs_compress_heuristic(struct inode *inode, u64 start, u64 end);
int zlib_compress_pages(struct list_head *ws, struct address_space *mapping, int btrfs_compress_filemap_get_folio(struct address_space *mapping, u64 start,
u64 start, struct page **pages, unsigned long *out_pages, struct folio **in_folio_ret);
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); unsigned long *total_in, unsigned long *total_out);
int zlib_decompress_bio(struct list_head *ws, struct compressed_bio *cb); int zlib_decompress_bio(struct list_head *ws, struct compressed_bio *cb);
int zlib_decompress(struct list_head *ws, const u8 *data_in, int zlib_decompress(struct list_head *ws, const u8 *data_in,
...@@ -160,8 +160,8 @@ struct list_head *zlib_alloc_workspace(unsigned int level); ...@@ -160,8 +160,8 @@ struct list_head *zlib_alloc_workspace(unsigned int level);
void zlib_free_workspace(struct list_head *ws); void zlib_free_workspace(struct list_head *ws);
struct list_head *zlib_get_workspace(unsigned int level); struct list_head *zlib_get_workspace(unsigned int level);
int lzo_compress_pages(struct list_head *ws, struct address_space *mapping, int lzo_compress_folios(struct list_head *ws, struct address_space *mapping,
u64 start, struct page **pages, unsigned long *out_pages, u64 start, struct folio **folios, unsigned long *out_folios,
unsigned long *total_in, unsigned long *total_out); unsigned long *total_in, unsigned long *total_out);
int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb); int lzo_decompress_bio(struct list_head *ws, struct compressed_bio *cb);
int lzo_decompress(struct list_head *ws, const u8 *data_in, int lzo_decompress(struct list_head *ws, const u8 *data_in,
...@@ -170,8 +170,8 @@ int lzo_decompress(struct list_head *ws, const u8 *data_in, ...@@ -170,8 +170,8 @@ int lzo_decompress(struct list_head *ws, const u8 *data_in,
struct list_head *lzo_alloc_workspace(unsigned int level); struct list_head *lzo_alloc_workspace(unsigned int level);
void lzo_free_workspace(struct list_head *ws); void lzo_free_workspace(struct list_head *ws);
int zstd_compress_pages(struct list_head *ws, struct address_space *mapping, int zstd_compress_folios(struct list_head *ws, struct address_space *mapping,
u64 start, struct page **pages, unsigned long *out_pages, u64 start, struct folio **folios, unsigned long *out_folios,
unsigned long *total_in, unsigned long *total_out); unsigned long *total_in, unsigned long *total_out);
int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb); int zstd_decompress_bio(struct list_head *ws, struct compressed_bio *cb);
int zstd_decompress(struct list_head *ws, const u8 *data_in, int zstd_decompress(struct list_head *ws, const u8 *data_in,
......
...@@ -291,7 +291,7 @@ static void add_root_to_dirty_list(struct btrfs_root *root) ...@@ -291,7 +291,7 @@ static void add_root_to_dirty_list(struct btrfs_root *root)
spin_lock(&fs_info->trans_lock); spin_lock(&fs_info->trans_lock);
if (!test_and_set_bit(BTRFS_ROOT_DIRTY, &root->state)) { if (!test_and_set_bit(BTRFS_ROOT_DIRTY, &root->state)) {
/* Want the extent tree to be the last on the list */ /* Want the extent tree to be the last on the list */
if (root->root_key.objectid == BTRFS_EXTENT_TREE_OBJECTID) if (btrfs_root_id(root) == BTRFS_EXTENT_TREE_OBJECTID)
list_move_tail(&root->dirty_list, list_move_tail(&root->dirty_list,
&fs_info->dirty_cowonly_roots); &fs_info->dirty_cowonly_roots);
else else
...@@ -454,7 +454,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, ...@@ -454,7 +454,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
} }
} else { } else {
refs = 1; refs = 1;
if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID || if (btrfs_root_id(root) == BTRFS_TREE_RELOC_OBJECTID ||
btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV) btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV)
flags = BTRFS_BLOCK_FLAG_FULL_BACKREF; flags = BTRFS_BLOCK_FLAG_FULL_BACKREF;
else else
...@@ -466,15 +466,14 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, ...@@ -466,15 +466,14 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)); !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF));
if (refs > 1) { if (refs > 1) {
if ((owner == root->root_key.objectid || if ((owner == btrfs_root_id(root) ||
root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) && btrfs_root_id(root) == BTRFS_TREE_RELOC_OBJECTID) &&
!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) { !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) {
ret = btrfs_inc_ref(trans, root, buf, 1); ret = btrfs_inc_ref(trans, root, buf, 1);
if (ret) if (ret)
return ret; return ret;
if (root->root_key.objectid == if (btrfs_root_id(root) == BTRFS_TREE_RELOC_OBJECTID) {
BTRFS_TREE_RELOC_OBJECTID) {
ret = btrfs_dec_ref(trans, root, buf, 0); ret = btrfs_dec_ref(trans, root, buf, 0);
if (ret) if (ret)
return ret; return ret;
...@@ -485,8 +484,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, ...@@ -485,8 +484,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF; new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
} else { } else {
if (root->root_key.objectid == if (btrfs_root_id(root) == BTRFS_TREE_RELOC_OBJECTID)
BTRFS_TREE_RELOC_OBJECTID)
ret = btrfs_inc_ref(trans, root, cow, 1); ret = btrfs_inc_ref(trans, root, cow, 1);
else else
ret = btrfs_inc_ref(trans, root, cow, 0); ret = btrfs_inc_ref(trans, root, cow, 0);
...@@ -500,8 +498,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, ...@@ -500,8 +498,7 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
} }
} else { } else {
if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) { if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
if (root->root_key.objectid == if (btrfs_root_id(root) == BTRFS_TREE_RELOC_OBJECTID)
BTRFS_TREE_RELOC_OBJECTID)
ret = btrfs_inc_ref(trans, root, cow, 1); ret = btrfs_inc_ref(trans, root, cow, 1);
else else
ret = btrfs_inc_ref(trans, root, cow, 0); ret = btrfs_inc_ref(trans, root, cow, 0);
...@@ -563,13 +560,13 @@ int btrfs_force_cow_block(struct btrfs_trans_handle *trans, ...@@ -563,13 +560,13 @@ int btrfs_force_cow_block(struct btrfs_trans_handle *trans,
else else
btrfs_node_key(buf, &disk_key, 0); btrfs_node_key(buf, &disk_key, 0);
if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) { if (btrfs_root_id(root) == BTRFS_TREE_RELOC_OBJECTID) {
if (parent) if (parent)
parent_start = parent->start; parent_start = parent->start;
reloc_src_root = btrfs_header_owner(buf); reloc_src_root = btrfs_header_owner(buf);
} }
cow = btrfs_alloc_tree_block(trans, root, parent_start, cow = btrfs_alloc_tree_block(trans, root, parent_start,
root->root_key.objectid, &disk_key, level, btrfs_root_id(root), &disk_key, level,
search_start, empty_size, reloc_src_root, nest); search_start, empty_size, reloc_src_root, nest);
if (IS_ERR(cow)) if (IS_ERR(cow))
return PTR_ERR(cow); return PTR_ERR(cow);
...@@ -582,10 +579,10 @@ int btrfs_force_cow_block(struct btrfs_trans_handle *trans, ...@@ -582,10 +579,10 @@ int btrfs_force_cow_block(struct btrfs_trans_handle *trans,
btrfs_set_header_backref_rev(cow, BTRFS_MIXED_BACKREF_REV); btrfs_set_header_backref_rev(cow, BTRFS_MIXED_BACKREF_REV);
btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN | btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN |
BTRFS_HEADER_FLAG_RELOC); BTRFS_HEADER_FLAG_RELOC);
if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) if (btrfs_root_id(root) == BTRFS_TREE_RELOC_OBJECTID)
btrfs_set_header_flag(cow, BTRFS_HEADER_FLAG_RELOC); btrfs_set_header_flag(cow, BTRFS_HEADER_FLAG_RELOC);
else else
btrfs_set_header_owner(cow, root->root_key.objectid); btrfs_set_header_owner(cow, btrfs_root_id(root));
write_extent_buffer_fsid(cow, fs_info->fs_devices->metadata_uuid); write_extent_buffer_fsid(cow, fs_info->fs_devices->metadata_uuid);
...@@ -609,7 +606,7 @@ int btrfs_force_cow_block(struct btrfs_trans_handle *trans, ...@@ -609,7 +606,7 @@ int btrfs_force_cow_block(struct btrfs_trans_handle *trans,
if (buf == root->node) { if (buf == root->node) {
WARN_ON(parent && parent != buf); WARN_ON(parent && parent != buf);
if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID || if (btrfs_root_id(root) == BTRFS_TREE_RELOC_OBJECTID ||
btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV) btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV)
parent_start = buf->start; parent_start = buf->start;
...@@ -685,7 +682,7 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans, ...@@ -685,7 +682,7 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,
*/ */
if (btrfs_header_generation(buf) == trans->transid && if (btrfs_header_generation(buf) == trans->transid &&
!btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) && !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) &&
!(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID && !(btrfs_root_id(root) != BTRFS_TREE_RELOC_OBJECTID &&
btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)) && btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)) &&
!test_bit(BTRFS_ROOT_FORCE_COW, &root->state)) !test_bit(BTRFS_ROOT_FORCE_COW, &root->state))
return 0; return 0;
...@@ -1003,7 +1000,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, ...@@ -1003,7 +1000,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
goto out; goto out;
} }
__btrfs_tree_lock(left, BTRFS_NESTING_LEFT); btrfs_tree_lock_nested(left, BTRFS_NESTING_LEFT);
wret = btrfs_cow_block(trans, root, left, wret = btrfs_cow_block(trans, root, left,
parent, pslot - 1, &left, parent, pslot - 1, &left,
BTRFS_NESTING_LEFT_COW); BTRFS_NESTING_LEFT_COW);
...@@ -1021,7 +1018,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, ...@@ -1021,7 +1018,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
goto out; goto out;
} }
__btrfs_tree_lock(right, BTRFS_NESTING_RIGHT); btrfs_tree_lock_nested(right, BTRFS_NESTING_RIGHT);
wret = btrfs_cow_block(trans, root, right, wret = btrfs_cow_block(trans, root, right,
parent, pslot + 1, &right, parent, pslot + 1, &right,
BTRFS_NESTING_RIGHT_COW); BTRFS_NESTING_RIGHT_COW);
...@@ -1205,7 +1202,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans, ...@@ -1205,7 +1202,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
if (IS_ERR(left)) if (IS_ERR(left))
return PTR_ERR(left); return PTR_ERR(left);
__btrfs_tree_lock(left, BTRFS_NESTING_LEFT); btrfs_tree_lock_nested(left, BTRFS_NESTING_LEFT);
left_nr = btrfs_header_nritems(left); left_nr = btrfs_header_nritems(left);
if (left_nr >= BTRFS_NODEPTRS_PER_BLOCK(fs_info) - 1) { if (left_nr >= BTRFS_NODEPTRS_PER_BLOCK(fs_info) - 1) {
...@@ -1265,7 +1262,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans, ...@@ -1265,7 +1262,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
if (IS_ERR(right)) if (IS_ERR(right))
return PTR_ERR(right); return PTR_ERR(right);
__btrfs_tree_lock(right, BTRFS_NESTING_RIGHT); btrfs_tree_lock_nested(right, BTRFS_NESTING_RIGHT);
right_nr = btrfs_header_nritems(right); right_nr = btrfs_header_nritems(right);
if (right_nr >= BTRFS_NODEPTRS_PER_BLOCK(fs_info) - 1) { if (right_nr >= BTRFS_NODEPTRS_PER_BLOCK(fs_info) - 1) {
...@@ -1511,7 +1508,7 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p, ...@@ -1511,7 +1508,7 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
check.has_first_key = true; check.has_first_key = true;
check.level = parent_level - 1; check.level = parent_level - 1;
check.transid = gen; check.transid = gen;
check.owner_root = root->root_key.objectid; check.owner_root = btrfs_root_id(root);
/* /*
* If we need to read an extent buffer from disk and we are holding locks * If we need to read an extent buffer from disk and we are holding locks
...@@ -1556,7 +1553,7 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p, ...@@ -1556,7 +1553,7 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
btrfs_release_path(p); btrfs_release_path(p);
return -EIO; return -EIO;
} }
if (btrfs_check_eb_owner(tmp, root->root_key.objectid)) { if (btrfs_check_eb_owner(tmp, btrfs_root_id(root))) {
free_extent_buffer(tmp); free_extent_buffer(tmp);
btrfs_release_path(p); btrfs_release_path(p);
return -EUCLEAN; return -EUCLEAN;
...@@ -2865,7 +2862,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans, ...@@ -2865,7 +2862,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
else else
btrfs_node_key(lower, &lower_key, 0); btrfs_node_key(lower, &lower_key, 0);
c = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid, c = btrfs_alloc_tree_block(trans, root, 0, btrfs_root_id(root),
&lower_key, level, root->node->start, 0, &lower_key, level, root->node->start, 0,
0, BTRFS_NESTING_NEW_ROOT); 0, BTRFS_NESTING_NEW_ROOT);
if (IS_ERR(c)) if (IS_ERR(c))
...@@ -3009,7 +3006,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans, ...@@ -3009,7 +3006,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
mid = (c_nritems + 1) / 2; mid = (c_nritems + 1) / 2;
btrfs_node_key(c, &disk_key, mid); btrfs_node_key(c, &disk_key, mid);
split = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid, split = btrfs_alloc_tree_block(trans, root, 0, btrfs_root_id(root),
&disk_key, level, c->start, 0, &disk_key, level, c->start, 0,
0, BTRFS_NESTING_SPLIT); 0, BTRFS_NESTING_SPLIT);
if (IS_ERR(split)) if (IS_ERR(split))
...@@ -3267,7 +3264,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -3267,7 +3264,7 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
if (IS_ERR(right)) if (IS_ERR(right))
return PTR_ERR(right); return PTR_ERR(right);
__btrfs_tree_lock(right, BTRFS_NESTING_RIGHT); btrfs_tree_lock_nested(right, BTRFS_NESTING_RIGHT);
free_space = btrfs_leaf_free_space(right); free_space = btrfs_leaf_free_space(right);
if (free_space < data_size) if (free_space < data_size)
...@@ -3483,7 +3480,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -3483,7 +3480,7 @@ static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
if (IS_ERR(left)) if (IS_ERR(left))
return PTR_ERR(left); return PTR_ERR(left);
__btrfs_tree_lock(left, BTRFS_NESTING_LEFT); btrfs_tree_lock_nested(left, BTRFS_NESTING_LEFT);
free_space = btrfs_leaf_free_space(left); free_space = btrfs_leaf_free_space(left);
if (free_space < data_size) { if (free_space < data_size) {
...@@ -3761,7 +3758,7 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans, ...@@ -3761,7 +3758,7 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
* BTRFS_NESTING_SPLIT_THE_SPLITTENING if we need to, but for now just * BTRFS_NESTING_SPLIT_THE_SPLITTENING if we need to, but for now just
* use BTRFS_NESTING_NEW_ROOT. * use BTRFS_NESTING_NEW_ROOT.
*/ */
right = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid, right = btrfs_alloc_tree_block(trans, root, 0, btrfs_root_id(root),
&disk_key, 0, l->start, 0, 0, &disk_key, 0, l->start, 0, 0,
num_doubles ? BTRFS_NESTING_NEW_ROOT : num_doubles ? BTRFS_NESTING_NEW_ROOT :
BTRFS_NESTING_SPLIT); BTRFS_NESTING_SPLIT);
......
...@@ -147,7 +147,7 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, ...@@ -147,7 +147,7 @@ int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
defrag->ino = btrfs_ino(inode); defrag->ino = btrfs_ino(inode);
defrag->transid = transid; defrag->transid = transid;
defrag->root = root->root_key.objectid; defrag->root = btrfs_root_id(root);
defrag->extent_thresh = extent_thresh; defrag->extent_thresh = extent_thresh;
spin_lock(&fs_info->defrag_inodes_lock); spin_lock(&fs_info->defrag_inodes_lock);
......
...@@ -1651,7 +1651,7 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans, ...@@ -1651,7 +1651,7 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
if (unlikely(ret)) { if (unlikely(ret)) {
btrfs_err(trans->fs_info, btrfs_err(trans->fs_info,
"err add delayed dir index item(index: %llu) into the deletion tree of the delayed node(root id: %llu, inode id: %llu, errno: %d)", "err add delayed dir index item(index: %llu) into the deletion tree of the delayed node(root id: %llu, inode id: %llu, errno: %d)",
index, node->root->root_key.objectid, index, btrfs_root_id(node->root),
node->inode_id, ret); node->inode_id, ret);
btrfs_delayed_item_release_metadata(dir->root, item); btrfs_delayed_item_release_metadata(dir->root, item);
btrfs_release_delayed_item(item); btrfs_release_delayed_item(item);
......
This diff is collapsed.
...@@ -30,6 +30,32 @@ enum btrfs_delayed_ref_action { ...@@ -30,6 +30,32 @@ enum btrfs_delayed_ref_action {
BTRFS_UPDATE_DELAYED_HEAD, BTRFS_UPDATE_DELAYED_HEAD,
} __packed; } __packed;
struct btrfs_data_ref {
/* For EXTENT_DATA_REF */
/* Inode which refers to this data extent */
u64 objectid;
/*
* file_offset - extent_offset
*
* file_offset is the key.offset of the EXTENT_DATA key.
* extent_offset is btrfs_file_extent_offset() of the EXTENT_DATA data.
*/
u64 offset;
};
struct btrfs_tree_ref {
/*
* Level of this tree block.
*
* Shared for skinny (TREE_BLOCK_REF) and normal tree ref.
*/
int level;
/* For non-skinny metadata, no special member needed */
};
struct btrfs_delayed_ref_node { struct btrfs_delayed_ref_node {
struct rb_node ref_node; struct rb_node ref_node;
/* /*
...@@ -48,6 +74,15 @@ struct btrfs_delayed_ref_node { ...@@ -48,6 +74,15 @@ struct btrfs_delayed_ref_node {
/* seq number to keep track of insertion order */ /* seq number to keep track of insertion order */
u64 seq; u64 seq;
/* The ref_root for this ref */
u64 ref_root;
/*
* The parent for this ref, if this isn't set the ref_root is the
* reference owner.
*/
u64 parent;
/* ref count on this data structure */ /* ref count on this data structure */
refcount_t refs; refcount_t refs;
...@@ -64,6 +99,11 @@ struct btrfs_delayed_ref_node { ...@@ -64,6 +99,11 @@ struct btrfs_delayed_ref_node {
unsigned int action:8; unsigned int action:8;
unsigned int type:8; unsigned int type:8;
union {
struct btrfs_tree_ref tree_ref;
struct btrfs_data_ref data_ref;
};
}; };
struct btrfs_delayed_extent_op { struct btrfs_delayed_extent_op {
...@@ -151,21 +191,6 @@ struct btrfs_delayed_ref_head { ...@@ -151,21 +191,6 @@ struct btrfs_delayed_ref_head {
bool processing; bool processing;
}; };
struct btrfs_delayed_tree_ref {
struct btrfs_delayed_ref_node node;
u64 root;
u64 parent;
int level;
};
struct btrfs_delayed_data_ref {
struct btrfs_delayed_ref_node node;
u64 root;
u64 parent;
u64 objectid;
u64 offset;
};
enum btrfs_delayed_ref_flags { enum btrfs_delayed_ref_flags {
/* Indicate that we are flushing delayed refs for the commit */ /* Indicate that we are flushing delayed refs for the commit */
BTRFS_DELAYED_REFS_FLUSHING, BTRFS_DELAYED_REFS_FLUSHING,
...@@ -214,42 +239,6 @@ enum btrfs_ref_type { ...@@ -214,42 +239,6 @@ enum btrfs_ref_type {
BTRFS_REF_LAST, BTRFS_REF_LAST,
} __packed; } __packed;
struct btrfs_data_ref {
/* For EXTENT_DATA_REF */
/* Root which owns this data reference. */
u64 ref_root;
/* Inode which refers to this data extent */
u64 ino;
/*
* file_offset - extent_offset
*
* file_offset is the key.offset of the EXTENT_DATA key.
* extent_offset is btrfs_file_extent_offset() of the EXTENT_DATA data.
*/
u64 offset;
};
struct btrfs_tree_ref {
/*
* Level of this tree block
*
* Shared for skinny (TREE_BLOCK_REF) and normal tree ref.
*/
int level;
/*
* Root which owns this tree block reference.
*
* For TREE_BLOCK_REF (skinny metadata, either inline or keyed)
*/
u64 ref_root;
/* For non-skinny metadata, no special member needed */
};
struct btrfs_ref { struct btrfs_ref {
enum btrfs_ref_type type; enum btrfs_ref_type type;
enum btrfs_delayed_ref_action action; enum btrfs_delayed_ref_action action;
...@@ -267,9 +256,15 @@ struct btrfs_ref { ...@@ -267,9 +256,15 @@ struct btrfs_ref {
u64 real_root; u64 real_root;
#endif #endif
u64 bytenr; u64 bytenr;
u64 len; u64 num_bytes;
u64 owning_root; u64 owning_root;
/*
* The root that owns the reference for this reference, this will be set
* or ->parent will be set, depending on what type of reference this is.
*/
u64 ref_root;
/* Bytenr of the parent tree block */ /* Bytenr of the parent tree block */
u64 parent; u64 parent;
union { union {
...@@ -279,8 +274,7 @@ struct btrfs_ref { ...@@ -279,8 +274,7 @@ struct btrfs_ref {
}; };
extern struct kmem_cache *btrfs_delayed_ref_head_cachep; extern struct kmem_cache *btrfs_delayed_ref_head_cachep;
extern struct kmem_cache *btrfs_delayed_tree_ref_cachep; extern struct kmem_cache *btrfs_delayed_ref_node_cachep;
extern struct kmem_cache *btrfs_delayed_data_ref_cachep;
extern struct kmem_cache *btrfs_delayed_extent_op_cachep; extern struct kmem_cache *btrfs_delayed_extent_op_cachep;
int __init btrfs_delayed_ref_init(void); int __init btrfs_delayed_ref_init(void);
...@@ -318,12 +312,10 @@ static inline u64 btrfs_calc_delayed_ref_csum_bytes(const struct btrfs_fs_info * ...@@ -318,12 +312,10 @@ static inline u64 btrfs_calc_delayed_ref_csum_bytes(const struct btrfs_fs_info *
return btrfs_calc_metadata_size(fs_info, num_csum_items); return btrfs_calc_metadata_size(fs_info, num_csum_items);
} }
void btrfs_init_generic_ref(struct btrfs_ref *generic_ref, int action, u64 bytenr, void btrfs_init_tree_ref(struct btrfs_ref *generic_ref, int level, u64 mod_root,
u64 len, u64 parent, u64 owning_root); bool skip_qgroup);
void btrfs_init_tree_ref(struct btrfs_ref *generic_ref, int level, u64 root, void btrfs_init_data_ref(struct btrfs_ref *generic_ref, u64 ino, u64 offset,
u64 mod_root, bool skip_qgroup); u64 mod_root, bool skip_qgroup);
void btrfs_init_data_ref(struct btrfs_ref *generic_ref, u64 ref_root, u64 ino,
u64 offset, u64 mod_root, bool skip_qgroup);
static inline struct btrfs_delayed_extent_op * static inline struct btrfs_delayed_extent_op *
btrfs_alloc_delayed_extent_op(void) btrfs_alloc_delayed_extent_op(void)
...@@ -398,19 +390,39 @@ void btrfs_migrate_to_delayed_refs_rsv(struct btrfs_fs_info *fs_info, ...@@ -398,19 +390,39 @@ void btrfs_migrate_to_delayed_refs_rsv(struct btrfs_fs_info *fs_info,
u64 num_bytes); u64 num_bytes);
bool btrfs_check_space_for_delayed_refs(struct btrfs_fs_info *fs_info); bool btrfs_check_space_for_delayed_refs(struct btrfs_fs_info *fs_info);
/* static inline u64 btrfs_delayed_ref_owner(struct btrfs_delayed_ref_node *node)
* helper functions to cast a node into its container {
*/ if (node->type == BTRFS_EXTENT_DATA_REF_KEY ||
static inline struct btrfs_delayed_tree_ref * node->type == BTRFS_SHARED_DATA_REF_KEY)
btrfs_delayed_node_to_tree_ref(struct btrfs_delayed_ref_node *node) return node->data_ref.objectid;
return node->tree_ref.level;
}
static inline u64 btrfs_delayed_ref_offset(struct btrfs_delayed_ref_node *node)
{ {
return container_of(node, struct btrfs_delayed_tree_ref, node); if (node->type == BTRFS_EXTENT_DATA_REF_KEY ||
node->type == BTRFS_SHARED_DATA_REF_KEY)
return node->data_ref.offset;
return 0;
} }
static inline struct btrfs_delayed_data_ref * static inline u8 btrfs_ref_type(struct btrfs_ref *ref)
btrfs_delayed_node_to_data_ref(struct btrfs_delayed_ref_node *node)
{ {
return container_of(node, struct btrfs_delayed_data_ref, node); ASSERT(ref->type == BTRFS_REF_DATA || ref->type == BTRFS_REF_METADATA);
if (ref->type == BTRFS_REF_DATA) {
if (ref->parent)
return BTRFS_SHARED_DATA_REF_KEY;
else
return BTRFS_EXTENT_DATA_REF_KEY;
} else {
if (ref->parent)
return BTRFS_SHARED_BLOCK_REF_KEY;
else
return BTRFS_TREE_BLOCK_REF_KEY;
}
return 0;
} }
#endif #endif
This diff is collapsed.
...@@ -34,7 +34,7 @@ static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len, ...@@ -34,7 +34,7 @@ static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len,
type = FILEID_BTRFS_WITHOUT_PARENT; type = FILEID_BTRFS_WITHOUT_PARENT;
fid->objectid = btrfs_ino(BTRFS_I(inode)); fid->objectid = btrfs_ino(BTRFS_I(inode));
fid->root_objectid = BTRFS_I(inode)->root->root_key.objectid; fid->root_objectid = btrfs_root_id(BTRFS_I(inode)->root);
fid->gen = inode->i_generation; fid->gen = inode->i_generation;
if (parent) { if (parent) {
...@@ -42,7 +42,7 @@ static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len, ...@@ -42,7 +42,7 @@ static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len,
fid->parent_objectid = BTRFS_I(parent)->location.objectid; fid->parent_objectid = BTRFS_I(parent)->location.objectid;
fid->parent_gen = parent->i_generation; fid->parent_gen = parent->i_generation;
parent_root_id = BTRFS_I(parent)->root->root_key.objectid; parent_root_id = btrfs_root_id(BTRFS_I(parent)->root);
if (parent_root_id != fid->root_objectid) { if (parent_root_id != fid->root_objectid) {
fid->parent_root_objectid = parent_root_id; fid->parent_root_objectid = parent_root_id;
...@@ -160,7 +160,7 @@ struct dentry *btrfs_get_parent(struct dentry *child) ...@@ -160,7 +160,7 @@ struct dentry *btrfs_get_parent(struct dentry *child)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
if (btrfs_ino(BTRFS_I(dir)) == BTRFS_FIRST_FREE_OBJECTID) { if (btrfs_ino(BTRFS_I(dir)) == BTRFS_FIRST_FREE_OBJECTID) {
key.objectid = root->root_key.objectid; key.objectid = btrfs_root_id(root);
key.type = BTRFS_ROOT_BACKREF_KEY; key.type = BTRFS_ROOT_BACKREF_KEY;
key.offset = (u64)-1; key.offset = (u64)-1;
root = fs_info->tree_root; root = fs_info->tree_root;
...@@ -243,7 +243,7 @@ static int btrfs_get_name(struct dentry *parent, char *name, ...@@ -243,7 +243,7 @@ static int btrfs_get_name(struct dentry *parent, char *name,
return -ENOMEM; return -ENOMEM;
if (ino == BTRFS_FIRST_FREE_OBJECTID) { if (ino == BTRFS_FIRST_FREE_OBJECTID) {
key.objectid = BTRFS_I(inode)->root->root_key.objectid; key.objectid = btrfs_root_id(BTRFS_I(inode)->root);
key.type = BTRFS_ROOT_BACKREF_KEY; key.type = BTRFS_ROOT_BACKREF_KEY;
key.offset = (u64)-1; key.offset = (u64)-1;
root = fs_info->tree_root; root = fs_info->tree_root;
......
...@@ -1059,7 +1059,7 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -1059,7 +1059,7 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
struct extent_state *prealloc = NULL; struct extent_state *prealloc = NULL;
struct rb_node **p = NULL; struct rb_node **p = NULL;
struct rb_node *parent = NULL; struct rb_node *parent = NULL;
int err = 0; int ret = 0;
u64 last_start; u64 last_start;
u64 last_end; u64 last_end;
u32 exclusive_bits = (bits & EXTENT_LOCKED); u32 exclusive_bits = (bits & EXTENT_LOCKED);
...@@ -1122,7 +1122,7 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -1122,7 +1122,7 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
if (state->state & exclusive_bits) { if (state->state & exclusive_bits) {
*failed_start = state->start; *failed_start = state->start;
cache_state(state, failed_state); cache_state(state, failed_state);
err = -EEXIST; ret = -EEXIST;
goto out; goto out;
} }
...@@ -1158,7 +1158,7 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -1158,7 +1158,7 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
if (state->state & exclusive_bits) { if (state->state & exclusive_bits) {
*failed_start = start; *failed_start = start;
cache_state(state, failed_state); cache_state(state, failed_state);
err = -EEXIST; ret = -EEXIST;
goto out; goto out;
} }
...@@ -1175,12 +1175,12 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -1175,12 +1175,12 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
prealloc = alloc_extent_state_atomic(prealloc); prealloc = alloc_extent_state_atomic(prealloc);
if (!prealloc) if (!prealloc)
goto search_again; goto search_again;
err = split_state(tree, state, prealloc, start); ret = split_state(tree, state, prealloc, start);
if (err) if (ret)
extent_io_tree_panic(tree, state, "split", err); extent_io_tree_panic(tree, state, "split", ret);
prealloc = NULL; prealloc = NULL;
if (err) if (ret)
goto out; goto out;
if (state->end <= end) { if (state->end <= end) {
set_state_bits(tree, state, bits, changeset); set_state_bits(tree, state, bits, changeset);
...@@ -1224,8 +1224,8 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -1224,8 +1224,8 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
prealloc->end = this_end; prealloc->end = this_end;
inserted_state = insert_state(tree, prealloc, bits, changeset); inserted_state = insert_state(tree, prealloc, bits, changeset);
if (IS_ERR(inserted_state)) { if (IS_ERR(inserted_state)) {
err = PTR_ERR(inserted_state); ret = PTR_ERR(inserted_state);
extent_io_tree_panic(tree, prealloc, "insert", err); extent_io_tree_panic(tree, prealloc, "insert", ret);
} }
cache_state(inserted_state, cached_state); cache_state(inserted_state, cached_state);
...@@ -1244,16 +1244,16 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -1244,16 +1244,16 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
if (state->state & exclusive_bits) { if (state->state & exclusive_bits) {
*failed_start = start; *failed_start = start;
cache_state(state, failed_state); cache_state(state, failed_state);
err = -EEXIST; ret = -EEXIST;
goto out; goto out;
} }
prealloc = alloc_extent_state_atomic(prealloc); prealloc = alloc_extent_state_atomic(prealloc);
if (!prealloc) if (!prealloc)
goto search_again; goto search_again;
err = split_state(tree, state, prealloc, end + 1); ret = split_state(tree, state, prealloc, end + 1);
if (err) if (ret)
extent_io_tree_panic(tree, state, "split", err); extent_io_tree_panic(tree, state, "split", ret);
set_state_bits(tree, prealloc, bits, changeset); set_state_bits(tree, prealloc, bits, changeset);
cache_state(prealloc, cached_state); cache_state(prealloc, cached_state);
...@@ -1275,7 +1275,7 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -1275,7 +1275,7 @@ static int __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
if (prealloc) if (prealloc)
free_extent_state(prealloc); free_extent_state(prealloc);
return err; return ret;
} }
...@@ -1312,7 +1312,7 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -1312,7 +1312,7 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
struct extent_state *prealloc = NULL; struct extent_state *prealloc = NULL;
struct rb_node **p = NULL; struct rb_node **p = NULL;
struct rb_node *parent = NULL; struct rb_node *parent = NULL;
int err = 0; int ret = 0;
u64 last_start; u64 last_start;
u64 last_end; u64 last_end;
bool first_iteration = true; bool first_iteration = true;
...@@ -1351,7 +1351,7 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -1351,7 +1351,7 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
if (!state) { if (!state) {
prealloc = alloc_extent_state_atomic(prealloc); prealloc = alloc_extent_state_atomic(prealloc);
if (!prealloc) { if (!prealloc) {
err = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
prealloc->start = start; prealloc->start = start;
...@@ -1402,14 +1402,14 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -1402,14 +1402,14 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
if (state->start < start) { if (state->start < start) {
prealloc = alloc_extent_state_atomic(prealloc); prealloc = alloc_extent_state_atomic(prealloc);
if (!prealloc) { if (!prealloc) {
err = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
err = split_state(tree, state, prealloc, start); ret = split_state(tree, state, prealloc, start);
if (err) if (ret)
extent_io_tree_panic(tree, state, "split", err); extent_io_tree_panic(tree, state, "split", ret);
prealloc = NULL; prealloc = NULL;
if (err) if (ret)
goto out; goto out;
if (state->end <= end) { if (state->end <= end) {
set_state_bits(tree, state, bits, NULL); set_state_bits(tree, state, bits, NULL);
...@@ -1442,7 +1442,7 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -1442,7 +1442,7 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
prealloc = alloc_extent_state_atomic(prealloc); prealloc = alloc_extent_state_atomic(prealloc);
if (!prealloc) { if (!prealloc) {
err = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
...@@ -1454,8 +1454,8 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -1454,8 +1454,8 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
prealloc->end = this_end; prealloc->end = this_end;
inserted_state = insert_state(tree, prealloc, bits, NULL); inserted_state = insert_state(tree, prealloc, bits, NULL);
if (IS_ERR(inserted_state)) { if (IS_ERR(inserted_state)) {
err = PTR_ERR(inserted_state); ret = PTR_ERR(inserted_state);
extent_io_tree_panic(tree, prealloc, "insert", err); extent_io_tree_panic(tree, prealloc, "insert", ret);
} }
cache_state(inserted_state, cached_state); cache_state(inserted_state, cached_state);
if (inserted_state == prealloc) if (inserted_state == prealloc)
...@@ -1472,13 +1472,13 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -1472,13 +1472,13 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
if (state->start <= end && state->end > end) { if (state->start <= end && state->end > end) {
prealloc = alloc_extent_state_atomic(prealloc); prealloc = alloc_extent_state_atomic(prealloc);
if (!prealloc) { if (!prealloc) {
err = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
err = split_state(tree, state, prealloc, end + 1); ret = split_state(tree, state, prealloc, end + 1);
if (err) if (ret)
extent_io_tree_panic(tree, state, "split", err); extent_io_tree_panic(tree, state, "split", ret);
set_state_bits(tree, prealloc, bits, NULL); set_state_bits(tree, prealloc, bits, NULL);
cache_state(prealloc, cached_state); cache_state(prealloc, cached_state);
...@@ -1500,7 +1500,7 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, ...@@ -1500,7 +1500,7 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
if (prealloc) if (prealloc)
free_extent_state(prealloc); free_extent_state(prealloc);
return err; return ret;
} }
/* /*
......
This diff is collapsed.
This diff is collapsed.
...@@ -27,6 +27,7 @@ struct address_space; ...@@ -27,6 +27,7 @@ struct address_space;
struct writeback_control; struct writeback_control;
struct extent_io_tree; struct extent_io_tree;
struct extent_map_tree; struct extent_map_tree;
struct extent_state;
struct btrfs_block_group; struct btrfs_block_group;
struct btrfs_fs_info; struct btrfs_fs_info;
struct btrfs_inode; struct btrfs_inode;
...@@ -230,18 +231,17 @@ static inline void extent_changeset_free(struct extent_changeset *changeset) ...@@ -230,18 +231,17 @@ static inline void extent_changeset_free(struct extent_changeset *changeset)
kfree(changeset); kfree(changeset);
} }
int try_release_extent_mapping(struct page *page, gfp_t mask); bool try_release_extent_mapping(struct page *page, gfp_t mask);
int try_release_extent_buffer(struct page *page); int try_release_extent_buffer(struct page *page);
int btrfs_read_folio(struct file *file, struct folio *folio); int btrfs_read_folio(struct file *file, struct folio *folio);
void extent_write_locked_range(struct inode *inode, struct page *locked_page, void extent_write_locked_range(struct inode *inode, struct page *locked_page,
u64 start, u64 end, struct writeback_control *wbc, u64 start, u64 end, struct writeback_control *wbc,
bool pages_dirty); bool pages_dirty);
int extent_writepages(struct address_space *mapping, int btrfs_writepages(struct address_space *mapping, struct writeback_control *wbc);
struct writeback_control *wbc);
int btree_write_cache_pages(struct address_space *mapping, int btree_write_cache_pages(struct address_space *mapping,
struct writeback_control *wbc); struct writeback_control *wbc);
void extent_readahead(struct readahead_control *rac); void btrfs_readahead(struct readahead_control *rac);
int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo, int extent_fiemap(struct btrfs_inode *inode, struct fiemap_extent_info *fieinfo,
u64 start, u64 len); u64 start, u64 len);
int set_folio_extent_mapped(struct folio *folio); int set_folio_extent_mapped(struct folio *folio);
...@@ -353,6 +353,7 @@ void clear_extent_buffer_uptodate(struct extent_buffer *eb); ...@@ -353,6 +353,7 @@ void clear_extent_buffer_uptodate(struct extent_buffer *eb);
void extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end); void extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end);
void extent_clear_unlock_delalloc(struct btrfs_inode *inode, u64 start, u64 end, void extent_clear_unlock_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
struct page *locked_page, struct page *locked_page,
struct extent_state **cached,
u32 bits_to_clear, unsigned long page_ops); u32 bits_to_clear, unsigned long page_ops);
int extent_invalidate_folio(struct extent_io_tree *tree, int extent_invalidate_folio(struct extent_io_tree *tree,
struct folio *folio, size_t offset); struct folio *folio, size_t offset);
...@@ -361,6 +362,8 @@ void btrfs_clear_buffer_dirty(struct btrfs_trans_handle *trans, ...@@ -361,6 +362,8 @@ void btrfs_clear_buffer_dirty(struct btrfs_trans_handle *trans,
int btrfs_alloc_page_array(unsigned int nr_pages, struct page **page_array, int btrfs_alloc_page_array(unsigned int nr_pages, struct page **page_array,
gfp_t extra_gfp); gfp_t extra_gfp);
int btrfs_alloc_folio_array(unsigned int nr_folios, struct folio **folio_array,
gfp_t extra_gfp);
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
bool find_lock_delalloc_range(struct inode *inode, bool find_lock_delalloc_range(struct inode *inode,
......
This diff is collapsed.
...@@ -30,28 +30,77 @@ enum { ...@@ -30,28 +30,77 @@ enum {
ENUM_BIT(EXTENT_FLAG_PREALLOC), ENUM_BIT(EXTENT_FLAG_PREALLOC),
/* Logging this extent */ /* Logging this extent */
ENUM_BIT(EXTENT_FLAG_LOGGING), ENUM_BIT(EXTENT_FLAG_LOGGING),
/* Filling in a preallocated extent */
ENUM_BIT(EXTENT_FLAG_FILLING),
/* This em is merged from two or more physically adjacent ems */ /* This em is merged from two or more physically adjacent ems */
ENUM_BIT(EXTENT_FLAG_MERGED), ENUM_BIT(EXTENT_FLAG_MERGED),
}; };
/* /*
* This structure represents file extents and holes.
*
* Unlike on-disk file extent items, extent maps can be merged to save memory.
* This means members only match file extent items before any merging.
*
* Keep this structure as compact as possible, as we can have really large * Keep this structure as compact as possible, as we can have really large
* amounts of allocated extent maps at any time. * amounts of allocated extent maps at any time.
*/ */
struct extent_map { struct extent_map {
struct rb_node rb_node; struct rb_node rb_node;
/* all of these are in bytes */ /* All of these are in bytes. */
/* File offset matching the offset of a BTRFS_EXTENT_ITEM_KEY key. */
u64 start; u64 start;
/*
* Length of the file extent.
*
* For non-inlined file extents it's btrfs_file_extent_item::num_bytes.
* For inline extents it's sectorsize, since inline data starts at
* offsetof(struct btrfs_file_extent_item, disk_bytenr) thus
* btrfs_file_extent_item::num_bytes is not valid.
*/
u64 len; u64 len;
u64 mod_start;
u64 mod_len; /*
* The file offset of the original file extent before splitting.
*
* This is an in-memory only member, matching
* extent_map::start - btrfs_file_extent_item::offset for
* regular/preallocated extents. EXTENT_MAP_HOLE otherwise.
*/
u64 orig_start; u64 orig_start;
/*
* The full on-disk extent length, matching
* btrfs_file_extent_item::disk_num_bytes.
*/
u64 orig_block_len; u64 orig_block_len;
/*
* The decompressed size of the whole on-disk extent, matching
* btrfs_file_extent_item::ram_bytes.
*/
u64 ram_bytes; u64 ram_bytes;
/*
* The on-disk logical bytenr for the file extent.
*
* For compressed extents it matches btrfs_file_extent_item::disk_bytenr.
* For uncompressed extents it matches
* btrfs_file_extent_item::disk_bytenr + btrfs_file_extent_item::offset
*
* For holes it is EXTENT_MAP_HOLE and for inline extents it is
* EXTENT_MAP_INLINE.
*/
u64 block_start; u64 block_start;
/*
* The on-disk length for the file extent.
*
* For compressed extents it matches btrfs_file_extent_item::disk_num_bytes.
* For uncompressed extents it matches extent_map::len.
* For holes and inline extents it's -1 and shouldn't be used.
*/
u64 block_len; u64 block_len;
/* /*
...@@ -124,7 +173,7 @@ static inline u64 extent_map_end(const struct extent_map *em) ...@@ -124,7 +173,7 @@ static inline u64 extent_map_end(const struct extent_map *em)
void extent_map_tree_init(struct extent_map_tree *tree); void extent_map_tree_init(struct extent_map_tree *tree);
struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree,
u64 start, u64 len); u64 start, u64 len);
void remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em); void remove_extent_mapping(struct btrfs_inode *inode, struct extent_map *em);
int split_extent_map(struct btrfs_inode *inode, u64 start, u64 len, u64 pre, int split_extent_map(struct btrfs_inode *inode, u64 start, u64 len, u64 pre,
u64 new_logical); u64 new_logical);
...@@ -133,11 +182,10 @@ void free_extent_map(struct extent_map *em); ...@@ -133,11 +182,10 @@ void free_extent_map(struct extent_map *em);
int __init extent_map_init(void); int __init extent_map_init(void);
void __cold extent_map_exit(void); void __cold extent_map_exit(void);
int unpin_extent_cache(struct btrfs_inode *inode, u64 start, u64 len, u64 gen); int unpin_extent_cache(struct btrfs_inode *inode, u64 start, u64 len, u64 gen);
void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em); void clear_em_logging(struct btrfs_inode *inode, struct extent_map *em);
struct extent_map *search_extent_mapping(struct extent_map_tree *tree, struct extent_map *search_extent_mapping(struct extent_map_tree *tree,
u64 start, u64 len); u64 start, u64 len);
int btrfs_add_extent_mapping(struct btrfs_fs_info *fs_info, int btrfs_add_extent_mapping(struct btrfs_inode *inode,
struct extent_map_tree *em_tree,
struct extent_map **em_in, u64 start, u64 len); struct extent_map **em_in, u64 start, u64 len);
void btrfs_drop_extent_map_range(struct btrfs_inode *inode, void btrfs_drop_extent_map_range(struct btrfs_inode *inode,
u64 start, u64 end, u64 start, u64 end,
...@@ -145,5 +193,6 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode, ...@@ -145,5 +193,6 @@ void btrfs_drop_extent_map_range(struct btrfs_inode *inode,
int btrfs_replace_extent_map_range(struct btrfs_inode *inode, int btrfs_replace_extent_map_range(struct btrfs_inode *inode,
struct extent_map *new_em, struct extent_map *new_em,
bool modified); bool modified);
long btrfs_free_extent_maps(struct btrfs_fs_info *fs_info, long nr_to_scan);
#endif #endif
...@@ -430,8 +430,7 @@ blk_status_t btrfs_lookup_bio_sums(struct btrfs_bio *bbio) ...@@ -430,8 +430,7 @@ blk_status_t btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
memset(csum_dst, 0, csum_size); memset(csum_dst, 0, csum_size);
count = 1; count = 1;
if (inode->root->root_key.objectid == if (btrfs_root_id(inode->root) == BTRFS_DATA_RELOC_TREE_OBJECTID) {
BTRFS_DATA_RELOC_TREE_OBJECTID) {
u64 file_offset = bbio->file_offset + bio_offset; u64 file_offset = bbio->file_offset + bio_offset;
set_extent_bit(&inode->io_tree, file_offset, set_extent_bit(&inode->io_tree, file_offset,
...@@ -450,9 +449,22 @@ blk_status_t btrfs_lookup_bio_sums(struct btrfs_bio *bbio) ...@@ -450,9 +449,22 @@ blk_status_t btrfs_lookup_bio_sums(struct btrfs_bio *bbio)
return ret; return ret;
} }
/*
* Search for checksums for a given logical range.
*
* @root: The root where to look for checksums.
* @start: Logical address of target checksum range.
* @end: End offset (inclusive) of the target checksum range.
* @list: List for adding each checksum that was found.
* Can be NULL in case the caller only wants to check if
* there any checksums for the range.
* @nowait: Indicate if the search must be non-blocking or not.
*
* Return < 0 on error, 0 if no checksums were found, or 1 if checksums were
* found.
*/
int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end, int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end,
struct list_head *list, int search_commit, struct list_head *list, bool nowait)
bool nowait)
{ {
struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_key key; struct btrfs_key key;
...@@ -460,8 +472,8 @@ int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end, ...@@ -460,8 +472,8 @@ int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end,
struct extent_buffer *leaf; struct extent_buffer *leaf;
struct btrfs_ordered_sum *sums; struct btrfs_ordered_sum *sums;
struct btrfs_csum_item *item; struct btrfs_csum_item *item;
LIST_HEAD(tmplist);
int ret; int ret;
bool found_csums = false;
ASSERT(IS_ALIGNED(start, fs_info->sectorsize) && ASSERT(IS_ALIGNED(start, fs_info->sectorsize) &&
IS_ALIGNED(end + 1, fs_info->sectorsize)); IS_ALIGNED(end + 1, fs_info->sectorsize));
...@@ -471,11 +483,6 @@ int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end, ...@@ -471,11 +483,6 @@ int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end,
return -ENOMEM; return -ENOMEM;
path->nowait = nowait; path->nowait = nowait;
if (search_commit) {
path->skip_locking = 1;
path->reada = READA_FORWARD;
path->search_commit_root = 1;
}
key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; key.objectid = BTRFS_EXTENT_CSUM_OBJECTID;
key.offset = start; key.offset = start;
...@@ -483,7 +490,7 @@ int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end, ...@@ -483,7 +490,7 @@ int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end,
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0) if (ret < 0)
goto fail; goto out;
if (ret > 0 && path->slots[0] > 0) { if (ret > 0 && path->slots[0] > 0) {
leaf = path->nodes[0]; leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1); btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1);
...@@ -518,7 +525,7 @@ int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end, ...@@ -518,7 +525,7 @@ int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end,
if (path->slots[0] >= btrfs_header_nritems(leaf)) { if (path->slots[0] >= btrfs_header_nritems(leaf)) {
ret = btrfs_next_leaf(root, path); ret = btrfs_next_leaf(root, path);
if (ret < 0) if (ret < 0)
goto fail; goto out;
if (ret > 0) if (ret > 0)
break; break;
leaf = path->nodes[0]; leaf = path->nodes[0];
...@@ -540,6 +547,10 @@ int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end, ...@@ -540,6 +547,10 @@ int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end,
continue; continue;
} }
found_csums = true;
if (!list)
goto out;
csum_end = min(csum_end, end + 1); csum_end = min(csum_end, end + 1);
item = btrfs_item_ptr(path->nodes[0], path->slots[0], item = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_csum_item); struct btrfs_csum_item);
...@@ -553,7 +564,7 @@ int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end, ...@@ -553,7 +564,7 @@ int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end,
GFP_NOFS); GFP_NOFS);
if (!sums) { if (!sums) {
ret = -ENOMEM; ret = -ENOMEM;
goto fail; goto out;
} }
sums->logical = start; sums->logical = start;
...@@ -567,21 +578,24 @@ int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end, ...@@ -567,21 +578,24 @@ int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end,
bytes_to_csum_size(fs_info, size)); bytes_to_csum_size(fs_info, size));
start += size; start += size;
list_add_tail(&sums->list, &tmplist); list_add_tail(&sums->list, list);
} }
path->slots[0]++; path->slots[0]++;
} }
ret = 0; out:
fail: btrfs_free_path(path);
while (ret < 0 && !list_empty(&tmplist)) { if (ret < 0) {
sums = list_entry(tmplist.next, struct btrfs_ordered_sum, list); if (list) {
list_del(&sums->list); struct btrfs_ordered_sum *tmp_sums;
kfree(sums);
list_for_each_entry_safe(sums, tmp_sums, list, list)
kfree(sums);
}
return ret;
} }
list_splice_tail(&tmplist, list);
btrfs_free_path(path); return found_csums ? 1 : 0;
return ret;
} }
/* /*
...@@ -870,8 +884,8 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans, ...@@ -870,8 +884,8 @@ int btrfs_del_csums(struct btrfs_trans_handle *trans,
const u32 csum_size = fs_info->csum_size; const u32 csum_size = fs_info->csum_size;
u32 blocksize_bits = fs_info->sectorsize_bits; u32 blocksize_bits = fs_info->sectorsize_bits;
ASSERT(root->root_key.objectid == BTRFS_CSUM_TREE_OBJECTID || ASSERT(btrfs_root_id(root) == BTRFS_CSUM_TREE_OBJECTID ||
root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID); btrfs_root_id(root) == BTRFS_TREE_LOG_OBJECTID);
path = btrfs_alloc_path(); path = btrfs_alloc_path();
if (!path) if (!path)
...@@ -1171,7 +1185,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, ...@@ -1171,7 +1185,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
* search, etc, because log trees are temporary anyway and it * search, etc, because log trees are temporary anyway and it
* would only save a few bytes of leaf space. * would only save a few bytes of leaf space.
*/ */
if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) { if (btrfs_root_id(root) == BTRFS_TREE_LOG_OBJECTID) {
if (path->slots[0] + 1 >= if (path->slots[0] + 1 >=
btrfs_header_nritems(path->nodes[0])) { btrfs_header_nritems(path->nodes[0])) {
ret = find_next_csum_offset(root, path, &next_offset); ret = find_next_csum_offset(root, path, &next_offset);
...@@ -1265,20 +1279,19 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode, ...@@ -1265,20 +1279,19 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
struct extent_buffer *leaf = path->nodes[0]; struct extent_buffer *leaf = path->nodes[0];
const int slot = path->slots[0]; const int slot = path->slots[0];
struct btrfs_key key; struct btrfs_key key;
u64 extent_start, extent_end; u64 extent_start;
u64 bytenr; u64 bytenr;
u8 type = btrfs_file_extent_type(leaf, fi); u8 type = btrfs_file_extent_type(leaf, fi);
int compress_type = btrfs_file_extent_compression(leaf, fi); int compress_type = btrfs_file_extent_compression(leaf, fi);
btrfs_item_key_to_cpu(leaf, &key, slot); btrfs_item_key_to_cpu(leaf, &key, slot);
extent_start = key.offset; extent_start = key.offset;
extent_end = btrfs_file_extent_end(path);
em->ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi); em->ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi);
em->generation = btrfs_file_extent_generation(leaf, fi); em->generation = btrfs_file_extent_generation(leaf, fi);
if (type == BTRFS_FILE_EXTENT_REG || if (type == BTRFS_FILE_EXTENT_REG ||
type == BTRFS_FILE_EXTENT_PREALLOC) { type == BTRFS_FILE_EXTENT_PREALLOC) {
em->start = extent_start; em->start = extent_start;
em->len = extent_end - extent_start; em->len = btrfs_file_extent_end(path) - extent_start;
em->orig_start = extent_start - em->orig_start = extent_start -
btrfs_file_extent_offset(leaf, fi); btrfs_file_extent_offset(leaf, fi);
em->orig_block_len = btrfs_file_extent_disk_num_bytes(leaf, fi); em->orig_block_len = btrfs_file_extent_disk_num_bytes(leaf, fi);
...@@ -1299,9 +1312,12 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode, ...@@ -1299,9 +1312,12 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
em->flags |= EXTENT_FLAG_PREALLOC; em->flags |= EXTENT_FLAG_PREALLOC;
} }
} else if (type == BTRFS_FILE_EXTENT_INLINE) { } else if (type == BTRFS_FILE_EXTENT_INLINE) {
/* Tree-checker has ensured this. */
ASSERT(extent_start == 0);
em->block_start = EXTENT_MAP_INLINE; em->block_start = EXTENT_MAP_INLINE;
em->start = extent_start; em->start = 0;
em->len = extent_end - extent_start; em->len = fs_info->sectorsize;
/* /*
* Initialize orig_start and block_len with the same values * Initialize orig_start and block_len with the same values
* as in inode.c:btrfs_get_extent(). * as in inode.c:btrfs_get_extent().
...@@ -1313,7 +1329,7 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode, ...@@ -1313,7 +1329,7 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,
btrfs_err(fs_info, btrfs_err(fs_info,
"unknown file extent item type %d, inode %llu, offset %llu, " "unknown file extent item type %d, inode %llu, offset %llu, "
"root %llu", type, btrfs_ino(inode), extent_start, "root %llu", type, btrfs_ino(inode), extent_start,
root->root_key.objectid); btrfs_root_id(root));
} }
} }
...@@ -1334,12 +1350,10 @@ u64 btrfs_file_extent_end(const struct btrfs_path *path) ...@@ -1334,12 +1350,10 @@ u64 btrfs_file_extent_end(const struct btrfs_path *path)
ASSERT(key.type == BTRFS_EXTENT_DATA_KEY); ASSERT(key.type == BTRFS_EXTENT_DATA_KEY);
fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE) { if (btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_INLINE)
end = btrfs_file_extent_ram_bytes(leaf, fi); end = leaf->fs_info->sectorsize;
end = ALIGN(key.offset + end, leaf->fs_info->sectorsize); else
} else {
end = key.offset + btrfs_file_extent_num_bytes(leaf, fi); end = key.offset + btrfs_file_extent_num_bytes(leaf, fi);
}
return end; return end;
} }
...@@ -68,8 +68,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, ...@@ -68,8 +68,7 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
struct list_head *list, int search_commit, struct list_head *list, int search_commit,
bool nowait); bool nowait);
int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end, int btrfs_lookup_csums_list(struct btrfs_root *root, u64 start, u64 end,
struct list_head *list, int search_commit, struct list_head *list, bool nowait);
bool nowait);
int btrfs_lookup_csums_bitmap(struct btrfs_root *root, struct btrfs_path *path, int btrfs_lookup_csums_bitmap(struct btrfs_root *root, struct btrfs_path *path,
u64 start, u64 end, u8 *csum_buf, u64 start, u64 end, u8 *csum_buf,
unsigned long *csum_bitmap); unsigned long *csum_bitmap);
......
This diff is collapsed.
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/math.h> #include <linux/math.h>
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/blkdev.h>
#include <linux/percpu_counter.h> #include <linux/percpu_counter.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/lockdep.h> #include <linux/lockdep.h>
...@@ -630,6 +629,10 @@ struct btrfs_fs_info { ...@@ -630,6 +629,10 @@ struct btrfs_fs_info {
s32 dirty_metadata_batch; s32 dirty_metadata_batch;
s32 delalloc_batch; s32 delalloc_batch;
struct percpu_counter evictable_extent_maps;
u64 extent_map_shrinker_last_root;
u64 extent_map_shrinker_last_ino;
/* Protected by 'trans_lock'. */ /* Protected by 'trans_lock'. */
struct list_head dirty_cowonly_roots; struct list_head dirty_cowonly_roots;
......
...@@ -670,16 +670,18 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, ...@@ -670,16 +670,18 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
} }
if (del_item && extent_start != 0 && !control->skip_ref_updates) { if (del_item && extent_start != 0 && !control->skip_ref_updates) {
struct btrfs_ref ref = { 0 }; struct btrfs_ref ref = {
.action = BTRFS_DROP_DELAYED_REF,
.bytenr = extent_start,
.num_bytes = extent_num_bytes,
.owning_root = btrfs_root_id(root),
.ref_root = btrfs_header_owner(leaf),
};
bytes_deleted += extent_num_bytes; bytes_deleted += extent_num_bytes;
btrfs_init_generic_ref(&ref, BTRFS_DROP_DELAYED_REF, btrfs_init_data_ref(&ref, control->ino, extent_offset,
extent_start, extent_num_bytes, 0, btrfs_root_id(root), false);
root->root_key.objectid);
btrfs_init_data_ref(&ref, btrfs_header_owner(leaf),
control->ino, extent_offset,
root->root_key.objectid, false);
ret = btrfs_free_extent(trans, &ref); ret = btrfs_free_extent(trans, &ref);
if (ret) { if (ret) {
btrfs_abort_transaction(trans, ret); btrfs_abort_transaction(trans, ret);
......
This diff is collapsed.
...@@ -668,7 +668,7 @@ static noinline int create_subvol(struct mnt_idmap *idmap, ...@@ -668,7 +668,7 @@ static noinline int create_subvol(struct mnt_idmap *idmap,
/* Tree log can't currently deal with an inode which is a new root. */ /* Tree log can't currently deal with an inode which is a new root. */
btrfs_set_log_full_commit(trans); btrfs_set_log_full_commit(trans);
ret = btrfs_qgroup_inherit(trans, 0, objectid, root->root_key.objectid, inherit); ret = btrfs_qgroup_inherit(trans, 0, objectid, btrfs_root_id(root), inherit);
if (ret) if (ret)
goto out; goto out;
...@@ -1510,7 +1510,7 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file, ...@@ -1510,7 +1510,7 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
spin_unlock(&root->root_item_lock); spin_unlock(&root->root_item_lock);
btrfs_warn(fs_info, btrfs_warn(fs_info,
"Attempt to set subvolume %llu read-write during send", "Attempt to set subvolume %llu read-write during send",
root->root_key.objectid); btrfs_root_id(root));
ret = -EPERM; ret = -EPERM;
goto out_drop_sem; goto out_drop_sem;
} }
...@@ -1919,7 +1919,7 @@ static int btrfs_search_path_in_tree_user(struct mnt_idmap *idmap, ...@@ -1919,7 +1919,7 @@ static int btrfs_search_path_in_tree_user(struct mnt_idmap *idmap,
struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct btrfs_key upper_limit = BTRFS_I(inode)->location; struct btrfs_key upper_limit = BTRFS_I(inode)->location;
u64 treeid = BTRFS_I(inode)->root->root_key.objectid; u64 treeid = btrfs_root_id(BTRFS_I(inode)->root);
u64 dirid = args->dirid; u64 dirid = args->dirid;
unsigned long item_off; unsigned long item_off;
unsigned long item_len; unsigned long item_len;
...@@ -2091,7 +2091,7 @@ static noinline int btrfs_ioctl_ino_lookup(struct btrfs_root *root, ...@@ -2091,7 +2091,7 @@ static noinline int btrfs_ioctl_ino_lookup(struct btrfs_root *root,
* path is reset so it's consistent with btrfs_search_path_in_tree. * path is reset so it's consistent with btrfs_search_path_in_tree.
*/ */
if (args->treeid == 0) if (args->treeid == 0)
args->treeid = root->root_key.objectid; args->treeid = btrfs_root_id(root);
if (args->objectid == BTRFS_FIRST_FREE_OBJECTID) { if (args->objectid == BTRFS_FIRST_FREE_OBJECTID) {
args->name[0] = 0; args->name[0] = 0;
...@@ -2187,7 +2187,7 @@ static int btrfs_ioctl_get_subvol_info(struct inode *inode, void __user *argp) ...@@ -2187,7 +2187,7 @@ static int btrfs_ioctl_get_subvol_info(struct inode *inode, void __user *argp)
fs_info = BTRFS_I(inode)->root->fs_info; fs_info = BTRFS_I(inode)->root->fs_info;
/* Get root_item of inode's subvolume */ /* Get root_item of inode's subvolume */
key.objectid = BTRFS_I(inode)->root->root_key.objectid; key.objectid = btrfs_root_id(BTRFS_I(inode)->root);
root = btrfs_get_fs_root(fs_info, key.objectid, true); root = btrfs_get_fs_root(fs_info, key.objectid, true);
if (IS_ERR(root)) { if (IS_ERR(root)) {
ret = PTR_ERR(root); ret = PTR_ERR(root);
...@@ -2302,7 +2302,7 @@ static int btrfs_ioctl_get_subvol_rootref(struct btrfs_root *root, ...@@ -2302,7 +2302,7 @@ static int btrfs_ioctl_get_subvol_rootref(struct btrfs_root *root,
return PTR_ERR(rootrefs); return PTR_ERR(rootrefs);
} }
objectid = root->root_key.objectid; objectid = btrfs_root_id(root);
key.objectid = objectid; key.objectid = objectid;
key.type = BTRFS_ROOT_REF_KEY; key.type = BTRFS_ROOT_REF_KEY;
key.offset = rootrefs->min_treeid; key.offset = rootrefs->min_treeid;
...@@ -2386,7 +2386,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, ...@@ -2386,7 +2386,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
struct mnt_idmap *idmap = file_mnt_idmap(file); struct mnt_idmap *idmap = file_mnt_idmap(file);
char *subvol_name, *subvol_name_ptr = NULL; char *subvol_name, *subvol_name_ptr = NULL;
int subvol_namelen; int subvol_namelen;
int err = 0; int ret = 0;
bool destroy_parent = false; bool destroy_parent = false;
/* We don't support snapshots with extent tree v2 yet. */ /* We don't support snapshots with extent tree v2 yet. */
...@@ -2402,7 +2402,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, ...@@ -2402,7 +2402,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
return PTR_ERR(vol_args2); return PTR_ERR(vol_args2);
if (vol_args2->flags & ~BTRFS_SUBVOL_DELETE_ARGS_MASK) { if (vol_args2->flags & ~BTRFS_SUBVOL_DELETE_ARGS_MASK) {
err = -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto out; goto out;
} }
...@@ -2411,31 +2411,31 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, ...@@ -2411,31 +2411,31 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
* name, same as v1 currently does. * name, same as v1 currently does.
*/ */
if (!(vol_args2->flags & BTRFS_SUBVOL_SPEC_BY_ID)) { if (!(vol_args2->flags & BTRFS_SUBVOL_SPEC_BY_ID)) {
err = btrfs_check_ioctl_vol_args2_subvol_name(vol_args2); ret = btrfs_check_ioctl_vol_args2_subvol_name(vol_args2);
if (err < 0) if (ret < 0)
goto out; goto out;
subvol_name = vol_args2->name; subvol_name = vol_args2->name;
err = mnt_want_write_file(file); ret = mnt_want_write_file(file);
if (err) if (ret)
goto out; goto out;
} else { } else {
struct inode *old_dir; struct inode *old_dir;
if (vol_args2->subvolid < BTRFS_FIRST_FREE_OBJECTID) { if (vol_args2->subvolid < BTRFS_FIRST_FREE_OBJECTID) {
err = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
err = mnt_want_write_file(file); ret = mnt_want_write_file(file);
if (err) if (ret)
goto out; goto out;
dentry = btrfs_get_dentry(fs_info->sb, dentry = btrfs_get_dentry(fs_info->sb,
BTRFS_FIRST_FREE_OBJECTID, BTRFS_FIRST_FREE_OBJECTID,
vol_args2->subvolid, 0); vol_args2->subvolid, 0);
if (IS_ERR(dentry)) { if (IS_ERR(dentry)) {
err = PTR_ERR(dentry); ret = PTR_ERR(dentry);
goto out_drop_write; goto out_drop_write;
} }
...@@ -2455,7 +2455,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, ...@@ -2455,7 +2455,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
*/ */
dput(dentry); dput(dentry);
if (IS_ERR(parent)) { if (IS_ERR(parent)) {
err = PTR_ERR(parent); ret = PTR_ERR(parent);
goto out_drop_write; goto out_drop_write;
} }
old_dir = dir; old_dir = dir;
...@@ -2479,14 +2479,14 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, ...@@ -2479,14 +2479,14 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
* to delete without an idmapped mount. * to delete without an idmapped mount.
*/ */
if (old_dir != dir && idmap != &nop_mnt_idmap) { if (old_dir != dir && idmap != &nop_mnt_idmap) {
err = -EOPNOTSUPP; ret = -EOPNOTSUPP;
goto free_parent; goto free_parent;
} }
subvol_name_ptr = btrfs_get_subvol_name_from_objectid( subvol_name_ptr = btrfs_get_subvol_name_from_objectid(
fs_info, vol_args2->subvolid); fs_info, vol_args2->subvolid);
if (IS_ERR(subvol_name_ptr)) { if (IS_ERR(subvol_name_ptr)) {
err = PTR_ERR(subvol_name_ptr); ret = PTR_ERR(subvol_name_ptr);
goto free_parent; goto free_parent;
} }
/* subvol_name_ptr is already nul terminated */ /* subvol_name_ptr is already nul terminated */
...@@ -2497,14 +2497,14 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, ...@@ -2497,14 +2497,14 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
if (IS_ERR(vol_args)) if (IS_ERR(vol_args))
return PTR_ERR(vol_args); return PTR_ERR(vol_args);
err = btrfs_check_ioctl_vol_args_path(vol_args); ret = btrfs_check_ioctl_vol_args_path(vol_args);
if (err < 0) if (ret < 0)
goto out; goto out;
subvol_name = vol_args->name; subvol_name = vol_args->name;
err = mnt_want_write_file(file); ret = mnt_want_write_file(file);
if (err) if (ret)
goto out; goto out;
} }
...@@ -2512,26 +2512,26 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, ...@@ -2512,26 +2512,26 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
if (strchr(subvol_name, '/') || if (strchr(subvol_name, '/') ||
strncmp(subvol_name, "..", subvol_namelen) == 0) { strncmp(subvol_name, "..", subvol_namelen) == 0) {
err = -EINVAL; ret = -EINVAL;
goto free_subvol_name; goto free_subvol_name;
} }
if (!S_ISDIR(dir->i_mode)) { if (!S_ISDIR(dir->i_mode)) {
err = -ENOTDIR; ret = -ENOTDIR;
goto free_subvol_name; goto free_subvol_name;
} }
err = down_write_killable_nested(&dir->i_rwsem, I_MUTEX_PARENT); ret = down_write_killable_nested(&dir->i_rwsem, I_MUTEX_PARENT);
if (err == -EINTR) if (ret == -EINTR)
goto free_subvol_name; goto free_subvol_name;
dentry = lookup_one(idmap, subvol_name, parent, subvol_namelen); dentry = lookup_one(idmap, subvol_name, parent, subvol_namelen);
if (IS_ERR(dentry)) { if (IS_ERR(dentry)) {
err = PTR_ERR(dentry); ret = PTR_ERR(dentry);
goto out_unlock_dir; goto out_unlock_dir;
} }
if (d_really_is_negative(dentry)) { if (d_really_is_negative(dentry)) {
err = -ENOENT; ret = -ENOENT;
goto out_dput; goto out_dput;
} }
...@@ -2551,7 +2551,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, ...@@ -2551,7 +2551,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
* Users who want to delete empty subvols should try * Users who want to delete empty subvols should try
* rmdir(2). * rmdir(2).
*/ */
err = -EPERM; ret = -EPERM;
if (!btrfs_test_opt(fs_info, USER_SUBVOL_RM_ALLOWED)) if (!btrfs_test_opt(fs_info, USER_SUBVOL_RM_ALLOWED))
goto out_dput; goto out_dput;
...@@ -2562,29 +2562,29 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, ...@@ -2562,29 +2562,29 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
* of the subvol, not a random directory contained * of the subvol, not a random directory contained
* within it. * within it.
*/ */
err = -EINVAL; ret = -EINVAL;
if (root == dest) if (root == dest)
goto out_dput; goto out_dput;
err = inode_permission(idmap, inode, MAY_WRITE | MAY_EXEC); ret = inode_permission(idmap, inode, MAY_WRITE | MAY_EXEC);
if (err) if (ret)
goto out_dput; goto out_dput;
} }
/* check if subvolume may be deleted by a user */ /* check if subvolume may be deleted by a user */
err = btrfs_may_delete(idmap, dir, dentry, 1); ret = btrfs_may_delete(idmap, dir, dentry, 1);
if (err) if (ret)
goto out_dput; goto out_dput;
if (btrfs_ino(BTRFS_I(inode)) != BTRFS_FIRST_FREE_OBJECTID) { if (btrfs_ino(BTRFS_I(inode)) != BTRFS_FIRST_FREE_OBJECTID) {
err = -EINVAL; ret = -EINVAL;
goto out_dput; goto out_dput;
} }
btrfs_inode_lock(BTRFS_I(inode), 0); btrfs_inode_lock(BTRFS_I(inode), 0);
err = btrfs_delete_subvolume(BTRFS_I(dir), dentry); ret = btrfs_delete_subvolume(BTRFS_I(dir), dentry);
btrfs_inode_unlock(BTRFS_I(inode), 0); btrfs_inode_unlock(BTRFS_I(inode), 0);
if (!err) if (!ret)
d_delete_notify(dir, dentry); d_delete_notify(dir, dentry);
out_dput: out_dput:
...@@ -2601,7 +2601,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, ...@@ -2601,7 +2601,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
out: out:
kfree(vol_args2); kfree(vol_args2);
kfree(vol_args); kfree(vol_args);
return err; return ret;
} }
static int btrfs_ioctl_defrag(struct file *file, void __user *argp) static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
...@@ -2981,7 +2981,7 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) ...@@ -2981,7 +2981,7 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
ret = PTR_ERR(new_root); ret = PTR_ERR(new_root);
goto out; goto out;
} }
if (!is_fstree(new_root->root_key.objectid)) { if (!is_fstree(btrfs_root_id(new_root))) {
ret = -ENOENT; ret = -ENOENT;
goto out_free; goto out_free;
} }
...@@ -3947,7 +3947,7 @@ static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg) ...@@ -3947,7 +3947,7 @@ static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg)
qgroupid = sa->qgroupid; qgroupid = sa->qgroupid;
if (!qgroupid) { if (!qgroupid) {
/* take the current subvol as qgroup */ /* take the current subvol as qgroup */
qgroupid = root->root_key.objectid; qgroupid = btrfs_root_id(root);
} }
ret = btrfs_limit_qgroup(trans, qgroupid, &sa->lim); ret = btrfs_limit_qgroup(trans, qgroupid, &sa->lim);
...@@ -4078,7 +4078,7 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file, ...@@ -4078,7 +4078,7 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
!btrfs_is_empty_uuid(root_item->received_uuid)) { !btrfs_is_empty_uuid(root_item->received_uuid)) {
ret = btrfs_uuid_tree_remove(trans, root_item->received_uuid, ret = btrfs_uuid_tree_remove(trans, root_item->received_uuid,
BTRFS_UUID_KEY_RECEIVED_SUBVOL, BTRFS_UUID_KEY_RECEIVED_SUBVOL,
root->root_key.objectid); btrfs_root_id(root));
if (ret && ret != -ENOENT) { if (ret && ret != -ENOENT) {
btrfs_abort_transaction(trans, ret); btrfs_abort_transaction(trans, ret);
btrfs_end_transaction(trans); btrfs_end_transaction(trans);
...@@ -4102,7 +4102,7 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file, ...@@ -4102,7 +4102,7 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
if (received_uuid_changed && !btrfs_is_empty_uuid(sa->uuid)) { if (received_uuid_changed && !btrfs_is_empty_uuid(sa->uuid)) {
ret = btrfs_uuid_tree_add(trans, sa->uuid, ret = btrfs_uuid_tree_add(trans, sa->uuid,
BTRFS_UUID_KEY_RECEIVED_SUBVOL, BTRFS_UUID_KEY_RECEIVED_SUBVOL,
root->root_key.objectid); btrfs_root_id(root));
if (ret < 0 && ret != -EEXIST) { if (ret < 0 && ret != -EEXIST) {
btrfs_abort_transaction(trans, ret); btrfs_abort_transaction(trans, ret);
btrfs_end_transaction(trans); btrfs_end_transaction(trans);
......
...@@ -97,7 +97,7 @@ void btrfs_set_buffer_lockdep_class(u64 objectid, struct extent_buffer *eb, int ...@@ -97,7 +97,7 @@ void btrfs_set_buffer_lockdep_class(u64 objectid, struct extent_buffer *eb, int
void btrfs_maybe_reset_lockdep_class(struct btrfs_root *root, struct extent_buffer *eb) void btrfs_maybe_reset_lockdep_class(struct btrfs_root *root, struct extent_buffer *eb)
{ {
if (test_bit(BTRFS_ROOT_RESET_LOCKDEP_CLASS, &root->state)) if (test_bit(BTRFS_ROOT_RESET_LOCKDEP_CLASS, &root->state))
btrfs_set_buffer_lockdep_class(root->root_key.objectid, btrfs_set_buffer_lockdep_class(btrfs_root_id(root),
eb, btrfs_header_level(eb)); eb, btrfs_header_level(eb));
} }
...@@ -129,14 +129,14 @@ static void btrfs_set_eb_lock_owner(struct extent_buffer *eb, pid_t owner) { } ...@@ -129,14 +129,14 @@ static void btrfs_set_eb_lock_owner(struct extent_buffer *eb, pid_t owner) { }
*/ */
/* /*
* __btrfs_tree_read_lock - lock extent buffer for read * btrfs_tree_read_lock_nested - lock extent buffer for read
* @eb: the eb to be locked * @eb: the eb to be locked
* @nest: the nesting level to be used for lockdep * @nest: the nesting level to be used for lockdep
* *
* This takes the read lock on the extent buffer, using the specified nesting * This takes the read lock on the extent buffer, using the specified nesting
* level for lockdep purposes. * level for lockdep purposes.
*/ */
void __btrfs_tree_read_lock(struct extent_buffer *eb, enum btrfs_lock_nesting nest) void btrfs_tree_read_lock_nested(struct extent_buffer *eb, enum btrfs_lock_nesting nest)
{ {
u64 start_ns = 0; u64 start_ns = 0;
...@@ -147,11 +147,6 @@ void __btrfs_tree_read_lock(struct extent_buffer *eb, enum btrfs_lock_nesting ne ...@@ -147,11 +147,6 @@ void __btrfs_tree_read_lock(struct extent_buffer *eb, enum btrfs_lock_nesting ne
trace_btrfs_tree_read_lock(eb, start_ns); trace_btrfs_tree_read_lock(eb, start_ns);
} }
void btrfs_tree_read_lock(struct extent_buffer *eb)
{
__btrfs_tree_read_lock(eb, BTRFS_NESTING_NORMAL);
}
/* /*
* Try-lock for read. * Try-lock for read.
* *
...@@ -198,7 +193,7 @@ void btrfs_tree_read_unlock(struct extent_buffer *eb) ...@@ -198,7 +193,7 @@ void btrfs_tree_read_unlock(struct extent_buffer *eb)
* *
* Returns with the eb->lock write locked. * Returns with the eb->lock write locked.
*/ */
void __btrfs_tree_lock(struct extent_buffer *eb, enum btrfs_lock_nesting nest) void btrfs_tree_lock_nested(struct extent_buffer *eb, enum btrfs_lock_nesting nest)
__acquires(&eb->lock) __acquires(&eb->lock)
{ {
u64 start_ns = 0; u64 start_ns = 0;
...@@ -211,11 +206,6 @@ void __btrfs_tree_lock(struct extent_buffer *eb, enum btrfs_lock_nesting nest) ...@@ -211,11 +206,6 @@ void __btrfs_tree_lock(struct extent_buffer *eb, enum btrfs_lock_nesting nest)
trace_btrfs_tree_lock(eb, start_ns); trace_btrfs_tree_lock(eb, start_ns);
} }
void btrfs_tree_lock(struct extent_buffer *eb)
{
__btrfs_tree_lock(eb, BTRFS_NESTING_NORMAL);
}
/* /*
* Release the write lock. * Release the write lock.
*/ */
...@@ -374,8 +364,12 @@ void btrfs_drew_write_lock(struct btrfs_drew_lock *lock) ...@@ -374,8 +364,12 @@ void btrfs_drew_write_lock(struct btrfs_drew_lock *lock)
void btrfs_drew_write_unlock(struct btrfs_drew_lock *lock) void btrfs_drew_write_unlock(struct btrfs_drew_lock *lock)
{ {
atomic_dec(&lock->writers); /*
cond_wake_up(&lock->pending_readers); * atomic_dec_and_test() implies a full barrier, so woken up readers are
* guaranteed to see the decrement.
*/
if (atomic_dec_and_test(&lock->writers))
wake_up(&lock->pending_readers);
} }
void btrfs_drew_read_lock(struct btrfs_drew_lock *lock) void btrfs_drew_read_lock(struct btrfs_drew_lock *lock)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -203,6 +203,7 @@ bool btrfs_try_lock_ordered_range(struct btrfs_inode *inode, u64 start, u64 end, ...@@ -203,6 +203,7 @@ bool btrfs_try_lock_ordered_range(struct btrfs_inode *inode, u64 start, u64 end,
struct extent_state **cached_state); struct extent_state **cached_state);
struct btrfs_ordered_extent *btrfs_split_ordered_extent( struct btrfs_ordered_extent *btrfs_split_ordered_extent(
struct btrfs_ordered_extent *ordered, u64 len); struct btrfs_ordered_extent *ordered, u64 len);
void btrfs_mark_ordered_extent_error(struct btrfs_ordered_extent *ordered);
int __init ordered_data_init(void); int __init ordered_data_init(void);
void __cold ordered_data_exit(void); void __cold ordered_data_exit(void);
......
...@@ -268,7 +268,7 @@ static void inode_prop_iterator(void *ctx, ...@@ -268,7 +268,7 @@ static void inode_prop_iterator(void *ctx,
btrfs_warn(root->fs_info, btrfs_warn(root->fs_info,
"error applying prop %s to ino %llu (root %llu): %d", "error applying prop %s to ino %llu (root %llu): %d",
handler->xattr_name, btrfs_ino(BTRFS_I(inode)), handler->xattr_name, btrfs_ino(BTRFS_I(inode)),
root->root_key.objectid, ret); btrfs_root_id(root), ret);
else else
set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags); set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment