📄 extent_map.c
字号:
} rb_erase(&old_ent->e_node, &em->em_extents); /* Now that he's erased, set him up for deletion */ ctxt->old_ent = old_ent; if (ctxt->need_left) { ret = ocfs2_extent_map_insert_entry(em, ctxt->left_ent); if (ret) goto out_unlock; ctxt->left_ent = NULL; } if (ctxt->need_right) { ret = ocfs2_extent_map_insert_entry(em, ctxt->right_ent); if (ret) goto out_unlock; ctxt->right_ent = NULL; } ret = ocfs2_extent_map_insert_entry(em, ctxt->new_ent); if (!ret) ctxt->new_ent = NULL;out_unlock: spin_unlock(&OCFS2_I(inode)->ip_lock); return ret;}int ocfs2_extent_map_insert(struct inode *inode, struct ocfs2_extent_rec *rec, int tree_depth){ int ret; struct ocfs2_em_insert_context ctxt = {0, }; if ((le32_to_cpu(rec->e_cpos) + le32_to_cpu(rec->e_clusters)) > OCFS2_I(inode)->ip_map.em_clusters) { ret = -EBADR; mlog_errno(ret); return ret; } /* Zero e_clusters means a truncated tail record. It better be EOF */ if (!rec->e_clusters) { if ((le32_to_cpu(rec->e_cpos) + le32_to_cpu(rec->e_clusters)) != OCFS2_I(inode)->ip_map.em_clusters) { ret = -EBADR; mlog_errno(ret); ocfs2_error(inode->i_sb, "Zero e_clusters on non-tail extent record at e_blkno %"MLFu64" on inode %"MLFu64"\n", le64_to_cpu(rec->e_blkno), OCFS2_I(inode)->ip_blkno); return ret; } /* Ignore the truncated tail */ return 0; } ret = -ENOMEM; ctxt.new_ent = kmem_cache_alloc(ocfs2_em_ent_cachep, GFP_NOFS); if (!ctxt.new_ent) { mlog_errno(ret); return ret; } ctxt.new_ent->e_rec = *rec; ctxt.new_ent->e_tree_depth = tree_depth; do { ret = -ENOMEM; if (ctxt.need_left && !ctxt.left_ent) { ctxt.left_ent = kmem_cache_alloc(ocfs2_em_ent_cachep, GFP_NOFS); if (!ctxt.left_ent) break; } if (ctxt.need_right && !ctxt.right_ent) { ctxt.right_ent = kmem_cache_alloc(ocfs2_em_ent_cachep, GFP_NOFS); if (!ctxt.right_ent) break; } ret = ocfs2_extent_map_try_insert(inode, rec, tree_depth, &ctxt); } while (ret == -EAGAIN); if ((ret < 0) && (ret != -EEXIST)) mlog_errno(ret); if (ctxt.left_ent) kmem_cache_free(ocfs2_em_ent_cachep, ctxt.left_ent); if (ctxt.right_ent) kmem_cache_free(ocfs2_em_ent_cachep, ctxt.right_ent); if (ctxt.old_ent) kmem_cache_free(ocfs2_em_ent_cachep, ctxt.old_ent); if (ctxt.new_ent) kmem_cache_free(ocfs2_em_ent_cachep, ctxt.new_ent); return ret;}/* * Append this record to the tail of the extent map. It must be * tree_depth 0. The record might be an extension of an existing * record, and as such that needs to be handled. eg: * * Existing record in the extent map: * * cpos = 10, len = 10 * |---------| * * New Record: * * cpos = 10, len = 20 * |------------------| * * The passed record is the new on-disk record. The new_clusters value * is how many clusters were added to the file. If the append is a * contiguous append, the new_clusters has been added to * rec->e_clusters. If the append is an entirely new extent, then * rec->e_clusters is == new_clusters. */int ocfs2_extent_map_append(struct inode *inode, struct ocfs2_extent_rec *rec, u32 new_clusters){ int ret; struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map; struct ocfs2_extent_map_entry *ent; struct ocfs2_extent_rec *old; BUG_ON(!new_clusters); BUG_ON(le32_to_cpu(rec->e_clusters) < new_clusters); if (em->em_clusters < OCFS2_I(inode)->ip_clusters) { /* * Size changed underneath us on disk. Drop any * straddling records and update our idea of * i_clusters */ ocfs2_extent_map_drop(inode, em->em_clusters - 1); em->em_clusters = OCFS2_I(inode)->ip_clusters; } mlog_bug_on_msg((le32_to_cpu(rec->e_cpos) + le32_to_cpu(rec->e_clusters)) != (em->em_clusters + new_clusters), "Inode %"MLFu64":\n" "rec->e_cpos = %u + rec->e_clusters = %u = %u\n" "em->em_clusters = %u + new_clusters = %u = %u\n", OCFS2_I(inode)->ip_blkno, le32_to_cpu(rec->e_cpos), le32_to_cpu(rec->e_clusters), le32_to_cpu(rec->e_cpos) + le32_to_cpu(rec->e_clusters), em->em_clusters, new_clusters, em->em_clusters + new_clusters); em->em_clusters += new_clusters; ret = -ENOENT; if (le32_to_cpu(rec->e_clusters) > new_clusters) { /* This is a contiguous append */ ent = ocfs2_extent_map_lookup(em, le32_to_cpu(rec->e_cpos), 1, NULL, NULL); if (ent) { old = &ent->e_rec; BUG_ON((le32_to_cpu(rec->e_cpos) + le32_to_cpu(rec->e_clusters)) != (le32_to_cpu(old->e_cpos) + le32_to_cpu(old->e_clusters) + new_clusters)); if (ent->e_tree_depth == 0) { BUG_ON(le32_to_cpu(old->e_cpos) != le32_to_cpu(rec->e_cpos)); BUG_ON(le64_to_cpu(old->e_blkno) != le64_to_cpu(rec->e_blkno)); ret = 0; } /* * Let non-leafs fall through as -ENOENT to * force insertion of the new leaf. */ le32_add_cpu(&old->e_clusters, new_clusters); } } if (ret == -ENOENT) ret = ocfs2_extent_map_insert(inode, rec, 0); if (ret < 0) mlog_errno(ret); return ret;}/* * Look up the record containing this cluster offset. This record is * part of the extent map. Do not free it. Any changes you make to * it will reflect in the extent map. So, if your last extent * is (cpos = 10, clusters = 10) and you truncate the file by 5 * clusters, you can do: * * ret = ocfs2_extent_map_get_rec(em, orig_size - 5, &rec); * rec->e_clusters -= 5; * * The lookup does not read from disk. If the map isn't filled in for * an entry, you won't find it. * * Also note that the returned record is valid until alloc_sem is * dropped. After that, truncate and extend can happen. Caveat Emptor. */int ocfs2_extent_map_get_rec(struct inode *inode, u32 cpos, struct ocfs2_extent_rec **rec, int *tree_depth){ int ret = -ENOENT; struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map; struct ocfs2_extent_map_entry *ent; *rec = NULL; if (cpos >= OCFS2_I(inode)->ip_clusters) return -EINVAL; if (cpos >= em->em_clusters) { /* * Size changed underneath us on disk. Drop any * straddling records and update our idea of * i_clusters */ ocfs2_extent_map_drop(inode, em->em_clusters - 1); em->em_clusters = OCFS2_I(inode)->ip_clusters ; } ent = ocfs2_extent_map_lookup(&OCFS2_I(inode)->ip_map, cpos, 1, NULL, NULL); if (ent) { *rec = &ent->e_rec; if (tree_depth) *tree_depth = ent->e_tree_depth; ret = 0; } return ret;}int ocfs2_extent_map_get_clusters(struct inode *inode, u32 v_cpos, int count, u32 *p_cpos, int *ret_count){ int ret; u32 coff, ccount; struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map; struct ocfs2_extent_map_entry *ent = NULL; *p_cpos = ccount = 0; if ((v_cpos + count) > OCFS2_I(inode)->ip_clusters) return -EINVAL; if ((v_cpos + count) > em->em_clusters) { /* * Size changed underneath us on disk. Drop any * straddling records and update our idea of * i_clusters */ ocfs2_extent_map_drop(inode, em->em_clusters - 1); em->em_clusters = OCFS2_I(inode)->ip_clusters; } ret = ocfs2_extent_map_lookup_read(inode, v_cpos, count, &ent); if (ret) return ret; if (ent) { /* We should never find ourselves straddling an interval */ if (!ocfs2_extent_rec_contains_clusters(&ent->e_rec, v_cpos, count)) return -ESRCH; coff = v_cpos - le32_to_cpu(ent->e_rec.e_cpos); *p_cpos = ocfs2_blocks_to_clusters(inode->i_sb, le64_to_cpu(ent->e_rec.e_blkno)) + coff; if (ret_count) *ret_count = le32_to_cpu(ent->e_rec.e_clusters) - coff; return 0; } return -ENOENT;}int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, int count, u64 *p_blkno, int *ret_count){ int ret; u64 boff; u32 cpos, clusters; int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1); struct ocfs2_extent_map_entry *ent = NULL; struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map; struct ocfs2_extent_rec *rec; *p_blkno = 0; cpos = ocfs2_blocks_to_clusters(inode->i_sb, v_blkno); clusters = ocfs2_blocks_to_clusters(inode->i_sb, (u64)count + bpc - 1); if ((cpos + clusters) > OCFS2_I(inode)->ip_clusters) { ret = -EINVAL; mlog_errno(ret); return ret; } if ((cpos + clusters) > em->em_clusters) { /* * Size changed underneath us on disk. Drop any * straddling records and update our idea of * i_clusters */ ocfs2_extent_map_drop(inode, em->em_clusters - 1); em->em_clusters = OCFS2_I(inode)->ip_clusters; } ret = ocfs2_extent_map_lookup_read(inode, cpos, clusters, &ent); if (ret) { mlog_errno(ret); return ret; } if (ent) { rec = &ent->e_rec; /* We should never find ourselves straddling an interval */ if (!ocfs2_extent_rec_contains_clusters(rec, cpos, clusters)) { ret = -ESRCH; mlog_errno(ret); return ret; } boff = ocfs2_clusters_to_blocks(inode->i_sb, cpos - le32_to_cpu(rec->e_cpos)); boff += (v_blkno & (u64)(bpc - 1)); *p_blkno = le64_to_cpu(rec->e_blkno) + boff; if (ret_count) { *ret_count = ocfs2_clusters_to_blocks(inode->i_sb, le32_to_cpu(rec->e_clusters)) - boff; } return 0; } return -ENOENT;}int ocfs2_extent_map_init(struct inode *inode){ struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map; em->em_extents = RB_ROOT; em->em_clusters = 0; return 0;}/* Needs the lock */static void __ocfs2_extent_map_drop(struct inode *inode, u32 new_clusters, struct rb_node **free_head, struct ocfs2_extent_map_entry **tail_ent){ struct rb_node *node, *next; struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map; struct ocfs2_extent_map_entry *ent; *free_head = NULL; ent = NULL; node = rb_last(&em->em_extents); while (node) { next = rb_prev(node); ent = rb_entry(node, struct ocfs2_extent_map_entry, e_node); if (le32_to_cpu(ent->e_rec.e_cpos) < new_clusters) break; rb_erase(&ent->e_node, &em->em_extents); node->rb_right = *free_head; *free_head = node; ent = NULL; node = next; } /* Do we have an entry straddling new_clusters? */ if (tail_ent) { if (ent && ((le32_to_cpu(ent->e_rec.e_cpos) + le32_to_cpu(ent->e_rec.e_clusters)) > new_clusters)) *tail_ent = ent; else *tail_ent = NULL; }}static void __ocfs2_extent_map_drop_cleanup(struct rb_node *free_head){ struct rb_node *node; struct ocfs2_extent_map_entry *ent; while (free_head) { node = free_head; free_head = node->rb_right; ent = rb_entry(node, struct ocfs2_extent_map_entry, e_node); kmem_cache_free(ocfs2_em_ent_cachep, ent); }}/* * Remove all entries past new_clusters, inclusive of an entry that * contains new_clusters. This is effectively a cache forget. * * If you want to also clip the last extent by some number of clusters, * you need to call ocfs2_extent_map_trunc(). * This code does not check or modify ip_clusters. */int ocfs2_extent_map_drop(struct inode *inode, u32 new_clusters){ struct rb_node *free_head = NULL; struct ocfs2_extent_map *em = &OCFS2_I(inode)->ip_map; struct ocfs2_extent_map_entry *ent; spin_lock(&OCFS2_I(inode)->ip_lock); __ocfs2_extent_map_drop(inode, new_clusters, &free_head, &ent); if (ent) { rb_erase(&ent->e_node, &em->em_extents); ent->e_node.rb_right = free_head; free_head = &ent->e_node; } spin_unlock(&OCFS2_I(inode)->ip_lock); if (free_head) __ocfs2_extent_map_drop_cleanup(free_head); return 0;}/* * Remove all entries past new_clusters and also clip any extent * straddling new_clusters, if there is one. This does not check * or modify ip_clusters */int ocfs2_extent_map_trunc(struct inode *inode, u32 new_clusters){ struct rb_node *free_head = NULL; struct ocfs2_extent_map_entry *ent = NULL; spin_lock(&OCFS2_I(inode)->ip_lock); __ocfs2_extent_map_drop(inode, new_clusters, &free_head, &ent); if (ent) ent->e_rec.e_clusters = cpu_to_le32(new_clusters - le32_to_cpu(ent->e_rec.e_cpos)); OCFS2_I(inode)->ip_map.em_clusters = new_clusters; spin_unlock(&OCFS2_I(inode)->ip_lock); if (free_head) __ocfs2_extent_map_drop_cleanup(free_head); return 0;}int __init init_ocfs2_extent_maps(void){ ocfs2_em_ent_cachep = kmem_cache_create("ocfs2_em_ent", sizeof(struct ocfs2_extent_map_entry), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!ocfs2_em_ent_cachep) return -ENOMEM; return 0;}void __exit exit_ocfs2_extent_maps(void){ kmem_cache_destroy(ocfs2_em_ent_cachep);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -