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

📄 localalloc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * localalloc.c * * Node local data allocation * * 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/bitops.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 "buffer_head_io.h"#define OCFS2_LOCAL_ALLOC(dinode)	(&((dinode)->id2.i_lab))static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb);static u32 ocfs2_local_alloc_count_bits(struct ocfs2_dinode *alloc);static int ocfs2_local_alloc_find_clear_bits(struct ocfs2_super *osb,					     struct ocfs2_dinode *alloc,					     u32 numbits);static void ocfs2_clear_local_alloc(struct ocfs2_dinode *alloc);static int ocfs2_sync_local_to_main(struct ocfs2_super *osb,				    handle_t *handle,				    struct ocfs2_dinode *alloc,				    struct inode *main_bm_inode,				    struct buffer_head *main_bm_bh);static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb,						struct ocfs2_alloc_context **ac,						struct inode **bitmap_inode,						struct buffer_head **bitmap_bh);static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,					handle_t *handle,					struct ocfs2_alloc_context *ac);static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,					  struct inode *local_alloc_inode);/* * Determine how large our local alloc window should be, in bits. * * These values (and the behavior in ocfs2_alloc_should_use_local) have * been chosen so that most allocations, including new block groups go * through local alloc. */static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb){	BUG_ON(osb->s_clustersize_bits < 12);	return 2048 >> (osb->s_clustersize_bits - 12);}/* * Tell us whether a given allocation should use the local alloc * file. Otherwise, it has to go to the main bitmap. */int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits){	int la_bits = ocfs2_local_alloc_window_bits(osb);	if (osb->local_alloc_state != OCFS2_LA_ENABLED)		return 0;	/* la_bits should be at least twice the size (in clusters) of	 * a new block group. We want to be sure block group	 * allocations go through the local alloc, so allow an	 * allocation to take up to half the bitmap. */	if (bits > (la_bits / 2))		return 0;	return 1;}int ocfs2_load_local_alloc(struct ocfs2_super *osb){	int status = 0;	struct ocfs2_dinode *alloc = NULL;	struct buffer_head *alloc_bh = NULL;	u32 num_used;	struct inode *inode = NULL;	struct ocfs2_local_alloc *la;	mlog_entry_void();	/* read the alloc off disk */	inode = ocfs2_get_system_file_inode(osb, LOCAL_ALLOC_SYSTEM_INODE,					    osb->slot_num);	if (!inode) {		status = -EINVAL;		mlog_errno(status);		goto bail;	}	status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno,				  &alloc_bh, 0, inode);	if (status < 0) {		mlog_errno(status);		goto bail;	}	alloc = (struct ocfs2_dinode *) alloc_bh->b_data;	la = OCFS2_LOCAL_ALLOC(alloc);	if (!(le32_to_cpu(alloc->i_flags) &	    (OCFS2_LOCAL_ALLOC_FL|OCFS2_BITMAP_FL))) {		mlog(ML_ERROR, "Invalid local alloc inode, %llu\n",		     (unsigned long long)OCFS2_I(inode)->ip_blkno);		status = -EINVAL;		goto bail;	}	if ((la->la_size == 0) ||	    (le16_to_cpu(la->la_size) > ocfs2_local_alloc_size(inode->i_sb))) {		mlog(ML_ERROR, "Local alloc size is invalid (la_size = %u)\n",		     le16_to_cpu(la->la_size));		status = -EINVAL;		goto bail;	}	/* do a little verification. */	num_used = ocfs2_local_alloc_count_bits(alloc);	/* hopefully the local alloc has always been recovered before	 * we load it. */	if (num_used	    || alloc->id1.bitmap1.i_used	    || alloc->id1.bitmap1.i_total	    || la->la_bm_off)		mlog(ML_ERROR, "Local alloc hasn't been recovered!\n"		     "found = %u, set = %u, taken = %u, off = %u\n",		     num_used, le32_to_cpu(alloc->id1.bitmap1.i_used),		     le32_to_cpu(alloc->id1.bitmap1.i_total),		     OCFS2_LOCAL_ALLOC(alloc)->la_bm_off);	osb->local_alloc_bh = alloc_bh;	osb->local_alloc_state = OCFS2_LA_ENABLED;bail:	if (status < 0)		if (alloc_bh)			brelse(alloc_bh);	if (inode)		iput(inode);	mlog_exit(status);	return status;}/* * return any unused bits to the bitmap and write out a clean * local_alloc. * * local_alloc_bh is optional. If not passed, we will simply use the * one off osb. If you do pass it however, be warned that it *will* be * returned brelse'd and NULL'd out.*/void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb){	int status;	handle_t *handle;	struct inode *local_alloc_inode = NULL;	struct buffer_head *bh = NULL;	struct buffer_head *main_bm_bh = NULL;	struct inode *main_bm_inode = NULL;	struct ocfs2_dinode *alloc_copy = NULL;	struct ocfs2_dinode *alloc = NULL;	mlog_entry_void();	if (osb->local_alloc_state == OCFS2_LA_UNUSED)		goto out;	local_alloc_inode =		ocfs2_get_system_file_inode(osb,					    LOCAL_ALLOC_SYSTEM_INODE,					    osb->slot_num);	if (!local_alloc_inode) {		status = -ENOENT;		mlog_errno(status);		goto out;	}	osb->local_alloc_state = OCFS2_LA_DISABLED;	main_bm_inode = ocfs2_get_system_file_inode(osb,						    GLOBAL_BITMAP_SYSTEM_INODE,						    OCFS2_INVALID_SLOT);	if (!main_bm_inode) {		status = -EINVAL;		mlog_errno(status);		goto out;	}	mutex_lock(&main_bm_inode->i_mutex);	status = ocfs2_meta_lock(main_bm_inode, &main_bm_bh, 1);	if (status < 0) {		mlog_errno(status);		goto out_mutex;	}	/* WINDOW_MOVE_CREDITS is a bit heavy... */	handle = ocfs2_start_trans(osb, OCFS2_WINDOW_MOVE_CREDITS);	if (IS_ERR(handle)) {		mlog_errno(PTR_ERR(handle));		handle = NULL;		goto out_unlock;	}	bh = osb->local_alloc_bh;	alloc = (struct ocfs2_dinode *) bh->b_data;	alloc_copy = kmalloc(bh->b_size, GFP_KERNEL);	if (!alloc_copy) {		status = -ENOMEM;		goto out_commit;	}	memcpy(alloc_copy, alloc, bh->b_size);	status = ocfs2_journal_access(handle, local_alloc_inode, bh,				      OCFS2_JOURNAL_ACCESS_WRITE);	if (status < 0) {		mlog_errno(status);		goto out_commit;	}	ocfs2_clear_local_alloc(alloc);	status = ocfs2_journal_dirty(handle, bh);	if (status < 0) {		mlog_errno(status);		goto out_commit;	}	brelse(bh);	osb->local_alloc_bh = NULL;	osb->local_alloc_state = OCFS2_LA_UNUSED;	status = ocfs2_sync_local_to_main(osb, handle, alloc_copy,					  main_bm_inode, main_bm_bh);	if (status < 0)		mlog_errno(status);out_commit:	ocfs2_commit_trans(osb, handle);out_unlock:	if (main_bm_bh)		brelse(main_bm_bh);	ocfs2_meta_unlock(main_bm_inode, 1);out_mutex:	mutex_unlock(&main_bm_inode->i_mutex);	iput(main_bm_inode);out:	if (local_alloc_inode)		iput(local_alloc_inode);	if (alloc_copy)		kfree(alloc_copy);	mlog_exit_void();}/* * We want to free the bitmap bits outside of any recovery context as * we'll need a cluster lock to do so, but we must clear the local * alloc before giving up the recovered nodes journal. To solve this, * we kmalloc a copy of the local alloc before it's change for the * caller to process with ocfs2_complete_local_alloc_recovery */int ocfs2_begin_local_alloc_recovery(struct ocfs2_super *osb,				     int slot_num,				     struct ocfs2_dinode **alloc_copy){	int status = 0;	struct buffer_head *alloc_bh = NULL;	struct inode *inode = NULL;	struct ocfs2_dinode *alloc;	mlog_entry("(slot_num = %d)\n", slot_num);	*alloc_copy = NULL;	inode = ocfs2_get_system_file_inode(osb,					    LOCAL_ALLOC_SYSTEM_INODE,					    slot_num);	if (!inode) {		status = -EINVAL;		mlog_errno(status);		goto bail;	}	mutex_lock(&inode->i_mutex);	status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno,				  &alloc_bh, 0, inode);	if (status < 0) {		mlog_errno(status);		goto bail;	}	*alloc_copy = kmalloc(alloc_bh->b_size, GFP_KERNEL);	if (!(*alloc_copy)) {		status = -ENOMEM;		goto bail;	}	memcpy((*alloc_copy), alloc_bh->b_data, alloc_bh->b_size);	alloc = (struct ocfs2_dinode *) alloc_bh->b_data;	ocfs2_clear_local_alloc(alloc);	status = ocfs2_write_block(osb, alloc_bh, inode);	if (status < 0)		mlog_errno(status);bail:	if ((status < 0) && (*alloc_copy)) {		kfree(*alloc_copy);		*alloc_copy = NULL;	}	if (alloc_bh)		brelse(alloc_bh);	if (inode) {		mutex_unlock(&inode->i_mutex);		iput(inode);	}	mlog_exit(status);	return status;}/* * Step 2: By now, we've completed the journal recovery, we've stamped * a clean local alloc on disk and dropped the node out of the * recovery map. Dlm locks will no longer stall, so lets clear out the * main bitmap. */int ocfs2_complete_local_alloc_recovery(struct ocfs2_super *osb,					struct ocfs2_dinode *alloc){	int status;	handle_t *handle;	struct buffer_head *main_bm_bh = NULL;	struct inode *main_bm_inode;	mlog_entry_void();	main_bm_inode = ocfs2_get_system_file_inode(osb,						    GLOBAL_BITMAP_SYSTEM_INODE,						    OCFS2_INVALID_SLOT);	if (!main_bm_inode) {		status = -EINVAL;		mlog_errno(status);		goto out;	}	mutex_lock(&main_bm_inode->i_mutex);	status = ocfs2_meta_lock(main_bm_inode, &main_bm_bh, 1);	if (status < 0) {		mlog_errno(status);		goto out_mutex;	}	handle = ocfs2_start_trans(osb, OCFS2_WINDOW_MOVE_CREDITS);	if (IS_ERR(handle)) {		status = PTR_ERR(handle);		handle = NULL;		mlog_errno(status);		goto out_unlock;	}	/* we want the bitmap change to be recorded on disk asap */	handle->h_sync = 1;	status = ocfs2_sync_local_to_main(osb, handle, alloc,					  main_bm_inode, main_bm_bh);	if (status < 0)		mlog_errno(status);	ocfs2_commit_trans(osb, handle);out_unlock:	ocfs2_meta_unlock(main_bm_inode, 1);out_mutex:	mutex_unlock(&main_bm_inode->i_mutex);	if (main_bm_bh)		brelse(main_bm_bh);	iput(main_bm_inode);out:	mlog_exit(status);	return status;}/* * make sure we've got at least bitswanted contiguous bits in the * local alloc. You lose them when you drop i_mutex. * * We will add ourselves to the transaction passed in, but may start * our own in order to shift windows. */int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,				   u32 bits_wanted,				   struct ocfs2_alloc_context *ac){	int status;	struct ocfs2_dinode *alloc;	struct inode *local_alloc_inode;	unsigned int free_bits;	mlog_entry_void();	BUG_ON(!ac);	local_alloc_inode =		ocfs2_get_system_file_inode(osb,					    LOCAL_ALLOC_SYSTEM_INODE,					    osb->slot_num);	if (!local_alloc_inode) {		status = -ENOENT;		mlog_errno(status);		goto bail;	}	mutex_lock(&local_alloc_inode->i_mutex);	if (osb->local_alloc_state != OCFS2_LA_ENABLED) {		status = -ENOSPC;		goto bail;	}	if (bits_wanted > ocfs2_local_alloc_window_bits(osb)) {		mlog(0, "Asking for more than my max window size!\n");		status = -ENOSPC;		goto bail;	}	alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data;#ifdef OCFS2_DEBUG_FS	if (le32_to_cpu(alloc->id1.bitmap1.i_used) !=	    ocfs2_local_alloc_count_bits(alloc)) {

⌨️ 快捷键说明

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