⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 alloc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* -*- 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>#include <linux/swap.h>#define MLOG_MASK_PREFIX ML_DISK_ALLOC#include <cluster/masklog.h>#include "ocfs2.h"#include "alloc.h"#include "aops.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 void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc);static int ocfs2_cache_extent_block_free(struct ocfs2_cached_dealloc_ctxt *ctxt,					 struct ocfs2_extent_block *eb);/* * Structures which describe a path through a btree, and functions to * manipulate them. * * The idea here is to be as generic as possible with the tree * manipulation code. */struct ocfs2_path_item {	struct buffer_head		*bh;	struct ocfs2_extent_list	*el;};#define OCFS2_MAX_PATH_DEPTH	5struct ocfs2_path {	int			p_tree_depth;	struct ocfs2_path_item	p_node[OCFS2_MAX_PATH_DEPTH];};#define path_root_bh(_path) ((_path)->p_node[0].bh)#define path_root_el(_path) ((_path)->p_node[0].el)#define path_leaf_bh(_path) ((_path)->p_node[(_path)->p_tree_depth].bh)#define path_leaf_el(_path) ((_path)->p_node[(_path)->p_tree_depth].el)#define path_num_items(_path) ((_path)->p_tree_depth + 1)/* * Reset the actual path elements so that we can re-use the structure * to build another path. Generally, this involves freeing the buffer * heads. */static void ocfs2_reinit_path(struct ocfs2_path *path, int keep_root){	int i, start = 0, depth = 0;	struct ocfs2_path_item *node;	if (keep_root)		start = 1;	for(i = start; i < path_num_items(path); i++) {		node = &path->p_node[i];		brelse(node->bh);		node->bh = NULL;		node->el = NULL;	}	/*	 * Tree depth may change during truncate, or insert. If we're	 * keeping the root extent list, then make sure that our path	 * structure reflects the proper depth.	 */	if (keep_root)		depth = le16_to_cpu(path_root_el(path)->l_tree_depth);	path->p_tree_depth = depth;}static void ocfs2_free_path(struct ocfs2_path *path){	if (path) {		ocfs2_reinit_path(path, 0);		kfree(path);	}}/* * All the elements of src into dest. After this call, src could be freed * without affecting dest. * * Both paths should have the same root. Any non-root elements of dest * will be freed. */static void ocfs2_cp_path(struct ocfs2_path *dest, struct ocfs2_path *src){	int i;	BUG_ON(path_root_bh(dest) != path_root_bh(src));	BUG_ON(path_root_el(dest) != path_root_el(src));	ocfs2_reinit_path(dest, 1);	for(i = 1; i < OCFS2_MAX_PATH_DEPTH; i++) {		dest->p_node[i].bh = src->p_node[i].bh;		dest->p_node[i].el = src->p_node[i].el;		if (dest->p_node[i].bh)			get_bh(dest->p_node[i].bh);	}}/* * Make the *dest path the same as src and re-initialize src path to * have a root only. */static void ocfs2_mv_path(struct ocfs2_path *dest, struct ocfs2_path *src){	int i;	BUG_ON(path_root_bh(dest) != path_root_bh(src));	for(i = 1; i < OCFS2_MAX_PATH_DEPTH; i++) {		brelse(dest->p_node[i].bh);		dest->p_node[i].bh = src->p_node[i].bh;		dest->p_node[i].el = src->p_node[i].el;		src->p_node[i].bh = NULL;		src->p_node[i].el = NULL;	}}/* * Insert an extent block at given index. * * This will not take an additional reference on eb_bh. */static inline void ocfs2_path_insert_eb(struct ocfs2_path *path, int index,					struct buffer_head *eb_bh){	struct ocfs2_extent_block *eb = (struct ocfs2_extent_block *)eb_bh->b_data;	/*	 * Right now, no root bh is an extent block, so this helps	 * catch code errors with dinode trees. The assertion can be	 * safely removed if we ever need to insert extent block	 * structures at the root.	 */	BUG_ON(index == 0);	path->p_node[index].bh = eb_bh;	path->p_node[index].el = &eb->h_list;}static struct ocfs2_path *ocfs2_new_path(struct buffer_head *root_bh,					 struct ocfs2_extent_list *root_el){	struct ocfs2_path *path;	BUG_ON(le16_to_cpu(root_el->l_tree_depth) >= OCFS2_MAX_PATH_DEPTH);	path = kzalloc(sizeof(*path), GFP_NOFS);	if (path) {		path->p_tree_depth = le16_to_cpu(root_el->l_tree_depth);		get_bh(root_bh);		path_root_bh(path) = root_bh;		path_root_el(path) = root_el;	}	return path;}/* * Allocate and initialize a new path based on a disk inode tree. */static struct ocfs2_path *ocfs2_new_inode_path(struct buffer_head *di_bh){	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;	struct ocfs2_extent_list *el = &di->id2.i_list;	return ocfs2_new_path(di_bh, el);}/* * Convenience function to journal all components in a path. */static int ocfs2_journal_access_path(struct inode *inode, handle_t *handle,				     struct ocfs2_path *path){	int i, ret = 0;	if (!path)		goto out;	for(i = 0; i < path_num_items(path); i++) {		ret = ocfs2_journal_access(handle, inode, path->p_node[i].bh,					   OCFS2_JOURNAL_ACCESS_WRITE);		if (ret < 0) {			mlog_errno(ret);			goto out;		}	}out:	return ret;}/* * Return the index of the extent record which contains cluster #v_cluster. * -1 is returned if it was not found. * * Should work fine on interior and exterior nodes. */int ocfs2_search_extent_list(struct ocfs2_extent_list *el, u32 v_cluster){	int ret = -1;	int i;	struct ocfs2_extent_rec *rec;	u32 rec_end, rec_start, clusters;	for(i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) {		rec = &el->l_recs[i];		rec_start = le32_to_cpu(rec->e_cpos);		clusters = ocfs2_rec_clusters(el, rec);		rec_end = rec_start + clusters;		if (v_cluster >= rec_start && v_cluster < rec_end) {			ret = i;			break;		}	}	return ret;}enum ocfs2_contig_type {	CONTIG_NONE = 0,	CONTIG_LEFT,	CONTIG_RIGHT,	CONTIG_LEFTRIGHT,};/* * NOTE: ocfs2_block_extent_contig(), ocfs2_extents_adjacent() and * ocfs2_extent_contig only work properly against leaf nodes! */static int ocfs2_block_extent_contig(struct super_block *sb,				     struct ocfs2_extent_rec *ext,				     u64 blkno){	u64 blk_end = le64_to_cpu(ext->e_blkno);	blk_end += ocfs2_clusters_to_blocks(sb,				    le16_to_cpu(ext->e_leaf_clusters));	return blkno == blk_end;}static int ocfs2_extents_adjacent(struct ocfs2_extent_rec *left,				  struct ocfs2_extent_rec *right){	u32 left_range;	left_range = le32_to_cpu(left->e_cpos) +		le16_to_cpu(left->e_leaf_clusters);	return (left_range == le32_to_cpu(right->e_cpos));}static enum ocfs2_contig_type	ocfs2_extent_contig(struct inode *inode,			    struct ocfs2_extent_rec *ext,			    struct ocfs2_extent_rec *insert_rec){	u64 blkno = le64_to_cpu(insert_rec->e_blkno);	/*	 * Refuse to coalesce extent records with different flag	 * fields - we don't want to mix unwritten extents with user	 * data.	 */	if (ext->e_flags != insert_rec->e_flags)		return CONTIG_NONE;	if (ocfs2_extents_adjacent(ext, insert_rec) &&	    ocfs2_block_extent_contig(inode->i_sb, ext, blkno))			return CONTIG_RIGHT;	blkno = le64_to_cpu(ext->e_blkno);	if (ocfs2_extents_adjacent(insert_rec, ext) &&	    ocfs2_block_extent_contig(inode->i_sb, insert_rec, blkno))		return CONTIG_LEFT;	return CONTIG_NONE;}/* * NOTE: We can have pretty much any combination of contiguousness and * appending. * * The usefulness of APPEND_TAIL is more in that it lets us know that * we'll have to update the path to that leaf. */enum ocfs2_append_type {	APPEND_NONE = 0,	APPEND_TAIL,};enum ocfs2_split_type {	SPLIT_NONE = 0,	SPLIT_LEFT,	SPLIT_RIGHT,};struct ocfs2_insert_type {	enum ocfs2_split_type	ins_split;	enum ocfs2_append_type	ins_appending;	enum ocfs2_contig_type	ins_contig;	int			ins_contig_index;	int			ins_tree_depth;};struct ocfs2_merge_ctxt {	enum ocfs2_contig_type	c_contig_type;	int			c_has_empty_extent;	int			c_split_covers_rec;};/* * 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,				     handle_t *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);			eb->h_suballoc_slot = cpu_to_le16(osb->slot_num);			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;}/* * Helper function for ocfs2_add_branch() and ocfs2_shift_tree_depth(). * * Returns the sum of the rightmost extent rec logical offset and * cluster count. * * ocfs2_add_branch() uses this to determine what logical cluster * value should be populated into the leftmost new branch records.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -