diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /fs/nilfs2/gcinode.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'fs/nilfs2/gcinode.c')
-rw-r--r-- | fs/nilfs2/gcinode.c | 151 |
1 files changed, 24 insertions, 127 deletions
diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c index bed3a783129b..08a07a218d26 100644 --- a/fs/nilfs2/gcinode.c +++ b/fs/nilfs2/gcinode.c | |||
@@ -28,13 +28,6 @@ | |||
28 | * gcinodes), and this file provides lookup function of the dummy | 28 | * gcinodes), and this file provides lookup function of the dummy |
29 | * inodes and their buffer read function. | 29 | * inodes and their buffer read function. |
30 | * | 30 | * |
31 | * Since NILFS2 keeps up multiple checkpoints/snapshots across GC, it | ||
32 | * has to treat blocks that belong to a same file but have different | ||
33 | * checkpoint numbers. To avoid interference among generations, dummy | ||
34 | * inodes are managed separately from actual inodes, and their lookup | ||
35 | * function (nilfs_gc_iget) is designed to be specified with a | ||
36 | * checkpoint number argument as well as an inode number. | ||
37 | * | ||
38 | * Buffers and pages held by the dummy inodes will be released each | 31 | * Buffers and pages held by the dummy inodes will be released each |
39 | * time after they are copied to a new log. Dirty blocks made on the | 32 | * time after they are copied to a new log. Dirty blocks made on the |
40 | * current generation and the blocks to be moved by GC never overlap | 33 | * current generation and the blocks to be moved by GC never overlap |
@@ -55,10 +48,6 @@ | |||
55 | #include "dat.h" | 48 | #include "dat.h" |
56 | #include "ifile.h" | 49 | #include "ifile.h" |
57 | 50 | ||
58 | static const struct address_space_operations def_gcinode_aops = { | ||
59 | .sync_page = block_sync_page, | ||
60 | }; | ||
61 | |||
62 | /* | 51 | /* |
63 | * nilfs_gccache_submit_read_data() - add data buffer and submit read request | 52 | * nilfs_gccache_submit_read_data() - add data buffer and submit read request |
64 | * @inode - gc inode | 53 | * @inode - gc inode |
@@ -95,9 +84,9 @@ int nilfs_gccache_submit_read_data(struct inode *inode, sector_t blkoff, | |||
95 | goto out; | 84 | goto out; |
96 | 85 | ||
97 | if (pbn == 0) { | 86 | if (pbn == 0) { |
98 | struct inode *dat_inode = NILFS_I_NILFS(inode)->ns_dat; | 87 | struct the_nilfs *nilfs = inode->i_sb->s_fs_info; |
99 | /* use original dat, not gc dat. */ | 88 | |
100 | err = nilfs_dat_translate(dat_inode, vbn, &pbn); | 89 | err = nilfs_dat_translate(nilfs->ns_dat, vbn, &pbn); |
101 | if (unlikely(err)) { /* -EIO, -ENOMEM, -ENOENT */ | 90 | if (unlikely(err)) { /* -EIO, -ENOMEM, -ENOENT */ |
102 | brelse(bh); | 91 | brelse(bh); |
103 | goto failed; | 92 | goto failed; |
@@ -111,7 +100,7 @@ int nilfs_gccache_submit_read_data(struct inode *inode, sector_t blkoff, | |||
111 | } | 100 | } |
112 | 101 | ||
113 | if (!buffer_mapped(bh)) { | 102 | if (!buffer_mapped(bh)) { |
114 | bh->b_bdev = NILFS_I_NILFS(inode)->ns_bdev; | 103 | bh->b_bdev = inode->i_sb->s_bdev; |
115 | set_buffer_mapped(bh); | 104 | set_buffer_mapped(bh); |
116 | } | 105 | } |
117 | bh->b_blocknr = pbn; | 106 | bh->b_blocknr = pbn; |
@@ -168,132 +157,40 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *bh) | |||
168 | if (buffer_dirty(bh)) | 157 | if (buffer_dirty(bh)) |
169 | return -EEXIST; | 158 | return -EEXIST; |
170 | 159 | ||
171 | if (buffer_nilfs_node(bh)) { | 160 | if (buffer_nilfs_node(bh) && nilfs_btree_broken_node_block(bh)) { |
172 | if (nilfs_btree_broken_node_block(bh)) { | 161 | clear_buffer_uptodate(bh); |
173 | clear_buffer_uptodate(bh); | 162 | return -EIO; |
174 | return -EIO; | ||
175 | } | ||
176 | nilfs_btnode_mark_dirty(bh); | ||
177 | } else { | ||
178 | nilfs_mdt_mark_buffer_dirty(bh); | ||
179 | } | 163 | } |
164 | mark_buffer_dirty(bh); | ||
180 | return 0; | 165 | return 0; |
181 | } | 166 | } |
182 | 167 | ||
183 | /* | 168 | int nilfs_init_gcinode(struct inode *inode) |
184 | * nilfs_init_gccache() - allocate and initialize gc_inode hash table | ||
185 | * @nilfs - the_nilfs | ||
186 | * | ||
187 | * Return Value: On success, 0. | ||
188 | * On error, a negative error code is returned. | ||
189 | */ | ||
190 | int nilfs_init_gccache(struct the_nilfs *nilfs) | ||
191 | { | ||
192 | int loop; | ||
193 | |||
194 | BUG_ON(nilfs->ns_gc_inodes_h); | ||
195 | |||
196 | INIT_LIST_HEAD(&nilfs->ns_gc_inodes); | ||
197 | |||
198 | nilfs->ns_gc_inodes_h = | ||
199 | kmalloc(sizeof(struct hlist_head) * NILFS_GCINODE_HASH_SIZE, | ||
200 | GFP_NOFS); | ||
201 | if (nilfs->ns_gc_inodes_h == NULL) | ||
202 | return -ENOMEM; | ||
203 | |||
204 | for (loop = 0; loop < NILFS_GCINODE_HASH_SIZE; loop++) | ||
205 | INIT_HLIST_HEAD(&nilfs->ns_gc_inodes_h[loop]); | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * nilfs_destroy_gccache() - free gc_inode hash table | ||
211 | * @nilfs - the nilfs | ||
212 | */ | ||
213 | void nilfs_destroy_gccache(struct the_nilfs *nilfs) | ||
214 | { | ||
215 | if (nilfs->ns_gc_inodes_h) { | ||
216 | nilfs_remove_all_gcinode(nilfs); | ||
217 | kfree(nilfs->ns_gc_inodes_h); | ||
218 | nilfs->ns_gc_inodes_h = NULL; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | static struct inode *alloc_gcinode(struct the_nilfs *nilfs, ino_t ino, | ||
223 | __u64 cno) | ||
224 | { | 169 | { |
225 | struct inode *inode; | 170 | struct nilfs_inode_info *ii = NILFS_I(inode); |
226 | struct nilfs_inode_info *ii; | ||
227 | |||
228 | inode = nilfs_mdt_new_common(nilfs, NULL, ino, GFP_NOFS, 0); | ||
229 | if (!inode) | ||
230 | return NULL; | ||
231 | 171 | ||
232 | inode->i_op = NULL; | 172 | inode->i_mode = S_IFREG; |
233 | inode->i_fop = NULL; | 173 | mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); |
234 | inode->i_mapping->a_ops = &def_gcinode_aops; | 174 | inode->i_mapping->a_ops = &empty_aops; |
175 | inode->i_mapping->backing_dev_info = inode->i_sb->s_bdi; | ||
235 | 176 | ||
236 | ii = NILFS_I(inode); | ||
237 | ii->i_cno = cno; | ||
238 | ii->i_flags = 0; | 177 | ii->i_flags = 0; |
239 | ii->i_state = 1 << NILFS_I_GCINODE; | ||
240 | ii->i_bh = NULL; | ||
241 | nilfs_bmap_init_gc(ii->i_bmap); | 178 | nilfs_bmap_init_gc(ii->i_bmap); |
242 | 179 | ||
243 | return inode; | 180 | return 0; |
244 | } | ||
245 | |||
246 | static unsigned long ihash(ino_t ino, __u64 cno) | ||
247 | { | ||
248 | return hash_long((unsigned long)((ino << 2) + cno), | ||
249 | NILFS_GCINODE_HASH_BITS); | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * nilfs_gc_iget() - find or create gc inode with specified (ino,cno) | ||
254 | */ | ||
255 | struct inode *nilfs_gc_iget(struct the_nilfs *nilfs, ino_t ino, __u64 cno) | ||
256 | { | ||
257 | struct hlist_head *head = nilfs->ns_gc_inodes_h + ihash(ino, cno); | ||
258 | struct hlist_node *node; | ||
259 | struct inode *inode; | ||
260 | |||
261 | hlist_for_each_entry(inode, node, head, i_hash) { | ||
262 | if (inode->i_ino == ino && NILFS_I(inode)->i_cno == cno) | ||
263 | return inode; | ||
264 | } | ||
265 | |||
266 | inode = alloc_gcinode(nilfs, ino, cno); | ||
267 | if (likely(inode)) { | ||
268 | hlist_add_head(&inode->i_hash, head); | ||
269 | list_add(&NILFS_I(inode)->i_dirty, &nilfs->ns_gc_inodes); | ||
270 | } | ||
271 | return inode; | ||
272 | } | ||
273 | |||
274 | /* | ||
275 | * nilfs_clear_gcinode() - clear and free a gc inode | ||
276 | */ | ||
277 | void nilfs_clear_gcinode(struct inode *inode) | ||
278 | { | ||
279 | nilfs_mdt_destroy(inode); | ||
280 | } | 181 | } |
281 | 182 | ||
282 | /* | 183 | /** |
283 | * nilfs_remove_all_gcinode() - remove all inodes from the_nilfs | 184 | * nilfs_remove_all_gcinodes() - remove all unprocessed gc inodes |
284 | */ | 185 | */ |
285 | void nilfs_remove_all_gcinode(struct the_nilfs *nilfs) | 186 | void nilfs_remove_all_gcinodes(struct the_nilfs *nilfs) |
286 | { | 187 | { |
287 | struct hlist_head *head = nilfs->ns_gc_inodes_h; | 188 | struct list_head *head = &nilfs->ns_gc_inodes; |
288 | struct hlist_node *node, *n; | 189 | struct nilfs_inode_info *ii; |
289 | struct inode *inode; | ||
290 | int loop; | ||
291 | 190 | ||
292 | for (loop = 0; loop < NILFS_GCINODE_HASH_SIZE; loop++, head++) { | 191 | while (!list_empty(head)) { |
293 | hlist_for_each_entry_safe(inode, node, n, head, i_hash) { | 192 | ii = list_first_entry(head, struct nilfs_inode_info, i_dirty); |
294 | hlist_del_init(&inode->i_hash); | 193 | list_del_init(&ii->i_dirty); |
295 | list_del_init(&NILFS_I(inode)->i_dirty); | 194 | iput(&ii->vfs_inode); |
296 | nilfs_clear_gcinode(inode); /* might sleep */ | ||
297 | } | ||
298 | } | 195 | } |
299 | } | 196 | } |