diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/xfs/libxfs/xfs_bmap.c | 15 | ||||
| -rw-r--r-- | fs/xfs/scrub/btree.c | 11 | ||||
| -rw-r--r-- | fs/xfs/scrub/dabtree.c | 5 | ||||
| -rw-r--r-- | fs/xfs/xfs_discard.c | 8 | ||||
| -rw-r--r-- | fs/xfs/xfs_file.c | 27 | 
5 files changed, 49 insertions, 17 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 48502cb9990f..4637ae1ae91c 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -1191,7 +1191,10 @@ xfs_iread_extents(  	 * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out.  	 */  	level = be16_to_cpu(block->bb_level); -	ASSERT(level > 0); +	if (unlikely(level == 0)) { +		XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); +		return -EFSCORRUPTED; +	}  	pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes);  	bno = be64_to_cpu(*pp); @@ -4249,9 +4252,13 @@ xfs_bmapi_write(  	struct xfs_bmbt_irec	*mval,		/* output: map values */  	int			*nmap)		/* i/o: mval size/count */  { +	struct xfs_bmalloca	bma = { +		.tp		= tp, +		.ip		= ip, +		.total		= total, +	};  	struct xfs_mount	*mp = ip->i_mount;  	struct xfs_ifork	*ifp; -	struct xfs_bmalloca	bma = { NULL };	/* args for xfs_bmap_alloc */  	xfs_fileoff_t		end;		/* end of mapped file region */  	bool			eof = false;	/* after the end of extents */  	int			error;		/* error return */ @@ -4319,10 +4326,6 @@ xfs_bmapi_write(  		eof = true;  	if (!xfs_iext_peek_prev_extent(ifp, &bma.icur, &bma.prev))  		bma.prev.br_startoff = NULLFILEOFF; -	bma.tp = tp; -	bma.ip = ip; -	bma.total = total; -	bma.datatype = 0;  	bma.minleft = xfs_bmapi_minleft(tp, ip, whichfork);  	n = 0; diff --git a/fs/xfs/scrub/btree.c b/fs/xfs/scrub/btree.c index 6f94d1f7322d..117910db51b8 100644 --- a/fs/xfs/scrub/btree.c +++ b/fs/xfs/scrub/btree.c @@ -415,8 +415,17 @@ xchk_btree_check_owner(  	struct xfs_btree_cur	*cur = bs->cur;  	struct check_owner	*co; -	if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && bp == NULL) +	/* +	 * In theory, xfs_btree_get_block should only give us a null buffer +	 * pointer for the root of a root-in-inode btree type, but we need +	 * to check defensively here in case the cursor state is also screwed +	 * up. +	 */ +	if (bp == NULL) { +		if (!(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE)) +			xchk_btree_set_corrupt(bs->sc, bs->cur, level);  		return 0; +	}  	/*  	 * We want to cross-reference each btree block with the bnobt diff --git a/fs/xfs/scrub/dabtree.c b/fs/xfs/scrub/dabtree.c index f1260b4bfdee..90527b094878 100644 --- a/fs/xfs/scrub/dabtree.c +++ b/fs/xfs/scrub/dabtree.c @@ -574,6 +574,11 @@ xchk_da_btree(  		/* Drill another level deeper. */  		blkno = be32_to_cpu(key->before);  		level++; +		if (level >= XFS_DA_NODE_MAXDEPTH) { +			/* Too deep! */ +			xchk_da_set_corrupt(&ds, level - 1); +			break; +		}  		ds.tree_level--;  		error = xchk_da_btree_block(&ds, level, blkno);  		if (error) diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c index 93f07edafd81..9ee2a7d02e70 100644 --- a/fs/xfs/xfs_discard.c +++ b/fs/xfs/xfs_discard.c @@ -161,6 +161,14 @@ xfs_ioc_trim(  		return -EPERM;  	if (!blk_queue_discard(q))  		return -EOPNOTSUPP; + +	/* +	 * We haven't recovered the log, so we cannot use our bnobt-guided +	 * storage zapping commands. +	 */ +	if (mp->m_flags & XFS_MOUNT_NORECOVERY) +		return -EROFS; +  	if (copy_from_user(&range, urange, sizeof(range)))  		return -EFAULT; diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 1f2e2845eb76..a7ceae90110e 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -529,18 +529,17 @@ xfs_file_dio_aio_write(  	count = iov_iter_count(from);  	/* -	 * If we are doing unaligned IO, wait for all other IO to drain, -	 * otherwise demote the lock if we had to take the exclusive lock -	 * for other reasons in xfs_file_aio_write_checks. +	 * If we are doing unaligned IO, we can't allow any other overlapping IO +	 * in-flight at the same time or we risk data corruption. Wait for all +	 * other IO to drain before we submit. If the IO is aligned, demote the +	 * iolock if we had to take the exclusive lock in +	 * xfs_file_aio_write_checks() for other reasons.  	 */  	if (unaligned_io) { -		/* If we are going to wait for other DIO to finish, bail */ -		if (iocb->ki_flags & IOCB_NOWAIT) { -			if (atomic_read(&inode->i_dio_count)) -				return -EAGAIN; -		} else { -			inode_dio_wait(inode); -		} +		/* unaligned dio always waits, bail */ +		if (iocb->ki_flags & IOCB_NOWAIT) +			return -EAGAIN; +		inode_dio_wait(inode);  	} else if (iolock == XFS_IOLOCK_EXCL) {  		xfs_ilock_demote(ip, XFS_IOLOCK_EXCL);  		iolock = XFS_IOLOCK_SHARED; @@ -548,6 +547,14 @@ xfs_file_dio_aio_write(  	trace_xfs_file_direct_write(ip, count, iocb->ki_pos);  	ret = iomap_dio_rw(iocb, from, &xfs_iomap_ops, xfs_dio_write_end_io); + +	/* +	 * If unaligned, this is the only IO in-flight. If it has not yet +	 * completed, wait on it before we release the iolock to prevent +	 * subsequent overlapping IO. +	 */ +	if (ret == -EIOCBQUEUED && unaligned_io) +		inode_dio_wait(inode);  out:  	xfs_iunlock(ip, iolock);  | 
