diff options
Diffstat (limited to 'fs/xfs/xfs_bmap.c')
| -rw-r--r-- | fs/xfs/xfs_bmap.c | 61 | 
1 files changed, 45 insertions, 16 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 4111cd3966c..dc3afd7739f 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -1038,17 +1038,34 @@ xfs_bmap_add_extent_delay_real(  		 * Filling in the middle part of a previous delayed allocation.  		 * Contiguity is impossible here.  		 * This case is avoided almost all the time. +		 * +		 * We start with a delayed allocation: +		 * +		 * +ddddddddddddddddddddddddddddddddddddddddddddddddddddddd+ +		 *  PREV @ idx +		 * +	         * and we are allocating: +		 *                     +rrrrrrrrrrrrrrrrr+ +		 *			      new +		 * +		 * and we set it up for insertion as: +		 * +ddddddddddddddddddd+rrrrrrrrrrrrrrrrr+ddddddddddddddddd+ +		 *                            new +		 *  PREV @ idx          LEFT              RIGHT +		 *                      inserted at idx + 1  		 */  		temp = new->br_startoff - PREV.br_startoff; -		trace_xfs_bmap_pre_update(ip, idx, 0, _THIS_IP_); -		xfs_bmbt_set_blockcount(ep, temp); -		r[0] = *new; -		r[1].br_state = PREV.br_state; -		r[1].br_startblock = 0; -		r[1].br_startoff = new_endoff;  		temp2 = PREV.br_startoff + PREV.br_blockcount - new_endoff; -		r[1].br_blockcount = temp2; -		xfs_iext_insert(ip, idx + 1, 2, &r[0], state); +		trace_xfs_bmap_pre_update(ip, idx, 0, _THIS_IP_); +		xfs_bmbt_set_blockcount(ep, temp);	/* truncate PREV */ +		LEFT = *new; +		RIGHT.br_state = PREV.br_state; +		RIGHT.br_startblock = nullstartblock( +				(int)xfs_bmap_worst_indlen(ip, temp2)); +		RIGHT.br_startoff = new_endoff; +		RIGHT.br_blockcount = temp2; +		/* insert LEFT (r[0]) and RIGHT (r[1]) at the same time */ +		xfs_iext_insert(ip, idx + 1, 2, &LEFT, state);  		ip->i_df.if_lastex = idx + 1;  		ip->i_d.di_nextents++;  		if (cur == NULL) @@ -2430,7 +2447,7 @@ xfs_bmap_btalloc_nullfb(  		startag = ag = 0;  	pag = xfs_perag_get(mp, ag); -	while (*blen < ap->alen) { +	while (*blen < args->maxlen) {  		if (!pag->pagf_init) {  			error = xfs_alloc_pagf_init(mp, args->tp, ag,  						    XFS_ALLOC_FLAG_TRYLOCK); @@ -2452,7 +2469,7 @@ xfs_bmap_btalloc_nullfb(  			notinit = 1;  		if (xfs_inode_is_filestream(ap->ip)) { -			if (*blen >= ap->alen) +			if (*blen >= args->maxlen)  				break;  			if (ap->userdata) { @@ -2498,14 +2515,14 @@ xfs_bmap_btalloc_nullfb(  	 * If the best seen length is less than the request  	 * length, use the best as the minimum.  	 */ -	else if (*blen < ap->alen) +	else if (*blen < args->maxlen)  		args->minlen = *blen;  	/* -	 * Otherwise we've seen an extent as big as alen, +	 * Otherwise we've seen an extent as big as maxlen,  	 * use that as the minimum.  	 */  	else -		args->minlen = ap->alen; +		args->minlen = args->maxlen;  	/*  	 * set the failure fallback case to look in the selected @@ -2573,7 +2590,9 @@ xfs_bmap_btalloc(  	args.tp = ap->tp;  	args.mp = mp;  	args.fsbno = ap->rval; -	args.maxlen = MIN(ap->alen, mp->m_sb.sb_agblocks); + +	/* Trim the allocation back to the maximum an AG can fit. */ +	args.maxlen = MIN(ap->alen, XFS_ALLOC_AG_MAX_USABLE(mp));  	args.firstblock = ap->firstblock;  	blen = 0;  	if (nullfb) { @@ -2621,7 +2640,7 @@ xfs_bmap_btalloc(  			/*  			 * Adjust for alignment  			 */ -			if (blen > args.alignment && blen <= ap->alen) +			if (blen > args.alignment && blen <= args.maxlen)  				args.minlen = blen - args.alignment;  			args.minalignslop = 0;  		} else { @@ -2640,7 +2659,7 @@ xfs_bmap_btalloc(  			 * of minlen+alignment+slop doesn't go up  			 * between the calls.  			 */ -			if (blen > mp->m_dalign && blen <= ap->alen) +			if (blen > mp->m_dalign && blen <= args.maxlen)  				nextminlen = blen - mp->m_dalign;  			else  				nextminlen = args.minlen; @@ -4485,6 +4504,16 @@ xfs_bmapi(  				/* Figure out the extent size, adjust alen */  				extsz = xfs_get_extsz_hint(ip);  				if (extsz) { +					/* +					 * make sure we don't exceed a single +					 * extent length when we align the +					 * extent by reducing length we are +					 * going to allocate by the maximum +					 * amount extent size aligment may +					 * require. +					 */ +					alen = XFS_FILBLKS_MIN(len, +						   MAXEXTLEN - (2 * extsz - 1));  					error = xfs_bmap_extsize_align(mp,  							&got, &prev, extsz,  							rt, eof,  |