xfs_iomap.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,001 行 · 第 1/2 页

C
1,001
字号
/* * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 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. * * Further, this software is distributed without any warranty that it is * free of the rightful claim of any third person regarding infringement * or the like.	 Any license provided herein, whether implied or * otherwise, applies only to this software file.  Patent licenses, if * any, provided herein do not apply to combinations of this program with * other software, or any other product whatsoever. * * You should have received a copy of the GNU General Public License along * with this program; if not, write the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston MA 02111-1307, USA. * * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA  94043, or: * * http://www.sgi.com * * For further information regarding this notice, see: * * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ */#include "xfs.h"#include "xfs_fs.h"#include "xfs_inum.h"#include "xfs_log.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir.h"#include "xfs_dir2.h"#include "xfs_alloc.h"#include "xfs_dmapi.h"#include "xfs_quota.h"#include "xfs_mount.h"#include "xfs_alloc_btree.h"#include "xfs_bmap_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_btree.h"#include "xfs_ialloc.h"#include "xfs_attr_sf.h"#include "xfs_dir_sf.h"#include "xfs_dir2_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_bmap.h"#include "xfs_bit.h"#include "xfs_rtalloc.h"#include "xfs_error.h"#include "xfs_itable.h"#include "xfs_rw.h"#include "xfs_acl.h"#include "xfs_cap.h"#include "xfs_mac.h"#include "xfs_attr.h"#include "xfs_buf_item.h"#include "xfs_trans_space.h"#include "xfs_utils.h"#include "xfs_iomap.h"#if defined(XFS_RW_TRACE)voidxfs_iomap_enter_trace(	int		tag,	xfs_iocore_t	*io,	xfs_off_t	offset,	ssize_t		count){	xfs_inode_t	*ip = XFS_IO_INODE(io);	if (!ip->i_rwtrace)		return;	ktrace_enter(ip->i_rwtrace,		(void *)((unsigned long)tag),		(void *)ip,		(void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)),		(void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)),		(void *)((unsigned long)((offset >> 32) & 0xffffffff)),		(void *)((unsigned long)(offset & 0xffffffff)),		(void *)((unsigned long)count),		(void *)((unsigned long)((io->io_new_size >> 32) & 0xffffffff)),		(void *)((unsigned long)(io->io_new_size & 0xffffffff)),		(void *)NULL,		(void *)NULL,		(void *)NULL,		(void *)NULL,		(void *)NULL,		(void *)NULL,		(void *)NULL);}voidxfs_iomap_map_trace(	int		tag,	xfs_iocore_t	*io,	xfs_off_t	offset,	ssize_t		count,	xfs_iomap_t	*iomapp,	xfs_bmbt_irec_t	*imapp,	int		flags){	xfs_inode_t	*ip = XFS_IO_INODE(io);	if (!ip->i_rwtrace)		return;	ktrace_enter(ip->i_rwtrace,		(void *)((unsigned long)tag),		(void *)ip,		(void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)),		(void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)),		(void *)((unsigned long)((offset >> 32) & 0xffffffff)),		(void *)((unsigned long)(offset & 0xffffffff)),		(void *)((unsigned long)count),		(void *)((unsigned long)flags),		(void *)((unsigned long)((iomapp->iomap_offset >> 32) & 0xffffffff)),		(void *)((unsigned long)(iomapp->iomap_offset & 0xffffffff)),		(void *)((unsigned long)(iomapp->iomap_delta)),		(void *)((unsigned long)(iomapp->iomap_bsize)),		(void *)((unsigned long)(iomapp->iomap_bn)),		(void *)(__psint_t)(imapp->br_startoff),		(void *)((unsigned long)(imapp->br_blockcount)),		(void *)(__psint_t)(imapp->br_startblock));}#else#define xfs_iomap_enter_trace(tag, io, offset, count)#define xfs_iomap_map_trace(tag, io, offset, count, iomapp, imapp, flags)#endif#define XFS_WRITEIO_ALIGN(mp,off)	(((off) >> mp->m_writeio_log) \						<< mp->m_writeio_log)#define XFS_STRAT_WRITE_IMAPS	2#define XFS_WRITE_IMAPS		XFS_BMAP_MAX_NMAPSTATIC intxfs_imap_to_bmap(	xfs_iocore_t	*io,	xfs_off_t	offset,	xfs_bmbt_irec_t *imap,	xfs_iomap_t	*iomapp,	int		imaps,			/* Number of imap entries */	int		iomaps,			/* Number of iomap entries */	int		flags){	xfs_mount_t	*mp;	xfs_fsize_t	nisize;	int		pbm;	xfs_fsblock_t	start_block;	mp = io->io_mount;	nisize = XFS_SIZE(mp, io);	if (io->io_new_size > nisize)		nisize = io->io_new_size;	for (pbm = 0; imaps && pbm < iomaps; imaps--, iomapp++, imap++, pbm++) {		iomapp->iomap_offset = XFS_FSB_TO_B(mp, imap->br_startoff);		iomapp->iomap_delta = offset - iomapp->iomap_offset;		iomapp->iomap_bsize = XFS_FSB_TO_B(mp, imap->br_blockcount);		iomapp->iomap_flags = flags;		if (io->io_flags & XFS_IOCORE_RT) {			iomapp->iomap_flags |= IOMAP_REALTIME;			iomapp->iomap_target = mp->m_rtdev_targp;		} else {			iomapp->iomap_target = mp->m_ddev_targp;		}		start_block = imap->br_startblock;		if (start_block == HOLESTARTBLOCK) {			iomapp->iomap_bn = IOMAP_DADDR_NULL;			iomapp->iomap_flags |= IOMAP_HOLE;		} else if (start_block == DELAYSTARTBLOCK) {			iomapp->iomap_bn = IOMAP_DADDR_NULL;			iomapp->iomap_flags |= IOMAP_DELAY;		} else {			iomapp->iomap_bn = XFS_FSB_TO_DB_IO(io, start_block);			if (ISUNWRITTEN(imap))				iomapp->iomap_flags |= IOMAP_UNWRITTEN;		}		if ((iomapp->iomap_offset + iomapp->iomap_bsize) >= nisize) {			iomapp->iomap_flags |= IOMAP_EOF;		}		offset += iomapp->iomap_bsize - iomapp->iomap_delta;	}	return pbm;	/* Return the number filled */}intxfs_iomap(	xfs_iocore_t	*io,	xfs_off_t	offset,	ssize_t		count,	int		flags,	xfs_iomap_t	*iomapp,	int		*niomaps){	xfs_mount_t	*mp = io->io_mount;	xfs_fileoff_t	offset_fsb, end_fsb;	int		error = 0;	int		lockmode = 0;	xfs_bmbt_irec_t	imap;	int		nimaps = 1;	int		bmapi_flags = 0;	int		iomap_flags = 0;	if (XFS_FORCED_SHUTDOWN(mp))		return XFS_ERROR(EIO);	switch (flags &		(BMAPI_READ | BMAPI_WRITE | BMAPI_ALLOCATE |		 BMAPI_UNWRITTEN | BMAPI_DEVICE)) {	case BMAPI_READ:		xfs_iomap_enter_trace(XFS_IOMAP_READ_ENTER, io, offset, count);		lockmode = XFS_LCK_MAP_SHARED(mp, io);		bmapi_flags = XFS_BMAPI_ENTIRE;		if (flags & BMAPI_IGNSTATE)			bmapi_flags |= XFS_BMAPI_IGSTATE;		break;	case BMAPI_WRITE:		xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, io, offset, count);		lockmode = XFS_ILOCK_EXCL|XFS_EXTSIZE_WR;		bmapi_flags = 0;		XFS_ILOCK(mp, io, lockmode);		break;	case BMAPI_ALLOCATE:		xfs_iomap_enter_trace(XFS_IOMAP_ALLOC_ENTER, io, offset, count);		lockmode = XFS_ILOCK_SHARED|XFS_EXTSIZE_RD;		bmapi_flags = XFS_BMAPI_ENTIRE;		/* Attempt non-blocking lock */		if (flags & BMAPI_TRYLOCK) {			if (!XFS_ILOCK_NOWAIT(mp, io, lockmode))				return XFS_ERROR(EAGAIN);		} else {			XFS_ILOCK(mp, io, lockmode);		}		break;	case BMAPI_UNWRITTEN:		goto phase2;	case BMAPI_DEVICE:		lockmode = XFS_LCK_MAP_SHARED(mp, io);		iomapp->iomap_target = io->io_flags & XFS_IOCORE_RT ?			mp->m_rtdev_targp : mp->m_ddev_targp;		error = 0;		*niomaps = 1;		goto out;	default:		BUG();	}	ASSERT(offset <= mp->m_maxioffset);	if ((xfs_fsize_t)offset + count > mp->m_maxioffset)		count = mp->m_maxioffset - offset;	end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count);	offset_fsb = XFS_B_TO_FSBT(mp, offset);	error = XFS_BMAPI(mp, NULL, io, offset_fsb,			(xfs_filblks_t)(end_fsb - offset_fsb),			bmapi_flags,  NULL, 0, &imap,			&nimaps, NULL);	if (error)		goto out;phase2:	switch (flags & (BMAPI_WRITE|BMAPI_ALLOCATE|BMAPI_UNWRITTEN)) {	case BMAPI_WRITE:		/* If we found an extent, return it */		if (nimaps && (imap.br_startblock != HOLESTARTBLOCK)) {			xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, io,					offset, count, iomapp, &imap, flags);			break;		}		if (flags & (BMAPI_DIRECT|BMAPI_MMAP)) {			error = XFS_IOMAP_WRITE_DIRECT(mp, io, offset,					count, flags, &imap, &nimaps, nimaps);		} else {			error = XFS_IOMAP_WRITE_DELAY(mp, io, offset, count,					flags, &imap, &nimaps);		}		if (!error) {			xfs_iomap_map_trace(XFS_IOMAP_ALLOC_MAP, io,					offset, count, iomapp, &imap, flags);		}		iomap_flags = IOMAP_NEW;		break;	case BMAPI_ALLOCATE:		/* If we found an extent, return it */		XFS_IUNLOCK(mp, io, lockmode);		lockmode = 0;		if (nimaps && !ISNULLSTARTBLOCK(imap.br_startblock)) {			xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP, io,					offset, count, iomapp, &imap, flags);			break;		}		error = XFS_IOMAP_WRITE_ALLOCATE(mp, io, &imap, &nimaps);		break;	case BMAPI_UNWRITTEN:		lockmode = 0;		error = XFS_IOMAP_WRITE_UNWRITTEN(mp, io, offset, count);		nimaps = 0;		break;	}	if (nimaps) {		*niomaps = xfs_imap_to_bmap(io, offset, &imap,					    iomapp, nimaps, *niomaps, iomap_flags);	} else if (niomaps) {		*niomaps = 0;	}out:	if (lockmode)		XFS_IUNLOCK(mp, io, lockmode);	return XFS_ERROR(error);}STATIC intxfs_flush_space(	xfs_inode_t	*ip,	int		*fsynced,	int		*ioflags){	switch (*fsynced) {	case 0:		if (ip->i_delayed_blks) {			xfs_iunlock(ip, XFS_ILOCK_EXCL);			xfs_flush_inode(ip);			xfs_ilock(ip, XFS_ILOCK_EXCL);			*fsynced = 1;		} else {			*ioflags |= BMAPI_SYNC;			*fsynced = 2;		}		return 0;	case 1:		*fsynced = 2;		*ioflags |= BMAPI_SYNC;		return 0;	case 2:		xfs_iunlock(ip, XFS_ILOCK_EXCL);		xfs_flush_device(ip);		xfs_ilock(ip, XFS_ILOCK_EXCL);		*fsynced = 3;		return 0;	}	return 1;}intxfs_iomap_write_direct(	xfs_inode_t	*ip,	loff_t		offset,	size_t		count,	int		flags,	xfs_bmbt_irec_t *ret_imap,	int		*nmaps,	int		found){	xfs_mount_t	*mp = ip->i_mount;	xfs_iocore_t	*io = &ip->i_iocore;	xfs_fileoff_t	offset_fsb;	xfs_fileoff_t	last_fsb;	xfs_filblks_t	count_fsb;	xfs_fsize_t	isize;	xfs_fsblock_t	firstfsb;	int		nimaps, maps;	int		error;	int		bmapi_flag;	int		rt;	xfs_trans_t	*tp;	xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS], *imapp;	xfs_bmap_free_t free_list;	int		aeof;	xfs_filblks_t	datablocks;	int		committed;	int		numrtextents;	uint		resblks;	/*	 * Make sure that the dquots are there. This doesn't hold	 * the ilock across a disk read.	 */	error = XFS_QM_DQATTACH(ip->i_mount, ip, XFS_QMOPT_ILOCKED);	if (error)		return XFS_ERROR(error);	maps = min(XFS_WRITE_IMAPS, *nmaps);	nimaps = maps;	isize = ip->i_d.di_size;	aeof = (offset + count) > isize;	if (io->io_new_size > isize)		isize = io->io_new_size;	offset_fsb = XFS_B_TO_FSBT(mp, offset);	last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));	count_fsb = last_fsb - offset_fsb;	if (found && (ret_imap->br_startblock == HOLESTARTBLOCK)) {		xfs_fileoff_t	map_last_fsb;		map_last_fsb = ret_imap->br_blockcount + ret_imap->br_startoff;		if (map_last_fsb < last_fsb) {			last_fsb = map_last_fsb;			count_fsb = last_fsb - offset_fsb;		}		ASSERT(count_fsb > 0);	}	/*	 * determine if reserving space on	 * the data or realtime partition.	 */	if ((rt = XFS_IS_REALTIME_INODE(ip))) {		int	sbrtextsize, iprtextsize;		sbrtextsize = mp->m_sb.sb_rextsize;		iprtextsize =			ip->i_d.di_extsize ? ip->i_d.di_extsize : sbrtextsize;		numrtextents = (count_fsb + iprtextsize - 1);		do_div(numrtextents, sbrtextsize);		datablocks = 0;	} else {		datablocks = count_fsb;		numrtextents = 0;	}	/*	 * allocate and setup the transaction	 */	xfs_iunlock(ip, XFS_ILOCK_EXCL);	tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);	resblks = XFS_DIOSTRAT_SPACE_RES(mp, datablocks);	error = xfs_trans_reserve(tp, resblks,			XFS_WRITE_LOG_RES(mp), numrtextents,			XFS_TRANS_PERM_LOG_RES,			XFS_WRITE_LOG_COUNT);	/*	 * check for running out of space	 */	if (error)		/*		 * Free the transaction structure.		 */		xfs_trans_cancel(tp, 0);	xfs_ilock(ip, XFS_ILOCK_EXCL);	if (error)		goto error_out; /* Don't return in above if .. trans ..,					need lock to return */	if (XFS_TRANS_RESERVE_BLKQUOTA(mp, tp, ip, resblks)) {		error = (EDQUOT);		goto error1;	}	nimaps = 1;	bmapi_flag = XFS_BMAPI_WRITE;	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);	xfs_trans_ihold(tp, ip);	if (!(flags & BMAPI_MMAP) && (offset < ip->i_d.di_size || rt))		bmapi_flag |= XFS_BMAPI_PREALLOC;	/*	 * issue the bmapi() call to allocate the blocks	 */	XFS_BMAP_INIT(&free_list, &firstfsb);	imapp = &imap[0];	error = xfs_bmapi(tp, ip, offset_fsb, count_fsb,		bmapi_flag, &firstfsb, 0, imapp, &nimaps, &free_list);	if (error) {		goto error0;	}	/*	 * complete the transaction	 */	error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed);

⌨️ 快捷键说明

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