/* * The extent caching implementation is intentionally trivial. * * We only cache a small number of extents stored directly on the * inode, so linear order operations are acceptable. If we ever want * to increase the size of the extent map, then these algorithms must * get smarter.
*/
list_for_each_entry_safe(emi, n, &tmp_list, ei_list) {
list_del(&emi->ei_list);
kfree(emi);
}
}
/* * Is any part of emi2 contained within emi1
*/ staticint ocfs2_ei_is_contained(struct ocfs2_extent_map_item *emi1, struct ocfs2_extent_map_item *emi2)
{ unsignedint range1, range2;
/* * Check if logical start of emi2 is inside emi1
*/
range1 = emi1->ei_cpos + emi1->ei_clusters; if (emi2->ei_cpos >= emi1->ei_cpos && emi2->ei_cpos < range1) return 1;
/* * Check if logical end of emi2 is inside emi1
*/
range2 = emi2->ei_cpos + emi2->ei_clusters; if (range2 > emi1->ei_cpos && range2 <= range1) return 1;
/* * Overlapping extents - this shouldn't happen unless we've * split an extent to change it's flags. That is exceedingly * rare, so there's no sense in trying to optimize it yet.
*/ if (ocfs2_ei_is_contained(emi, ins) ||
ocfs2_ei_is_contained(ins, emi)) {
ocfs2_copy_emi_fields(emi, ins); return 1;
}
/* No merge was possible. */ return 0;
}
/* * In order to reduce complexity on the caller, this insert function * is intentionally liberal in what it will accept. * * The only rule is that the truncate call *must* be used whenever * records have been deleted. This avoids inserting overlapping * records with different physical mappings.
*/ void ocfs2_extent_map_insert_rec(struct inode *inode, struct ocfs2_extent_rec *rec)
{ struct ocfs2_inode_info *oi = OCFS2_I(inode); struct ocfs2_extent_map *em = &oi->ip_extent_map; struct ocfs2_extent_map_item *emi, *new_emi = NULL; struct ocfs2_extent_map_item ins;
ret = ocfs2_read_extent_block(INODE_CACHE(inode), last_eb_blk, &eb_bh); if (ret) {
mlog_errno(ret); goto out;
}
eb = (struct ocfs2_extent_block *) eb_bh->b_data;
el = &eb->h_list;
if (el->l_tree_depth) {
ocfs2_error(inode->i_sb, "Inode %lu has non zero tree depth in leaf block %llu\n",
inode->i_ino,
(unsignedlonglong)eb_bh->b_blocknr);
ret = -EROFS; goto out;
}
next_free = le16_to_cpu(el->l_next_free_rec);
if (next_free == 0 ||
(next_free == 1 && ocfs2_is_empty_extent(&el->l_recs[0])))
ret = 1;
out:
brelse(eb_bh); return ret;
}
/* * Return the 1st index within el which contains an extent start * larger than v_cluster.
*/ staticint ocfs2_search_for_hole_index(struct ocfs2_extent_list *el,
u32 v_cluster)
{ int i; struct ocfs2_extent_rec *rec;
if (v_cluster < le32_to_cpu(rec->e_cpos)) break;
}
return i;
}
/* * Figure out the size of a hole which starts at v_cluster within the given * extent list. * * If there is no more allocation past v_cluster, we return the maximum * cluster size minus v_cluster. * * If we have in-inode extents, then el points to the dinode list and * eb_bh is NULL. Otherwise, eb_bh should point to the extent block * containing el.
*/ int ocfs2_figure_hole_clusters(struct ocfs2_caching_info *ci, struct ocfs2_extent_list *el, struct buffer_head *eb_bh,
u32 v_cluster,
u32 *num_clusters)
{ int ret, i; struct buffer_head *next_eb_bh = NULL; struct ocfs2_extent_block *eb, *next_eb;
i = ocfs2_search_for_hole_index(el, v_cluster);
if (i == le16_to_cpu(el->l_next_free_rec) && eb_bh) {
eb = (struct ocfs2_extent_block *)eb_bh->b_data;
/* * Check the next leaf for any extents.
*/
if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL) goto no_more_extents;
ret = ocfs2_read_extent_block(ci,
le64_to_cpu(eb->h_next_leaf_blk),
&next_eb_bh); if (ret) {
mlog_errno(ret); goto out;
}
next_eb = (struct ocfs2_extent_block *)next_eb_bh->b_data;
el = &next_eb->h_list;
i = ocfs2_search_for_hole_index(el, v_cluster);
}
no_more_extents: if (i == le16_to_cpu(el->l_next_free_rec)) { /* * We're at the end of our existing allocation. Just * return the maximum number of clusters we could * possibly allocate.
*/
*num_clusters = UINT_MAX - v_cluster;
} else {
*num_clusters = le32_to_cpu(el->l_recs[i].e_cpos) - v_cluster;
}
memset(ret_rec, 0, sizeof(*ret_rec)); if (is_last)
*is_last = 0;
di = (struct ocfs2_dinode *) di_bh->b_data;
el = &di->id2.i_list;
tree_height = le16_to_cpu(el->l_tree_depth);
if (tree_height > 0) {
ret = ocfs2_find_leaf(INODE_CACHE(inode), el, v_cluster,
&eb_bh); if (ret) {
mlog_errno(ret); goto out;
}
eb = (struct ocfs2_extent_block *) eb_bh->b_data;
el = &eb->h_list;
if (el->l_tree_depth) {
ocfs2_error(inode->i_sb, "Inode %lu has non zero tree depth in leaf block %llu\n",
inode->i_ino,
(unsignedlonglong)eb_bh->b_blocknr);
ret = -EROFS; goto out;
}
}
if (le16_to_cpu(el->l_next_free_rec) > le16_to_cpu(el->l_count)) {
ocfs2_error(inode->i_sb, "Inode %lu has an invalid extent (next_free_rec %u, count %u)\n",
inode->i_ino,
le16_to_cpu(el->l_next_free_rec),
le16_to_cpu(el->l_count));
ret = -EROFS; goto out;
}
i = ocfs2_search_extent_list(el, v_cluster); if (i == -1) { /* * Holes can be larger than the maximum size of an * extent, so we return their lengths in a separate * field.
*/ if (hole_len) {
ret = ocfs2_figure_hole_clusters(INODE_CACHE(inode),
el, eb_bh,
v_cluster, &len); if (ret) {
mlog_errno(ret); goto out;
}
*hole_len = len;
} goto out_hole;
}
rec = &el->l_recs[i];
BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos));
if (!rec->e_blkno) {
ocfs2_error(inode->i_sb, "Inode %lu has bad extent record (%u, %u, 0)\n",
inode->i_ino,
le32_to_cpu(rec->e_cpos),
ocfs2_rec_clusters(el, rec));
ret = -EROFS; goto out;
}
*ret_rec = *rec;
/* * Checking for last extent is potentially expensive - we * might have to look at the next leaf over to see if it's * empty. * * The first two checks are to see whether the caller even * cares for this information, and if the extent is at least * the last in it's list. * * If those hold true, then the extent is last if any of the * additional conditions hold true: * - Extent list is in-inode * - Extent list is right-most * - Extent list is 2nd to rightmost, with empty right-most
*/ if (is_last) { if (i == (le16_to_cpu(el->l_next_free_rec) - 1)) { if (tree_height == 0)
*is_last = 1; elseif (eb->h_blkno == di->i_last_eb_blk)
*is_last = 1; elseif (eb->h_next_leaf_blk == di->i_last_eb_blk) {
ret = ocfs2_last_eb_is_empty(inode, di); if (ret < 0) {
mlog_errno(ret); goto out;
} if (ret == 1)
*is_last = 1;
}
}
}
out_hole:
ret = 0;
out:
brelse(eb_bh); return ret;
}
if (el->l_tree_depth) {
ret = ocfs2_find_leaf(INODE_CACHE(inode), el, v_cluster,
&eb_bh); if (ret) {
mlog_errno(ret); goto out;
}
eb = (struct ocfs2_extent_block *) eb_bh->b_data;
el = &eb->h_list;
if (el->l_tree_depth) {
ocfs2_error(inode->i_sb, "Inode %lu has non zero tree depth in xattr leaf block %llu\n",
inode->i_ino,
(unsignedlonglong)eb_bh->b_blocknr);
ret = -EROFS; goto out;
}
}
i = ocfs2_search_extent_list(el, v_cluster); if (i == -1) {
ret = -EROFS;
mlog_errno(ret); goto out;
} else {
rec = &el->l_recs[i];
BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos));
if (!rec->e_blkno) {
ocfs2_error(inode->i_sb, "Inode %lu has bad extent record (%u, %u, 0) in xattr\n",
inode->i_ino,
le32_to_cpu(rec->e_cpos),
ocfs2_rec_clusters(el, rec));
ret = -EROFS; goto out;
}
coff = v_cluster - le32_to_cpu(rec->e_cpos);
*p_cluster = ocfs2_blocks_to_clusters(inode->i_sb,
le64_to_cpu(rec->e_blkno));
*p_cluster = *p_cluster + coff; if (num_clusters)
*num_clusters = ocfs2_rec_clusters(el, rec) - coff;
if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
ret = -ERANGE;
mlog_errno(ret); goto out;
}
ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster,
num_clusters, extent_flags); if (ret == 0) goto out;
ret = ocfs2_read_inode_block(inode, &di_bh); if (ret) {
mlog_errno(ret); goto out;
}
ret = ocfs2_get_clusters_nocache(inode, di_bh, v_cluster, &hole_len,
&rec, NULL); if (ret) {
mlog_errno(ret); goto out;
}
if (rec.e_blkno == 0ULL) { /* * A hole was found. Return some canned values that * callers can key on. If asked for, num_clusters will * be populated with the size of the hole.
*/
*p_cluster = 0; if (num_clusters) {
*num_clusters = hole_len;
}
} else {
ocfs2_relative_extent_offsets(inode->i_sb, v_cluster, &rec,
p_cluster, num_clusters);
flags = rec.e_flags;
ocfs2_extent_map_insert_rec(inode, &rec);
}
if (extent_flags)
*extent_flags = flags;
out:
brelse(di_bh); return ret;
}
/* * This expects alloc_sem to be held. The allocation cannot change at * all while the map is in the process of being updated.
*/ int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno,
u64 *ret_count, unsignedint *extent_flags)
{ int ret; int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
u32 cpos, num_clusters, p_cluster;
u64 boff = 0;
/* * The ocfs2_fiemap_inline() may be a little bit misleading, since * it not only handles the fiemap for inlined files, but also deals * with the fast symlink, cause they have no difference for extent * mapping per se. * * Must be called with ip_alloc_sem semaphore held.
*/ staticint ocfs2_fiemap_inline(struct inode *inode, struct buffer_head *di_bh, struct fiemap_extent_info *fieinfo,
u64 map_start)
{ int ret; unsignedint id_count; struct ocfs2_dinode *di;
u64 phys;
u32 flags = FIEMAP_EXTENT_DATA_INLINE|FIEMAP_EXTENT_LAST; struct ocfs2_inode_info *oi = OCFS2_I(inode);
lockdep_assert_held_read(&oi->ip_alloc_sem);
di = (struct ocfs2_dinode *)di_bh->b_data; if (ocfs2_inode_is_fast_symlink(inode))
id_count = ocfs2_fast_symlink_chars(inode->i_sb); else
id_count = le16_to_cpu(di->id2.i_data.id_count);
int ocfs2_read_virt_blocks(struct inode *inode, u64 v_block, int nr, struct buffer_head *bhs[], int flags, int (*validate)(struct super_block *sb, struct buffer_head *bh))
{ int rc = 0;
u64 p_block, p_count; int i, count, done = 0;
if (((v_block + nr - 1) << inode->i_sb->s_blocksize_bits) >=
i_size_read(inode)) {
BUG_ON(!(flags & OCFS2_BH_READAHEAD)); goto out;
}
while (done < nr) { if (!down_read_trylock(&OCFS2_I(inode)->ip_alloc_sem)) {
rc = -EAGAIN;
mlog(ML_ERROR, "Inode #%llu ip_alloc_sem is temporarily unavailable\n",
(unsignedlonglong)OCFS2_I(inode)->ip_blkno); break;
}
rc = ocfs2_extent_map_get_blocks(inode, v_block + done,
&p_block, &p_count, NULL);
up_read(&OCFS2_I(inode)->ip_alloc_sem); if (rc) {
mlog_errno(rc); break;
}
if (!p_block) {
rc = -EIO;
mlog(ML_ERROR, "Inode #%llu contains a hole at offset %llu\n",
(unsignedlonglong)OCFS2_I(inode)->ip_blkno,
(unsignedlonglong)(v_block + done) <<
inode->i_sb->s_blocksize_bits); break;
}
count = nr - done; if (p_count < count)
count = p_count;
/* * If the caller passed us bhs, they should have come * from a previous readahead call to this function. Thus, * they should have the right b_blocknr.
*/ for (i = 0; i < count; i++) { if (!bhs[done + i]) continue;
BUG_ON(bhs[done + i]->b_blocknr != (p_block + i));
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.8Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.