Btrfs: New inode number allocator
cover Btrfs: New inode number allocator
Currently btrfs stores the highest objectid of the fs tree, and it always returns (highest+1) inode number when we create a file, so inode numbers won't be reclaimed when we delete files, so we'll run out of inode numbers as we keep create/delete files in 32bit machines.
This patchset aims to fix this, and it works similar to free space caching for block groups.
I've run xfstests, and I also tested it with snapshot, balance etc.
The patchset is also available in:
git://repo.or.cz/linux-btrfs-devel.git ino-alloc
--- fs/btrfs/btrfs_inode.h | 9 + fs/btrfs/compression.c | 5 +- fs/btrfs/ctree.h | 29 +- fs/btrfs/disk-io.c | 19 + fs/btrfs/export.c | 25 +- fs/btrfs/extent-tree.c | 50 ++-- fs/btrfs/extent_io.c | 4 +- fs/btrfs/file-item.c | 5 +- fs/btrfs/file.c | 27 +- fs/btrfs/free-space-cache.c | 873 ++++++++++++++++++++++++++----------------- fs/btrfs/free-space-cache.h | 48 +++- fs/btrfs/inode-map.c | 428 +++++++++++++++++++++- fs/btrfs/inode-map.h | 13 + fs/btrfs/inode.c | 282 ++++++++------ fs/btrfs/ioctl.c | 22 +- fs/btrfs/relocation.c | 27 +- fs/btrfs/transaction.c | 13 +- fs/btrfs/tree-log.c | 58 ++-- fs/btrfs/xattr.c | 8 +- 19 files changed, 1352 insertions(+), 593 deletions(-)
PATCH 1/7 Btrfs: Remove unused btrfs_block_group_free_space()
--- fs/btrfs/free-space-cache.c | 15 --------------- fs/btrfs/free-space-cache.h | 1 - 2 files changed, 0 insertions(+), 16 deletions(-)
fs/btrfs/free-space-cache.c +0 -15
@@ -1601,21 +1601,6 @@ void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group, "\n", count); } -u64 btrfs_block_group_free_space (struct btrfs_block_group_cache *block_group) -{ -struct btrfs_free_space *info; -struct rb_node *n; -u64 ret =0 ; - -for (n =rb_first (&block_group->free_space_offset); n; - n =rb_next (n)) { - info = rb_entry(n, struct btrfs_free_space, offset_index); - ret += info->bytes; - } - -return ret; -} -/* * for a given cluster, put all of its extents back into the free * space cache. If the block group passed doesn't match the block group
fs/btrfs/free-space-cache.h +0 -1
@@ -55,7 +55,6 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group, u64 offset, u64 bytes, u64 empty_size);void btrfs_dump_free_space (struct btrfs_block_group_cache *block_group,u64 bytes); -u64 btrfs_block_group_free_space (struct btrfs_block_group_cache *block_group); int btrfs_find_space_cluster(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_block_group_cache *block_group,
Signature · 1 line
1.7.3.1
PATCH 2/7 Btrfs: Use bitmap_set/clear()
In reply to Li Zefan--- fs/btrfs/free-space-cache.c | 20 ++++++++------------ 1 files changed, 8 insertions(+), 12 deletions(-)
fs/btrfs/free-space-cache.c +8 -12
@@ -1063,15 +1063,13 @@ static void bitmap_clear_bits(struct btrfs_block_group_cache *block_group, struct btrfs_free_space *info, u64 offset, u64 bytes) { - unsigned long start, end; -unsigned long i; + unsigned long start, count; start =offset_to_bit (info->offset, block_group->sectorsize, offset); - end = start +bytes_to_bits (bytes, block_group->sectorsize); -BUG_ON (end >BITS_PER_BITMAP ); + count =bytes_to_bits (bytes, block_group->sectorsize); +BUG_ON (start + count >BITS_PER_BITMAP ); -for (i = start; i < end; i++) -clear_bit (i, info->bitmap); +bitmap_clear (info->bitmap, start, count); info->bytes -= bytes; block_group->free_space -= bytes;
@@ -1081,15 +1079,13 @@ static void bitmap_set_bits(struct btrfs_block_group_cache *block_group, struct btrfs_free_space *info, u64 offset, u64 bytes) { - unsigned long start, end; -unsigned long i; + unsigned long start, count; start =offset_to_bit (info->offset, block_group->sectorsize, offset); - end = start +bytes_to_bits (bytes, block_group->sectorsize); -BUG_ON (end >BITS_PER_BITMAP ); + count =bytes_to_bits (bytes, block_group->sectorsize); +BUG_ON (start + count >BITS_PER_BITMAP ); -for (i = start; i < end; i++) -set_bit (i, info->bitmap); +bitmap_set (info->bitmap, start, count); info->bytes += bytes; block_group->free_space += bytes;
Signature · 1 line
1.7.3.1
PATCH 3/7 Btrfs: Make free space cache code generic
In reply to Li ZefanSo we can re-use the code to cache free inode numbers.
The change is quite straightforward. Two new structures are introduced.
- struct btrfs_free_space_ctl
We move those variables that are used for caching free space from struct btrfs_block_group_cache to this new struct.
- struct btrfs_free_space_op
We do block group specific work (e.g. calculation of extents threshold) through functions registered in this struct.
And then we can remove references to struct btrfs_block_group_cache.
--- fs/btrfs/ctree.h | 7 +- fs/btrfs/extent-tree.c | 37 +++-- fs/btrfs/free-space-cache.c | 367 +++++++++++++++++++++++-------------------- fs/btrfs/free-space-cache.h | 20 +++ 4 files changed, 238 insertions(+), 193 deletions(-)
fs/btrfs/ctree.h +1 -6
@@ -829,9 +829,6 @@ struct btrfs_block_group_cache {u64 bytes_super;u64 flags;u64 sectorsize; -int extents_thresh; -int free_extents; -int total_bitmaps; unsigned int ro:1; unsigned int dirty:1; unsigned int iref:1;
@@ -846,9 +843,7 @@ struct btrfs_block_group_cache {struct btrfs_space_info *space_info;/* free space cache stuff */ -spinlock_t tree_lock; -struct rb_root free_space_offset; -u64 free_space; +struct btrfs_free_space_ctl *free_space_ctl;/* block group cache stuff */ struct rb_node cache_node;
fs/btrfs/extent-tree.c +19 -18
@@ -88,6 +88,7 @@ void btrfs_put_block_group(struct btrfs_block_group_cache *cache)WARN_ON (cache->pinned >0 );WARN_ON (cache->reserved >0 );WARN_ON (cache->reserved_pinned >0 ); +kfree (cache->free_space_ctl);kfree (cache); } }
@@ -4808,7 +4809,7 @@ wait_block_group_cache_progress(struct btrfs_block_group_cache *cache,return 0 ;wait_event (caching_ctl->wait,block_group_cache_done (cache) || - (cache->free_space >= num_bytes)); + (cache->free_space_ctl->free_space >= num_bytes));put_caching_control (caching_ctl);return 0 ;
@@ -8433,10 +8434,16 @@ int btrfs_read_block_groups(struct btrfs_root *root) ret = -ENOMEM ; goto error; } + cache->free_space_ctl =kzalloc (sizeof (*cache->free_space_ctl), +GFP_NOFS ); +if (!cache->free_space_ctl) { +kfree (cache); + ret = -ENOMEM ; + goto error; + }atomic_set (&cache->count,1 );spin_lock_init (&cache->lock); -spin_lock_init (&cache->tree_lock); cache->fs_info = info;INIT_LIST_HEAD (&cache->list);INIT_LIST_HEAD (&cache->cluster_list);
@@ -8444,14 +8451,6 @@ int btrfs_read_block_groups(struct btrfs_root *root)if (need_clear) cache->disk_cache_state =BTRFS_DC_CLEAR ; -/* -* we only want to have 32k of ram per block group for keeping -* track of free space, and if we pass 1/2 of that we want to -* start converting things over to using bitmaps -*/ - cache->extents_thresh = ((1024 *32 ) /2 ) / -sizeof (struct btrfs_free_space ); -read_extent_buffer (leaf, &cache->item,btrfs_item_ptr_offset (leaf, path->slots[0 ]),sizeof (cache->item));
@@ -8462,6 +8461,8 @@ int btrfs_read_block_groups(struct btrfs_root *root) cache->flags =btrfs_block_group_flags (&cache->item); cache->sectorsize = root->sectorsize; +btrfs_init_free_space_ctl (cache); +/* * We need to exclude the super stripes now so that the space * info has super bytes accounted for, otherwise we'll think
@@ -8548,6 +8549,12 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, cache =kzalloc (sizeof (*cache),GFP_NOFS );if (!cache)return -ENOMEM ; + cache->free_space_ctl =kzalloc (sizeof (*cache->free_space_ctl), +GFP_NOFS ); +if (!cache->free_space_ctl) { +kfree (cache); +return -ENOMEM ; + } cache->key.objectid = chunk_offset; cache->key.offset = size;
@@ -8555,19 +8562,13 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, cache->sectorsize = root->sectorsize; cache->fs_info = root->fs_info; -/* -* we only want to have 32k of ram per block group for keeping track -* of free space, and if we pass 1/2 of that we want to start -* converting things over to using bitmaps -*/ - cache->extents_thresh = ((1024 *32 ) /2 ) / -sizeof (struct btrfs_free_space );atomic_set (&cache->count,1 );spin_lock_init (&cache->lock); -spin_lock_init (&cache->tree_lock);INIT_LIST_HEAD (&cache->list);INIT_LIST_HEAD (&cache->cluster_list); +btrfs_init_free_space_ctl (cache); +btrfs_set_block_group_used (&cache->item, bytes_used);btrfs_set_block_group_chunk_objectid (&cache->item, chunk_objectid); cache->flags = type;
fs/btrfs/free-space-cache.c +198 -169
950 lines not on this page · raw message
fs/btrfs/free-space-cache.h +20 -0
@@ -27,6 +27,25 @@ struct btrfs_free_space {struct list_head list; }; +struct btrfs_free_space_ctl { +spinlock_t tree_lock; +struct rb_root free_space_offset; +u64 free_space; +int extents_thresh; +int free_extents; +int total_bitmaps; +int unit; +u64 start; +struct btrfs_free_space_op *op; +void *private; +}; + +struct btrfs_free_space_op { +void (*recalc_thresholds)(struct btrfs_free_space_ctl *ctl); +bool (*use_bitmap)(struct btrfs_free_space_ctl *ctl, +struct btrfs_free_space *info); +}; +struct inode *lookup_free_space_inode (struct btrfs_root *root,struct btrfs_block_group_cache *block_group,struct btrfs_path *path);
@@ -45,6 +64,7 @@ int btrfs_write_out_cache(struct btrfs_root *root,struct btrfs_trans_handle *trans, struct btrfs_block_group_cache *block_group, struct btrfs_path *path); +void btrfs_init_free_space_ctl (struct btrfs_block_group_cache *block_group);int btrfs_add_free_space (struct btrfs_block_group_cache *block_group,u64 bytenr,u64 size); int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
Signature · 1 line
1.7.3.1
PATCH 4/7 Btrfs: Cache free inode numbers in memory
In reply to Li ZefanCurrently btrfs stores the highest objectid of the fs tree, and it always returns (highest+1) inode number when we create a file, so inode numbers won't be reclaimed when we delete files, so we'll run out of inode numbers as we keep create/delete files in 32bits machines.
This fixes it, and it works similarly to how we cache free space in block cgroups.
We start a kernel thread to read the file tree. By scanning inode items, we know which chunks of inode numbers are free, and we cache them in an rb-tree.
Because we are searching the commit root, we have to carefully handle the cross-transaction case.
The rb-tree is a hybrid extent+bitmap tree, so if we have too many small chunks of inode numbers, we'll use bitmaps. Initially we allow 16K ram of extents, and a bitmap will be used if we exceed this threshold. The extents threshold is adjusted in runtime.
--- fs/btrfs/ctree.h | 15 +- fs/btrfs/disk-io.c | 18 +++ fs/btrfs/free-space-cache.c | 95 ++++++++++--- fs/btrfs/free-space-cache.h | 16 ++- fs/btrfs/inode-map.c | 341 ++++++++++++++++++++++++++++++++++++++++++- fs/btrfs/inode-map.h | 11 ++ fs/btrfs/inode.c | 42 ++++-- fs/btrfs/ioctl.c | 4 +- fs/btrfs/relocation.c | 3 +- fs/btrfs/transaction.c | 7 +- 10 files changed, 499 insertions(+), 53 deletions(-) create mode 100644 fs/btrfs/inode-map.h
fs/btrfs/ctree.h +9 -6
@@ -1101,6 +1101,15 @@ struct btrfs_root {spinlock_t accounting_lock;struct btrfs_block_rsv *block_rsv; +/* free ino cache stuff */ +struct mutex fs_commit_mutex; +struct btrfs_free_space_ctl *free_ino_ctl; +enum btrfs_caching_type cached; +spinlock_t cache_lock; +wait_queue_head_t cache_wait; +struct btrfs_free_space_ctl *free_ino_pinned; +u64 cache_progress; +struct mutex log_mutex;wait_queue_head_t log_writer_wait;wait_queue_head_t log_commit_wait[2 ];
@@ -2395,12 +2404,6 @@ int btrfs_del_orphan_item(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 offset);int btrfs_find_orphan_item (struct btrfs_root *root,u64 offset); -/* inode-map.c */ -int btrfs_find_free_objectid (struct btrfs_trans_handle *trans, -struct btrfs_root *fs_root, -u64 dirid,u64 *objectid); -int btrfs_find_highest_inode (struct btrfs_root *fs_root,u64 *objectid); -/* inode-item.c */ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
fs/btrfs/disk-io.c +18 -0
@@ -40,6 +40,7 @@#include "locking.h" #include "tree-log.h" #include "free-space-cache.h" +#include "inode-map.h" static struct extent_io_ops btree_extent_io_ops;static void end_workqueue_fn (struct btrfs_work *work);
@@ -1233,6 +1234,19 @@ again:if (IS_ERR (root))return root; + root->free_ino_ctl =kzalloc (sizeof (*root->free_ino_ctl),GFP_NOFS ); +if (!root->free_ino_ctl) + goto fail; + root->free_ino_pinned =kzalloc (sizeof (*root->free_ino_pinned), +GFP_NOFS ); +if (!root->free_ino_pinned) + goto fail; + +btrfs_init_free_ino_ctl (root); +mutex_init (&root->fs_commit_mutex); +spin_lock_init (&root->cache_lock); +init_waitqueue_head (&root->cache_wait); +set_anon_super (&root->anon_super,NULL );if (btrfs_root_refs (&root->root_item) ==0 ) {
@@ -2381,6 +2395,8 @@ int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)if (btrfs_root_refs (&root->root_item) ==0 )synchronize_srcu (&fs_info->subvol_srcu); +__btrfs_remove_free_space_cache (root->free_ino_pinned); +__btrfs_remove_free_space_cache (root->free_ino_ctl);free_fs_root (root);return 0 ; }
@@ -2394,6 +2410,8 @@ static void free_fs_root(struct btrfs_root *root) }free_extent_buffer (root->node);free_extent_buffer (root->commit_root); +kfree (root->free_ino_ctl); +kfree (root->free_ino_pinned);kfree (root->name);kfree (root); }
fs/btrfs/free-space-cache.c +75 -20
133 lines not on this page · raw message
fs/btrfs/free-space-cache.h +13 -3
@@ -64,15 +64,25 @@ int btrfs_write_out_cache(struct btrfs_root *root,struct btrfs_trans_handle *trans, struct btrfs_block_group_cache *block_group, struct btrfs_path *path); +void btrfs_init_free_space_ctl (struct btrfs_block_group_cache *block_group); -int btrfs_add_free_space (struct btrfs_block_group_cache *block_group, -u64 bytenr,u64 size); +int __btrfs_add_free_space (struct btrfs_free_space_ctl *ctl, +u64 bytenr,u64 size); +static inline int +btrfs_add_free_space (struct btrfs_block_group_cache *block_group, +u64 bytenr,u64 size) +{ +return __btrfs_add_free_space (block_group->free_space_ctl, + bytenr, size); +}int btrfs_remove_free_space (struct btrfs_block_group_cache *block_group,u64 bytenr,u64 size); +void __btrfs_remove_free_space_cache (struct btrfs_free_space_ctl *ctl);void btrfs_remove_free_space_cache (struct btrfs_block_group_cache - *block_group); + *block_group);u64 btrfs_find_space_for_alloc (struct btrfs_block_group_cache *block_group,u64 offset,u64 bytes,u64 empty_size); +u64 btrfs_find_ino_for_alloc (struct btrfs_root *fs_root);void btrfs_dump_free_space (struct btrfs_block_group_cache *block_group,u64 bytes); int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
fs/btrfs/inode-map.c +336 -5
362 lines not on this page · raw message
fs/btrfs/inode-map.h new file +11 -0
@@ -0,0 +1,11 @@ +#ifndef __BTRFS_INODE_MAP +#define __BTRFS_INODE_MAP + +void btrfs_init_free_ino_ctl (struct btrfs_root *root); +void btrfs_unpin_free_ino (struct btrfs_root *root); +void btrfs_return_ino (struct btrfs_root *root,u64 objectid); +int btrfs_find_free_ino (struct btrfs_root *root,u64 *objectid); + +int btrfs_find_free_objectid (struct btrfs_root *root,u64 *objectid); + +#endif
fs/btrfs/inode.c +27 -15
114 lines not on this page · raw message
fs/btrfs/ioctl.c +2 -2
@@ -49,6 +49,7 @@#include "print-tree.h" #include "volumes.h" #include "locking.h" +#include "inode-map.h" /* Mask out flags that are inappropriate for the given type of inode. */ static inline __u32 btrfs_mask_flags (umode_t mode,__u32 flags)
@@ -244,8 +245,7 @@ static noinline int create_subvol(struct btrfs_root *root,u64 new_dirid =BTRFS_FIRST_FREE_OBJECTID ;u64 index =0 ; - ret =btrfs_find_free_objectid (NULL , root->fs_info->tree_root, -0 , &objectid); + ret =btrfs_find_free_objectid (root->fs_info->tree_root, &objectid);if (ret) {dput (parent);return ret;
fs/btrfs/relocation.c +2 -1
@@ -30,6 +30,7 @@#include "btrfs_inode.h" #include "async-thread.h" #include "free-space-cache.h" +#include "inode-map.h" /* * backref_node, mapping_node and tree_block start with this
@@ -3891,7 +3892,7 @@ struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info,if (IS_ERR (trans))return ERR_CAST (trans); - err =btrfs_find_free_objectid (trans, root, objectid, &objectid); + err =btrfs_find_free_objectid (root, &objectid);if (err) goto out;
fs/btrfs/transaction.c +6 -1
@@ -27,6 +27,7 @@#include "transaction.h" #include "locking.h" #include "tree-log.h" +#include "inode-map.h" #define BTRFS_ROOT_TRANS_TAG 0
@@ -752,7 +753,11 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,btrfs_orphan_commit_root (trans, root);if (root->commit_root != root->node) { +mutex_lock (&root->fs_commit_mutex);switch_commit_root (root); +btrfs_unpin_free_ino (root); +mutex_unlock (&root->fs_commit_mutex); +btrfs_set_root_node (&root->root_item, root->node); }
@@ -921,7 +926,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, goto fail; } - ret =btrfs_find_free_objectid (trans, tree_root,0 , &objectid); + ret =btrfs_find_free_objectid (tree_root, &objectid);if (ret) { pending->error = ret; goto fail;
Signature · 1 line
1.7.3.1
PATCH 5/7 Btrfs: Make the code for reading/writing free space cache generic
In reply to Li ZefanExtract out block group specific code from lookup_free_space_inode(), create_free_space_inode(), load_free_space_cache() and btrfs_write_out_cache(), so the code can be used to read/write free ino cache.
--- fs/btrfs/free-space-cache.c | 317 ++++++++++++++++++++++++------------------ 1 files changed, 181 insertions(+), 136 deletions(-)
fs/btrfs/free-space-cache.c +181 -136
@@ -32,9 +32,9 @@static int link_free_space (struct btrfs_free_space_ctl *ctl,struct btrfs_free_space *info); -struct inode *lookup_free_space_inode (struct btrfs_root *root, -struct btrfs_block_group_cache - *block_group,struct btrfs_path *path) +static struct inode *__lookup_free_space_inode (struct btrfs_root *root, +struct btrfs_path *path, +u64 offset) {struct btrfs_key key;struct btrfs_key location;
@@ -44,15 +44,8 @@ struct inode *lookup_free_space_inode(struct btrfs_root *root,struct inode *inode =NULL ;int ret; -spin_lock (&block_group->lock); -if (block_group->inode) - inode =igrab (block_group->inode); -spin_unlock (&block_group->lock); -if (inode) -return inode; - key.objectid =BTRFS_FREE_SPACE_OBJECTID ; - key.offset = block_group->key.objectid; + key.offset = offset; key.type =0 ; ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 );
@@ -80,6 +73,27 @@ struct inode *lookup_free_space_inode(struct btrfs_root *root,return ERR_PTR (-ENOENT ); } +return inode; +} + +struct inode *lookup_free_space_inode (struct btrfs_root *root, +struct btrfs_block_group_cache + *block_group,struct btrfs_path *path) +{ +struct inode *inode =NULL ; + +spin_lock (&block_group->lock); +if (block_group->inode) + inode =igrab (block_group->inode); +spin_unlock (&block_group->lock); +if (inode) +return inode; + + inode =__lookup_free_space_inode (root, path, + block_group->key.objectid); +if (IS_ERR (inode)) +return inode; +spin_lock (&block_group->lock);if (!root->fs_info->closing) { block_group->inode =igrab (inode);
@@ -90,24 +104,18 @@ struct inode *lookup_free_space_inode(struct btrfs_root *root,return inode; } -int create_free_space_inode (struct btrfs_root *root, -struct btrfs_trans_handle *trans, -struct btrfs_block_group_cache *block_group, -struct btrfs_path *path) +int __create_free_space_inode (struct btrfs_root *root, +struct btrfs_trans_handle *trans, +struct btrfs_path *path,u64 ino,u64 offset) {struct btrfs_key key;struct btrfs_disk_key disk_key;struct btrfs_free_space_header *header;struct btrfs_inode_item *inode_item;struct extent_buffer *leaf; -u64 objectid;int ret; - ret =btrfs_find_free_objectid (root, &objectid); -if (ret <0 ) -return ret; - - ret =btrfs_insert_empty_inode (trans, root, path, objectid); + ret =btrfs_insert_empty_inode (trans, root, path, ino);if (ret)return ret;
@@ -127,13 +135,12 @@ int create_free_space_inode(struct btrfs_root *root, BTRFS_INODE_PREALLOC | BTRFS_INODE_NODATASUM);btrfs_set_inode_nlink (leaf, inode_item,1 );btrfs_set_inode_transid (leaf, inode_item, trans->transid); -btrfs_set_inode_block_group (leaf, inode_item, - block_group->key.objectid); +btrfs_set_inode_block_group (leaf, inode_item, offset);btrfs_mark_buffer_dirty (leaf);btrfs_release_path (root, path); key.objectid =BTRFS_FREE_SPACE_OBJECTID ; - key.offset = block_group->key.objectid; + key.offset = offset; key.type =0 ; ret = btrfs_insert_empty_item(trans, root, path, &key,
@@ -153,6 +160,22 @@ int create_free_space_inode(struct btrfs_root *root,return 0 ; } +int create_free_space_inode (struct btrfs_root *root, +struct btrfs_trans_handle *trans, +struct btrfs_block_group_cache *block_group, +struct btrfs_path *path) +{ +int ret; +u64 ino; + + ret =btrfs_find_free_objectid (root, &ino); +if (ret <0 ) +return ret; + +return __create_free_space_inode (root, trans, path, ino, + block_group->key.objectid); +} + int btrfs_truncate_free_space_cache(struct btrfs_root *root, struct btrfs_trans_handle *trans, struct btrfs_path *path,
@@ -205,16 +228,13 @@ static int readahead_cache(struct inode *inode)return 0 ; } -int load_free_space_cache (struct btrfs_fs_info *fs_info, -struct btrfs_block_group_cache *block_group) +int __load_free_space_cache (struct btrfs_root *root,struct inode *inode, +struct btrfs_free_space_ctl *ctl, +struct btrfs_path *path,u64 offset) { -struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; -struct btrfs_root *root = fs_info->tree_root; -struct inode *inode;struct btrfs_free_space_header *header;struct extent_buffer *leaf;struct page *page; -struct btrfs_path *path;u32 *checksums =NULL , *crc;char *disk_crcs =NULL ;struct btrfs_key key;
@@ -226,71 +246,43 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,pgoff_t index =0 ;unsigned long first_page_offset;int num_checksums; -int ret =0 ; - -/* -* If we're unmounting then just return, since this does a search on the -* normal root and not the commit root and we could deadlock. -*/ -smp_mb (); -if (fs_info->closing) -return 0 ; - -/* -* If this block group has been marked to be cleared for one reason or -* another then we can't trust the on disk cache, so just return. -*/ -spin_lock (&block_group->lock); -if (block_group->disk_cache_state !=BTRFS_DC_WRITTEN ) { -spin_unlock (&block_group->lock); -return 0 ; - } -spin_unlock (&block_group->lock); +int ret =0 , ret2;INIT_LIST_HEAD (&bitmaps); - path =btrfs_alloc_path (); -if (!path) -return 0 ; - - inode =lookup_free_space_inode (root, block_group, path); -if (IS_ERR (inode)) { -btrfs_free_path (path); -return 0 ; - } -/* Nothing in the space cache, goodbye */ -if (!i_size_read (inode)) { -btrfs_free_path (path); +if (!i_size_read (inode)) goto out; - } key.objectid =BTRFS_FREE_SPACE_OBJECTID ; - key.offset = block_group->key.objectid; + key.offset = offset; key.type =0 ; ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); -if (ret) { -btrfs_free_path (path); +if (ret <0 ) + goto out; +else if (ret >0 ) { +btrfs_release_path (root, path); + ret =0 ; goto out; } + ret =-1 ; + leaf = path->nodes[0 ]; header =btrfs_item_ptr (leaf, path->slots[0 ], struct btrfs_free_space_header); num_entries =btrfs_free_space_entries (leaf, header); num_bitmaps =btrfs_free_space_bitmaps (leaf, header); generation =btrfs_free_space_generation (leaf, header); -btrfs_free_path (path); +btrfs_release_path (root, path);if (BTRFS_I (inode)->generation != generation) {printk (KERN_ERR "btrfs: free space inode generation (%llu) did" -" not match free space cache generation (%llu) for " -"block group %llu\n" , +" not match free space cache generation (%llu)\n" , (unsigned long long )BTRFS_I (inode)->generation, - (unsigned long long )generation, - (unsigned long long )block_group->key.objectid); - goto free_cache; + (unsigned long long )generation); + goto out; }if (!num_entries)
@@ -307,10 +299,8 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info, goto out; ret =readahead_cache (inode); -if (ret) { - ret =0 ; +if (ret) goto out; - }while (1 ) {struct btrfs_free_space_entry *entry;
@@ -329,10 +319,8 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info, } page =grab_cache_page (inode->i_mapping, index); -if (!page) { - ret =0 ; +if (!page) goto free_cache; - }if (!PageUptodate (page)) {btrfs_readpage (NULL , page);
@@ -341,9 +329,7 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,unlock_page (page);page_cache_release (page);printk (KERN_ERR "btrfs: error reading free " -"space cache: %llu\n" , - (unsigned long long ) - block_group->key.objectid); +"space cache\n" ); goto free_cache; } }
@@ -356,13 +342,10 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info, gen = addr + (sizeof (u32) * num_checksums);if (*gen !=BTRFS_I (inode)->generation) {printk (KERN_ERR "btrfs: space cache generation" -" (%llu) does not match inode (%llu) " -"for block group %llu\n" , +" (%llu) does not match inode (%llu)\n" , (unsigned long long )*gen, (unsigned long long ) -BTRFS_I (inode)->generation, - (unsigned long long ) - block_group->key.objectid); +BTRFS_I (inode)->generation);kunmap (page);unlock_page (page);page_cache_release (page);
@@ -378,9 +361,8 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info, PAGE_CACHE_SIZE - start_offset);btrfs_csum_final (cur_crc, (char *)&cur_crc);if (cur_crc != *crc) { -printk (KERN_ERR "btrfs: crc mismatch for page %lu in " -"block group %llu\n" , index, - (unsigned long long )block_group->key.objectid); +printk (KERN_ERR "btrfs: crc mismatch for page %lu\n" , + index);kunmap (page);unlock_page (page);page_cache_release (page);
@@ -426,7 +408,7 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info, goto free_cache; }spin_lock (&ctl->tree_lock); - ret =link_free_space (ctl, e); + ret2 =link_free_space (ctl, e); ctl->total_bitmaps++; ctl->op->recalc_thresholds (ctl);spin_unlock (&ctl->tree_lock);
@@ -469,27 +451,75 @@ next: out:kfree (checksums);kfree (disk_crcs); -iput (inode);return ret; - free_cache: -/* This cache is bogus, make sure it gets cleared */ -spin_lock (&block_group->lock); - block_group->disk_cache_state =BTRFS_DC_CLEAR ; -spin_unlock (&block_group->lock); -btrfs_remove_free_space_cache (block_group); +__btrfs_remove_free_space_cache (ctl); goto out; } -int btrfs_write_out_cache (struct btrfs_root *root, -struct btrfs_trans_handle *trans, -struct btrfs_block_group_cache *block_group, -struct btrfs_path *path) +int load_free_space_cache (struct btrfs_fs_info *fs_info, +struct btrfs_block_group_cache *block_group) {struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; +struct btrfs_root *root = fs_info->tree_root; +struct inode *inode; +struct btrfs_path *path; +int ret; + +/* +* If we're unmounting then just return, since this does a search on the +* normal root and not the commit root and we could deadlock. +*/ +smp_mb (); +if (fs_info->closing) +return 0 ; + +/* +* If this block group has been marked to be cleared for one reason or +* another then we can't trust the on disk cache, so just return. +*/ +spin_lock (&block_group->lock); +if (block_group->disk_cache_state !=BTRFS_DC_WRITTEN ) { +spin_unlock (&block_group->lock); +return 0 ; + } +spin_unlock (&block_group->lock); + + path =btrfs_alloc_path (); +if (!path) +return 0 ; + + inode =lookup_free_space_inode (root, block_group, path); +if (IS_ERR (inode)) { +btrfs_free_path (path); +return 0 ; + } + + ret =__load_free_space_cache (fs_info->tree_root, inode, ctl, + path, block_group->key.objectid); +btrfs_free_path (path); + +if (ret <0 ) { +/* This cache is bogus, make sure it gets cleared */ +spin_lock (&block_group->lock); + block_group->disk_cache_state =BTRFS_DC_CLEAR ; +spin_unlock (&block_group->lock); + +printk (KERN_ERR "btrfs: failed to load free space cache " +"for block group %llu\n" , block_group->key.objectid); + } + +iput (inode); +return ret; +} + +int __btrfs_write_out_cache (struct btrfs_root *root,struct inode *inode, +struct btrfs_free_space_ctl *ctl, +struct btrfs_trans_handle *trans, +struct btrfs_path *path,u64 offset) +{struct btrfs_free_space_header *header;struct extent_buffer *leaf; -struct inode *inode;struct rb_node *node;struct list_head *pos, *n;struct page *page;
@@ -503,33 +533,16 @@ int btrfs_write_out_cache(struct btrfs_root *root,int num_checksums;int entries =0 ;int bitmaps =0 ; -int ret =0 ; - - root = root->fs_info->tree_root; +int ret =-1 ;INIT_LIST_HEAD (&bitmap_list); -spin_lock (&block_group->lock); -if (block_group->disk_cache_state <BTRFS_DC_SETUP ) { -spin_unlock (&block_group->lock); -return 0 ; - } -spin_unlock (&block_group->lock); - - inode =lookup_free_space_inode (root, block_group, path); -if (IS_ERR (inode)) -return 0 ; - -if (!i_size_read (inode)) { -iput (inode); -return 0 ; - } - node =rb_first (&ctl->free_space_offset); -if (!node) { -iput (inode); +if (!node)return 0 ; - } + +if (!i_size_read (inode)) +return -1 ; last_index = (i_size_read (inode) -1 ) >>PAGE_CACHE_SHIFT ;filemap_write_and_wait (inode->i_mapping);
@@ -539,10 +552,8 @@ int btrfs_write_out_cache(struct btrfs_root *root,/* We need a checksum per page. */ num_checksums =i_size_read (inode) /PAGE_CACHE_SIZE ; crc = checksums =kzalloc (sizeof (u32) * num_checksums,GFP_NOFS ); -if (!crc) { -iput (inode); -return 0 ; - } +if (!crc) +return -1 ;/* Since the first page has all of our checksums and our generation we * need to calculate the offset into the page that we can start writing
@@ -729,12 +740,12 @@ int btrfs_write_out_cache(struct btrfs_root *root,filemap_write_and_wait (inode->i_mapping); key.objectid =BTRFS_FREE_SPACE_OBJECTID ; - key.offset = block_group->key.objectid; + key.offset = offset; key.type =0 ; ret =btrfs_search_slot (trans, root, &key, path,1 ,1 );if (ret <0 ) { - ret =0 ; + ret =-1 ;clear_extent_bit (&BTRFS_I (inode)->io_tree,0 , bytes -1 ,EXTENT_DIRTY |EXTENT_DELALLOC |EXTENT_DO_ACCOUNTING ,0 ,0 ,NULL ,GFP_NOFS );
@@ -747,8 +758,8 @@ int btrfs_write_out_cache(struct btrfs_root *root, path->slots[0 ]--;btrfs_item_key_to_cpu (leaf, &found_key, path->slots[0 ]);if (found_key.objectid !=BTRFS_FREE_SPACE_OBJECTID || - found_key.offset != block_group->key.objectid) { - ret =0 ; + found_key.offset != offset) { + ret =-1 ; clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, bytes - 1, EXTENT_DIRTY | EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING, 0, 0, NULL,
@@ -768,15 +779,49 @@ int btrfs_write_out_cache(struct btrfs_root *root, ret =1 ; out_free: -if (ret ==0 ) { +if (ret !=1 ) {invalidate_inode_pages2_range (inode->i_mapping,0 , index); -spin_lock (&block_group->lock); - block_group->disk_cache_state =BTRFS_DC_ERROR ; -spin_unlock (&block_group->lock);BTRFS_I (inode)->generation =0 ; }kfree (checksums);btrfs_update_inode (trans, root, inode); +return ret; +} + +int btrfs_write_out_cache (struct btrfs_root *root, +struct btrfs_trans_handle *trans, +struct btrfs_block_group_cache *block_group, +struct btrfs_path *path) +{ +struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; +struct inode *inode; +int ret =0 ; + + root = root->fs_info->tree_root; + +spin_lock (&block_group->lock); +if (block_group->disk_cache_state <BTRFS_DC_SETUP ) { +spin_unlock (&block_group->lock); +return 0 ; + } +spin_unlock (&block_group->lock); + + inode =lookup_free_space_inode (root, block_group, path); +if (IS_ERR (inode)) +return 0 ; + + ret =__btrfs_write_out_cache (root->fs_info->tree_root, inode, ctl, + trans, path, block_group->key.objectid); + +if (ret <0 ) { +spin_lock (&block_group->lock); + block_group->disk_cache_state =BTRFS_DC_ERROR ; +spin_unlock (&block_group->lock); + +printk (KERN_ERR "btrfs: failed to write free space cache " +"for block group %llu\n" , block_group->key.objectid); + } +iput (inode);return ret; }
Signature · 1 line
1.7.3.1
PATCH 6/7 Btrfs: Always use 64bit inode number
In reply to Li ZefanThere's a potential problem in 32bit system when we exhaust 32bit inode numbers and start to allocate big inode numbers, because btrfs uses inode->i_ino in many places.
So here we always use BTRFS_I(inode)->location.objectid, which is an u64 variable.
There are 2 exceptions that BTRFS_I(inode)->location.objectid != inode->i_ino: the btree inode (0 vs 1) and empty subvol dirs (256 vs 2), and inode->i_ino will be used in those cases.
Another reason to make this change is I'm going to use a special inode to save free ino cache, and the inode number must be > (u64)-256.
--- fs/btrfs/btrfs_inode.h | 9 ++ fs/btrfs/compression.c | 5 +- fs/btrfs/export.c | 25 ++++--- fs/btrfs/extent-tree.c | 10 +- fs/btrfs/extent_io.c | 4 +- fs/btrfs/file-item.c | 5 +- fs/btrfs/file.c | 27 ++++--- fs/btrfs/inode.c | 195 +++++++++++++++++++++++++----------------------- fs/btrfs/ioctl.c | 18 ++-- fs/btrfs/relocation.c | 24 +++--- fs/btrfs/transaction.c | 4 +- fs/btrfs/tree-log.c | 58 +++++++------- fs/btrfs/xattr.c | 8 +- 13 files changed, 209 insertions(+), 183 deletions(-)
fs/btrfs/btrfs_inode.h +9 -0
@@ -167,6 +167,15 @@ static inline struct btrfs_inode *BTRFS_I(struct inode *inode) return container_of(inode, struct btrfs_inode, vfs_inode); } +static inline u64 btrfs_ino (struct inode *inode) +{ +u64 ino =BTRFS_I (inode)->location.objectid; + +if (ino <=BTRFS_FIRST_FREE_OBJECTID ) + ino = inode->i_ino; +return ino; +} +static inline void btrfs_i_size_write (struct inode *inode,u64 size) {i_size_write (inode, size);
fs/btrfs/compression.c +3 -2
@@ -125,9 +125,10 @@ static int check_compressed_csum(struct inode *inode,kunmap_atomic (kaddr,KM_USER0 );if (csum != *cb_sum) { -printk (KERN_INFO "btrfs csum failed ino %lu " +printk (KERN_INFO "btrfs csum failed ino %llu " "extent %llu csum %u " -"wanted %u mirror %d\n" , inode->i_ino, +"wanted %u mirror %d\n" , + (unsigned long long )btrfs_ino (inode), (unsigned long long )disk_start, csum, *cb_sum, cb->mirror_num); ret = -EIO ;
fs/btrfs/export.c +14 -11
@@ -28,7 +28,7 @@ static int btrfs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len, len =BTRFS_FID_SIZE_NON_CONNECTABLE ; type =FILEID_BTRFS_WITHOUT_PARENT ; - fid->objectid = inode->i_ino; + fid->objectid =btrfs_ino (inode); fid->root_objectid =BTRFS_I (inode)->root->objectid; fid->gen = inode->i_generation;
@@ -179,13 +179,13 @@ static struct dentry *btrfs_get_parent(struct dentry *child)if (!path)return ERR_PTR (-ENOMEM ); -if (dir->i_ino ==BTRFS_FIRST_FREE_OBJECTID ) { +if (btrfs_ino (dir) ==BTRFS_FIRST_FREE_OBJECTID ) { key.objectid = root->root_key.objectid; key.type =BTRFS_ROOT_BACKREF_KEY ; key.offset = (u64)-1 ; root = root->fs_info->tree_root; }else { - key.objectid = dir->i_ino; + key.objectid =btrfs_ino (dir); key.type =BTRFS_INODE_REF_KEY ; key.offset = (u64)-1 ; }
@@ -248,6 +248,7 @@ static int btrfs_get_name(struct dentry *parent, char *name,struct btrfs_key key;int name_len;int ret; +u64 ino;if (!dir || !inode)return -EINVAL ;
@@ -255,19 +256,21 @@ static int btrfs_get_name(struct dentry *parent, char *name,if (!S_ISDIR (dir->i_mode))return -EINVAL ; + ino =btrfs_ino (inode); + path =btrfs_alloc_path ();if (!path)return -ENOMEM ; path->leave_spinning =1 ; -if (inode->i_ino ==BTRFS_FIRST_FREE_OBJECTID ) { +if (ino ==BTRFS_FIRST_FREE_OBJECTID ) { key.objectid =BTRFS_I (inode)->root->root_key.objectid; key.type =BTRFS_ROOT_BACKREF_KEY ; key.offset = (u64)-1 ; root = root->fs_info->tree_root; }else { - key.objectid = inode->i_ino; - key.offset = dir->i_ino; + key.objectid = ino; + key.offset =btrfs_ino (dir); key.type =BTRFS_INODE_REF_KEY ; }
@@ -276,7 +279,7 @@ static int btrfs_get_name(struct dentry *parent, char *name,btrfs_free_path (path);return ret; }else if (ret >0 ) { -if (inode->i_ino ==BTRFS_FIRST_FREE_OBJECTID ) { +if (ino ==BTRFS_FIRST_FREE_OBJECTID ) { path->slots[0 ]--; }else {btrfs_free_path (path);
@@ -285,11 +288,11 @@ static int btrfs_get_name(struct dentry *parent, char *name, } leaf = path->nodes[0 ]; -if (inode->i_ino ==BTRFS_FIRST_FREE_OBJECTID ) { - rref =btrfs_item_ptr (leaf, path->slots[0 ], +if (ino ==BTRFS_FIRST_FREE_OBJECTID ) { + rref =btrfs_item_ptr (leaf, path->slots[0 ], struct btrfs_root_ref); - name_ptr = (unsigned long )(rref +1 ); - name_len =btrfs_root_ref_name_len (leaf, rref); + name_ptr = (unsigned long )(rref +1 ); + name_len =btrfs_root_ref_name_len (leaf, rref); }else { iref =btrfs_item_ptr (leaf, path->slots[0 ], struct btrfs_inode_ref);
fs/btrfs/extent-tree.c +5 -5
@@ -6905,8 +6905,8 @@ static noinline int get_new_locations(struct inode *reloc_inode, cur_pos = extent_key->objectid - offset; last_byte = extent_key->objectid + extent_key->offset; - ret =btrfs_lookup_file_extent (NULL , root, path, reloc_inode->i_ino, - cur_pos,0 ); + ret =btrfs_lookup_file_extent (NULL , root, path, +btrfs_ino (reloc_inode), cur_pos,0 );if (ret <0 ) goto out;if (ret >0 ) {
@@ -6929,7 +6929,7 @@ static noinline int get_new_locations(struct inode *reloc_inode,btrfs_item_key_to_cpu (leaf, &found_key, path->slots[0 ]);if (found_key.offset != cur_pos || found_key.type !=BTRFS_EXTENT_DATA_KEY || - found_key.objectid != reloc_inode->i_ino) + found_key.objectid !=btrfs_ino (reloc_inode))break ; fi = btrfs_item_ptr(leaf, path->slots[0],
@@ -7071,7 +7071,7 @@ next:break ; } -if (inode && key.objectid != inode->i_ino) { +if (inode && key.objectid !=btrfs_ino (inode)) {BUG_ON (extent_locked);btrfs_release_path (root, path);mutex_unlock (&inode->i_mutex);
@@ -7380,7 +7380,7 @@ static noinline int invalidate_extent_cache(struct btrfs_root *root,continue ;if (btrfs_file_extent_disk_bytenr (leaf, fi) ==0 )continue ; -if (!inode || inode->i_ino != key.objectid) { +if (!inode ||btrfs_ino (inode) != key.objectid) {iput (inode); inode =btrfs_ilookup (target_root->fs_info->sb, key.objectid, target_root,1 );
fs/btrfs/extent_io.c +2 -2
@@ -2994,7 +2994,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,* because there might be preallocation past i_size */ ret =btrfs_lookup_file_extent (NULL ,BTRFS_I (inode)->root, - path, inode->i_ino,-1 ,0 ); + path,btrfs_ino (inode),-1 ,0 );if (ret <0 ) {btrfs_free_path (path);return ret;
@@ -3007,7 +3007,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, found_type =btrfs_key_type (&found_key);/* No extents, but there might be delalloc bits */ -if (found_key.objectid != inode->i_ino || +if (found_key.objectid !=btrfs_ino (inode) || found_type !=BTRFS_EXTENT_DATA_KEY ) {/* have to trust i_size as the end */ last = (u64)-1 ;
fs/btrfs/file-item.c +3 -2
@@ -205,8 +205,9 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, EXTENT_NODATASUM, GFP_NOFS); }else {printk (KERN_INFO "btrfs no csum found " -"for inode %lu start %llu\n" , - inode->i_ino, +"for inode %llu start %llu\n" , + (unsigned long long ) +btrfs_ino (inode), (unsigned long long )offset); } item =NULL ;
fs/btrfs/file.c +14 -13
@@ -302,6 +302,7 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,struct btrfs_path *path;struct btrfs_key key;struct btrfs_key new_key; +u64 ino =btrfs_ino (inode);u64 search_start = start;u64 disk_bytenr =0 ;u64 num_bytes =0 ;
@@ -322,14 +323,14 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, struct inode *inode,while (1 ) { recow =0 ; - ret =btrfs_lookup_file_extent (trans, root, path, inode->i_ino, + ret =btrfs_lookup_file_extent (trans, root, path, ino, search_start,-1 );if (ret <0 )break ;if (ret >0 && path->slots[0 ] >0 && search_start == start) { leaf = path->nodes[0 ];btrfs_item_key_to_cpu (leaf, &key, path->slots[0 ] -1 ); -if (key.objectid == inode->i_ino && +if (key.objectid == ino && key.type ==BTRFS_EXTENT_DATA_KEY ) path->slots[0 ]--; }
@@ -350,7 +351,7 @@ next_slot: }btrfs_item_key_to_cpu (leaf, &key, path->slots[0 ]); -if (key.objectid > inode->i_ino || +if (key.objectid > ino || key.type >BTRFS_EXTENT_DATA_KEY || key.offset >= end)break ;
@@ -596,6 +597,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,int del_slot =0 ;int recow;int ret; +u64 ino =btrfs_ino (inode);btrfs_drop_extent_cache (inode, start, end -1 ,0 );
@@ -604,7 +606,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, again: recow =0 ; split = start; - key.objectid = inode->i_ino; + key.objectid = ino; key.type =BTRFS_EXTENT_DATA_KEY ; key.offset = split;
@@ -614,8 +616,7 @@ again: leaf = path->nodes[0 ];btrfs_item_key_to_cpu (leaf, &key, path->slots[0 ]); -BUG_ON (key.objectid != inode->i_ino || - key.type !=BTRFS_EXTENT_DATA_KEY ); +BUG_ON (key.objectid != ino || key.type !=BTRFS_EXTENT_DATA_KEY ); fi =btrfs_item_ptr (leaf, path->slots[0 ], struct btrfs_file_extent_item); BUG_ON(btrfs_file_extent_type(leaf, fi) !=
@@ -632,7 +633,7 @@ again: other_start =0 ; other_end = start;if (extent_mergeable (leaf, path->slots[0 ] -1 , - inode->i_ino, bytenr, orig_offset, + ino, bytenr, orig_offset, &other_start, &other_end)) { new_key.offset = end;btrfs_set_item_key_safe (trans, root, path, &new_key);
@@ -655,7 +656,7 @@ again: other_start = end; other_end =0 ;if (extent_mergeable (leaf, path->slots[0 ] +1 , - inode->i_ino, bytenr, orig_offset, + ino, bytenr, orig_offset, &other_start, &other_end)) { fi =btrfs_item_ptr (leaf, path->slots[0 ], struct btrfs_file_extent_item);
@@ -704,7 +705,7 @@ again: ret =btrfs_inc_extent_ref (trans, root, bytenr, num_bytes,0 , root->root_key.objectid, - inode->i_ino, orig_offset); + ino, orig_offset);BUG_ON (ret);if (split == start) {
@@ -720,7 +721,7 @@ again: other_start = end; other_end =0 ;if (extent_mergeable (leaf, path->slots[0 ] +1 , - inode->i_ino, bytenr, orig_offset, + ino, bytenr, orig_offset, &other_start, &other_end)) {if (recow) {btrfs_release_path (root, path);
@@ -731,13 +732,13 @@ again: del_nr++; ret =btrfs_free_extent (trans, root, bytenr, num_bytes,0 , root->root_key.objectid, - inode->i_ino, orig_offset); + ino, orig_offset);BUG_ON (ret); } other_start =0 ; other_end = start;if (extent_mergeable (leaf, path->slots[0 ] -1 , - inode->i_ino, bytenr, orig_offset, + ino, bytenr, orig_offset, &other_start, &other_end)) {if (recow) {btrfs_release_path (root, path);
@@ -748,7 +749,7 @@ again: del_nr++; ret =btrfs_free_extent (trans, root, bytenr, num_bytes,0 , root->root_key.objectid, - inode->i_ino, orig_offset); + ino, orig_offset);BUG_ON (ret); }if (del_nr ==0 ) {
fs/btrfs/inode.c +102 -93
639 lines not on this page · raw message
fs/btrfs/ioctl.c +9 -9
@@ -333,7 +333,7 @@ static noinline int create_subvol(struct btrfs_root *root,BUG_ON (ret); ret =btrfs_insert_dir_item (trans, root, - name, namelen, dir->i_ino, &key, + name, namelen,btrfs_ino (dir), &key,BTRFS_FT_DIR , index);if (ret) goto fail;
@@ -344,7 +344,7 @@ static noinline int create_subvol(struct btrfs_root *root, ret =btrfs_add_root_ref (trans, root->fs_info->tree_root, objectid, root->root_key.objectid, - dir->i_ino, index, name, namelen); +btrfs_ino (dir), index, name, namelen);BUG_ON (ret);
@@ -1038,7 +1038,7 @@ static noinline int btrfs_ioctl_subvol_getflags(struct file *file,int ret =0 ;u64 flags =0 ; -if (inode->i_ino !=BTRFS_FIRST_FREE_OBJECTID ) +if (btrfs_ino (inode) !=BTRFS_FIRST_FREE_OBJECTID )return -EINVAL ;down_read (&root->fs_info->subvol_sem);
@@ -1065,7 +1065,7 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,if (root->fs_info->sb->s_flags &MS_RDONLY )return -EROFS ; -if (inode->i_ino !=BTRFS_FIRST_FREE_OBJECTID ) +if (btrfs_ino (inode) !=BTRFS_FIRST_FREE_OBJECTID )return -EINVAL ;if (copy_from_user (&flags, arg,sizeof (flags)))
@@ -1548,7 +1548,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, goto out_dput; } -if (inode->i_ino !=BTRFS_FIRST_FREE_OBJECTID ) { +if (btrfs_ino (inode) !=BTRFS_FIRST_FREE_OBJECTID ) { err = -EINVAL ; goto out_dput; }
@@ -1834,7 +1834,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, }/* clone data */ - key.objectid = src->i_ino; + key.objectid =btrfs_ino (src); key.type =BTRFS_EXTENT_DATA_KEY ; key.offset =0 ;
@@ -1861,7 +1861,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,btrfs_item_key_to_cpu (leaf, &key, slot);if (btrfs_key_type (&key) >BTRFS_EXTENT_DATA_KEY || - key.objectid != src->i_ino) + key.objectid !=btrfs_ino (src))break ;if (btrfs_key_type (&key) ==BTRFS_EXTENT_DATA_KEY ) {
@@ -1904,7 +1904,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, goto next;memcpy (&new_key, &key,sizeof (new_key)); - new_key.objectid = inode->i_ino; + new_key.objectid =btrfs_ino (inode);if (off <= key.offset) new_key.offset = key.offset + destoff - off;else
@@ -1958,7 +1958,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, ret =btrfs_inc_extent_ref (trans, root, disko, diskl,0 , root->root_key.objectid, - inode->i_ino, +btrfs_ino (inode), new_key.offset - datao);BUG_ON (ret); }
fs/btrfs/relocation.c +13 -11
@@ -1410,9 +1410,9 @@ again: prev = node; entry = rb_entry(node, struct btrfs_inode, rb_node); -if (objectid < entry->vfs_inode.i_ino) +if (objectid <btrfs_ino (&entry->vfs_inode)) node = node->rb_left; -else if (objectid > entry->vfs_inode.i_ino) +else if (objectid >btrfs_ino (&entry->vfs_inode)) node = node->rb_right;else break ;
@@ -1420,7 +1420,7 @@ again:if (!node) {while (prev) { entry = rb_entry(prev, struct btrfs_inode, rb_node); -if (objectid <= entry->vfs_inode.i_ino) { +if (objectid <=btrfs_ino (&entry->vfs_inode)) { node = prev;break ; }
@@ -1435,7 +1435,7 @@ again:return inode; } - objectid = entry->vfs_inode.i_ino +1 ; + objectid =btrfs_ino (&entry->vfs_inode) +1 ;if (cond_resched_lock (&root->inode_lock)) goto again;
@@ -1471,7 +1471,7 @@ static int get_new_location(struct inode *reloc_inode, u64 *new_bytenr,return -ENOMEM ; bytenr -=BTRFS_I (reloc_inode)->index_cnt; - ret =btrfs_lookup_file_extent (NULL , root, path, reloc_inode->i_ino, + ret =btrfs_lookup_file_extent (NULL , root, path,btrfs_ino (reloc_inode), bytenr,0 );if (ret <0 ) goto out;
@@ -1559,11 +1559,11 @@ int replace_file_extents(struct btrfs_trans_handle *trans,if (first) { inode =find_next_inode (root, key.objectid); first =0 ; - }else if (inode && inode->i_ino < key.objectid) { + }else if (inode &&btrfs_ino (inode) < key.objectid) {btrfs_add_delayed_iput (inode); inode =find_next_inode (root, key.objectid); } - if (inode && inode->i_ino == key.objectid) { + if (inode && btrfs_ino(inode) == key.objectid) { end = key.offset + btrfs_file_extent_num_bytes(leaf, fi); WARN_ON(!IS_ALIGNED(key.offset,
@@ -1893,6 +1893,7 @@ static int invalidate_extent_cache(struct btrfs_root *root,struct inode *inode =NULL ;u64 objectid;u64 start, end; +u64 ino; objectid = min_key->objectid;while (1 ) {
@@ -1905,17 +1906,18 @@ static int invalidate_extent_cache(struct btrfs_root *root, inode =find_next_inode (root, objectid);if (!inode)break ; + ino =btrfs_ino (inode); -if (inode->i_ino > max_key->objectid) { +if (ino > max_key->objectid) {iput (inode);break ; } - objectid = inode->i_ino +1 ; + objectid = ino +1 ;if (!S_ISREG (inode->i_mode))continue ; -if (unlikely (min_key->objectid == inode->i_ino)) { +if (unlikely (min_key->objectid == ino)) {if (min_key->type >BTRFS_EXTENT_DATA_KEY )continue ;if (min_key->type <BTRFS_EXTENT_DATA_KEY )
@@ -1928,7 +1930,7 @@ static int invalidate_extent_cache(struct btrfs_root *root, start =0 ; } -if (unlikely (max_key->objectid == inode->i_ino)) { +if (unlikely (max_key->objectid == ino)) {if (max_key->type <BTRFS_EXTENT_DATA_KEY )continue ;if (max_key->type >BTRFS_EXTENT_DATA_KEY ) {
fs/btrfs/transaction.c +2 -2
@@ -963,7 +963,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,BUG_ON (ret); ret =btrfs_insert_dir_item (trans, parent_root, dentry->d_name.name, dentry->d_name.len, - parent_inode->i_ino, &key, +btrfs_ino (parent_inode), &key,BTRFS_FT_DIR , index);BUG_ON (ret);
@@ -1004,7 +1004,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,*/ ret =btrfs_add_root_ref (trans, tree_root, objectid, parent_root->root_key.objectid, - parent_inode->i_ino, index, +btrfs_ino (parent_inode), index, dentry->d_name.name, dentry->d_name.len);BUG_ON (ret);dput (parent);
fs/btrfs/tree-log.c +29 -29
207 lines not on this page · raw message
fs/btrfs/xattr.c +4 -4
@@ -44,7 +44,7 @@ ssize_t __btrfs_getxattr(struct inode *inode, const char *name,return -ENOMEM ;/* lookup the xattr by name */ - di =btrfs_lookup_xattr (NULL , root, path, inode->i_ino, name, + di =btrfs_lookup_xattr (NULL , root, path,btrfs_ino (inode), name,strlen (name),0 );if (!di) { ret = -ENODATA ;
@@ -103,7 +103,7 @@ static int do_setxattr(struct btrfs_trans_handle *trans,return -ENOMEM ;/* first lets see if we already have this xattr */ - di =btrfs_lookup_xattr (trans, root, path, inode->i_ino, name, + di =btrfs_lookup_xattr (trans, root, path,btrfs_ino (inode), name,strlen (name),-1 );if (IS_ERR (di)) { ret =PTR_ERR (di);
@@ -136,7 +136,7 @@ static int do_setxattr(struct btrfs_trans_handle *trans, }/* ok we have to create a completely new xattr */ - ret =btrfs_insert_xattr_item (trans, root, path, inode->i_ino, + ret =btrfs_insert_xattr_item (trans, root, path,btrfs_ino (inode), name, name_len, value, size);BUG_ON (ret); out:
@@ -191,7 +191,7 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)* NOTE: we set key.offset = 0; because we want to start with the * first xattr that we find and walk forward */ - key.objectid = inode->i_ino; + key.objectid =btrfs_ino (inode);btrfs_set_key_type (&key,BTRFS_XATTR_ITEM_KEY ); key.offset =0 ;
Signature · 1 line
1.7.3.1
PATCH 7/7 Btrfs: Support reading/writing on disk free ino cache
In reply to Li ZefanThis is similar to block group caching.
We dedicate a special inode in fs tree to save free ino cache.
At the very first time we create/delete a file after mount, the free ino cache will be loaded from disk into memory. When the fs tree is commited, the cache will be written back to disk.
To keep compatibility, we check the root generation against the generation of the special inode when loading the cache, so the loading will fail if the btrfs filesystem was mounted in an older kernel before.
--- fs/btrfs/ctree.h | 7 +++ fs/btrfs/disk-io.c | 1 + fs/btrfs/extent-tree.c | 3 +- fs/btrfs/free-space-cache.c | 97 ++++++++++++++++++++++++++++++++++++++++++- fs/btrfs/free-space-cache.h | 11 +++++ fs/btrfs/inode-map.c | 87 ++++++++++++++++++++++++++++++++++++++ fs/btrfs/inode-map.h | 2 + fs/btrfs/inode.c | 45 ++++++++++++-------- fs/btrfs/transaction.c | 2 + 9 files changed, 236 insertions(+), 19 deletions(-)
fs/btrfs/ctree.h +7 -0
@@ -103,6 +103,12 @@ struct btrfs_ordered_sum;/* For storing free space cache */ #define BTRFS_FREE_SPACE_OBJECTID -11ULL +/* +* The inode number assigned to the special inode for sotring +* free ino cache +*/ +#define BTRFS_FREE_INO_OBJECTID -12ULL +/* dummy objectid represents multiple objectids */ #define BTRFS_MULTIPLE_OBJECTIDS -255ULL
@@ -1109,6 +1115,7 @@ struct btrfs_root {wait_queue_head_t cache_wait;struct btrfs_free_space_ctl *free_ino_pinned;u64 cache_progress; +struct inode *cache_inode;struct mutex log_mutex;wait_queue_head_t log_writer_wait;
fs/btrfs/disk-io.c +1 -0
@@ -2403,6 +2403,7 @@ int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)static void free_fs_root (struct btrfs_root *root) { +iput (root->cache_inode);WARN_ON (!RB_EMPTY_ROOT (&root->inode_tree));if (root->anon_super.s_dev) {down_write (&root->anon_super.s_umount);
fs/btrfs/extent-tree.c +2 -1
@@ -3122,7 +3122,8 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes)/* make sure bytes are sectorsize aligned */ bytes = (bytes + root->sectorsize -1 ) & ~((u64 )root->sectorsize -1 ); -if (root == root->fs_info->tree_root) { +if (root == root->fs_info->tree_root || +BTRFS_I (inode)->location.objectid ==BTRFS_FREE_INO_OBJECTID ) { alloc_chunk =0 ; committed =1 ; }
fs/btrfs/free-space-cache.c +96 -1
118 lines not on this page · raw message
fs/btrfs/free-space-cache.h +11 -0
@@ -65,6 +65,17 @@ int btrfs_write_out_cache(struct btrfs_root *root,struct btrfs_block_group_cache *block_group, struct btrfs_path *path); +struct inode *lookup_free_ino_inode (struct btrfs_root *root, +struct btrfs_path *path); +int create_free_ino_inode (struct btrfs_root *root, +struct btrfs_trans_handle *trans, +struct btrfs_path *path); +int load_free_ino_cache (struct btrfs_fs_info *fs_info, +struct btrfs_root *root); +int btrfs_write_out_ino_cache (struct btrfs_root *root, +struct btrfs_trans_handle *trans, +struct btrfs_path *path); +void btrfs_init_free_space_ctl (struct btrfs_block_group_cache *block_group);int __btrfs_add_free_space (struct btrfs_free_space_ctl *ctl,u64 bytenr,u64 size);
fs/btrfs/inode-map.c +87 -0
105 lines not on this page · raw message
fs/btrfs/inode-map.h +2 -0
@@ -5,6 +5,8 @@ void btrfs_init_free_ino_ctl(struct btrfs_root *root);void btrfs_unpin_free_ino (struct btrfs_root *root);void btrfs_return_ino (struct btrfs_root *root,u64 objectid);int btrfs_find_free_ino (struct btrfs_root *root,u64 *objectid); +int btrfs_save_ino_cache (struct btrfs_root *root, +struct btrfs_trans_handle *trans);int btrfs_find_free_objectid (struct btrfs_root *root,u64 *objectid);
fs/btrfs/inode.c +28 -17
123 lines not on this page · raw message
fs/btrfs/transaction.c +2 -0
@@ -752,6 +752,8 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,btrfs_update_reloc_root (trans, root);btrfs_orphan_commit_root (trans, root); +btrfs_save_ino_cache (root, trans); +if (root->commit_root != root->node) {mutex_lock (&root->fs_commit_mutex);switch_commit_root (root);
Signature · 1 line
1.7.3.1