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

📄 xfs_bmap.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 */STATIC int					/* error */xfs_bmap_add_attrfork_btree(	xfs_trans_t		*tp,		/* transaction pointer */	xfs_inode_t		*ip,		/* incore inode pointer */	xfs_fsblock_t		*firstblock,	/* first block allocated */	xfs_bmap_free_t		*flist,		/* blocks to free at commit */	int			*flags)		/* inode logging flags */{	xfs_btree_cur_t		*cur;		/* btree cursor */	int			error;		/* error return value */	xfs_mount_t		*mp;		/* file system mount struct */	int			stat;		/* newroot status */	mp = ip->i_mount;	if (ip->i_df.if_broot_bytes <= XFS_IFORK_DSIZE(ip))		*flags |= XFS_ILOG_DBROOT;	else {		cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip,			XFS_DATA_FORK);		cur->bc_private.b.flist = flist;		cur->bc_private.b.firstblock = *firstblock;		if ((error = xfs_bmbt_lookup_ge(cur, 0, 0, 0, &stat)))			goto error0;		ASSERT(stat == 1);	/* must be at least one entry */		if ((error = xfs_bmbt_newroot(cur, flags, &stat)))			goto error0;		if (stat == 0) {			xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);			return XFS_ERROR(ENOSPC);		}		*firstblock = cur->bc_private.b.firstblock;		cur->bc_private.b.allocated = 0;		xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);	}	return 0;error0:	xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);	return error;}/* * Called from xfs_bmap_add_attrfork to handle extents format files. */STATIC int					/* error */xfs_bmap_add_attrfork_extents(	xfs_trans_t		*tp,		/* transaction pointer */	xfs_inode_t		*ip,		/* incore inode pointer */	xfs_fsblock_t		*firstblock,	/* first block allocated */	xfs_bmap_free_t		*flist,		/* blocks to free at commit */	int			*flags)		/* inode logging flags */{	xfs_btree_cur_t		*cur;		/* bmap btree cursor */	int			error;		/* error return value */	if (ip->i_d.di_nextents * sizeof(xfs_bmbt_rec_t) <= XFS_IFORK_DSIZE(ip))		return 0;	cur = NULL;	error = xfs_bmap_extents_to_btree(tp, ip, firstblock, flist, &cur, 0,		flags, XFS_DATA_FORK);	if (cur) {		cur->bc_private.b.allocated = 0;		xfs_btree_del_cursor(cur,			error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);	}	return error;}/* * Called from xfs_bmap_add_attrfork to handle local format files. */STATIC int					/* error */xfs_bmap_add_attrfork_local(	xfs_trans_t		*tp,		/* transaction pointer */	xfs_inode_t		*ip,		/* incore inode pointer */	xfs_fsblock_t		*firstblock,	/* first block allocated */	xfs_bmap_free_t		*flist,		/* blocks to free at commit */	int			*flags)		/* inode logging flags */{	xfs_da_args_t		dargs;		/* args for dir/attr code */	int			error;		/* error return value */	xfs_mount_t		*mp;		/* mount structure pointer */	if (ip->i_df.if_bytes <= XFS_IFORK_DSIZE(ip))		return 0;	if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {		mp = ip->i_mount;		memset(&dargs, 0, sizeof(dargs));		dargs.dp = ip;		dargs.firstblock = firstblock;		dargs.flist = flist;		dargs.total = mp->m_dirblkfsbs;		dargs.whichfork = XFS_DATA_FORK;		dargs.trans = tp;		error = xfs_dir2_sf_to_block(&dargs);	} else		error = xfs_bmap_local_to_extents(tp, ip, firstblock, 1, flags,			XFS_DATA_FORK);	return error;}/* * Called by xfs_bmapi to update file extent records and the btree * after allocating space (or doing a delayed allocation). */STATIC int				/* error */xfs_bmap_add_extent(	xfs_inode_t		*ip,	/* incore inode pointer */	xfs_extnum_t		idx,	/* extent number to update/insert */	xfs_btree_cur_t		**curp,	/* if *curp is null, not a btree */	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */	xfs_fsblock_t		*first,	/* pointer to firstblock variable */	xfs_bmap_free_t		*flist,	/* list of extents to be freed */	int			*logflagsp, /* inode logging flags */	xfs_extdelta_t		*delta, /* Change made to incore extents */	int			whichfork, /* data or attr fork */	int			rsvd)	/* OK to use reserved data blocks */{	xfs_btree_cur_t		*cur;	/* btree cursor or null */	xfs_filblks_t		da_new; /* new count del alloc blocks used */	xfs_filblks_t		da_old; /* old count del alloc blocks used */	int			error;	/* error return value */	xfs_ifork_t		*ifp;	/* inode fork ptr */	int			logflags; /* returned value */	xfs_extnum_t		nextents; /* number of extents in file now */	XFS_STATS_INC(xs_add_exlist);	cur = *curp;	ifp = XFS_IFORK_PTR(ip, whichfork);	nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);	ASSERT(idx <= nextents);	da_old = da_new = 0;	error = 0;	/*	 * This is the first extent added to a new/empty file.	 * Special case this one, so other routines get to assume there are	 * already extents in the list.	 */	if (nextents == 0) {		XFS_BMAP_TRACE_INSERT("insert empty", ip, 0, 1, new, NULL,			whichfork);		xfs_iext_insert(ifp, 0, 1, new);		ASSERT(cur == NULL);		ifp->if_lastex = 0;		if (!ISNULLSTARTBLOCK(new->br_startblock)) {			XFS_IFORK_NEXT_SET(ip, whichfork, 1);			logflags = XFS_ILOG_CORE | XFS_ILOG_FEXT(whichfork);		} else			logflags = 0;		/* DELTA: single new extent */		if (delta) {			if (delta->xed_startoff > new->br_startoff)				delta->xed_startoff = new->br_startoff;			if (delta->xed_blockcount <					new->br_startoff + new->br_blockcount)				delta->xed_blockcount = new->br_startoff +						new->br_blockcount;		}	}	/*	 * Any kind of new delayed allocation goes here.	 */	else if (ISNULLSTARTBLOCK(new->br_startblock)) {		if (cur)			ASSERT((cur->bc_private.b.flags &				XFS_BTCUR_BPRV_WASDEL) == 0);		if ((error = xfs_bmap_add_extent_hole_delay(ip, idx, new,				&logflags, delta, rsvd)))			goto done;	}	/*	 * Real allocation off the end of the file.	 */	else if (idx == nextents) {		if (cur)			ASSERT((cur->bc_private.b.flags &				XFS_BTCUR_BPRV_WASDEL) == 0);		if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur, new,				&logflags, delta, whichfork)))			goto done;	} else {		xfs_bmbt_irec_t	prev;	/* old extent at offset idx */		/*		 * Get the record referred to by idx.		 */		xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), &prev);		/*		 * If it's a real allocation record, and the new allocation ends		 * after the start of the referred to record, then we're filling		 * in a delayed or unwritten allocation with a real one, or		 * converting real back to unwritten.		 */		if (!ISNULLSTARTBLOCK(new->br_startblock) &&		    new->br_startoff + new->br_blockcount > prev.br_startoff) {			if (prev.br_state != XFS_EXT_UNWRITTEN &&			    ISNULLSTARTBLOCK(prev.br_startblock)) {				da_old = STARTBLOCKVAL(prev.br_startblock);				if (cur)					ASSERT(cur->bc_private.b.flags &						XFS_BTCUR_BPRV_WASDEL);				if ((error = xfs_bmap_add_extent_delay_real(ip,					idx, &cur, new, &da_new, first, flist,					&logflags, delta, rsvd)))					goto done;			} else if (new->br_state == XFS_EXT_NORM) {				ASSERT(new->br_state == XFS_EXT_NORM);				if ((error = xfs_bmap_add_extent_unwritten_real(					ip, idx, &cur, new, &logflags, delta)))					goto done;			} else {				ASSERT(new->br_state == XFS_EXT_UNWRITTEN);				if ((error = xfs_bmap_add_extent_unwritten_real(					ip, idx, &cur, new, &logflags, delta)))					goto done;			}			ASSERT(*curp == cur || *curp == NULL);		}		/*		 * Otherwise we're filling in a hole with an allocation.		 */		else {			if (cur)				ASSERT((cur->bc_private.b.flags &					XFS_BTCUR_BPRV_WASDEL) == 0);			if ((error = xfs_bmap_add_extent_hole_real(ip, idx, cur,					new, &logflags, delta, whichfork)))				goto done;		}	}	ASSERT(*curp == cur || *curp == NULL);	/*	 * Convert to a btree if necessary.	 */	if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS &&	    XFS_IFORK_NEXTENTS(ip, whichfork) > ifp->if_ext_max) {		int	tmp_logflags;	/* partial log flag return val */		ASSERT(cur == NULL);		error = xfs_bmap_extents_to_btree(ip->i_transp, ip, first,			flist, &cur, da_old > 0, &tmp_logflags, whichfork);		logflags |= tmp_logflags;		if (error)			goto done;	}	/*	 * Adjust for changes in reserved delayed indirect blocks.	 * Nothing to do for disk quotas here.	 */	if (da_old || da_new) {		xfs_filblks_t	nblks;		nblks = da_new;		if (cur)			nblks += cur->bc_private.b.allocated;		ASSERT(nblks <= da_old);		if (nblks < da_old)			xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS,				(int64_t)(da_old - nblks), rsvd);	}	/*	 * Clear out the allocated field, done with it now in any case.	 */	if (cur) {		cur->bc_private.b.allocated = 0;		*curp = cur;	}done:#ifdef DEBUG	if (!error)		xfs_bmap_check_leaf_extents(*curp, ip, whichfork);#endif	*logflagsp = logflags;	return error;}/* * Called by xfs_bmap_add_extent to handle cases converting a delayed * allocation to a real allocation. */STATIC int				/* error */xfs_bmap_add_extent_delay_real(	xfs_inode_t		*ip,	/* incore inode pointer */	xfs_extnum_t		idx,	/* extent number to update/insert */	xfs_btree_cur_t		**curp,	/* if *curp is null, not a btree */	xfs_bmbt_irec_t		*new,	/* new data to add to file extents */	xfs_filblks_t		*dnew,	/* new delayed-alloc indirect blocks */	xfs_fsblock_t		*first,	/* pointer to firstblock variable */	xfs_bmap_free_t		*flist,	/* list of extents to be freed */	int			*logflagsp, /* inode logging flags */	xfs_extdelta_t		*delta, /* Change made to incore extents */	int			rsvd)	/* OK to use reserved data block allocation */{	xfs_btree_cur_t		*cur;	/* btree cursor */	int			diff;	/* temp value */	xfs_bmbt_rec_host_t	*ep;	/* extent entry for idx */	int			error;	/* error return value */	int			i;	/* temp state */	xfs_ifork_t		*ifp;	/* inode fork pointer */	xfs_fileoff_t		new_endoff;	/* end offset of new entry */	xfs_bmbt_irec_t		r[3];	/* neighbor extent entries */					/* left is 0, right is 1, prev is 2 */	int			rval=0;	/* return value (logging flags) */	int			state = 0;/* state bits, accessed thru macros */	xfs_filblks_t		temp=0;	/* value for dnew calculations */	xfs_filblks_t		temp2=0;/* value for dnew calculations */	int			tmp_rval;	/* partial logging flags */	enum {				/* bit number definitions for state */		LEFT_CONTIG,	RIGHT_CONTIG,		LEFT_FILLING,	RIGHT_FILLING,		LEFT_DELAY,	RIGHT_DELAY,		LEFT_VALID,	RIGHT_VALID	};#define	LEFT		r[0]#define	RIGHT		r[1]#define	PREV		r[2]#define	MASK(b)		(1 << (b))#define	MASK2(a,b)	(MASK(a) | MASK(b))#define	MASK3(a,b,c)	(MASK2(a,b) | MASK(c))#define	MASK4(a,b,c,d)	(MASK3(a,b,c) | MASK(d))#define	STATE_SET(b,v)	((v) ? (state |= MASK(b)) : (state &= ~MASK(b)))#define	STATE_TEST(b)	(state & MASK(b))#define	STATE_SET_TEST(b,v)	((v) ? ((state |= MASK(b)), 1) : \				       ((state &= ~MASK(b)), 0))#define	SWITCH_STATE		\	(state & MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG))	/*	 * Set up a bunch of variables to make the tests simpler.	 */	cur = *curp;	ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);	ep = xfs_iext_get_ext(ifp, idx);	xfs_bmbt_get_all(ep, &PREV);	new_endoff = new->br_startoff + new->br_blockcount;	ASSERT(PREV.br_startoff <= new->br_startoff);	ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff);	/*	 * Set flags determining what part of the previous delayed allocation	 * extent is being replaced by a real allocation.	 */	STATE_SET(LEFT_FILLING, PREV.br_startoff == new->br_startoff);	STATE_SET(RIGHT_FILLING,		PREV.br_startoff + PREV.br_blockcount == new_endoff);	/*	 * Check and set flags if this segment has a left neighbor.	 * Don't set contiguous if the combined extent would be too large.	 */	if (STATE_SET_TEST(LEFT_VALID, idx > 0)) {		xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx - 1), &LEFT);		STATE_SET(LEFT_DELAY, ISNULLSTARTBLOCK(LEFT.br_startblock));	}	STATE_SET(LEFT_CONTIG,		STATE_TEST(LEFT_VALID) && !STATE_TEST(LEFT_DELAY) &&		LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff &&		LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock &&		LEFT.br_state == new->br_state &&		LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN);	/*	 * Check and set flags if this segment has a right neighbor.	 * Don't set contiguous if the combined extent would be too large.	 * Also check for all-three-contiguous being too large.	 */	if (STATE_SET_TEST(RIGHT_VALID,			idx <			ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1)) {		xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx + 1), &RIGHT);		STATE_SET(RIGHT_DELAY, ISNULLSTARTBLOCK(RIGHT.br_startblock));	}	STATE_SET(RIGHT_CONTIG,		STATE_TEST(RIGHT_VALID) && !STATE_TEST(RIGHT_DELAY) &&		new_endoff == RIGHT.br_startoff &&		new->br_startblock + new->br_blockcount ==		    RIGHT.br_startblock &&		new->br_state == RIGHT.br_state &&		new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN &&		((state & MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING)) !=		  MASK3(LEFT_CONTIG, LEFT_FILLING, RIGHT_FILLING) ||		 LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount		     <= MAXEXTLEN));	error = 0;	/*	 * Switch out based on the FILLING and CONTIG state bits.	 */	switch (SWITCH_STATE) {	case MASK4(LEFT_FILLING, RIGHT_FILLING, LEFT_CONTIG, RIGHT_CONTIG):		/*		 * Filling in all of a previously delayed allocation extent.		 * The left and right neighbors are both contiguous with new.		 */		XFS_BMAP_TRACE_PRE_UPDATE("LF|RF|LC|RC", ip, idx - 1,			XFS_DATA_FORK);		xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),			LEFT.br_blockcount + PREV.br_blockcount +			RIGHT.br_blockcount);		XFS_BMAP_TRACE_POST_UPDATE("LF|RF|LC|RC", ip, idx - 1,			XFS_DATA_FORK);		XFS_BMAP_TRACE_DELETE("LF|RF|LC|RC", ip, idx, 2, XFS_DATA_FORK);		xfs_iext_remove(ifp, idx, 2);		ip->i_df.if_lastex = idx - 1;		ip->i_d.di_nextents--;		if (cur == NULL)			rval = XFS_ILOG_CORE | XFS_ILOG_DEXT;

⌨️ 快捷键说明

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