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

📄 xfs_filestream.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2006-2007 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_bmap_btree.h"#include "xfs_inum.h"#include "xfs_dir2.h"#include "xfs_dir2_sf.h"#include "xfs_attr_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_ag.h"#include "xfs_dmapi.h"#include "xfs_log.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_mount.h"#include "xfs_bmap.h"#include "xfs_alloc.h"#include "xfs_utils.h"#include "xfs_mru_cache.h"#include "xfs_filestream.h"#ifdef XFS_FILESTREAMS_TRACEktrace_t *xfs_filestreams_trace_buf;STATIC voidxfs_filestreams_trace(	xfs_mount_t	*mp,	/* mount point */	int		type,	/* type of trace */	const char	*func,	/* source function */	int		line,	/* source line number */	__psunsigned_t	arg0,	__psunsigned_t	arg1,	__psunsigned_t	arg2,	__psunsigned_t	arg3,	__psunsigned_t	arg4,	__psunsigned_t	arg5){	ktrace_enter(xfs_filestreams_trace_buf,		(void *)(__psint_t)(type | (line << 16)),		(void *)func,		(void *)(__psunsigned_t)current_pid(),		(void *)mp,		(void *)(__psunsigned_t)arg0,		(void *)(__psunsigned_t)arg1,		(void *)(__psunsigned_t)arg2,		(void *)(__psunsigned_t)arg3,		(void *)(__psunsigned_t)arg4,		(void *)(__psunsigned_t)arg5,		NULL, NULL, NULL, NULL, NULL, NULL);}#define TRACE0(mp,t)			TRACE6(mp,t,0,0,0,0,0,0)#define TRACE1(mp,t,a0)			TRACE6(mp,t,a0,0,0,0,0,0)#define TRACE2(mp,t,a0,a1)		TRACE6(mp,t,a0,a1,0,0,0,0)#define TRACE3(mp,t,a0,a1,a2)		TRACE6(mp,t,a0,a1,a2,0,0,0)#define TRACE4(mp,t,a0,a1,a2,a3)	TRACE6(mp,t,a0,a1,a2,a3,0,0)#define TRACE5(mp,t,a0,a1,a2,a3,a4)	TRACE6(mp,t,a0,a1,a2,a3,a4,0)#define TRACE6(mp,t,a0,a1,a2,a3,a4,a5) \	xfs_filestreams_trace(mp, t, __FUNCTION__, __LINE__, \				(__psunsigned_t)a0, (__psunsigned_t)a1, \				(__psunsigned_t)a2, (__psunsigned_t)a3, \				(__psunsigned_t)a4, (__psunsigned_t)a5)#define TRACE_AG_SCAN(mp, ag, ag2) \		TRACE2(mp, XFS_FSTRM_KTRACE_AGSCAN, ag, ag2);#define TRACE_AG_PICK1(mp, max_ag, maxfree) \		TRACE2(mp, XFS_FSTRM_KTRACE_AGPICK1, max_ag, maxfree);#define TRACE_AG_PICK2(mp, ag, ag2, cnt, free, scan, flag) \		TRACE6(mp, XFS_FSTRM_KTRACE_AGPICK2, ag, ag2, \			 cnt, free, scan, flag)#define TRACE_UPDATE(mp, ip, ag, cnt, ag2, cnt2) \		TRACE5(mp, XFS_FSTRM_KTRACE_UPDATE, ip, ag, cnt, ag2, cnt2)#define TRACE_FREE(mp, ip, pip, ag, cnt) \		TRACE4(mp, XFS_FSTRM_KTRACE_FREE, ip, pip, ag, cnt)#define TRACE_LOOKUP(mp, ip, pip, ag, cnt) \		TRACE4(mp, XFS_FSTRM_KTRACE_ITEM_LOOKUP, ip, pip, ag, cnt)#define TRACE_ASSOCIATE(mp, ip, pip, ag, cnt) \		TRACE4(mp, XFS_FSTRM_KTRACE_ASSOCIATE, ip, pip, ag, cnt)#define TRACE_MOVEAG(mp, ip, pip, oag, ocnt, nag, ncnt) \		TRACE6(mp, XFS_FSTRM_KTRACE_MOVEAG, ip, pip, oag, ocnt, nag, ncnt)#define TRACE_ORPHAN(mp, ip, ag) \		TRACE2(mp, XFS_FSTRM_KTRACE_ORPHAN, ip, ag);#else#define TRACE_AG_SCAN(mp, ag, ag2)#define TRACE_AG_PICK1(mp, max_ag, maxfree)#define TRACE_AG_PICK2(mp, ag, ag2, cnt, free, scan, flag)#define TRACE_UPDATE(mp, ip, ag, cnt, ag2, cnt2)#define TRACE_FREE(mp, ip, pip, ag, cnt)#define TRACE_LOOKUP(mp, ip, pip, ag, cnt)#define TRACE_ASSOCIATE(mp, ip, pip, ag, cnt)#define TRACE_MOVEAG(mp, ip, pip, oag, ocnt, nag, ncnt)#define TRACE_ORPHAN(mp, ip, ag)#endifstatic kmem_zone_t *item_zone;/* * Structure for associating a file or a directory with an allocation group. * The parent directory pointer is only needed for files, but since there will * generally be vastly more files than directories in the cache, using the same * data structure simplifies the code with very little memory overhead. */typedef struct fstrm_item{	xfs_agnumber_t	ag;	/* AG currently in use for the file/directory. */	xfs_inode_t	*ip;	/* inode self-pointer. */	xfs_inode_t	*pip;	/* Parent directory inode pointer. */} fstrm_item_t;/* * Scan the AGs starting at startag looking for an AG that isn't in use and has * at least minlen blocks free. */static int_xfs_filestream_pick_ag(	xfs_mount_t	*mp,	xfs_agnumber_t	startag,	xfs_agnumber_t	*agp,	int		flags,	xfs_extlen_t	minlen){	int		err, trylock, nscan;	xfs_extlen_t	delta, longest, need, free, minfree, maxfree = 0;	xfs_agnumber_t	ag, max_ag = NULLAGNUMBER;	struct xfs_perag *pag;	/* 2% of an AG's blocks must be free for it to be chosen. */	minfree = mp->m_sb.sb_agblocks / 50;	ag = startag;	*agp = NULLAGNUMBER;	/* For the first pass, don't sleep trying to init the per-AG. */	trylock = XFS_ALLOC_FLAG_TRYLOCK;	for (nscan = 0; 1; nscan++) {		TRACE_AG_SCAN(mp, ag, xfs_filestream_peek_ag(mp, ag));		pag = mp->m_perag + ag;		if (!pag->pagf_init) {			err = xfs_alloc_pagf_init(mp, NULL, ag, trylock);			if (err && !trylock)				return err;		}		/* Might fail sometimes during the 1st pass with trylock set. */		if (!pag->pagf_init)			goto next_ag;		/* Keep track of the AG with the most free blocks. */		if (pag->pagf_freeblks > maxfree) {			maxfree = pag->pagf_freeblks;			max_ag = ag;		}		/*		 * The AG reference count does two things: it enforces mutual		 * exclusion when examining the suitability of an AG in this		 * loop, and it guards against two filestreams being established		 * in the same AG as each other.		 */		if (xfs_filestream_get_ag(mp, ag) > 1) {			xfs_filestream_put_ag(mp, ag);			goto next_ag;		}		need = XFS_MIN_FREELIST_PAG(pag, mp);		delta = need > pag->pagf_flcount ? need - pag->pagf_flcount : 0;		longest = (pag->pagf_longest > delta) ?		          (pag->pagf_longest - delta) :		          (pag->pagf_flcount > 0 || pag->pagf_longest > 0);		if (((minlen && longest >= minlen) ||		     (!minlen && pag->pagf_freeblks >= minfree)) &&		    (!pag->pagf_metadata || !(flags & XFS_PICK_USERDATA) ||		     (flags & XFS_PICK_LOWSPACE))) {			/* Break out, retaining the reference on the AG. */			free = pag->pagf_freeblks;			*agp = ag;			break;		}		/* Drop the reference on this AG, it's not usable. */		xfs_filestream_put_ag(mp, ag);next_ag:		/* Move to the next AG, wrapping to AG 0 if necessary. */		if (++ag >= mp->m_sb.sb_agcount)			ag = 0;		/* If a full pass of the AGs hasn't been done yet, continue. */		if (ag != startag)			continue;		/* Allow sleeping in xfs_alloc_pagf_init() on the 2nd pass. */		if (trylock != 0) {			trylock = 0;			continue;		}		/* Finally, if lowspace wasn't set, set it for the 3rd pass. */		if (!(flags & XFS_PICK_LOWSPACE)) {			flags |= XFS_PICK_LOWSPACE;			continue;		}		/*		 * Take the AG with the most free space, regardless of whether		 * it's already in use by another filestream.		 */		if (max_ag != NULLAGNUMBER) {			xfs_filestream_get_ag(mp, max_ag);			TRACE_AG_PICK1(mp, max_ag, maxfree);			free = maxfree;			*agp = max_ag;			break;		}		/* take AG 0 if none matched */		TRACE_AG_PICK1(mp, max_ag, maxfree);		*agp = 0;		return 0;	}	TRACE_AG_PICK2(mp, startag, *agp, xfs_filestream_peek_ag(mp, *agp),			free, nscan, flags);	return 0;}/* * Set the allocation group number for a file or a directory, updating inode * references and per-AG references as appropriate.  Must be called with the * m_peraglock held in read mode. */static int_xfs_filestream_update_ag(	xfs_inode_t	*ip,	xfs_inode_t	*pip,	xfs_agnumber_t	ag){	int		err = 0;	xfs_mount_t	*mp;	xfs_mru_cache_t	*cache;	fstrm_item_t	*item;	xfs_agnumber_t	old_ag;	xfs_inode_t	*old_pip;	/*	 * Either ip is a regular file and pip is a directory, or ip is a	 * directory and pip is NULL.	 */	ASSERT(ip && (((ip->i_d.di_mode & S_IFREG) && pip &&	               (pip->i_d.di_mode & S_IFDIR)) ||	              ((ip->i_d.di_mode & S_IFDIR) && !pip)));	mp = ip->i_mount;	cache = mp->m_filestream;	item = xfs_mru_cache_lookup(cache, ip->i_ino);	if (item) {		ASSERT(item->ip == ip);		old_ag = item->ag;		item->ag = ag;		old_pip = item->pip;		item->pip = pip;		xfs_mru_cache_done(cache);		/*		 * If the AG has changed, drop the old ref and take a new one,		 * effectively transferring the reference from old to new AG.		 */		if (ag != old_ag) {			xfs_filestream_put_ag(mp, old_ag);			xfs_filestream_get_ag(mp, ag);		}		/*		 * If ip is a file and its pip has changed, drop the old ref and		 * take a new one.		 */		if (pip && pip != old_pip) {			IRELE(old_pip);			IHOLD(pip);		}		TRACE_UPDATE(mp, ip, old_ag, xfs_filestream_peek_ag(mp, old_ag),				ag, xfs_filestream_peek_ag(mp, ag));		return 0;	}	item = kmem_zone_zalloc(item_zone, KM_MAYFAIL);	if (!item)		return ENOMEM;	item->ag = ag;	item->ip = ip;	item->pip = pip;	err = xfs_mru_cache_insert(cache, ip->i_ino, item);	if (err) {		kmem_zone_free(item_zone, item);		return err;	}	/* Take a reference on the AG. */	xfs_filestream_get_ag(mp, ag);	/*	 * Take a reference on the inode itself regardless of whether it's a	 * regular file or a directory.	 */	IHOLD(ip);	/*	 * In the case of a regular file, take a reference on the parent inode	 * as well to ensure it remains in-core.	 */	if (pip)		IHOLD(pip);	TRACE_UPDATE(mp, ip, ag, xfs_filestream_peek_ag(mp, ag),			ag, xfs_filestream_peek_ag(mp, ag));	return 0;}/* xfs_fstrm_free_func(): callback for freeing cached stream items. */voidxfs_fstrm_free_func(	unsigned long	ino,	void		*data){	fstrm_item_t	*item  = (fstrm_item_t *)data;	xfs_inode_t	*ip = item->ip;	int ref;	ASSERT(ip->i_ino == ino);	xfs_iflags_clear(ip, XFS_IFILESTREAM);	/* Drop the reference taken on the AG when the item was added. */	ref = xfs_filestream_put_ag(ip->i_mount, item->ag);	ASSERT(ref >= 0);	TRACE_FREE(ip->i_mount, ip, item->pip, item->ag,		xfs_filestream_peek_ag(ip->i_mount, item->ag));	/*	 * _xfs_filestream_update_ag() always takes a reference on the inode	 * itself, whether it's a file or a directory.  Release it here.	 * This can result in the inode being freed and so we must	 * not hold any inode locks when freeing filesstreams objects	 * otherwise we can deadlock here.	 */	IRELE(ip);	/*	 * In the case of a regular file, _xfs_filestream_update_ag() also	 * takes a ref on the parent inode to keep it in-core.  Release that	 * too.	 */	if (item->pip)		IRELE(item->pip);

⌨️ 快捷键说明

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