Hello,
This patch adds two hooks to 'extent_map_ops'. 'set_extent_bit'
and
'set_extent_bit' call the hook functions before they modify
'extent_state->state'. The last parameter of the hook functions
indicates bits that will be inverted. By using these hooks, do delay
allocation accounting is easy.
Regards
YZ
---
diff -r dc03d8df4762 ctree.h
--- a/ctree.h Wed Nov 07 21:08:16 2007 -0500
+++ b/ctree.h Mon Nov 12 11:03:16 2007 +0800
@@ -323,6 +323,9 @@ struct btrfs_fs_info {
struct completion kobj_unregister;
int do_barriers;
int closing;
+
+ u64 total_delalloc;
+ spinlock_t stat_lock;
};
/*
diff -r dc03d8df4762 disk-io.c
--- a/disk-io.c Wed Nov 07 21:08:16 2007 -0500
+++ b/disk-io.c Mon Nov 12 11:03:16 2007 +0800
@@ -570,6 +570,9 @@ struct btrfs_root *open_ctree(struct sup
fs_info->do_barriers = 1;
fs_info->closing = 0;
+ fs_info->total_delalloc = 0;
+ spin_lock_init(&fs_info->stat_lock);
+
INIT_DELAYED_WORK(&fs_info->trans_work, btrfs_transaction_cleaner);
BTRFS_I(fs_info->btree_inode)->root = tree_root;
memset(&BTRFS_I(fs_info->btree_inode)->location, 0,
diff -r dc03d8df4762 extent_map.c
--- a/extent_map.c Wed Nov 07 21:08:16 2007 -0500
+++ b/extent_map.c Mon Nov 12 11:03:16 2007 +0800
@@ -502,7 +502,15 @@ int clear_extent_bit(struct extent_map_t
unsigned long flags;
int err;
int set = 0;
-
+ int clear = bits;
+ void (*hook)(struct extent_map_tree *, struct extent_state *, int);
+
+ if (delete)
+ clear = -1;
+ if (tree->ops)
+ hook = tree->ops->clear_extent_bits_hook;
+ else
+ hook = NULL;
again:
if (!prealloc && (mask & __GFP_WAIT)) {
prealloc = alloc_extent_state(mask);
@@ -546,6 +554,8 @@ again:
if (err)
goto out;
if (state->end <= end) {
+ if (hook)
+ hook(tree, state, clear & state->state);
start = state->end + 1;
set |= clear_state_bit(tree, state, bits,
wake, delete);
@@ -566,12 +576,16 @@ again:
if (wake)
wake_up(&state->wq);
+ if (hook)
+ hook(tree, prealloc, clear & prealloc->state);
set |= clear_state_bit(tree, prealloc, bits,
wake, delete);
prealloc = NULL;
goto out;
}
+ if (hook)
+ hook(tree, state, clear & state->state);
start = state->end + 1;
set |= clear_state_bit(tree, state, bits, wake, delete);
goto search_again;
@@ -677,6 +691,12 @@ int set_extent_bit(struct extent_map_tre
int set;
u64 last_start;
u64 last_end;
+ void (*hook)(struct extent_map_tree *, struct extent_state *, int);
+
+ if (tree->ops)
+ hook = tree->ops->set_extent_bits_hook;
+ else
+ hook = NULL;
again:
if (!prealloc && (mask & __GFP_WAIT)) {
prealloc = alloc_extent_state(mask);
@@ -691,6 +711,11 @@ again:
*/
node = tree_search(&tree->state, start);
if (!node) {
+ if (hook) {
+ prealloc->start = start;
+ prealloc->end = end;
+ hook(tree, prealloc, bits);
+ }
err = insert_state(tree, prealloc, start, end, bits);
prealloc = NULL;
BUG_ON(err == -EEXIST);
@@ -714,6 +739,8 @@ again:
err = -EEXIST;
goto out;
}
+ if (hook)
+ hook(tree, state, bits ^ set);
state->state |= bits;
start = state->end + 1;
merge_state(tree, state);
@@ -749,6 +776,8 @@ again:
if (err)
goto out;
if (state->end <= end) {
+ if (hook)
+ hook(tree, state, bits ^ set);
state->state |= bits;
start = state->end + 1;
merge_state(tree, state);
@@ -770,6 +799,11 @@ again:
this_end = end;
else
this_end = last_start -1;
+ if (hook) {
+ prealloc->start = start;
+ prealloc->end = this_end;
+ hook(tree, prealloc, bits);
+ }
err = insert_state(tree, prealloc, start, this_end,
bits);
prealloc = NULL;
@@ -794,7 +828,8 @@ again:
}
err = split_state(tree, state, prealloc, end + 1);
BUG_ON(err == -EEXIST);
-
+ if (hook)
+ hook(tree, prealloc, bits ^ set);
prealloc->state |= bits;
merge_state(tree, prealloc);
prealloc = NULL;
diff -r dc03d8df4762 extent_map.h
--- a/extent_map.h Wed Nov 07 21:08:16 2007 -0500
+++ b/extent_map.h Mon Nov 12 11:03:16 2007 +0800
@@ -27,6 +27,9 @@
#define EXTENT_PAGE_PRIVATE 1
#define EXTENT_PAGE_PRIVATE_FIRST_PAGE 3
+struct extent_map;
+struct extent_state;
+struct extent_map_tree;
struct extent_map_ops {
int (*fill_delalloc)(struct inode *inode, u64 start, u64 end);
@@ -34,6 +37,10 @@ struct extent_map_ops {
int (*readpage_io_hook)(struct page *page, u64 start, u64 end);
int (*readpage_end_io_hook)(struct page *page, u64 start, u64 end);
void (*writepage_end_io_hook)(struct page *page, u64 start, u64 end);
+ void (*set_extent_bits_hook)(struct extent_map_tree *tree,
+ struct extent_state *state, int diff);
+ void (*clear_extent_bits_hook)(struct extent_map_tree *tree,
+ struct extent_state *state, int diff);
};
struct extent_map_tree {
diff -r dc03d8df4762 inode.c
--- a/inode.c Wed Nov 07 21:08:16 2007 -0500
+++ b/inode.c Mon Nov 12 11:03:16 2007 +0800
@@ -196,6 +196,36 @@ zeroit:
kunmap_atomic(kaddr, KM_IRQ0);
local_irq_restore(flags);
return 0;
+}
+
+void btrfs_set_extent_bits_hook(struct extent_map_tree *tree,
+ struct extent_state *state, int diff)
+{
+ struct inode *inode = tree->mapping->host;
+ struct btrfs_fs_info *info = BTRFS_I(inode)->root->fs_info;
+
+ /* local irq has already been disabled */
+ if (diff & EXTENT_DELALLOC) {
+ spin_lock(&info->stat_lock);
+ info->total_delalloc += state->end + 1 - state->start;
+ spin_unlock(&info->stat_lock);
+ }
+ return;
+}
+
+void btrfs_clear_extent_bits_hook(struct extent_map_tree *tree,
+ struct extent_state *state, int diff)
+{
+ struct inode *inode = tree->mapping->host;
+ struct btrfs_fs_info *info = BTRFS_I(inode)->root->fs_info;
+
+ /* local irq has already been disabled */
+ if (diff & EXTENT_DELALLOC) {
+ spin_lock(&info->stat_lock);
+ info->total_delalloc -= state->end + 1 - state->start;
+ spin_unlock(&info->stat_lock);
+ }
+ return;
}
void btrfs_read_locked_inode(struct inode *inode)
@@ -2531,6 +2561,8 @@ static struct extent_map_ops btrfs_exten
.writepage_io_hook = btrfs_writepage_io_hook,
.readpage_io_hook = btrfs_readpage_io_hook,
.readpage_end_io_hook = btrfs_readpage_end_io_hook,
+ .set_extent_bits_hook = btrfs_set_extent_bits_hook,
+ .clear_extent_bits_hook = btrfs_clear_extent_bits_hook,
};
static struct address_space_operations btrfs_aops = {