diff options
Diffstat (limited to 'fs/xfs')
| -rw-r--r-- | fs/xfs/xfs_alloc.c | 43 | ||||
| -rw-r--r-- | fs/xfs/xfs_alloc.h | 3 | ||||
| -rw-r--r-- | fs/xfs/xfs_alloc_btree.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_aops.c | 54 | ||||
| -rw-r--r-- | fs/xfs/xfs_attr_leaf.c | 20 | ||||
| -rw-r--r-- | fs/xfs/xfs_bmap.c | 63 | ||||
| -rw-r--r-- | fs/xfs/xfs_bmap.h | 9 | ||||
| -rw-r--r-- | fs/xfs/xfs_buf.c | 14 | ||||
| -rw-r--r-- | fs/xfs/xfs_buf_item.c | 18 | ||||
| -rw-r--r-- | fs/xfs/xfs_fsops.c | 21 | ||||
| -rw-r--r-- | fs/xfs/xfs_ialloc.c | 1 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode.c | 3 | ||||
| -rw-r--r-- | fs/xfs/xfs_ioctl.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_iomap.c | 4 | ||||
| -rw-r--r-- | fs/xfs/xfs_log.c | 19 | ||||
| -rw-r--r-- | fs/xfs/xfs_log_recover.c | 2 | 
16 files changed, 196 insertions, 82 deletions
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index 4f33c32affe..335206a9c69 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -1866,6 +1866,7 @@ xfs_alloc_fix_freelist(  	/*  	 * Initialize the args structure.  	 */ +	memset(&targs, 0, sizeof(targs));  	targs.tp = tp;  	targs.mp = mp;  	targs.agbp = agbp; @@ -2207,7 +2208,7 @@ xfs_alloc_read_agf(   * group or loop over the allocation groups to find the result.   */  int				/* error */ -__xfs_alloc_vextent( +xfs_alloc_vextent(  	xfs_alloc_arg_t	*args)	/* allocation argument structure */  {  	xfs_agblock_t	agsize;	/* allocation group size */ @@ -2417,46 +2418,6 @@ error0:  	return error;  } -static void -xfs_alloc_vextent_worker( -	struct work_struct	*work) -{ -	struct xfs_alloc_arg	*args = container_of(work, -						struct xfs_alloc_arg, work); -	unsigned long		pflags; - -	/* we are in a transaction context here */ -	current_set_flags_nested(&pflags, PF_FSTRANS); - -	args->result = __xfs_alloc_vextent(args); -	complete(args->done); - -	current_restore_flags_nested(&pflags, PF_FSTRANS); -} - -/* - * Data allocation requests often come in with little stack to work on. Push - * them off to a worker thread so there is lots of stack to use. Metadata - * requests, OTOH, are generally from low stack usage paths, so avoid the - * context switch overhead here. - */ -int -xfs_alloc_vextent( -	struct xfs_alloc_arg	*args) -{ -	DECLARE_COMPLETION_ONSTACK(done); - -	if (!args->userdata) -		return __xfs_alloc_vextent(args); - - -	args->done = &done; -	INIT_WORK_ONSTACK(&args->work, xfs_alloc_vextent_worker); -	queue_work(xfs_alloc_wq, &args->work); -	wait_for_completion(&done); -	return args->result; -} -  /*   * Free an extent.   * Just break up the extent address and hand off to xfs_free_ag_extent diff --git a/fs/xfs/xfs_alloc.h b/fs/xfs/xfs_alloc.h index 93be4a667ca..feacb061bab 100644 --- a/fs/xfs/xfs_alloc.h +++ b/fs/xfs/xfs_alloc.h @@ -120,9 +120,6 @@ typedef struct xfs_alloc_arg {  	char		isfl;		/* set if is freelist blocks - !acctg */  	char		userdata;	/* set if this is user data */  	xfs_fsblock_t	firstblock;	/* io first block allocated */ -	struct completion *done; -	struct work_struct work; -	int		result;  } xfs_alloc_arg_t;  /* diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c index f1647caace8..f7876c6d616 100644 --- a/fs/xfs/xfs_alloc_btree.c +++ b/fs/xfs/xfs_alloc_btree.c @@ -121,6 +121,8 @@ xfs_allocbt_free_block(  	xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1,  			      XFS_EXTENT_BUSY_SKIP_DISCARD);  	xfs_trans_agbtree_delta(cur->bc_tp, -1); + +	xfs_trans_binval(cur->bc_tp, bp);  	return 0;  } diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index e562dd43f41..e57e2daa357 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -481,11 +481,17 @@ static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh)   *   * The fix is two passes across the ioend list - one to start writeback on the   * buffer_heads, and then submit them for I/O on the second pass. + * + * If @fail is non-zero, it means that we have a situation where some part of + * the submission process has failed after we have marked paged for writeback + * and unlocked them. In this situation, we need to fail the ioend chain rather + * than submit it to IO. This typically only happens on a filesystem shutdown.   */  STATIC void  xfs_submit_ioend(  	struct writeback_control *wbc, -	xfs_ioend_t		*ioend) +	xfs_ioend_t		*ioend, +	int			fail)  {  	xfs_ioend_t		*head = ioend;  	xfs_ioend_t		*next; @@ -506,6 +512,18 @@ xfs_submit_ioend(  		next = ioend->io_list;  		bio = NULL; +		/* +		 * If we are failing the IO now, just mark the ioend with an +		 * error and finish it. This will run IO completion immediately +		 * as there is only one reference to the ioend at this point in +		 * time. +		 */ +		if (fail) { +			ioend->io_error = -fail; +			xfs_finish_ioend(ioend); +			continue; +		} +  		for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) {  			if (!bio) { @@ -1060,7 +1078,18 @@ xfs_vm_writepage(  	xfs_start_page_writeback(page, 1, count); -	if (ioend && imap_valid) { +	/* if there is no IO to be submitted for this page, we are done */ +	if (!ioend) +		return 0; + +	ASSERT(iohead); + +	/* +	 * Any errors from this point onwards need tobe reported through the IO +	 * completion path as we have marked the initial page as under writeback +	 * and unlocked it. +	 */ +	if (imap_valid) {  		xfs_off_t		end_index;  		end_index = imap.br_startoff + imap.br_blockcount; @@ -1079,20 +1108,15 @@ xfs_vm_writepage(  				  wbc, end_index);  	} -	if (iohead) { -		/* -		 * Reserve log space if we might write beyond the on-disk -		 * inode size. -		 */ -		if (ioend->io_type != XFS_IO_UNWRITTEN && -		    xfs_ioend_is_append(ioend)) { -			err = xfs_setfilesize_trans_alloc(ioend); -			if (err) -				goto error; -		} -		xfs_submit_ioend(wbc, iohead); -	} +	/* +	 * Reserve log space if we might write beyond the on-disk inode size. +	 */ +	err = 0; +	if (ioend->io_type != XFS_IO_UNWRITTEN && xfs_ioend_is_append(ioend)) +		err = xfs_setfilesize_trans_alloc(ioend); + +	xfs_submit_ioend(wbc, iohead, err);  	return 0; diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index d330111ca73..70eec182977 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c @@ -1291,6 +1291,7 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,  	leaf2 = blk2->bp->b_addr;  	ASSERT(leaf1->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));  	ASSERT(leaf2->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC)); +	ASSERT(leaf2->hdr.count == 0);  	args = state->args;  	trace_xfs_attr_leaf_rebalance(args); @@ -1361,6 +1362,7 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,  		 * I assert that since all callers pass in an empty  		 * second buffer, this code should never execute.  		 */ +		ASSERT(0);  		/*  		 * Figure the total bytes to be added to the destination leaf. @@ -1422,10 +1424,24 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,  			args->index2 = 0;  			args->blkno2 = blk2->blkno;  		} else { +			/* +			 * On a double leaf split, the original attr location +			 * is already stored in blkno2/index2, so don't +			 * overwrite it overwise we corrupt the tree. +			 */  			blk2->index = blk1->index  				    - be16_to_cpu(leaf1->hdr.count); -			args->index = args->index2 = blk2->index; -			args->blkno = args->blkno2 = blk2->blkno; +			args->index = blk2->index; +			args->blkno = blk2->blkno; +			if (!state->extravalid) { +				/* +				 * set the new attr location to match the old +				 * one and let the higher level split code +				 * decide where in the leaf to place it. +				 */ +				args->index2 = blk2->index; +				args->blkno2 = blk2->blkno; +			}  		}  	} else {  		ASSERT(state->inleaf == 1); diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 848ffa77707..83d0cf3df93 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -2437,6 +2437,7 @@ xfs_bmap_btalloc(  	 * Normal allocation, done through xfs_alloc_vextent.  	 */  	tryagain = isaligned = 0; +	memset(&args, 0, sizeof(args));  	args.tp = ap->tp;  	args.mp = mp;  	args.fsbno = ap->blkno; @@ -3082,6 +3083,7 @@ xfs_bmap_extents_to_btree(  	 * Convert to a btree with two levels, one record in root.  	 */  	XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_BTREE); +	memset(&args, 0, sizeof(args));  	args.tp = tp;  	args.mp = mp;  	args.firstblock = *firstblock; @@ -3237,6 +3239,7 @@ xfs_bmap_local_to_extents(  		xfs_buf_t	*bp;	/* buffer for extent block */  		xfs_bmbt_rec_host_t *ep;/* extent record pointer */ +		memset(&args, 0, sizeof(args));  		args.tp = tp;  		args.mp = ip->i_mount;  		args.firstblock = *firstblock; @@ -4616,12 +4619,11 @@ xfs_bmapi_delay(  STATIC int -xfs_bmapi_allocate( -	struct xfs_bmalloca	*bma, -	int			flags) +__xfs_bmapi_allocate( +	struct xfs_bmalloca	*bma)  {  	struct xfs_mount	*mp = bma->ip->i_mount; -	int			whichfork = (flags & XFS_BMAPI_ATTRFORK) ? +	int			whichfork = (bma->flags & XFS_BMAPI_ATTRFORK) ?  						XFS_ATTR_FORK : XFS_DATA_FORK;  	struct xfs_ifork	*ifp = XFS_IFORK_PTR(bma->ip, whichfork);  	int			tmp_logflags = 0; @@ -4654,24 +4656,27 @@ xfs_bmapi_allocate(  	 * Indicate if this is the first user data in the file, or just any  	 * user data.  	 */ -	if (!(flags & XFS_BMAPI_METADATA)) { +	if (!(bma->flags & XFS_BMAPI_METADATA)) {  		bma->userdata = (bma->offset == 0) ?  			XFS_ALLOC_INITIAL_USER_DATA : XFS_ALLOC_USERDATA;  	} -	bma->minlen = (flags & XFS_BMAPI_CONTIG) ? bma->length : 1; +	bma->minlen = (bma->flags & XFS_BMAPI_CONTIG) ? bma->length : 1;  	/*  	 * Only want to do the alignment at the eof if it is userdata and  	 * allocation length is larger than a stripe unit.  	 */  	if (mp->m_dalign && bma->length >= mp->m_dalign && -	    !(flags & XFS_BMAPI_METADATA) && whichfork == XFS_DATA_FORK) { +	    !(bma->flags & XFS_BMAPI_METADATA) && whichfork == XFS_DATA_FORK) {  		error = xfs_bmap_isaeof(bma, whichfork);  		if (error)  			return error;  	} +	if (bma->flags & XFS_BMAPI_STACK_SWITCH) +		bma->stack_switch = 1; +  	error = xfs_bmap_alloc(bma);  	if (error)  		return error; @@ -4706,7 +4711,7 @@ xfs_bmapi_allocate(  	 * A wasdelay extent has been initialized, so shouldn't be flagged  	 * as unwritten.  	 */ -	if (!bma->wasdel && (flags & XFS_BMAPI_PREALLOC) && +	if (!bma->wasdel && (bma->flags & XFS_BMAPI_PREALLOC) &&  	    xfs_sb_version_hasextflgbit(&mp->m_sb))  		bma->got.br_state = XFS_EXT_UNWRITTEN; @@ -4734,6 +4739,45 @@ xfs_bmapi_allocate(  	return 0;  } +static void +xfs_bmapi_allocate_worker( +	struct work_struct	*work) +{ +	struct xfs_bmalloca	*args = container_of(work, +						struct xfs_bmalloca, work); +	unsigned long		pflags; + +	/* we are in a transaction context here */ +	current_set_flags_nested(&pflags, PF_FSTRANS); + +	args->result = __xfs_bmapi_allocate(args); +	complete(args->done); + +	current_restore_flags_nested(&pflags, PF_FSTRANS); +} + +/* + * Some allocation requests often come in with little stack to work on. Push + * them off to a worker thread so there is lots of stack to use. Otherwise just + * call directly to avoid the context switch overhead here. + */ +int +xfs_bmapi_allocate( +	struct xfs_bmalloca	*args) +{ +	DECLARE_COMPLETION_ONSTACK(done); + +	if (!args->stack_switch) +		return __xfs_bmapi_allocate(args); + + +	args->done = &done; +	INIT_WORK_ONSTACK(&args->work, xfs_bmapi_allocate_worker); +	queue_work(xfs_alloc_wq, &args->work); +	wait_for_completion(&done); +	return args->result; +} +  STATIC int  xfs_bmapi_convert_unwritten(  	struct xfs_bmalloca	*bma, @@ -4919,6 +4963,7 @@ xfs_bmapi_write(  			bma.conv = !!(flags & XFS_BMAPI_CONVERT);  			bma.wasdel = wasdelay;  			bma.offset = bno; +			bma.flags = flags;  			/*  			 * There's a 32/64 bit type mismatch between the @@ -4934,7 +4979,7 @@ xfs_bmapi_write(  			ASSERT(len > 0);  			ASSERT(bma.length > 0); -			error = xfs_bmapi_allocate(&bma, flags); +			error = xfs_bmapi_allocate(&bma);  			if (error)  				goto error0;  			if (bma.blkno == NULLFSBLOCK) diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h index 803b56d7ce1..5f469c3516e 100644 --- a/fs/xfs/xfs_bmap.h +++ b/fs/xfs/xfs_bmap.h @@ -77,6 +77,7 @@ typedef	struct xfs_bmap_free   * from written to unwritten, otherwise convert from unwritten to written.   */  #define XFS_BMAPI_CONVERT	0x040 +#define XFS_BMAPI_STACK_SWITCH	0x080  #define XFS_BMAPI_FLAGS \  	{ XFS_BMAPI_ENTIRE,	"ENTIRE" }, \ @@ -85,7 +86,8 @@ typedef	struct xfs_bmap_free  	{ XFS_BMAPI_PREALLOC,	"PREALLOC" }, \  	{ XFS_BMAPI_IGSTATE,	"IGSTATE" }, \  	{ XFS_BMAPI_CONTIG,	"CONTIG" }, \ -	{ XFS_BMAPI_CONVERT,	"CONVERT" } +	{ XFS_BMAPI_CONVERT,	"CONVERT" }, \ +	{ XFS_BMAPI_STACK_SWITCH, "STACK_SWITCH" }  static inline int xfs_bmapi_aflag(int w) @@ -133,6 +135,11 @@ typedef struct xfs_bmalloca {  	char			userdata;/* set if is user data */  	char			aeof;	/* allocated space at eof */  	char			conv;	/* overwriting unwritten extents */ +	char			stack_switch; +	int			flags; +	struct completion	*done; +	struct work_struct	work; +	int			result;  } xfs_bmalloca_t;  /* diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 933b7930b86..4b0b8dd1b7b 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -1197,9 +1197,14 @@ xfs_buf_bio_end_io(  {  	xfs_buf_t		*bp = (xfs_buf_t *)bio->bi_private; -	xfs_buf_ioerror(bp, -error); +	/* +	 * don't overwrite existing errors - otherwise we can lose errors on +	 * buffers that require multiple bios to complete. +	 */ +	if (!bp->b_error) +		xfs_buf_ioerror(bp, -error); -	if (!error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ)) +	if (!bp->b_error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ))  		invalidate_kernel_vmap_range(bp->b_addr, xfs_buf_vmap_len(bp));  	_xfs_buf_ioend(bp, 1); @@ -1279,6 +1284,11 @@ next_chunk:  		if (size)  			goto next_chunk;  	} else { +		/* +		 * This is guaranteed not to be the last io reference count +		 * because the caller (xfs_buf_iorequest) holds a count itself. +		 */ +		atomic_dec(&bp->b_io_remaining);  		xfs_buf_ioerror(bp, EIO);  		bio_put(bio);  	} diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index a8d0ed91119..becf4a97efc 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -526,7 +526,25 @@ xfs_buf_item_unpin(  		}  		xfs_buf_relse(bp);  	} else if (freed && remove) { +		/* +		 * There are currently two references to the buffer - the active +		 * LRU reference and the buf log item. What we are about to do +		 * here - simulate a failed IO completion - requires 3 +		 * references. +		 * +		 * The LRU reference is removed by the xfs_buf_stale() call. The +		 * buf item reference is removed by the xfs_buf_iodone() +		 * callback that is run by xfs_buf_do_callbacks() during ioend +		 * processing (via the bp->b_iodone callback), and then finally +		 * the ioend processing will drop the IO reference if the buffer +		 * is marked XBF_ASYNC. +		 * +		 * Hence we need to take an additional reference here so that IO +		 * completion processing doesn't free the buffer prematurely. +		 */  		xfs_buf_lock(bp); +		xfs_buf_hold(bp); +		bp->b_flags |= XBF_ASYNC;  		xfs_buf_ioerror(bp, EIO);  		XFS_BUF_UNDONE(bp);  		xfs_buf_stale(bp); diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index c25b094efbf..4beaede4327 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -399,9 +399,26 @@ xfs_growfs_data_private(  	/* update secondary superblocks. */  	for (agno = 1; agno < nagcount; agno++) { -		error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, +		error = 0; +		/* +		 * new secondary superblocks need to be zeroed, not read from +		 * disk as the contents of the new area we are growing into is +		 * completely unknown. +		 */ +		if (agno < oagcount) { +			error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,  				  XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),  				  XFS_FSS_TO_BB(mp, 1), 0, &bp); +		} else { +			bp = xfs_trans_get_buf(NULL, mp->m_ddev_targp, +				  XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), +				  XFS_FSS_TO_BB(mp, 1), 0); +			if (bp) +				xfs_buf_zero(bp, 0, BBTOB(bp->b_length)); +			else +				error = ENOMEM; +		} +  		if (error) {  			xfs_warn(mp,  		"error %d reading secondary superblock for ag %d", @@ -423,7 +440,7 @@ xfs_growfs_data_private(  			break; /* no point in continuing */  		}  	} -	return 0; +	return error;   error0:  	xfs_trans_cancel(tp, XFS_TRANS_ABORT); diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index 445bf1aef31..c5c4ef4f2bd 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c @@ -250,6 +250,7 @@ xfs_ialloc_ag_alloc(  					/* boundary */  	struct xfs_perag *pag; +	memset(&args, 0, sizeof(args));  	args.tp = tp;  	args.mp = tp->t_mountp; diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 2778258fcfa..1938b41ee9f 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1509,7 +1509,8 @@ xfs_ifree_cluster(  		 * to mark all the active inodes on the buffer stale.  		 */  		bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno, -					mp->m_bsize * blks_per_cluster, 0); +					mp->m_bsize * blks_per_cluster, +					XBF_UNMAPPED);  		if (!bp)  			return ENOMEM; diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 8305f2ac677..c1df3c623de 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -70,7 +70,7 @@ xfs_find_handle(  	int			hsize;  	xfs_handle_t		handle;  	struct inode		*inode; -	struct fd		f; +	struct fd		f = {0};  	struct path		path;  	int			error;  	struct xfs_inode	*ip; diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 973dff6ad93..7f537663365 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -584,7 +584,9 @@ xfs_iomap_write_allocate(  			 * pointer that the caller gave to us.  			 */  			error = xfs_bmapi_write(tp, ip, map_start_fsb, -						count_fsb, 0, &first_block, 1, +						count_fsb, +						XFS_BMAPI_STACK_SWITCH, +						&first_block, 1,  						imap, &nimaps, &free_list);  			if (error)  				goto trans_cancel; diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 7f4f9370d0e..4dad756962d 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -2387,14 +2387,27 @@ xlog_state_do_callback(  				/* -				 * update the last_sync_lsn before we drop the +				 * Completion of a iclog IO does not imply that +				 * a transaction has completed, as transactions +				 * can be large enough to span many iclogs. We +				 * cannot change the tail of the log half way +				 * through a transaction as this may be the only +				 * transaction in the log and moving th etail to +				 * point to the middle of it will prevent +				 * recovery from finding the start of the +				 * transaction. Hence we should only update the +				 * last_sync_lsn if this iclog contains +				 * transaction completion callbacks on it. +				 * +				 * We have to do this before we drop the  				 * icloglock to ensure we are the only one that  				 * can update it.  				 */  				ASSERT(XFS_LSN_CMP(atomic64_read(&log->l_last_sync_lsn),  					be64_to_cpu(iclog->ic_header.h_lsn)) <= 0); -				atomic64_set(&log->l_last_sync_lsn, -					be64_to_cpu(iclog->ic_header.h_lsn)); +				if (iclog->ic_callback) +					atomic64_set(&log->l_last_sync_lsn, +						be64_to_cpu(iclog->ic_header.h_lsn));  			} else  				ioerrors++; diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 5da3ace352b..d308749fabf 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -3541,7 +3541,7 @@ xlog_do_recovery_pass(  				 *   - order is important.  				 */  				error = xlog_bread_offset(log, 0, -						bblks - split_bblks, hbp, +						bblks - split_bblks, dbp,  						offset + BBTOB(split_bblks));  				if (error)  					goto bread_err2;  |