📄 alloc.c
字号:
/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * alloc.c * * Extent allocs and frees * * Copyright (C) 2002, 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */#include <linux/fs.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/highmem.h>#define MLOG_MASK_PREFIX ML_DISK_ALLOC#include <cluster/masklog.h>#include "ocfs2.h"#include "alloc.h"#include "dlmglue.h"#include "extent_map.h"#include "inode.h"#include "journal.h"#include "localalloc.h"#include "suballoc.h"#include "sysfile.h"#include "file.h"#include "super.h"#include "uptodate.h"#include "buffer_head_io.h"static int ocfs2_extent_contig(struct inode *inode, struct ocfs2_extent_rec *ext, u64 blkno);static int ocfs2_create_new_meta_bhs(struct ocfs2_super *osb, struct ocfs2_journal_handle *handle, struct inode *inode, int wanted, struct ocfs2_alloc_context *meta_ac, struct buffer_head *bhs[]);static int ocfs2_add_branch(struct ocfs2_super *osb, struct ocfs2_journal_handle *handle, struct inode *inode, struct buffer_head *fe_bh, struct buffer_head *eb_bh, struct buffer_head *last_eb_bh, struct ocfs2_alloc_context *meta_ac);static int ocfs2_shift_tree_depth(struct ocfs2_super *osb, struct ocfs2_journal_handle *handle, struct inode *inode, struct buffer_head *fe_bh, struct ocfs2_alloc_context *meta_ac, struct buffer_head **ret_new_eb_bh);static int ocfs2_do_insert_extent(struct ocfs2_super *osb, struct ocfs2_journal_handle *handle, struct inode *inode, struct buffer_head *fe_bh, u64 blkno, u32 new_clusters);static int ocfs2_find_branch_target(struct ocfs2_super *osb, struct inode *inode, struct buffer_head *fe_bh, struct buffer_head **target_bh);static int ocfs2_find_new_last_ext_blk(struct ocfs2_super *osb, struct inode *inode, struct ocfs2_dinode *fe, unsigned int new_i_clusters, struct buffer_head *old_last_eb, struct buffer_head **new_last_eb);static int ocfs2_extent_contig(struct inode *inode, struct ocfs2_extent_rec *ext, u64 blkno){ return blkno == (le64_to_cpu(ext->e_blkno) + ocfs2_clusters_to_blocks(inode->i_sb, le32_to_cpu(ext->e_clusters)));}/* * How many free extents have we got before we need more meta data? */int ocfs2_num_free_extents(struct ocfs2_super *osb, struct inode *inode, struct ocfs2_dinode *fe){ int retval; struct ocfs2_extent_list *el; struct ocfs2_extent_block *eb; struct buffer_head *eb_bh = NULL; mlog_entry_void(); if (!OCFS2_IS_VALID_DINODE(fe)) { OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe); retval = -EIO; goto bail; } if (fe->i_last_eb_blk) { retval = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk), &eb_bh, OCFS2_BH_CACHED, inode); if (retval < 0) { mlog_errno(retval); goto bail; } eb = (struct ocfs2_extent_block *) eb_bh->b_data; el = &eb->h_list; } else el = &fe->id2.i_list; BUG_ON(el->l_tree_depth != 0); retval = le16_to_cpu(el->l_count) - le16_to_cpu(el->l_next_free_rec);bail: if (eb_bh) brelse(eb_bh); mlog_exit(retval); return retval;}/* expects array to already be allocated * * sets h_signature, h_blkno, h_suballoc_bit, h_suballoc_slot, and * l_count for you */static int ocfs2_create_new_meta_bhs(struct ocfs2_super *osb, struct ocfs2_journal_handle *handle, struct inode *inode, int wanted, struct ocfs2_alloc_context *meta_ac, struct buffer_head *bhs[]){ int count, status, i; u16 suballoc_bit_start; u32 num_got; u64 first_blkno; struct ocfs2_extent_block *eb; mlog_entry_void(); count = 0; while (count < wanted) { status = ocfs2_claim_metadata(osb, handle, meta_ac, wanted - count, &suballoc_bit_start, &num_got, &first_blkno); if (status < 0) { mlog_errno(status); goto bail; } for(i = count; i < (num_got + count); i++) { bhs[i] = sb_getblk(osb->sb, first_blkno); if (bhs[i] == NULL) { status = -EIO; mlog_errno(status); goto bail; } ocfs2_set_new_buffer_uptodate(inode, bhs[i]); status = ocfs2_journal_access(handle, inode, bhs[i], OCFS2_JOURNAL_ACCESS_CREATE); if (status < 0) { mlog_errno(status); goto bail; } memset(bhs[i]->b_data, 0, osb->sb->s_blocksize); eb = (struct ocfs2_extent_block *) bhs[i]->b_data; /* Ok, setup the minimal stuff here. */ strcpy(eb->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE); eb->h_blkno = cpu_to_le64(first_blkno); eb->h_fs_generation = cpu_to_le32(osb->fs_generation);#ifndef OCFS2_USE_ALL_METADATA_SUBALLOCATORS /* we always use slot zero's suballocator */ eb->h_suballoc_slot = 0;#else eb->h_suballoc_slot = cpu_to_le16(osb->slot_num);#endif eb->h_suballoc_bit = cpu_to_le16(suballoc_bit_start); eb->h_list.l_count = cpu_to_le16(ocfs2_extent_recs_per_eb(osb->sb)); suballoc_bit_start++; first_blkno++; /* We'll also be dirtied by the caller, so * this isn't absolutely necessary. */ status = ocfs2_journal_dirty(handle, bhs[i]); if (status < 0) { mlog_errno(status); goto bail; } } count += num_got; } status = 0;bail: if (status < 0) { for(i = 0; i < wanted; i++) { if (bhs[i]) brelse(bhs[i]); bhs[i] = NULL; } } mlog_exit(status); return status;}/* * Add an entire tree branch to our inode. eb_bh is the extent block * to start at, if we don't want to start the branch at the dinode * structure. * * last_eb_bh is required as we have to update it's next_leaf pointer * for the new last extent block. * * the new branch will be 'empty' in the sense that every block will * contain a single record with e_clusters == 0. */static int ocfs2_add_branch(struct ocfs2_super *osb, struct ocfs2_journal_handle *handle, struct inode *inode, struct buffer_head *fe_bh, struct buffer_head *eb_bh, struct buffer_head *last_eb_bh, struct ocfs2_alloc_context *meta_ac){ int status, new_blocks, i; u64 next_blkno, new_last_eb_blk; struct buffer_head *bh; struct buffer_head **new_eb_bhs = NULL; struct ocfs2_dinode *fe; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *eb_el; struct ocfs2_extent_list *el; mlog_entry_void(); BUG_ON(!last_eb_bh); fe = (struct ocfs2_dinode *) fe_bh->b_data; if (eb_bh) { eb = (struct ocfs2_extent_block *) eb_bh->b_data; el = &eb->h_list; } else el = &fe->id2.i_list; /* we never add a branch to a leaf. */ BUG_ON(!el->l_tree_depth); new_blocks = le16_to_cpu(el->l_tree_depth); /* allocate the number of new eb blocks we need */ new_eb_bhs = kcalloc(new_blocks, sizeof(struct buffer_head *), GFP_KERNEL); if (!new_eb_bhs) { status = -ENOMEM; mlog_errno(status); goto bail; } status = ocfs2_create_new_meta_bhs(osb, handle, inode, new_blocks, meta_ac, new_eb_bhs); if (status < 0) { mlog_errno(status); goto bail; } /* Note: new_eb_bhs[new_blocks - 1] is the guy which will be * linked with the rest of the tree. * conversly, new_eb_bhs[0] is the new bottommost leaf. * * when we leave the loop, new_last_eb_blk will point to the * newest leaf, and next_blkno will point to the topmost extent * block. */ next_blkno = new_last_eb_blk = 0; for(i = 0; i < new_blocks; i++) { bh = new_eb_bhs[i]; eb = (struct ocfs2_extent_block *) bh->b_data; if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) { OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb); status = -EIO; goto bail; } eb_el = &eb->h_list; status = ocfs2_journal_access(handle, inode, bh, OCFS2_JOURNAL_ACCESS_CREATE); if (status < 0) { mlog_errno(status); goto bail; } eb->h_next_leaf_blk = 0; eb_el->l_tree_depth = cpu_to_le16(i); eb_el->l_next_free_rec = cpu_to_le16(1); eb_el->l_recs[0].e_cpos = fe->i_clusters; eb_el->l_recs[0].e_blkno = cpu_to_le64(next_blkno); eb_el->l_recs[0].e_clusters = cpu_to_le32(0); if (!eb_el->l_tree_depth) new_last_eb_blk = le64_to_cpu(eb->h_blkno); status = ocfs2_journal_dirty(handle, bh); if (status < 0) { mlog_errno(status); goto bail; } next_blkno = le64_to_cpu(eb->h_blkno); } /* This is a bit hairy. We want to update up to three blocks * here without leaving any of them in an inconsistent state * in case of error. We don't have to worry about * journal_dirty erroring as it won't unless we've aborted the * handle (in which case we would never be here) so reserving * the write with journal_access is all we need to do. */ status = ocfs2_journal_access(handle, inode, last_eb_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } status = ocfs2_journal_access(handle, inode, fe_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } if (eb_bh) { status = ocfs2_journal_access(handle, inode, eb_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } } /* Link the new branch into the rest of the tree (el will * either be on the fe, or the extent block passed in. */ i = le16_to_cpu(el->l_next_free_rec); el->l_recs[i].e_blkno = cpu_to_le64(next_blkno); el->l_recs[i].e_cpos = fe->i_clusters; el->l_recs[i].e_clusters = 0; le16_add_cpu(&el->l_next_free_rec, 1); /* fe needs a new last extent block pointer, as does the * next_leaf on the previously last-extent-block. */ fe->i_last_eb_blk = cpu_to_le64(new_last_eb_blk); eb = (struct ocfs2_extent_block *) last_eb_bh->b_data; eb->h_next_leaf_blk = cpu_to_le64(new_last_eb_blk); status = ocfs2_journal_dirty(handle, last_eb_bh); if (status < 0) mlog_errno(status); status = ocfs2_journal_dirty(handle, fe_bh); if (status < 0) mlog_errno(status); if (eb_bh) { status = ocfs2_journal_dirty(handle, eb_bh); if (status < 0) mlog_errno(status); } status = 0;bail: if (new_eb_bhs) { for (i = 0; i < new_blocks; i++) if (new_eb_bhs[i]) brelse(new_eb_bhs[i]); kfree(new_eb_bhs); } mlog_exit(status); return status;}/* * adds another level to the allocation tree. * returns back the new extent block so you can add a branch to it * after this call. */static int ocfs2_shift_tree_depth(struct ocfs2_super *osb, struct ocfs2_journal_handle *handle, struct inode *inode, struct buffer_head *fe_bh, struct ocfs2_alloc_context *meta_ac, struct buffer_head **ret_new_eb_bh){ int status, i; struct buffer_head *new_eb_bh = NULL; struct ocfs2_dinode *fe; struct ocfs2_extent_block *eb; struct ocfs2_extent_list *fe_el; struct ocfs2_extent_list *eb_el; mlog_entry_void(); status = ocfs2_create_new_meta_bhs(osb, handle, inode, 1, meta_ac, &new_eb_bh); if (status < 0) { mlog_errno(status); goto bail; } eb = (struct ocfs2_extent_block *) new_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; } eb_el = &eb->h_list; fe = (struct ocfs2_dinode *) fe_bh->b_data; fe_el = &fe->id2.i_list; status = ocfs2_journal_access(handle, inode, new_eb_bh, OCFS2_JOURNAL_ACCESS_CREATE); if (status < 0) { mlog_errno(status); goto bail; } /* copy the fe data into the new extent block */ eb_el->l_tree_depth = fe_el->l_tree_depth; eb_el->l_next_free_rec = fe_el->l_next_free_rec; for(i = 0; i < le16_to_cpu(fe_el->l_next_free_rec); i++) { eb_el->l_recs[i].e_cpos = fe_el->l_recs[i].e_cpos; eb_el->l_recs[i].e_clusters = fe_el->l_recs[i].e_clusters; eb_el->l_recs[i].e_blkno = fe_el->l_recs[i].e_blkno; } status = ocfs2_journal_dirty(handle, new_eb_bh); if (status < 0) { mlog_errno(status); goto bail; } status = ocfs2_journal_access(handle, inode, fe_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); goto bail; } /* update fe now */ le16_add_cpu(&fe_el->l_tree_depth, 1); fe_el->l_recs[0].e_cpos = 0; fe_el->l_recs[0].e_blkno = eb->h_blkno; fe_el->l_recs[0].e_clusters = fe->i_clusters; for(i = 1; i < le16_to_cpu(fe_el->l_next_free_rec); i++) { fe_el->l_recs[i].e_cpos = 0; fe_el->l_recs[i].e_clusters = 0; fe_el->l_recs[i].e_blkno = 0; } fe_el->l_next_free_rec = cpu_to_le16(1); /* If this is our 1st tree depth shift, then last_eb_blk * becomes the allocated extent block */ if (fe_el->l_tree_depth == cpu_to_le16(1)) fe->i_last_eb_blk = eb->h_blkno; status = ocfs2_journal_dirty(handle, fe_bh); if (status < 0) { mlog_errno(status); goto bail; } *ret_new_eb_bh = new_eb_bh; new_eb_bh = NULL; status = 0;bail: if (new_eb_bh) brelse(new_eb_bh);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -