diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-03-01 18:59:40 -0500 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-03-01 18:59:40 -0500 |
commit | ed2ff2cba766dfe7976a0113f667c9a0a50dff02 (patch) | |
tree | cbae5fcf89fa248c656f2c27532b15f34107d93f /fs/btrfs/disk-io.c | |
parent | 79f95c82dca7665f32bafd68b7cdf4a01fab0840 (diff) |
Btrfs: pretend page cache & commit code
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 91 |
1 files changed, 89 insertions, 2 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index c42dc72706bf..656ace6147a8 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -11,6 +11,8 @@ | |||
11 | #include "disk-io.h" | 11 | #include "disk-io.h" |
12 | 12 | ||
13 | static int allocated_blocks = 0; | 13 | static int allocated_blocks = 0; |
14 | int cache_size = 0; | ||
15 | int cache_max = 10000; | ||
14 | 16 | ||
15 | static int check_tree_block(struct ctree_root *root, struct tree_buffer *buf) | 17 | static int check_tree_block(struct ctree_root *root, struct tree_buffer *buf) |
16 | { | 18 | { |
@@ -21,6 +23,25 @@ static int check_tree_block(struct ctree_root *root, struct tree_buffer *buf) | |||
21 | return 0; | 23 | return 0; |
22 | } | 24 | } |
23 | 25 | ||
26 | static int free_some_buffers(struct ctree_root *root) | ||
27 | { | ||
28 | struct list_head *node, *next; | ||
29 | struct tree_buffer *b; | ||
30 | if (root->cache_size < cache_max) | ||
31 | return 0; | ||
32 | list_for_each_safe(node, next, &root->cache) { | ||
33 | b = list_entry(node, struct tree_buffer, cache); | ||
34 | if (b->count == 1) { | ||
35 | BUG_ON(!list_empty(&b->dirty)); | ||
36 | list_del_init(&b->cache); | ||
37 | tree_block_release(root, b); | ||
38 | if (root->cache_size < cache_max) | ||
39 | return 0; | ||
40 | } | ||
41 | } | ||
42 | return 0; | ||
43 | } | ||
44 | |||
24 | struct tree_buffer *alloc_tree_block(struct ctree_root *root, u64 blocknr) | 45 | struct tree_buffer *alloc_tree_block(struct ctree_root *root, u64 blocknr) |
25 | { | 46 | { |
26 | struct tree_buffer *buf; | 47 | struct tree_buffer *buf; |
@@ -30,10 +51,14 @@ struct tree_buffer *alloc_tree_block(struct ctree_root *root, u64 blocknr) | |||
30 | return buf; | 51 | return buf; |
31 | allocated_blocks++; | 52 | allocated_blocks++; |
32 | buf->blocknr = blocknr; | 53 | buf->blocknr = blocknr; |
33 | buf->count = 1; | 54 | buf->count = 2; |
55 | INIT_LIST_HEAD(&buf->dirty); | ||
56 | free_some_buffers(root); | ||
34 | radix_tree_preload(GFP_KERNEL); | 57 | radix_tree_preload(GFP_KERNEL); |
35 | ret = radix_tree_insert(&root->cache_radix, blocknr, buf); | 58 | ret = radix_tree_insert(&root->cache_radix, blocknr, buf); |
36 | radix_tree_preload_end(); | 59 | radix_tree_preload_end(); |
60 | list_add_tail(&buf->cache, &root->cache); | ||
61 | root->cache_size++; | ||
37 | if (ret) { | 62 | if (ret) { |
38 | free(buf); | 63 | free(buf); |
39 | return NULL; | 64 | return NULL; |
@@ -57,7 +82,6 @@ struct tree_buffer *find_tree_block(struct ctree_root *root, u64 blocknr) | |||
57 | return buf; | 82 | return buf; |
58 | } | 83 | } |
59 | 84 | ||
60 | |||
61 | struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr) | 85 | struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr) |
62 | { | 86 | { |
63 | loff_t offset = blocknr * CTREE_BLOCKSIZE; | 87 | loff_t offset = blocknr * CTREE_BLOCKSIZE; |
@@ -82,6 +106,24 @@ struct tree_buffer *read_tree_block(struct ctree_root *root, u64 blocknr) | |||
82 | return buf; | 106 | return buf; |
83 | } | 107 | } |
84 | 108 | ||
109 | int dirty_tree_block(struct ctree_root *root, struct tree_buffer *buf) | ||
110 | { | ||
111 | if (!list_empty(&buf->dirty)) | ||
112 | return 0; | ||
113 | list_add_tail(&buf->dirty, &root->trans); | ||
114 | buf->count++; | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | int clean_tree_block(struct ctree_root *root, struct tree_buffer *buf) | ||
119 | { | ||
120 | if (!list_empty(&buf->dirty)) { | ||
121 | list_del_init(&buf->dirty); | ||
122 | tree_block_release(root, buf); | ||
123 | } | ||
124 | return 0; | ||
125 | } | ||
126 | |||
85 | int write_tree_block(struct ctree_root *root, struct tree_buffer *buf) | 127 | int write_tree_block(struct ctree_root *root, struct tree_buffer *buf) |
86 | { | 128 | { |
87 | u64 blocknr = buf->blocknr; | 129 | u64 blocknr = buf->blocknr; |
@@ -96,9 +138,37 @@ int write_tree_block(struct ctree_root *root, struct tree_buffer *buf) | |||
96 | return 0; | 138 | return 0; |
97 | } | 139 | } |
98 | 140 | ||
141 | static int __commit_transaction(struct ctree_root *root) | ||
142 | { | ||
143 | struct tree_buffer *b; | ||
144 | int ret = 0; | ||
145 | int wret; | ||
146 | while(!list_empty(&root->trans)) { | ||
147 | b = list_entry(root->trans.next, struct tree_buffer, dirty); | ||
148 | list_del_init(&b->dirty); | ||
149 | wret = write_tree_block(root, b); | ||
150 | if (wret) | ||
151 | ret = wret; | ||
152 | tree_block_release(root, b); | ||
153 | } | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | int commit_transaction(struct ctree_root *root) | ||
158 | { | ||
159 | int ret; | ||
160 | ret = __commit_transaction(root); | ||
161 | if (!ret && root != root->extent_root) | ||
162 | ret = __commit_transaction(root->extent_root); | ||
163 | BUG_ON(ret); | ||
164 | return ret; | ||
165 | } | ||
166 | |||
99 | static int __setup_root(struct ctree_root *root, struct ctree_root *extent_root, | 167 | static int __setup_root(struct ctree_root *root, struct ctree_root *extent_root, |
100 | struct ctree_root_info *info, int fp) | 168 | struct ctree_root_info *info, int fp) |
101 | { | 169 | { |
170 | INIT_LIST_HEAD(&root->trans); | ||
171 | INIT_LIST_HEAD(&root->cache); | ||
102 | root->fp = fp; | 172 | root->fp = fp; |
103 | root->node = NULL; | 173 | root->node = NULL; |
104 | root->node = read_tree_block(root, info->tree_root); | 174 | root->node = read_tree_block(root, info->tree_root); |
@@ -157,8 +227,23 @@ int write_ctree_super(struct ctree_root *root, struct ctree_super_block *s) | |||
157 | return 0; | 227 | return 0; |
158 | } | 228 | } |
159 | 229 | ||
230 | static int drop_cache(struct ctree_root *root) | ||
231 | { | ||
232 | while(!list_empty(&root->cache)) { | ||
233 | struct tree_buffer *b = list_entry(root->cache.next, | ||
234 | struct tree_buffer, cache); | ||
235 | list_del_init(&b->cache); | ||
236 | tree_block_release(root, b); | ||
237 | } | ||
238 | return 0; | ||
239 | } | ||
160 | int close_ctree(struct ctree_root *root) | 240 | int close_ctree(struct ctree_root *root) |
161 | { | 241 | { |
242 | drop_cache(root->extent_root); | ||
243 | drop_cache(root); | ||
244 | BUG_ON(!list_empty(&root->trans)); | ||
245 | BUG_ON(!list_empty(&root->extent_root->trans)); | ||
246 | |||
162 | close(root->fp); | 247 | close(root->fp); |
163 | if (root->node) | 248 | if (root->node) |
164 | tree_block_release(root, root->node); | 249 | tree_block_release(root, root->node); |
@@ -182,6 +267,8 @@ void tree_block_release(struct ctree_root *root, struct tree_buffer *buf) | |||
182 | free(buf); | 267 | free(buf); |
183 | BUG_ON(allocated_blocks == 0); | 268 | BUG_ON(allocated_blocks == 0); |
184 | allocated_blocks--; | 269 | allocated_blocks--; |
270 | BUG_ON(root->cache_size == 0); | ||
271 | root->cache_size--; | ||
185 | } | 272 | } |
186 | } | 273 | } |
187 | 274 | ||