diff options
Diffstat (limited to 'fs/nilfs2/gcinode.c')
-rw-r--r-- | fs/nilfs2/gcinode.c | 134 |
1 files changed, 24 insertions, 110 deletions
diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c index bed3a783129b..33ad25ddd5c4 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 |
@@ -175,125 +168,46 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *bh) | |||
175 | } | 168 | } |
176 | nilfs_btnode_mark_dirty(bh); | 169 | nilfs_btnode_mark_dirty(bh); |
177 | } else { | 170 | } else { |
178 | nilfs_mdt_mark_buffer_dirty(bh); | 171 | nilfs_mark_buffer_dirty(bh); |
179 | } | 172 | } |
180 | return 0; | 173 | return 0; |
181 | } | 174 | } |
182 | 175 | ||
183 | /* | 176 | 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 | { | 177 | { |
192 | int loop; | 178 | struct nilfs_inode_info *ii = NILFS_I(inode); |
193 | 179 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; | |
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 | { | ||
225 | struct inode *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 | 180 | ||
232 | inode->i_op = NULL; | 181 | inode->i_mode = S_IFREG; |
233 | inode->i_fop = NULL; | 182 | mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); |
234 | inode->i_mapping->a_ops = &def_gcinode_aops; | 183 | inode->i_mapping->a_ops = &def_gcinode_aops; |
184 | inode->i_mapping->backing_dev_info = inode->i_sb->s_bdi; | ||
235 | 185 | ||
236 | ii = NILFS_I(inode); | ||
237 | ii->i_cno = cno; | ||
238 | ii->i_flags = 0; | 186 | 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); | 187 | nilfs_bmap_init_gc(ii->i_bmap); |
242 | 188 | ||
243 | return inode; | 189 | /* |
244 | } | 190 | * Add the inode to GC inode list. Garbage Collection |
245 | 191 | * is serialized and no two processes manipulate the | |
246 | static unsigned long ihash(ino_t ino, __u64 cno) | 192 | * list simultaneously. |
247 | { | 193 | */ |
248 | return hash_long((unsigned long)((ino << 2) + cno), | 194 | igrab(inode); |
249 | NILFS_GCINODE_HASH_BITS); | 195 | list_add(&NILFS_I(inode)->i_dirty, &nilfs->ns_gc_inodes); |
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 | 196 | ||
266 | inode = alloc_gcinode(nilfs, ino, cno); | 197 | return 0; |
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 | } | 198 | } |
281 | 199 | ||
282 | /* | 200 | /** |
283 | * nilfs_remove_all_gcinode() - remove all inodes from the_nilfs | 201 | * nilfs_remove_all_gcinodes() - remove all unprocessed gc inodes |
284 | */ | 202 | */ |
285 | void nilfs_remove_all_gcinode(struct the_nilfs *nilfs) | 203 | void nilfs_remove_all_gcinodes(struct the_nilfs *nilfs) |
286 | { | 204 | { |
287 | struct hlist_head *head = nilfs->ns_gc_inodes_h; | 205 | struct list_head *head = &nilfs->ns_gc_inodes; |
288 | struct hlist_node *node, *n; | 206 | struct nilfs_inode_info *ii; |
289 | struct inode *inode; | ||
290 | int loop; | ||
291 | 207 | ||
292 | for (loop = 0; loop < NILFS_GCINODE_HASH_SIZE; loop++, head++) { | 208 | while (!list_empty(head)) { |
293 | hlist_for_each_entry_safe(inode, node, n, head, i_hash) { | 209 | ii = list_first_entry(head, struct nilfs_inode_info, i_dirty); |
294 | hlist_del_init(&inode->i_hash); | 210 | list_del_init(&ii->i_dirty); |
295 | list_del_init(&NILFS_I(inode)->i_dirty); | 211 | iput(&ii->vfs_inode); |
296 | nilfs_clear_gcinode(inode); /* might sleep */ | ||
297 | } | ||
298 | } | 212 | } |
299 | } | 213 | } |