📄 alloc.c
字号:
bail: if (bh) brelse(bh); return status;}static int ocfs2_do_truncate(struct ocfs2_super *osb, unsigned int clusters_to_del, struct inode *inode, struct buffer_head *fe_bh, struct buffer_head *old_last_eb_bh, struct ocfs2_journal_handle *handle, struct ocfs2_truncate_context *tc){ int status, i, depth; struct ocfs2_dinode *fe; struct ocfs2_extent_block *eb; struct ocfs2_extent_block *last_eb = NULL; struct ocfs2_extent_list *el; struct buffer_head *eb_bh = NULL; struct buffer_head *last_eb_bh = NULL; u64 next_eb = 0; u64 delete_blk = 0; fe = (struct ocfs2_dinode *) fe_bh->b_data; status = ocfs2_find_new_last_ext_blk(osb, inode, fe, le32_to_cpu(fe->i_clusters) - clusters_to_del, old_last_eb_bh, &last_eb_bh); if (status < 0) { mlog_errno(status); goto bail; } if (last_eb_bh) last_eb = (struct ocfs2_extent_block *) last_eb_bh->b_data; status = ocfs2_journal_access(handle, inode, fe_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } el = &(fe->id2.i_list); spin_lock(&OCFS2_I(inode)->ip_lock); OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters) - clusters_to_del; spin_unlock(&OCFS2_I(inode)->ip_lock); le32_add_cpu(&fe->i_clusters, -clusters_to_del); fe->i_mtime = cpu_to_le64(CURRENT_TIME.tv_sec); fe->i_mtime_nsec = cpu_to_le32(CURRENT_TIME.tv_nsec); i = le16_to_cpu(el->l_next_free_rec) - 1; BUG_ON(le32_to_cpu(el->l_recs[i].e_clusters) < clusters_to_del); le32_add_cpu(&el->l_recs[i].e_clusters, -clusters_to_del); /* tree depth zero, we can just delete the clusters, otherwise * we need to record the offset of the next level extent block * as we may overwrite it. */ if (!el->l_tree_depth) delete_blk = le64_to_cpu(el->l_recs[i].e_blkno) + ocfs2_clusters_to_blocks(osb->sb, le32_to_cpu(el->l_recs[i].e_clusters)); else next_eb = le64_to_cpu(el->l_recs[i].e_blkno); if (!el->l_recs[i].e_clusters) { /* if we deleted the whole extent record, then clear * out the other fields and update the extent * list. For depth > 0 trees, we've already recorded * the extent block in 'next_eb' */ el->l_recs[i].e_cpos = 0; el->l_recs[i].e_blkno = 0; BUG_ON(!el->l_next_free_rec); le16_add_cpu(&el->l_next_free_rec, -1); } depth = le16_to_cpu(el->l_tree_depth); if (!fe->i_clusters) { /* trunc to zero is a special case. */ el->l_tree_depth = 0; fe->i_last_eb_blk = 0; } else if (last_eb) fe->i_last_eb_blk = last_eb->h_blkno; status = ocfs2_journal_dirty(handle, fe_bh); if (status < 0) { mlog_errno(status); goto bail; } if (last_eb) { /* If there will be a new last extent block, then by * definition, there cannot be any leaves to the right of * him. */ status = ocfs2_journal_access(handle, inode, last_eb_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } last_eb->h_next_leaf_blk = 0; status = ocfs2_journal_dirty(handle, last_eb_bh); if (status < 0) { mlog_errno(status); goto bail; } } /* if our tree depth > 0, update all the tree blocks below us. */ while (depth) { mlog(0, "traveling tree (depth = %d, next_eb = %"MLFu64")\n", depth, next_eb); status = ocfs2_read_block(osb, next_eb, &eb_bh, OCFS2_BH_CACHED, inode); if (status < 0) { mlog_errno(status); goto bail; } eb = (struct ocfs2_extent_block *)eb_bh->b_data; if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) { OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb); status = -EIO; goto bail; } el = &(eb->h_list); status = ocfs2_journal_access(handle, inode, eb_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } BUG_ON(le16_to_cpu(el->l_next_free_rec) == 0); BUG_ON(depth != (le16_to_cpu(el->l_tree_depth) + 1)); i = le16_to_cpu(el->l_next_free_rec) - 1; mlog(0, "extent block %"MLFu64", before: record %d: " "(%u, %u, %"MLFu64"), next = %u\n", le64_to_cpu(eb->h_blkno), i, le32_to_cpu(el->l_recs[i].e_cpos), le32_to_cpu(el->l_recs[i].e_clusters), le64_to_cpu(el->l_recs[i].e_blkno), le16_to_cpu(el->l_next_free_rec)); BUG_ON(le32_to_cpu(el->l_recs[i].e_clusters) < clusters_to_del); le32_add_cpu(&el->l_recs[i].e_clusters, -clusters_to_del); next_eb = le64_to_cpu(el->l_recs[i].e_blkno); /* bottom-most block requires us to delete data.*/ if (!el->l_tree_depth) delete_blk = le64_to_cpu(el->l_recs[i].e_blkno) + ocfs2_clusters_to_blocks(osb->sb, le32_to_cpu(el->l_recs[i].e_clusters)); if (!el->l_recs[i].e_clusters) { el->l_recs[i].e_cpos = 0; el->l_recs[i].e_blkno = 0; BUG_ON(!el->l_next_free_rec); le16_add_cpu(&el->l_next_free_rec, -1); } mlog(0, "extent block %"MLFu64", after: record %d: " "(%u, %u, %"MLFu64"), next = %u\n", le64_to_cpu(eb->h_blkno), i, le32_to_cpu(el->l_recs[i].e_cpos), le32_to_cpu(el->l_recs[i].e_clusters), le64_to_cpu(el->l_recs[i].e_blkno), le16_to_cpu(el->l_next_free_rec)); status = ocfs2_journal_dirty(handle, eb_bh); if (status < 0) { mlog_errno(status); goto bail; } if (!el->l_next_free_rec) { mlog(0, "deleting this extent block.\n"); ocfs2_remove_from_cache(inode, eb_bh); BUG_ON(eb->h_suballoc_slot); BUG_ON(el->l_recs[0].e_clusters); BUG_ON(el->l_recs[0].e_cpos); BUG_ON(el->l_recs[0].e_blkno); status = ocfs2_free_extent_block(handle, tc->tc_ext_alloc_inode, tc->tc_ext_alloc_bh, eb); if (status < 0) { mlog_errno(status); goto bail; } } brelse(eb_bh); eb_bh = NULL; depth--; } BUG_ON(!delete_blk); status = ocfs2_truncate_log_append(osb, handle, delete_blk, clusters_to_del); if (status < 0) { mlog_errno(status); goto bail; } status = 0;bail: if (!status) ocfs2_extent_map_trunc(inode, le32_to_cpu(fe->i_clusters)); else ocfs2_extent_map_drop(inode, 0); mlog_exit(status); return status;}/* * It is expected, that by the time you call this function, * inode->i_size and fe->i_size have been adjusted. * * WARNING: This will kfree the truncate context */int ocfs2_commit_truncate(struct ocfs2_super *osb, struct inode *inode, struct buffer_head *fe_bh, struct ocfs2_truncate_context *tc){ int status, i, credits, tl_sem = 0; u32 clusters_to_del, target_i_clusters; u64 last_eb = 0; struct ocfs2_dinode *fe; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *el; struct buffer_head *last_eb_bh; struct ocfs2_journal_handle *handle = NULL; struct inode *tl_inode = osb->osb_tl_inode; mlog_entry_void(); down_write(&OCFS2_I(inode)->ip_alloc_sem); target_i_clusters = ocfs2_clusters_for_bytes(osb->sb, i_size_read(inode)); last_eb_bh = tc->tc_last_eb_bh; tc->tc_last_eb_bh = NULL; fe = (struct ocfs2_dinode *) fe_bh->b_data; if (fe->id2.i_list.l_tree_depth) { eb = (struct ocfs2_extent_block *) last_eb_bh->b_data; el = &eb->h_list; } else el = &fe->id2.i_list; last_eb = le64_to_cpu(fe->i_last_eb_blk);start: mlog(0, "ocfs2_commit_truncate: fe->i_clusters = %u, " "last_eb = %"MLFu64", fe->i_last_eb_blk = %"MLFu64", " "fe->id2.i_list.l_tree_depth = %u last_eb_bh = %p\n", le32_to_cpu(fe->i_clusters), last_eb, le64_to_cpu(fe->i_last_eb_blk), le16_to_cpu(fe->id2.i_list.l_tree_depth), last_eb_bh); if (last_eb != le64_to_cpu(fe->i_last_eb_blk)) { mlog(0, "last_eb changed!\n"); BUG_ON(!fe->id2.i_list.l_tree_depth); last_eb = le64_to_cpu(fe->i_last_eb_blk); /* i_last_eb_blk may have changed, read it if * necessary. We don't have to worry about the * truncate to zero case here (where there becomes no * last_eb) because we never loop back after our work * is done. */ if (last_eb_bh) { brelse(last_eb_bh); last_eb_bh = NULL; } status = ocfs2_read_block(osb, last_eb, &last_eb_bh, OCFS2_BH_CACHED, inode); if (status < 0) { mlog_errno(status); goto bail; } eb = (struct ocfs2_extent_block *) last_eb_bh->b_data; if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) { OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb); status = -EIO; goto bail; } el = &(eb->h_list); } /* by now, el will point to the extent list on the bottom most * portion of this tree. */ i = le16_to_cpu(el->l_next_free_rec) - 1; if (le32_to_cpu(el->l_recs[i].e_cpos) >= target_i_clusters) clusters_to_del = le32_to_cpu(el->l_recs[i].e_clusters); else clusters_to_del = (le32_to_cpu(el->l_recs[i].e_clusters) + le32_to_cpu(el->l_recs[i].e_cpos)) - target_i_clusters; mlog(0, "clusters_to_del = %u in this pass\n", clusters_to_del); mutex_lock(&tl_inode->i_mutex); tl_sem = 1; /* ocfs2_truncate_log_needs_flush guarantees us at least one * record is free for use. If there isn't any, we flush to get * an empty truncate log. */ if (ocfs2_truncate_log_needs_flush(osb)) { status = __ocfs2_flush_truncate_log(osb); if (status < 0) { mlog_errno(status); goto bail; } } credits = ocfs2_calc_tree_trunc_credits(osb->sb, clusters_to_del, fe, el); handle = ocfs2_start_trans(osb, NULL, credits); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; mlog_errno(status); goto bail; } inode->i_ctime = inode->i_mtime = CURRENT_TIME; status = ocfs2_mark_inode_dirty(handle, inode, fe_bh); if (status < 0) mlog_errno(status); status = ocfs2_do_truncate(osb, clusters_to_del, inode, fe_bh, last_eb_bh, handle, tc); if (status < 0) { mlog_errno(status); goto bail; } mutex_unlock(&tl_inode->i_mutex); tl_sem = 0; ocfs2_commit_trans(handle); handle = NULL; BUG_ON(le32_to_cpu(fe->i_clusters) < target_i_clusters); if (le32_to_cpu(fe->i_clusters) > target_i_clusters) goto start;bail: up_write(&OCFS2_I(inode)->ip_alloc_sem); ocfs2_schedule_truncate_log_flush(osb, 1); if (tl_sem) mutex_unlock(&tl_inode->i_mutex); if (handle) ocfs2_commit_trans(handle); if (last_eb_bh) brelse(last_eb_bh); /* This will drop the ext_alloc cluster lock for us */ ocfs2_free_truncate_context(tc); mlog_exit(status); return status;}/* * Expects the inode to already be locked. This will figure out which * inodes need to be locked and will put them on the returned truncate * context. */int ocfs2_prepare_truncate(struct ocfs2_super *osb, struct inode *inode, struct buffer_head *fe_bh, struct ocfs2_truncate_context **tc){ int status, metadata_delete; unsigned int new_i_clusters; struct ocfs2_dinode *fe; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *el; struct buffer_head *last_eb_bh = NULL; struct inode *ext_alloc_inode = NULL; struct buffer_head *ext_alloc_bh = NULL; mlog_entry_void(); *tc = NULL; new_i_clusters = ocfs2_clusters_for_bytes(osb->sb, i_size_read(inode)); fe = (struct ocfs2_dinode *) fe_bh->b_data; mlog(0, "fe->i_clusters = %u, new_i_clusters = %u, fe->i_size =" "%"MLFu64"\n", fe->i_clusters, new_i_clusters, fe->i_size); if (le32_to_cpu(fe->i_clusters) <= new_i_clusters) { ocfs2_error(inode->i_sb, "Dinode %"MLFu64" has cluster count " "%u and size %"MLFu64" whereas struct inode has " "cluster count %u and size %llu which caused an " "invalid truncate to %u clusters.", le64_to_cpu(fe->i_blkno), le32_to_cpu(fe->i_clusters), le64_to_cpu(fe->i_size), OCFS2_I(inode)->ip_clusters, i_size_read(inode), new_i_clusters); mlog_meta_lvb(ML_ERROR, &OCFS2_I(inode)->ip_meta_lockres); status = -EIO; goto bail; } *tc = kcalloc(1, sizeof(struct ocfs2_truncate_context), GFP_KERNEL); if (!(*tc)) { status = -ENOMEM; mlog_errno(status); goto bail; } metadata_delete = 0; if (fe->id2.i_list.l_tree_depth) { /* If we have a tree, then the truncate may result in * metadata deletes. Figure this out from the * rightmost leaf block.*/ status = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk), &last_eb_bh, OCFS2_BH_CACHED, inode); if (status < 0) { mlog_errno(status); goto bail; } eb = (struct ocfs2_extent_block *) last_eb_bh->b_data; if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) { OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb); brelse(last_eb_bh); status = -EIO; goto bail; } el = &(eb->h_list); if (le32_to_cpu(el->l_recs[0].e_cpos) >= new_i_clusters) metadata_delete = 1; } (*tc)->tc_last_eb_bh = last_eb_bh; if (metadata_delete) { mlog(0, "Will have to delete metadata for this trunc. " "locking allocator.\n"); ext_alloc_inode = ocfs2_get_system_file_inode(osb, EXTENT_ALLOC_SYSTEM_INODE, 0); if (!ext_alloc_inode) { status = -ENOMEM; mlog_errno(status); goto bail; } mutex_lock(&ext_alloc_inode->i_mutex); (*tc)->tc_ext_alloc_inode = ext_alloc_inode; status = ocfs2_meta_lock(ext_alloc_inode, NULL, &ext_alloc_bh, 1); if (status < 0) { mlog_errno(status); goto bail; } (*tc)->tc_ext_alloc_bh = ext_alloc_bh; (*tc)->tc_ext_alloc_locked = 1; } status = 0;bail: if (status < 0) { if (*tc) ocfs2_free_truncate_context(*tc); *tc = NULL; } mlog_exit_void(); return status;}void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc){ if (tc->tc_ext_alloc_inode) { if (tc->tc_ext_alloc_locked) ocfs2_meta_unlock(tc->tc_ext_alloc_inode, 1); mutex_unlock(&tc->tc_ext_alloc_inode->i_mutex); iput(tc->tc_ext_alloc_inode); } if (tc->tc_ext_alloc_bh) brelse(tc->tc_ext_alloc_bh); if (tc->tc_last_eb_bh) brelse(tc->tc_last_eb_bh); kfree(tc);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -