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

📄 xfs_alloc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. * 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. * * This program is distributed in the hope that it would 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 the Free Software Foundation, * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */#include "xfs.h"#include "xfs_fs.h"#include "xfs_types.h"#include "xfs_bit.h"#include "xfs_log.h"#include "xfs_inum.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir2.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_bmap_btree.h"#include "xfs_alloc_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_dir2_sf.h"#include "xfs_attr_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_btree.h"#include "xfs_ialloc.h"#include "xfs_alloc.h"#include "xfs_error.h"#define XFS_ABSDIFF(a,b)	(((a) <= (b)) ? ((b) - (a)) : ((a) - (b)))#define	XFSA_FIXUP_BNO_OK	1#define	XFSA_FIXUP_CNT_OK	2STATIC intxfs_alloc_search_busy(xfs_trans_t *tp,		    xfs_agnumber_t agno,		    xfs_agblock_t bno,		    xfs_extlen_t len);#if defined(XFS_ALLOC_TRACE)ktrace_t *xfs_alloc_trace_buf;#define	TRACE_ALLOC(s,a)	\	xfs_alloc_trace_alloc(__FUNCTION__, s, a, __LINE__)#define	TRACE_FREE(s,a,b,x,f)	\	xfs_alloc_trace_free(__FUNCTION__, s, mp, a, b, x, f, __LINE__)#define	TRACE_MODAGF(s,a,f)	\	xfs_alloc_trace_modagf(__FUNCTION__, s, mp, a, f, __LINE__)#define	TRACE_BUSY(__FUNCTION__,s,ag,agb,l,sl,tp)	\	xfs_alloc_trace_busy(__FUNCTION__, s, mp, ag, agb, l, sl, tp, XFS_ALLOC_KTRACE_BUSY, __LINE__)#define	TRACE_UNBUSY(__FUNCTION__,s,ag,sl,tp)	\	xfs_alloc_trace_busy(__FUNCTION__, s, mp, ag, -1, -1, sl, tp, XFS_ALLOC_KTRACE_UNBUSY, __LINE__)#define	TRACE_BUSYSEARCH(__FUNCTION__,s,ag,agb,l,sl,tp)	\	xfs_alloc_trace_busy(__FUNCTION__, s, mp, ag, agb, l, sl, tp, XFS_ALLOC_KTRACE_BUSYSEARCH, __LINE__)#else#define	TRACE_ALLOC(s,a)#define	TRACE_FREE(s,a,b,x,f)#define	TRACE_MODAGF(s,a,f)#define	TRACE_BUSY(s,a,ag,agb,l,sl,tp)#define	TRACE_UNBUSY(fname,s,ag,sl,tp)#define	TRACE_BUSYSEARCH(fname,s,ag,agb,l,sl,tp)#endif	/* XFS_ALLOC_TRACE *//* * Prototypes for per-ag allocation routines */STATIC int xfs_alloc_ag_vextent_exact(xfs_alloc_arg_t *);STATIC int xfs_alloc_ag_vextent_near(xfs_alloc_arg_t *);STATIC int xfs_alloc_ag_vextent_size(xfs_alloc_arg_t *);STATIC int xfs_alloc_ag_vextent_small(xfs_alloc_arg_t *,	xfs_btree_cur_t *, xfs_agblock_t *, xfs_extlen_t *, int *);/* * Internal functions. *//* * Compute aligned version of the found extent. * Takes alignment and min length into account. */STATIC int				/* success (>= minlen) */xfs_alloc_compute_aligned(	xfs_agblock_t	foundbno,	/* starting block in found extent */	xfs_extlen_t	foundlen,	/* length in found extent */	xfs_extlen_t	alignment,	/* alignment for allocation */	xfs_extlen_t	minlen,		/* minimum length for allocation */	xfs_agblock_t	*resbno,	/* result block number */	xfs_extlen_t	*reslen)	/* result length */{	xfs_agblock_t	bno;	xfs_extlen_t	diff;	xfs_extlen_t	len;	if (alignment > 1 && foundlen >= minlen) {		bno = roundup(foundbno, alignment);		diff = bno - foundbno;		len = diff >= foundlen ? 0 : foundlen - diff;	} else {		bno = foundbno;		len = foundlen;	}	*resbno = bno;	*reslen = len;	return len >= minlen;}/* * Compute best start block and diff for "near" allocations. * freelen >= wantlen already checked by caller. */STATIC xfs_extlen_t			/* difference value (absolute) */xfs_alloc_compute_diff(	xfs_agblock_t	wantbno,	/* target starting block */	xfs_extlen_t	wantlen,	/* target length */	xfs_extlen_t	alignment,	/* target alignment */	xfs_agblock_t	freebno,	/* freespace's starting block */	xfs_extlen_t	freelen,	/* freespace's length */	xfs_agblock_t	*newbnop)	/* result: best start block from free */{	xfs_agblock_t	freeend;	/* end of freespace extent */	xfs_agblock_t	newbno1;	/* return block number */	xfs_agblock_t	newbno2;	/* other new block number */	xfs_extlen_t	newlen1=0;	/* length with newbno1 */	xfs_extlen_t	newlen2=0;	/* length with newbno2 */	xfs_agblock_t	wantend;	/* end of target extent */	ASSERT(freelen >= wantlen);	freeend = freebno + freelen;	wantend = wantbno + wantlen;	if (freebno >= wantbno) {		if ((newbno1 = roundup(freebno, alignment)) >= freeend)			newbno1 = NULLAGBLOCK;	} else if (freeend >= wantend && alignment > 1) {		newbno1 = roundup(wantbno, alignment);		newbno2 = newbno1 - alignment;		if (newbno1 >= freeend)			newbno1 = NULLAGBLOCK;		else			newlen1 = XFS_EXTLEN_MIN(wantlen, freeend - newbno1);		if (newbno2 < freebno)			newbno2 = NULLAGBLOCK;		else			newlen2 = XFS_EXTLEN_MIN(wantlen, freeend - newbno2);		if (newbno1 != NULLAGBLOCK && newbno2 != NULLAGBLOCK) {			if (newlen1 < newlen2 ||			    (newlen1 == newlen2 &&			     XFS_ABSDIFF(newbno1, wantbno) >			     XFS_ABSDIFF(newbno2, wantbno)))				newbno1 = newbno2;		} else if (newbno2 != NULLAGBLOCK)			newbno1 = newbno2;	} else if (freeend >= wantend) {		newbno1 = wantbno;	} else if (alignment > 1) {		newbno1 = roundup(freeend - wantlen, alignment);		if (newbno1 > freeend - wantlen &&		    newbno1 - alignment >= freebno)			newbno1 -= alignment;		else if (newbno1 >= freeend)			newbno1 = NULLAGBLOCK;	} else		newbno1 = freeend - wantlen;	*newbnop = newbno1;	return newbno1 == NULLAGBLOCK ? 0 : XFS_ABSDIFF(newbno1, wantbno);}/* * Fix up the length, based on mod and prod. * len should be k * prod + mod for some k. * If len is too small it is returned unchanged. * If len hits maxlen it is left alone. */STATIC voidxfs_alloc_fix_len(	xfs_alloc_arg_t	*args)		/* allocation argument structure */{	xfs_extlen_t	k;	xfs_extlen_t	rlen;	ASSERT(args->mod < args->prod);	rlen = args->len;	ASSERT(rlen >= args->minlen);	ASSERT(rlen <= args->maxlen);	if (args->prod <= 1 || rlen < args->mod || rlen == args->maxlen ||	    (args->mod == 0 && rlen < args->prod))		return;	k = rlen % args->prod;	if (k == args->mod)		return;	if (k > args->mod) {		if ((int)(rlen = rlen - k - args->mod) < (int)args->minlen)			return;	} else {		if ((int)(rlen = rlen - args->prod - (args->mod - k)) <		    (int)args->minlen)			return;	}	ASSERT(rlen >= args->minlen);	ASSERT(rlen <= args->maxlen);	args->len = rlen;}/* * Fix up length if there is too little space left in the a.g. * Return 1 if ok, 0 if too little, should give up. */STATIC intxfs_alloc_fix_minleft(	xfs_alloc_arg_t	*args)		/* allocation argument structure */{	xfs_agf_t	*agf;		/* a.g. freelist header */	int		diff;		/* free space difference */	if (args->minleft == 0)		return 1;	agf = XFS_BUF_TO_AGF(args->agbp);	diff = be32_to_cpu(agf->agf_freeblks)		+ be32_to_cpu(agf->agf_flcount)		- args->len - args->minleft;	if (diff >= 0)		return 1;	args->len += diff;		/* shrink the allocated space */	if (args->len >= args->minlen)		return 1;	args->agbno = NULLAGBLOCK;	return 0;}/* * Update the two btrees, logically removing from freespace the extent * starting at rbno, rlen blocks.  The extent is contained within the * actual (current) free extent fbno for flen blocks. * Flags are passed in indicating whether the cursors are set to the * relevant records. */STATIC int				/* error code */xfs_alloc_fixup_trees(	xfs_btree_cur_t	*cnt_cur,	/* cursor for by-size btree */	xfs_btree_cur_t	*bno_cur,	/* cursor for by-block btree */	xfs_agblock_t	fbno,		/* starting block of free extent */	xfs_extlen_t	flen,		/* length of free extent */	xfs_agblock_t	rbno,		/* starting block of returned extent */	xfs_extlen_t	rlen,		/* length of returned extent */	int		flags)		/* flags, XFSA_FIXUP_... */{	int		error;		/* error code */	int		i;		/* operation results */	xfs_agblock_t	nfbno1;		/* first new free startblock */	xfs_agblock_t	nfbno2;		/* second new free startblock */	xfs_extlen_t	nflen1=0;	/* first new free length */	xfs_extlen_t	nflen2=0;	/* second new free length */	/*	 * Look up the record in the by-size tree if necessary.	 */	if (flags & XFSA_FIXUP_CNT_OK) {#ifdef DEBUG		if ((error = xfs_alloc_get_rec(cnt_cur, &nfbno1, &nflen1, &i)))			return error;		XFS_WANT_CORRUPTED_RETURN(			i == 1 && nfbno1 == fbno && nflen1 == flen);#endif	} else {		if ((error = xfs_alloc_lookup_eq(cnt_cur, fbno, flen, &i)))			return error;		XFS_WANT_CORRUPTED_RETURN(i == 1);	}	/*	 * Look up the record in the by-block tree if necessary.	 */	if (flags & XFSA_FIXUP_BNO_OK) {#ifdef DEBUG		if ((error = xfs_alloc_get_rec(bno_cur, &nfbno1, &nflen1, &i)))			return error;		XFS_WANT_CORRUPTED_RETURN(			i == 1 && nfbno1 == fbno && nflen1 == flen);#endif	} else {		if ((error = xfs_alloc_lookup_eq(bno_cur, fbno, flen, &i)))			return error;		XFS_WANT_CORRUPTED_RETURN(i == 1);	}#ifdef DEBUG	{		xfs_alloc_block_t	*bnoblock;		xfs_alloc_block_t	*cntblock;		if (bno_cur->bc_nlevels == 1 &&		    cnt_cur->bc_nlevels == 1) {			bnoblock = XFS_BUF_TO_ALLOC_BLOCK(bno_cur->bc_bufs[0]);			cntblock = XFS_BUF_TO_ALLOC_BLOCK(cnt_cur->bc_bufs[0]);			XFS_WANT_CORRUPTED_RETURN(				be16_to_cpu(bnoblock->bb_numrecs) ==				be16_to_cpu(cntblock->bb_numrecs));		}	}#endif	/*	 * Deal with all four cases: the allocated record is contained	 * within the freespace record, so we can have new freespace	 * at either (or both) end, or no freespace remaining.	 */	if (rbno == fbno && rlen == flen)		nfbno1 = nfbno2 = NULLAGBLOCK;	else if (rbno == fbno) {		nfbno1 = rbno + rlen;		nflen1 = flen - rlen;		nfbno2 = NULLAGBLOCK;	} else if (rbno + rlen == fbno + flen) {		nfbno1 = fbno;		nflen1 = flen - rlen;		nfbno2 = NULLAGBLOCK;	} else {		nfbno1 = fbno;		nflen1 = rbno - fbno;		nfbno2 = rbno + rlen;		nflen2 = (fbno + flen) - nfbno2;	}	/*	 * Delete the entry from the by-size btree.	 */	if ((error = xfs_alloc_delete(cnt_cur, &i)))		return error;	XFS_WANT_CORRUPTED_RETURN(i == 1);	/*	 * Add new by-size btree entry(s).	 */	if (nfbno1 != NULLAGBLOCK) {		if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno1, nflen1, &i)))			return error;		XFS_WANT_CORRUPTED_RETURN(i == 0);		if ((error = xfs_alloc_insert(cnt_cur, &i)))			return error;		XFS_WANT_CORRUPTED_RETURN(i == 1);	}	if (nfbno2 != NULLAGBLOCK) {		if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno2, nflen2, &i)))			return error;		XFS_WANT_CORRUPTED_RETURN(i == 0);		if ((error = xfs_alloc_insert(cnt_cur, &i)))			return error;		XFS_WANT_CORRUPTED_RETURN(i == 1);	}	/*	 * Fix up the by-block btree entry(s).	 */	if (nfbno1 == NULLAGBLOCK) {		/*		 * No remaining freespace, just delete the by-block tree entry.		 */		if ((error = xfs_alloc_delete(bno_cur, &i)))			return error;		XFS_WANT_CORRUPTED_RETURN(i == 1);	} else {		/*		 * Update the by-block entry to start later|be shorter.		 */		if ((error = xfs_alloc_update(bno_cur, nfbno1, nflen1)))			return error;	}	if (nfbno2 != NULLAGBLOCK) {		/*		 * 2 resulting free entries, need to add one.		 */		if ((error = xfs_alloc_lookup_eq(bno_cur, nfbno2, nflen2, &i)))			return error;		XFS_WANT_CORRUPTED_RETURN(i == 0);		if ((error = xfs_alloc_insert(bno_cur, &i)))			return error;		XFS_WANT_CORRUPTED_RETURN(i == 1);	}	return 0;}/* * Read in the allocation group free block array. */STATIC int				/* error */xfs_alloc_read_agfl(	xfs_mount_t	*mp,		/* mount point structure */	xfs_trans_t	*tp,		/* transaction pointer */	xfs_agnumber_t	agno,		/* allocation group number */	xfs_buf_t	**bpp)		/* buffer for the ag free block array */{	xfs_buf_t	*bp;		/* return value */	int		error;	ASSERT(agno != NULLAGNUMBER);	error = xfs_trans_read_buf(			mp, tp, mp->m_ddev_targp,			XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)),			XFS_FSS_TO_BB(mp, 1), 0, &bp);	if (error)		return error;	ASSERT(bp);	ASSERT(!XFS_BUF_GETERROR(bp));	XFS_BUF_SET_VTYPE_REF(bp, B_FS_AGFL, XFS_AGFL_REF);	*bpp = bp;	return 0;}#if defined(XFS_ALLOC_TRACE)/* * Add an allocation trace entry for an alloc call. */STATIC voidxfs_alloc_trace_alloc(	const char	*name,		/* function tag string */	char		*str,		/* additional string */	xfs_alloc_arg_t	*args,		/* allocation argument structure */	int		line)		/* source line number */{	ktrace_enter(xfs_alloc_trace_buf,		(void *)(__psint_t)(XFS_ALLOC_KTRACE_ALLOC | (line << 16)),		(void *)name,		(void *)str,		(void *)args->mp,		(void *)(__psunsigned_t)args->agno,		(void *)(__psunsigned_t)args->agbno,		(void *)(__psunsigned_t)args->minlen,		(void *)(__psunsigned_t)args->maxlen,		(void *)(__psunsigned_t)args->mod,		(void *)(__psunsigned_t)args->prod,		(void *)(__psunsigned_t)args->minleft,		(void *)(__psunsigned_t)args->total,		(void *)(__psunsigned_t)args->alignment,		(void *)(__psunsigned_t)args->len,		(void *)((((__psint_t)args->type) << 16) |			 (__psint_t)args->otype),		(void *)(__psint_t)((args->wasdel << 3) |				    (args->wasfromfl << 2) |				    (args->isfl << 1) |				    (args->userdata << 0)));}/*

⌨️ 快捷键说明

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