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 | } |
