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

📄 suballoc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * suballoc.c * * metadata alloc and free * Inspired by ext3 block groups. * * 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 "inode.h"#include "journal.h"#include "localalloc.h"#include "suballoc.h"#include "super.h"#include "sysfile.h"#include "uptodate.h"#include "buffer_head_io.h"static inline void ocfs2_debug_bg(struct ocfs2_group_desc *bg);static inline void ocfs2_debug_suballoc_inode(struct ocfs2_dinode *fe);static inline u16 ocfs2_find_victim_chain(struct ocfs2_chain_list *cl);static int ocfs2_block_group_fill(handle_t *handle,				  struct inode *alloc_inode,				  struct buffer_head *bg_bh,				  u64 group_blkno,				  u16 my_chain,				  struct ocfs2_chain_list *cl);static int ocfs2_block_group_alloc(struct ocfs2_super *osb,				   struct inode *alloc_inode,				   struct buffer_head *bh);static int ocfs2_cluster_group_search(struct inode *inode,				      struct buffer_head *group_bh,				      u32 bits_wanted, u32 min_bits,				      u16 *bit_off, u16 *bits_found);static int ocfs2_block_group_search(struct inode *inode,				    struct buffer_head *group_bh,				    u32 bits_wanted, u32 min_bits,				    u16 *bit_off, u16 *bits_found);static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb,				     struct ocfs2_alloc_context *ac,				     handle_t *handle,				     u32 bits_wanted,				     u32 min_bits,				     u16 *bit_off,				     unsigned int *num_bits,				     u64 *bg_blkno);static int ocfs2_test_bg_bit_allocatable(struct buffer_head *bg_bh,					 int nr);static inline int ocfs2_block_group_set_bits(handle_t *handle,					     struct inode *alloc_inode,					     struct ocfs2_group_desc *bg,					     struct buffer_head *group_bh,					     unsigned int bit_off,					     unsigned int num_bits);static inline int ocfs2_block_group_clear_bits(handle_t *handle,					       struct inode *alloc_inode,					       struct ocfs2_group_desc *bg,					       struct buffer_head *group_bh,					       unsigned int bit_off,					       unsigned int num_bits);static int ocfs2_relink_block_group(handle_t *handle,				    struct inode *alloc_inode,				    struct buffer_head *fe_bh,				    struct buffer_head *bg_bh,				    struct buffer_head *prev_bg_bh,				    u16 chain);static inline int ocfs2_block_group_reasonably_empty(struct ocfs2_group_desc *bg,						     u32 wanted);static inline u32 ocfs2_desc_bitmap_to_cluster_off(struct inode *inode,						   u64 bg_blkno,						   u16 bg_bit_off);static inline u64 ocfs2_which_cluster_group(struct inode *inode,					    u32 cluster);static inline void ocfs2_block_to_cluster_group(struct inode *inode,						u64 data_blkno,						u64 *bg_blkno,						u16 *bg_bit_off);void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac){	struct inode *inode = ac->ac_inode;	if (inode) {		if (ac->ac_which != OCFS2_AC_USE_LOCAL)			ocfs2_meta_unlock(inode, 1);		mutex_unlock(&inode->i_mutex);		iput(inode);	}	if (ac->ac_bh)		brelse(ac->ac_bh);	kfree(ac);}static u32 ocfs2_bits_per_group(struct ocfs2_chain_list *cl){	return (u32)le16_to_cpu(cl->cl_cpg) * (u32)le16_to_cpu(cl->cl_bpc);}/* somewhat more expensive than our other checks, so use sparingly. */static int ocfs2_check_group_descriptor(struct super_block *sb,					struct ocfs2_dinode *di,					struct ocfs2_group_desc *gd){	unsigned int max_bits;	if (!OCFS2_IS_VALID_GROUP_DESC(gd)) {		OCFS2_RO_ON_INVALID_GROUP_DESC(sb, gd);		return -EIO;	}	if (di->i_blkno != gd->bg_parent_dinode) {		ocfs2_error(sb, "Group descriptor # %llu has bad parent "			    "pointer (%llu, expected %llu)",			    (unsigned long long)le64_to_cpu(gd->bg_blkno),			    (unsigned long long)le64_to_cpu(gd->bg_parent_dinode),			    (unsigned long long)le64_to_cpu(di->i_blkno));		return -EIO;	}	max_bits = le16_to_cpu(di->id2.i_chain.cl_cpg) * le16_to_cpu(di->id2.i_chain.cl_bpc);	if (le16_to_cpu(gd->bg_bits) > max_bits) {		ocfs2_error(sb, "Group descriptor # %llu has bit count of %u",			    (unsigned long long)le64_to_cpu(gd->bg_blkno),			    le16_to_cpu(gd->bg_bits));		return -EIO;	}	if (le16_to_cpu(gd->bg_chain) >=	    le16_to_cpu(di->id2.i_chain.cl_next_free_rec)) {		ocfs2_error(sb, "Group descriptor # %llu has bad chain %u",			    (unsigned long long)le64_to_cpu(gd->bg_blkno),			    le16_to_cpu(gd->bg_chain));		return -EIO;	}	if (le16_to_cpu(gd->bg_free_bits_count) > le16_to_cpu(gd->bg_bits)) {		ocfs2_error(sb, "Group descriptor # %llu has bit count %u but "			    "claims that %u are free",			    (unsigned long long)le64_to_cpu(gd->bg_blkno),			    le16_to_cpu(gd->bg_bits),			    le16_to_cpu(gd->bg_free_bits_count));		return -EIO;	}	if (le16_to_cpu(gd->bg_bits) > (8 * le16_to_cpu(gd->bg_size))) {		ocfs2_error(sb, "Group descriptor # %llu has bit count %u but "			    "max bitmap bits of %u",			    (unsigned long long)le64_to_cpu(gd->bg_blkno),			    le16_to_cpu(gd->bg_bits),			    8 * le16_to_cpu(gd->bg_size));		return -EIO;	}	return 0;}static int ocfs2_block_group_fill(handle_t *handle,				  struct inode *alloc_inode,				  struct buffer_head *bg_bh,				  u64 group_blkno,				  u16 my_chain,				  struct ocfs2_chain_list *cl){	int status = 0;	struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) bg_bh->b_data;	struct super_block * sb = alloc_inode->i_sb;	mlog_entry_void();	if (((unsigned long long) bg_bh->b_blocknr) != group_blkno) {		ocfs2_error(alloc_inode->i_sb, "group block (%llu) != "			    "b_blocknr (%llu)",			    (unsigned long long)group_blkno,			    (unsigned long long) bg_bh->b_blocknr);		status = -EIO;		goto bail;	}	status = ocfs2_journal_access(handle,				      alloc_inode,				      bg_bh,				      OCFS2_JOURNAL_ACCESS_CREATE);	if (status < 0) {		mlog_errno(status);		goto bail;	}	memset(bg, 0, sb->s_blocksize);	strcpy(bg->bg_signature, OCFS2_GROUP_DESC_SIGNATURE);	bg->bg_generation = cpu_to_le32(OCFS2_SB(sb)->fs_generation);	bg->bg_size = cpu_to_le16(ocfs2_group_bitmap_size(sb));	bg->bg_bits = cpu_to_le16(ocfs2_bits_per_group(cl));	bg->bg_chain = cpu_to_le16(my_chain);	bg->bg_next_group = cl->cl_recs[my_chain].c_blkno;	bg->bg_parent_dinode = cpu_to_le64(OCFS2_I(alloc_inode)->ip_blkno);	bg->bg_blkno = cpu_to_le64(group_blkno);	/* set the 1st bit in the bitmap to account for the descriptor block */	ocfs2_set_bit(0, (unsigned long *)bg->bg_bitmap);	bg->bg_free_bits_count = cpu_to_le16(le16_to_cpu(bg->bg_bits) - 1);	status = ocfs2_journal_dirty(handle, bg_bh);	if (status < 0)		mlog_errno(status);	/* There is no need to zero out or otherwise initialize the	 * other blocks in a group - All valid FS metadata in a block	 * group stores the superblock fs_generation value at	 * allocation time. */bail:	mlog_exit(status);	return status;}static inline u16 ocfs2_find_smallest_chain(struct ocfs2_chain_list *cl){	u16 curr, best;	best = curr = 0;	while (curr < le16_to_cpu(cl->cl_count)) {		if (le32_to_cpu(cl->cl_recs[best].c_total) >		    le32_to_cpu(cl->cl_recs[curr].c_total))			best = curr;		curr++;	}	return best;}/* * We expect the block group allocator to already be locked. */static int ocfs2_block_group_alloc(struct ocfs2_super *osb,				   struct inode *alloc_inode,				   struct buffer_head *bh){	int status, credits;	struct ocfs2_dinode *fe = (struct ocfs2_dinode *) bh->b_data;	struct ocfs2_chain_list *cl;	struct ocfs2_alloc_context *ac = NULL;	handle_t *handle = NULL;	u32 bit_off, num_bits;	u16 alloc_rec;	u64 bg_blkno;	struct buffer_head *bg_bh = NULL;	struct ocfs2_group_desc *bg;	BUG_ON(ocfs2_is_cluster_bitmap(alloc_inode));	mlog_entry_void();	cl = &fe->id2.i_chain;	status = ocfs2_reserve_clusters(osb,					le16_to_cpu(cl->cl_cpg),					&ac);	if (status < 0) {		if (status != -ENOSPC)			mlog_errno(status);		goto bail;	}	credits = ocfs2_calc_group_alloc_credits(osb->sb,						 le16_to_cpu(cl->cl_cpg));	handle = ocfs2_start_trans(osb, credits);	if (IS_ERR(handle)) {		status = PTR_ERR(handle);		handle = NULL;		mlog_errno(status);		goto bail;	}	status = ocfs2_claim_clusters(osb,				      handle,				      ac,				      le16_to_cpu(cl->cl_cpg),				      &bit_off,				      &num_bits);	if (status < 0) {		if (status != -ENOSPC)			mlog_errno(status);		goto bail;	}	alloc_rec = ocfs2_find_smallest_chain(cl);	/* setup the group */	bg_blkno = ocfs2_clusters_to_blocks(osb->sb, bit_off);	mlog(0, "new descriptor, record %u, at block %llu\n",	     alloc_rec, (unsigned long long)bg_blkno);	bg_bh = sb_getblk(osb->sb, bg_blkno);	if (!bg_bh) {		status = -EIO;		mlog_errno(status);		goto bail;	}	ocfs2_set_new_buffer_uptodate(alloc_inode, bg_bh);	status = ocfs2_block_group_fill(handle,					alloc_inode,					bg_bh,					bg_blkno,					alloc_rec,					cl);	if (status < 0) {		mlog_errno(status);		goto bail;	}	bg = (struct ocfs2_group_desc *) bg_bh->b_data;	status = ocfs2_journal_access(handle, alloc_inode,				      bh, OCFS2_JOURNAL_ACCESS_WRITE);	if (status < 0) {		mlog_errno(status);		goto bail;	}	le32_add_cpu(&cl->cl_recs[alloc_rec].c_free,		     le16_to_cpu(bg->bg_free_bits_count));	le32_add_cpu(&cl->cl_recs[alloc_rec].c_total, le16_to_cpu(bg->bg_bits));	cl->cl_recs[alloc_rec].c_blkno  = cpu_to_le64(bg_blkno);	if (le16_to_cpu(cl->cl_next_free_rec) < le16_to_cpu(cl->cl_count))		le16_add_cpu(&cl->cl_next_free_rec, 1);	le32_add_cpu(&fe->id1.bitmap1.i_used, le16_to_cpu(bg->bg_bits) -					le16_to_cpu(bg->bg_free_bits_count));	le32_add_cpu(&fe->id1.bitmap1.i_total, le16_to_cpu(bg->bg_bits));	le32_add_cpu(&fe->i_clusters, le16_to_cpu(cl->cl_cpg));	status = ocfs2_journal_dirty(handle, bh);	if (status < 0) {		mlog_errno(status);		goto bail;	}	spin_lock(&OCFS2_I(alloc_inode)->ip_lock);	OCFS2_I(alloc_inode)->ip_clusters = le32_to_cpu(fe->i_clusters);	fe->i_size = cpu_to_le64(ocfs2_clusters_to_bytes(alloc_inode->i_sb,					     le32_to_cpu(fe->i_clusters)));	spin_unlock(&OCFS2_I(alloc_inode)->ip_lock);	i_size_write(alloc_inode, le64_to_cpu(fe->i_size));	alloc_inode->i_blocks = ocfs2_inode_sector_count(alloc_inode);	status = 0;bail:	if (handle)		ocfs2_commit_trans(osb, handle);	if (ac)		ocfs2_free_alloc_context(ac);	if (bg_bh)		brelse(bg_bh);	mlog_exit(status);	return status;}static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb,				       struct ocfs2_alloc_context *ac,				       int type,				       u32 slot){	int status;	u32 bits_wanted = ac->ac_bits_wanted;	struct inode *alloc_inode;	struct buffer_head *bh = NULL;	struct ocfs2_dinode *fe;	u32 free_bits;	mlog_entry_void();	alloc_inode = ocfs2_get_system_file_inode(osb, type, slot);	if (!alloc_inode) {		mlog_errno(-EINVAL);		return -EINVAL;	}	mutex_lock(&alloc_inode->i_mutex);	status = ocfs2_meta_lock(alloc_inode, &bh, 1);	if (status < 0) {		mutex_unlock(&alloc_inode->i_mutex);		iput(alloc_inode);		mlog_errno(status);		return status;	}	ac->ac_inode = alloc_inode;	fe = (struct ocfs2_dinode *) bh->b_data;	if (!OCFS2_IS_VALID_DINODE(fe)) {		OCFS2_RO_ON_INVALID_DINODE(alloc_inode->i_sb, fe);		status = -EIO;		goto bail;	}	if (!(fe->i_flags & cpu_to_le32(OCFS2_CHAIN_FL))) {		ocfs2_error(alloc_inode->i_sb, "Invalid chain allocator %llu",			    (unsigned long long)le64_to_cpu(fe->i_blkno));		status = -EIO;		goto bail;	}	free_bits = le32_to_cpu(fe->id1.bitmap1.i_total) -		le32_to_cpu(fe->id1.bitmap1.i_used);	if (bits_wanted > free_bits) {		/* cluster bitmap never grows */		if (ocfs2_is_cluster_bitmap(alloc_inode)) {			mlog(0, "Disk Full: wanted=%u, free_bits=%u\n",			     bits_wanted, free_bits);			status = -ENOSPC;			goto bail;		}		status = ocfs2_block_group_alloc(osb, alloc_inode, bh);		if (status < 0) {

⌨️ 快捷键说明

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