diff options
Diffstat (limited to 'fs/xfs')
| -rw-r--r-- | fs/xfs/libxfs/xfs_ag_resv.c | 12 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_alloc.c | 8 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_bmap.c | 32 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_bmap.h | 1 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_cksum.h | 1 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_ialloc.c | 4 | ||||
| -rw-r--r-- | fs/xfs/libxfs/xfs_log_format.h | 27 | ||||
| -rw-r--r-- | fs/xfs/xfs_acl.c | 22 | ||||
| -rw-r--r-- | fs/xfs/xfs_aops.c | 50 | ||||
| -rw-r--r-- | fs/xfs/xfs_attr_inactive.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_bmap_util.c | 40 | ||||
| -rw-r--r-- | fs/xfs/xfs_bmap_util.h | 13 | ||||
| -rw-r--r-- | fs/xfs/xfs_buf.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_discard.h | 1 | ||||
| -rw-r--r-- | fs/xfs/xfs_error.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_file.c | 64 | ||||
| -rw-r--r-- | fs/xfs/xfs_fsmap.c | 58 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode.c | 8 | ||||
| -rw-r--r-- | fs/xfs/xfs_inode_item.c | 81 | ||||
| -rw-r--r-- | fs/xfs/xfs_ioctl.c | 3 | ||||
| -rw-r--r-- | fs/xfs/xfs_iomap.c | 7 | ||||
| -rw-r--r-- | fs/xfs/xfs_iomap.h | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_log.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_message.h | 1 | ||||
| -rw-r--r-- | fs/xfs/xfs_mount.c | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_ondisk.h | 2 | ||||
| -rw-r--r-- | fs/xfs/xfs_pnfs.c | 3 | ||||
| -rw-r--r-- | fs/xfs/xfs_pnfs.h | 1 | ||||
| -rw-r--r-- | fs/xfs/xfs_reflink.c | 9 | ||||
| -rw-r--r-- | fs/xfs/xfs_super.c | 12 | 
30 files changed, 304 insertions, 168 deletions
| diff --git a/fs/xfs/libxfs/xfs_ag_resv.c b/fs/xfs/libxfs/xfs_ag_resv.c index b008ff3250eb..df3e600835e8 100644 --- a/fs/xfs/libxfs/xfs_ag_resv.c +++ b/fs/xfs/libxfs/xfs_ag_resv.c @@ -156,7 +156,8 @@ __xfs_ag_resv_free(  	trace_xfs_ag_resv_free(pag, type, 0);  	resv = xfs_perag_resv(pag, type); -	pag->pag_mount->m_ag_max_usable += resv->ar_asked; +	if (pag->pag_agno == 0) +		pag->pag_mount->m_ag_max_usable += resv->ar_asked;  	/*  	 * AGFL blocks are always considered "free", so whatever  	 * was reserved at mount time must be given back at umount. @@ -216,7 +217,14 @@ __xfs_ag_resv_init(  		return error;  	} -	mp->m_ag_max_usable -= ask; +	/* +	 * Reduce the maximum per-AG allocation length by however much we're +	 * trying to reserve for an AG.  Since this is a filesystem-wide +	 * counter, we only make the adjustment for AG 0.  This assumes that +	 * there aren't any AGs hungrier for per-AG reservation than AG 0. +	 */ +	if (pag->pag_agno == 0) +		mp->m_ag_max_usable -= ask;  	resv = xfs_perag_resv(pag, type);  	resv->ar_asked = ask; diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index 744dcaec34cc..f965ce832bc0 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c @@ -1584,6 +1584,10 @@ xfs_alloc_ag_vextent_small(  				bp = xfs_btree_get_bufs(args->mp, args->tp,  					args->agno, fbno, 0); +				if (!bp) { +					error = -EFSCORRUPTED; +					goto error0; +				}  				xfs_trans_binval(args->tp, bp);  			}  			args->len = 1; @@ -2141,6 +2145,10 @@ xfs_alloc_fix_freelist(  		if (error)  			goto out_agbp_relse;  		bp = xfs_btree_get_bufs(mp, tp, args->agno, bno, 0); +		if (!bp) { +			error = -EFSCORRUPTED; +			goto out_agbp_relse; +		}  		xfs_trans_binval(tp, bp);  	} diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 459f4b4f08fe..89263797cf32 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -49,7 +49,6 @@  #include "xfs_rmap.h"  #include "xfs_ag_resv.h"  #include "xfs_refcount.h" -#include "xfs_rmap_btree.h"  #include "xfs_icache.h" @@ -192,12 +191,8 @@ xfs_bmap_worst_indlen(  	int		maxrecs;	/* maximum record count at this level */  	xfs_mount_t	*mp;		/* mount structure */  	xfs_filblks_t	rval;		/* return value */ -	xfs_filblks_t   orig_len;  	mp = ip->i_mount; - -	/* Calculate the worst-case size of the bmbt. */ -	orig_len = len;  	maxrecs = mp->m_bmap_dmxr[0];  	for (level = 0, rval = 0;  	     level < XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK); @@ -205,20 +200,12 @@ xfs_bmap_worst_indlen(  		len += maxrecs - 1;  		do_div(len, maxrecs);  		rval += len; -		if (len == 1) { -			rval += XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - +		if (len == 1) +			return rval + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) -  				level - 1; -			break; -		}  		if (level == 0)  			maxrecs = mp->m_bmap_dmxr[1];  	} - -	/* Calculate the worst-case size of the rmapbt. */ -	if (xfs_sb_version_hasrmapbt(&mp->m_sb)) -		rval += 1 + xfs_rmapbt_calc_size(mp, orig_len) + -				mp->m_rmap_maxlevels; -  	return rval;  } @@ -1490,14 +1477,14 @@ xfs_bmap_isaeof(  	int			is_empty;  	int			error; -	bma->aeof = 0; +	bma->aeof = false;  	error = xfs_bmap_last_extent(NULL, bma->ip, whichfork, &rec,  				     &is_empty);  	if (error)  		return error;  	if (is_empty) { -		bma->aeof = 1; +		bma->aeof = true;  		return 0;  	} @@ -3865,6 +3852,17 @@ xfs_trim_extent(  	}  } +/* trim extent to within eof */ +void +xfs_trim_extent_eof( +	struct xfs_bmbt_irec	*irec, +	struct xfs_inode	*ip) + +{ +	xfs_trim_extent(irec, 0, XFS_B_TO_FSB(ip->i_mount, +					      i_size_read(VFS_I(ip)))); +} +  /*   * Trim the returned map to the required bounds   */ diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h index 851982a5dfbc..502e0d8fb4ff 100644 --- a/fs/xfs/libxfs/xfs_bmap.h +++ b/fs/xfs/libxfs/xfs_bmap.h @@ -208,6 +208,7 @@ void	xfs_bmap_trace_exlist(struct xfs_inode *ip, xfs_extnum_t cnt,  void	xfs_trim_extent(struct xfs_bmbt_irec *irec, xfs_fileoff_t bno,  		xfs_filblks_t len); +void	xfs_trim_extent_eof(struct xfs_bmbt_irec *, struct xfs_inode *);  int	xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd);  void	xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork);  void	xfs_bmap_add_free(struct xfs_mount *mp, struct xfs_defer_ops *dfops, diff --git a/fs/xfs/libxfs/xfs_cksum.h b/fs/xfs/libxfs/xfs_cksum.h index 8211f48b98e6..999a290cfd72 100644 --- a/fs/xfs/libxfs/xfs_cksum.h +++ b/fs/xfs/libxfs/xfs_cksum.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  #ifndef _XFS_CKSUM_H  #define _XFS_CKSUM_H 1 diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index 988bb3f31446..dfd643909f85 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c @@ -1962,7 +1962,7 @@ xfs_difree_inobt(  	if (!(mp->m_flags & XFS_MOUNT_IKEEP) &&  	    rec.ir_free == XFS_INOBT_ALL_FREE &&  	    mp->m_sb.sb_inopblock <= XFS_INODES_PER_CHUNK) { -		xic->deleted = 1; +		xic->deleted = true;  		xic->first_ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino);  		xic->alloc = xfs_inobt_irec_to_allocmask(&rec); @@ -1989,7 +1989,7 @@ xfs_difree_inobt(  		xfs_difree_inode_chunk(mp, agno, &rec, dfops);  	} else { -		xic->deleted = 0; +		xic->deleted = false;  		error = xfs_inobt_update(cur, &rec);  		if (error) { diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h index 8372e9bcd7b6..71de185735e0 100644 --- a/fs/xfs/libxfs/xfs_log_format.h +++ b/fs/xfs/libxfs/xfs_log_format.h @@ -270,6 +270,7 @@ typedef struct xfs_inode_log_format {  	uint32_t		ilf_fields;	/* flags for fields logged */  	uint16_t		ilf_asize;	/* size of attr d/ext/root */  	uint16_t		ilf_dsize;	/* size of data/ext/root */ +	uint32_t		ilf_pad;	/* pad for 64 bit boundary */  	uint64_t		ilf_ino;	/* inode number */  	union {  		uint32_t	ilfu_rdev;	/* rdev value for dev inode*/ @@ -280,29 +281,17 @@ typedef struct xfs_inode_log_format {  	int32_t			ilf_boffset;	/* off of inode in buffer */  } xfs_inode_log_format_t; -typedef struct xfs_inode_log_format_32 { -	uint16_t		ilf_type;	/* inode log item type */ -	uint16_t		ilf_size;	/* size of this item */ -	uint32_t		ilf_fields;	/* flags for fields logged */ -	uint16_t		ilf_asize;	/* size of attr d/ext/root */ -	uint16_t		ilf_dsize;	/* size of data/ext/root */ -	uint64_t		ilf_ino;	/* inode number */ -	union { -		uint32_t	ilfu_rdev;	/* rdev value for dev inode*/ -		uuid_t		ilfu_uuid;	/* mount point value */ -	} ilf_u; -	int64_t			ilf_blkno;	/* blkno of inode buffer */ -	int32_t			ilf_len;	/* len of inode buffer */ -	int32_t			ilf_boffset;	/* off of inode in buffer */ -} __attribute__((packed)) xfs_inode_log_format_32_t; - -typedef struct xfs_inode_log_format_64 { +/* + * Old 32 bit systems will log in this format without the 64 bit + * alignment padding. Recovery will detect this and convert it to the + * correct format. + */ +struct xfs_inode_log_format_32 {  	uint16_t		ilf_type;	/* inode log item type */  	uint16_t		ilf_size;	/* size of this item */  	uint32_t		ilf_fields;	/* flags for fields logged */  	uint16_t		ilf_asize;	/* size of attr d/ext/root */  	uint16_t		ilf_dsize;	/* size of data/ext/root */ -	uint32_t		ilf_pad;	/* pad for 64 bit boundary */  	uint64_t		ilf_ino;	/* inode number */  	union {  		uint32_t	ilfu_rdev;	/* rdev value for dev inode*/ @@ -311,7 +300,7 @@ typedef struct xfs_inode_log_format_64 {  	int64_t			ilf_blkno;	/* blkno of inode buffer */  	int32_t			ilf_len;	/* len of inode buffer */  	int32_t			ilf_boffset;	/* off of inode in buffer */ -} xfs_inode_log_format_64_t; +} __attribute__((packed));  /* diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 7034e17535de..3354140de07e 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c @@ -247,6 +247,8 @@ xfs_set_mode(struct inode *inode, umode_t mode)  int  xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)  { +	umode_t mode; +	bool set_mode = false;  	int error = 0;  	if (!acl) @@ -257,16 +259,24 @@ xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)  		return error;  	if (type == ACL_TYPE_ACCESS) { -		umode_t mode; -  		error = posix_acl_update_mode(inode, &mode, &acl);  		if (error)  			return error; -		error = xfs_set_mode(inode, mode); -		if (error) -			return error; +		set_mode = true;  	}   set_acl: -	return __xfs_set_acl(inode, acl, type); +	error =  __xfs_set_acl(inode, acl, type); +	if (error) +		return error; + +	/* +	 * We set the mode after successfully updating the ACL xattr because the +	 * xattr update can fail at ENOSPC and we don't want to change the mode +	 * if the ACL update hasn't been applied. +	 */ +	if (set_mode) +		error = xfs_set_mode(inode, mode); + +	return error;  } diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 29172609f2a3..a3eeaba156c5 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -343,7 +343,8 @@ xfs_end_io(  		error = xfs_reflink_end_cow(ip, offset, size);  		break;  	case XFS_IO_UNWRITTEN: -		error = xfs_iomap_write_unwritten(ip, offset, size); +		/* writeback should never update isize */ +		error = xfs_iomap_write_unwritten(ip, offset, size, false);  		break;  	default:  		ASSERT(!xfs_ioend_is_append(ioend) || ioend->io_append_trans); @@ -445,6 +446,19 @@ xfs_imap_valid(  {  	offset >>= inode->i_blkbits; +	/* +	 * We have to make sure the cached mapping is within EOF to protect +	 * against eofblocks trimming on file release leaving us with a stale +	 * mapping. Otherwise, a page for a subsequent file extending buffered +	 * write could get picked up by this writeback cycle and written to the +	 * wrong blocks. +	 * +	 * Note that what we really want here is a generic mapping invalidation +	 * mechanism to protect us from arbitrary extent modifying contexts, not +	 * just eofblocks. +	 */ +	xfs_trim_extent_eof(imap, XFS_I(inode)); +  	return offset >= imap->br_startoff &&  		offset < imap->br_startoff + imap->br_blockcount;  } @@ -734,6 +748,14 @@ xfs_vm_invalidatepage(  {  	trace_xfs_invalidatepage(page->mapping->host, page, offset,  				 length); + +	/* +	 * If we are invalidating the entire page, clear the dirty state from it +	 * so that we can check for attempts to release dirty cached pages in +	 * xfs_vm_releasepage(). +	 */ +	if (offset == 0 && length >= PAGE_SIZE) +		cancel_dirty_page(page);  	block_invalidatepage(page, offset, length);  } @@ -1189,25 +1211,27 @@ xfs_vm_releasepage(  	 * mm accommodates an old ext3 case where clean pages might not have had  	 * the dirty bit cleared. Thus, it can send actual dirty pages to  	 * ->releasepage() via shrink_active_list(). Conversely, -	 * block_invalidatepage() can send pages that are still marked dirty -	 * but otherwise have invalidated buffers. +	 * block_invalidatepage() can send pages that are still marked dirty but +	 * otherwise have invalidated buffers.  	 *  	 * We want to release the latter to avoid unnecessary buildup of the -	 * LRU, skip the former and warn if we've left any lingering -	 * delalloc/unwritten buffers on clean pages. Skip pages with delalloc -	 * or unwritten buffers and warn if the page is not dirty. Otherwise -	 * try to release the buffers. +	 * LRU, so xfs_vm_invalidatepage() clears the page dirty flag on pages +	 * that are entirely invalidated and need to be released.  Hence the +	 * only time we should get dirty pages here is through +	 * shrink_active_list() and so we can simply skip those now. +	 * +	 * warn if we've left any lingering delalloc/unwritten buffers on clean +	 * or invalidated pages we are about to release.  	 */ +	if (PageDirty(page)) +		return 0; +  	xfs_count_page_state(page, &delalloc, &unwritten); -	if (delalloc) { -		WARN_ON_ONCE(!PageDirty(page)); +	if (WARN_ON_ONCE(delalloc))  		return 0; -	} -	if (unwritten) { -		WARN_ON_ONCE(!PageDirty(page)); +	if (WARN_ON_ONCE(unwritten))  		return 0; -	}  	return try_to_free_buffers(page);  } diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c index ebd66b19fbfc..e3a950ed35a8 100644 --- a/fs/xfs/xfs_attr_inactive.c +++ b/fs/xfs/xfs_attr_inactive.c @@ -302,6 +302,8 @@ xfs_attr3_node_inactive(  						 &bp, XFS_ATTR_FORK);  			if (error)  				return error; +			node = bp->b_addr; +			btree = dp->d_ops->node_tree_p(node);  			child_fsb = be32_to_cpu(btree[i + 1].before);  			xfs_trans_brelse(*trans, bp);  		} diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index cd9a5400ba4f..6503cfa44262 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c @@ -84,6 +84,7 @@ xfs_zero_extent(  		GFP_NOFS, 0);  } +#ifdef CONFIG_XFS_RT  int  xfs_bmap_rtalloc(  	struct xfs_bmalloca	*ap)	/* bmap alloc argument struct */ @@ -190,6 +191,7 @@ xfs_bmap_rtalloc(  	}  	return 0;  } +#endif /* CONFIG_XFS_RT */  /*   * Check if the endoff is outside the last extent. If so the caller will grow @@ -1459,7 +1461,19 @@ xfs_shift_file_space(  		return error;  	/* -	 * The extent shiting code works on extent granularity. So, if +	 * Clean out anything hanging around in the cow fork now that +	 * we've flushed all the dirty data out to disk to avoid having +	 * CoW extents at the wrong offsets. +	 */ +	if (xfs_is_reflink_inode(ip)) { +		error = xfs_reflink_cancel_cow_range(ip, offset, NULLFILEOFF, +				true); +		if (error) +			return error; +	} + +	/* +	 * The extent shifting code works on extent granularity. So, if  	 * stop_fsb is not the starting block of extent, we need to split  	 * the extent at stop_fsb.  	 */ @@ -2110,11 +2124,31 @@ xfs_swap_extents(  		ip->i_d.di_flags2 |= tip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK;  		tip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK;  		tip->i_d.di_flags2 |= f & XFS_DIFLAG2_REFLINK; +	} + +	/* Swap the cow forks. */ +	if (xfs_sb_version_hasreflink(&mp->m_sb)) { +		xfs_extnum_t	extnum; + +		ASSERT(ip->i_cformat == XFS_DINODE_FMT_EXTENTS); +		ASSERT(tip->i_cformat == XFS_DINODE_FMT_EXTENTS); + +		extnum = ip->i_cnextents; +		ip->i_cnextents = tip->i_cnextents; +		tip->i_cnextents = extnum; +  		cowfp = ip->i_cowfp;  		ip->i_cowfp = tip->i_cowfp;  		tip->i_cowfp = cowfp; -		xfs_inode_set_cowblocks_tag(ip); -		xfs_inode_set_cowblocks_tag(tip); + +		if (ip->i_cowfp && ip->i_cnextents) +			xfs_inode_set_cowblocks_tag(ip); +		else +			xfs_inode_clear_cowblocks_tag(ip); +		if (tip->i_cowfp && tip->i_cnextents) +			xfs_inode_set_cowblocks_tag(tip); +		else +			xfs_inode_clear_cowblocks_tag(tip);  	}  	xfs_trans_log_inode(tp, ip,  src_log_flags); diff --git a/fs/xfs/xfs_bmap_util.h b/fs/xfs/xfs_bmap_util.h index 0eaa81dc49be..7d330b3c77c3 100644 --- a/fs/xfs/xfs_bmap_util.h +++ b/fs/xfs/xfs_bmap_util.h @@ -28,7 +28,20 @@ struct xfs_mount;  struct xfs_trans;  struct xfs_bmalloca; +#ifdef CONFIG_XFS_RT  int	xfs_bmap_rtalloc(struct xfs_bmalloca *ap); +#else /* !CONFIG_XFS_RT */ +/* + * Attempts to allocate RT extents when RT is disable indicates corruption and + * should trigger a shutdown. + */ +static inline int +xfs_bmap_rtalloc(struct xfs_bmalloca *ap) +{ +	return -EFSCORRUPTED; +} +#endif /* CONFIG_XFS_RT */ +  int	xfs_bmap_eof(struct xfs_inode *ip, xfs_fileoff_t endoff,  		     int whichfork, int *eof);  int	xfs_bmap_punch_delalloc_range(struct xfs_inode *ip, diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index da14658da310..2f97c12ca75e 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -1258,8 +1258,6 @@ xfs_buf_ioapply_map(  	int		size;  	int		offset; -	total_nr_pages = bp->b_page_count; -  	/* skip the pages in the buffer before the start offset */  	page_index = 0;  	offset = *buf_offset; diff --git a/fs/xfs/xfs_discard.h b/fs/xfs/xfs_discard.h index 0f070f9e44e1..de92d9cc958f 100644 --- a/fs/xfs/xfs_discard.h +++ b/fs/xfs/xfs_discard.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  #ifndef XFS_DISCARD_H  #define XFS_DISCARD_H 1 diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c index bd786a9ac2c3..eaf86f55b7f2 100644 --- a/fs/xfs/xfs_error.c +++ b/fs/xfs/xfs_error.c @@ -347,7 +347,7 @@ xfs_verifier_error(  {  	struct xfs_mount *mp = bp->b_target->bt_mount; -	xfs_alert(mp, "Metadata %s detected at %pF, %s block 0x%llx", +	xfs_alert(mp, "Metadata %s detected at %pS, %s block 0x%llx",  		  bp->b_error == -EFSBADCRC ? "CRC error" : "corruption",  		  __return_address, bp->b_ops->name, bp->b_bn); diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index ebdd0bd2b261..6526ef0e2a23 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -58,7 +58,7 @@ xfs_zero_range(  	xfs_off_t		count,  	bool			*did_zero)  { -	return iomap_zero_range(VFS_I(ip), pos, count, NULL, &xfs_iomap_ops); +	return iomap_zero_range(VFS_I(ip), pos, count, did_zero, &xfs_iomap_ops);  }  int @@ -237,11 +237,13 @@ xfs_file_dax_read(  	if (!count)  		return 0; /* skip atime */ -	if (!xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED)) { -		if (iocb->ki_flags & IOCB_NOWAIT) +	if (iocb->ki_flags & IOCB_NOWAIT) { +		if (!xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED))  			return -EAGAIN; +	} else {  		xfs_ilock(ip, XFS_IOLOCK_SHARED);  	} +  	ret = dax_iomap_rw(iocb, to, &xfs_iomap_ops);  	xfs_iunlock(ip, XFS_IOLOCK_SHARED); @@ -259,9 +261,10 @@ xfs_file_buffered_aio_read(  	trace_xfs_file_buffered_read(ip, iov_iter_count(to), iocb->ki_pos); -	if (!xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED)) { -		if (iocb->ki_flags & IOCB_NOWAIT) +	if (iocb->ki_flags & IOCB_NOWAIT) { +		if (!xfs_ilock_nowait(ip, XFS_IOLOCK_SHARED))  			return -EAGAIN; +	} else {  		xfs_ilock(ip, XFS_IOLOCK_SHARED);  	}  	ret = generic_file_read_iter(iocb, to); @@ -377,8 +380,6 @@ restart:  	 */  	spin_lock(&ip->i_flags_lock);  	if (iocb->ki_pos > i_size_read(inode)) { -		bool	zero = false; -  		spin_unlock(&ip->i_flags_lock);  		if (!drained_dio) {  			if (*iolock == XFS_IOLOCK_SHARED) { @@ -399,7 +400,7 @@ restart:  			drained_dio = true;  			goto restart;  		} -		error = xfs_zero_eof(ip, iocb->ki_pos, i_size_read(inode), &zero); +		error = xfs_zero_eof(ip, iocb->ki_pos, i_size_read(inode), NULL);  		if (error)  			return error;  	} else @@ -436,7 +437,6 @@ xfs_dio_write_end_io(  	struct inode		*inode = file_inode(iocb->ki_filp);  	struct xfs_inode	*ip = XFS_I(inode);  	loff_t			offset = iocb->ki_pos; -	bool			update_size = false;  	int			error = 0;  	trace_xfs_end_io_direct_write(ip, offset, size); @@ -447,6 +447,21 @@ xfs_dio_write_end_io(  	if (size <= 0)  		return size; +	if (flags & IOMAP_DIO_COW) { +		error = xfs_reflink_end_cow(ip, offset, size); +		if (error) +			return error; +	} + +	/* +	 * Unwritten conversion updates the in-core isize after extent +	 * conversion but before updating the on-disk size. Updating isize any +	 * earlier allows a racing dio read to find unwritten extents before +	 * they are converted. +	 */ +	if (flags & IOMAP_DIO_UNWRITTEN) +		return xfs_iomap_write_unwritten(ip, offset, size, true); +  	/*  	 * We need to update the in-core inode size here so that we don't end up  	 * with the on-disk inode size being outside the in-core inode size. We @@ -461,20 +476,11 @@ xfs_dio_write_end_io(  	spin_lock(&ip->i_flags_lock);  	if (offset + size > i_size_read(inode)) {  		i_size_write(inode, offset + size); -		update_size = true; -	} -	spin_unlock(&ip->i_flags_lock); - -	if (flags & IOMAP_DIO_COW) { -		error = xfs_reflink_end_cow(ip, offset, size); -		if (error) -			return error; -	} - -	if (flags & IOMAP_DIO_UNWRITTEN) -		error = xfs_iomap_write_unwritten(ip, offset, size); -	else if (update_size) +		spin_unlock(&ip->i_flags_lock);  		error = xfs_setfilesize(ip, offset, size); +	} else { +		spin_unlock(&ip->i_flags_lock); +	}  	return error;  } @@ -549,9 +555,10 @@ xfs_file_dio_aio_write(  		iolock = XFS_IOLOCK_SHARED;  	} -	if (!xfs_ilock_nowait(ip, iolock)) { -		if (iocb->ki_flags & IOCB_NOWAIT) +	if (iocb->ki_flags & IOCB_NOWAIT) { +		if (!xfs_ilock_nowait(ip, iolock))  			return -EAGAIN; +	} else {  		xfs_ilock(ip, iolock);  	} @@ -603,9 +610,10 @@ xfs_file_dax_write(  	size_t			count;  	loff_t			pos; -	if (!xfs_ilock_nowait(ip, iolock)) { -		if (iocb->ki_flags & IOCB_NOWAIT) +	if (iocb->ki_flags & IOCB_NOWAIT) { +		if (!xfs_ilock_nowait(ip, iolock))  			return -EAGAIN; +	} else {  		xfs_ilock(ip, iolock);  	} @@ -761,7 +769,7 @@ xfs_file_fallocate(  	enum xfs_prealloc_flags	flags = 0;  	uint			iolock = XFS_IOLOCK_EXCL;  	loff_t			new_size = 0; -	bool			do_file_insert = 0; +	bool			do_file_insert = false;  	if (!S_ISREG(inode->i_mode))  		return -EINVAL; @@ -822,7 +830,7 @@ xfs_file_fallocate(  			error = -EINVAL;  			goto out_unlock;  		} -		do_file_insert = 1; +		do_file_insert = true;  	} else {  		flags |= XFS_PREALLOC_SET; diff --git a/fs/xfs/xfs_fsmap.c b/fs/xfs/xfs_fsmap.c index 814ed729881d..43cfc07996a4 100644 --- a/fs/xfs/xfs_fsmap.c +++ b/fs/xfs/xfs_fsmap.c @@ -367,29 +367,6 @@ xfs_getfsmap_datadev_helper(  	return xfs_getfsmap_helper(cur->bc_tp, info, rec, rec_daddr);  } -/* Transform a rtbitmap "record" into a fsmap */ -STATIC int -xfs_getfsmap_rtdev_rtbitmap_helper( -	struct xfs_trans		*tp, -	struct xfs_rtalloc_rec		*rec, -	void				*priv) -{ -	struct xfs_mount		*mp = tp->t_mountp; -	struct xfs_getfsmap_info	*info = priv; -	struct xfs_rmap_irec		irec; -	xfs_daddr_t			rec_daddr; - -	rec_daddr = XFS_FSB_TO_BB(mp, rec->ar_startblock); - -	irec.rm_startblock = rec->ar_startblock; -	irec.rm_blockcount = rec->ar_blockcount; -	irec.rm_owner = XFS_RMAP_OWN_NULL;	/* "free" */ -	irec.rm_offset = 0; -	irec.rm_flags = 0; - -	return xfs_getfsmap_helper(tp, info, &irec, rec_daddr); -} -  /* Transform a bnobt irec into a fsmap */  STATIC int  xfs_getfsmap_datadev_bnobt_helper( @@ -475,6 +452,30 @@ xfs_getfsmap_logdev(  	return xfs_getfsmap_helper(tp, info, &rmap, 0);  } +#ifdef CONFIG_XFS_RT +/* Transform a rtbitmap "record" into a fsmap */ +STATIC int +xfs_getfsmap_rtdev_rtbitmap_helper( +	struct xfs_trans		*tp, +	struct xfs_rtalloc_rec		*rec, +	void				*priv) +{ +	struct xfs_mount		*mp = tp->t_mountp; +	struct xfs_getfsmap_info	*info = priv; +	struct xfs_rmap_irec		irec; +	xfs_daddr_t			rec_daddr; + +	rec_daddr = XFS_FSB_TO_BB(mp, rec->ar_startblock); + +	irec.rm_startblock = rec->ar_startblock; +	irec.rm_blockcount = rec->ar_blockcount; +	irec.rm_owner = XFS_RMAP_OWN_NULL;	/* "free" */ +	irec.rm_offset = 0; +	irec.rm_flags = 0; + +	return xfs_getfsmap_helper(tp, info, &irec, rec_daddr); +} +  /* Execute a getfsmap query against the realtime device. */  STATIC int  __xfs_getfsmap_rtdev( @@ -561,6 +562,7 @@ xfs_getfsmap_rtdev_rtbitmap(  	return __xfs_getfsmap_rtdev(tp, keys, xfs_getfsmap_rtdev_rtbitmap_query,  			info);  } +#endif /* CONFIG_XFS_RT */  /* Execute a getfsmap query against the regular data device. */  STATIC int @@ -795,7 +797,15 @@ xfs_getfsmap_check_keys(  	return false;  } +/* + * There are only two devices if we didn't configure RT devices at build time. + */ +#ifdef CONFIG_XFS_RT  #define XFS_GETFSMAP_DEVS	3 +#else +#define XFS_GETFSMAP_DEVS	2 +#endif /* CONFIG_XFS_RT */ +  /*   * Get filesystem's extents as described in head, and format for   * output.  Calls formatter to fill the user's buffer until all @@ -853,10 +863,12 @@ xfs_getfsmap(  		handlers[1].dev = new_encode_dev(mp->m_logdev_targp->bt_dev);  		handlers[1].fn = xfs_getfsmap_logdev;  	} +#ifdef CONFIG_XFS_RT  	if (mp->m_rtdev_targp) {  		handlers[2].dev = new_encode_dev(mp->m_rtdev_targp->bt_dev);  		handlers[2].fn = xfs_getfsmap_rtdev_rtbitmap;  	} +#endif /* CONFIG_XFS_RT */  	xfs_sort(handlers, XFS_GETFSMAP_DEVS, sizeof(struct xfs_getfsmap_dev),  			xfs_getfsmap_dev_compare); diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 5599dda4727a..4ec5b7f45401 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1624,10 +1624,12 @@ xfs_itruncate_extents(  		goto out;  	/* -	 * Clear the reflink flag if we truncated everything. +	 * Clear the reflink flag if there are no data fork blocks and +	 * there are no extents staged in the cow fork.  	 */ -	if (ip->i_d.di_nblocks == 0 && xfs_is_reflink_inode(ip)) { -		ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; +	if (xfs_is_reflink_inode(ip) && ip->i_cnextents == 0) { +		if (ip->i_d.di_nblocks == 0) +			ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK;  		xfs_inode_clear_cowblocks_tag(ip);  	} diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index 6d0f74ec31e8..9bbc2d7cc8cb 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c @@ -364,6 +364,9 @@ xfs_inode_to_log_dinode(  	to->di_dmstate = from->di_dmstate;  	to->di_flags = from->di_flags; +	/* log a dummy value to ensure log structure is fully initialised */ +	to->di_next_unlinked = NULLAGINO; +  	if (from->di_version == 3) {  		to->di_changecount = inode->i_version;  		to->di_crtime.t_sec = from->di_crtime.t_sec; @@ -404,6 +407,11 @@ xfs_inode_item_format_core(   * the second with the on-disk inode structure, and a possible third and/or   * fourth with the inode data/extents/b-tree root and inode attributes   * data/extents/b-tree root. + * + * Note: Always use the 64 bit inode log format structure so we don't + * leave an uninitialised hole in the format item on 64 bit systems. Log + * recovery on 32 bit systems handles this just fine, so there's no reason + * for not using an initialising the properly padded structure all the time.   */  STATIC void  xfs_inode_item_format( @@ -412,8 +420,8 @@ xfs_inode_item_format(  {  	struct xfs_inode_log_item *iip = INODE_ITEM(lip);  	struct xfs_inode	*ip = iip->ili_inode; -	struct xfs_inode_log_format *ilf;  	struct xfs_log_iovec	*vecp = NULL; +	struct xfs_inode_log_format *ilf;  	ASSERT(ip->i_d.di_version > 1); @@ -425,7 +433,17 @@ xfs_inode_item_format(  	ilf->ilf_boffset = ip->i_imap.im_boffset;  	ilf->ilf_fields = XFS_ILOG_CORE;  	ilf->ilf_size = 2; /* format + core */ -	xlog_finish_iovec(lv, vecp, sizeof(struct xfs_inode_log_format)); + +	/* +	 * make sure we don't leak uninitialised data into the log in the case +	 * when we don't log every field in the inode. +	 */ +	ilf->ilf_dsize = 0; +	ilf->ilf_asize = 0; +	ilf->ilf_pad = 0; +	uuid_copy(&ilf->ilf_u.ilfu_uuid, &uuid_null); + +	xlog_finish_iovec(lv, vecp, sizeof(*ilf));  	xfs_inode_item_format_core(ip, lv, &vecp);  	xfs_inode_item_format_data_fork(iip, ilf, lv, &vecp); @@ -745,7 +763,7 @@ xfs_iflush_done(  		 */  		iip = INODE_ITEM(blip);  		if ((iip->ili_logged && blip->li_lsn == iip->ili_flush_lsn) || -		    lip->li_flags & XFS_LI_FAILED) +		    (blip->li_flags & XFS_LI_FAILED))  			need_ail++;  		blip = next; @@ -855,44 +873,29 @@ xfs_istale_done(  }  /* - * convert an xfs_inode_log_format struct from either 32 or 64 bit versions - * (which can have different field alignments) to the native version + * convert an xfs_inode_log_format struct from the old 32 bit version + * (which can have different field alignments) to the native 64 bit version   */  int  xfs_inode_item_format_convert( -	xfs_log_iovec_t		*buf, -	xfs_inode_log_format_t	*in_f) +	struct xfs_log_iovec		*buf, +	struct xfs_inode_log_format	*in_f)  { -	if (buf->i_len == sizeof(xfs_inode_log_format_32_t)) { -		xfs_inode_log_format_32_t *in_f32 = buf->i_addr; - -		in_f->ilf_type = in_f32->ilf_type; -		in_f->ilf_size = in_f32->ilf_size; -		in_f->ilf_fields = in_f32->ilf_fields; -		in_f->ilf_asize = in_f32->ilf_asize; -		in_f->ilf_dsize = in_f32->ilf_dsize; -		in_f->ilf_ino = in_f32->ilf_ino; -		/* copy biggest field of ilf_u */ -		uuid_copy(&in_f->ilf_u.ilfu_uuid, &in_f32->ilf_u.ilfu_uuid); -		in_f->ilf_blkno = in_f32->ilf_blkno; -		in_f->ilf_len = in_f32->ilf_len; -		in_f->ilf_boffset = in_f32->ilf_boffset; -		return 0; -	} else if (buf->i_len == sizeof(xfs_inode_log_format_64_t)){ -		xfs_inode_log_format_64_t *in_f64 = buf->i_addr; - -		in_f->ilf_type = in_f64->ilf_type; -		in_f->ilf_size = in_f64->ilf_size; -		in_f->ilf_fields = in_f64->ilf_fields; -		in_f->ilf_asize = in_f64->ilf_asize; -		in_f->ilf_dsize = in_f64->ilf_dsize; -		in_f->ilf_ino = in_f64->ilf_ino; -		/* copy biggest field of ilf_u */ -		uuid_copy(&in_f->ilf_u.ilfu_uuid, &in_f64->ilf_u.ilfu_uuid); -		in_f->ilf_blkno = in_f64->ilf_blkno; -		in_f->ilf_len = in_f64->ilf_len; -		in_f->ilf_boffset = in_f64->ilf_boffset; -		return 0; -	} -	return -EFSCORRUPTED; +	struct xfs_inode_log_format_32	*in_f32 = buf->i_addr; + +	if (buf->i_len != sizeof(*in_f32)) +		return -EFSCORRUPTED; + +	in_f->ilf_type = in_f32->ilf_type; +	in_f->ilf_size = in_f32->ilf_size; +	in_f->ilf_fields = in_f32->ilf_fields; +	in_f->ilf_asize = in_f32->ilf_asize; +	in_f->ilf_dsize = in_f32->ilf_dsize; +	in_f->ilf_ino = in_f32->ilf_ino; +	/* copy biggest field of ilf_u */ +	uuid_copy(&in_f->ilf_u.ilfu_uuid, &in_f32->ilf_u.ilfu_uuid); +	in_f->ilf_blkno = in_f32->ilf_blkno; +	in_f->ilf_len = in_f32->ilf_len; +	in_f->ilf_boffset = in_f32->ilf_boffset; +	return 0;  } diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 5049e8ab6e30..aa75389be8cf 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -1088,6 +1088,7 @@ xfs_ioctl_setattr_dax_invalidate(  	int			*join_flags)  {  	struct inode		*inode = VFS_I(ip); +	struct super_block	*sb = inode->i_sb;  	int			error;  	*join_flags = 0; @@ -1100,7 +1101,7 @@ xfs_ioctl_setattr_dax_invalidate(  	if (fa->fsx_xflags & FS_XFLAG_DAX) {  		if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))  			return -EINVAL; -		if (ip->i_mount->m_sb.sb_blocksize != PAGE_SIZE) +		if (bdev_dax_supported(sb, sb->s_blocksize) < 0)  			return -EINVAL;  	} diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index a1909bc064e9..f179bdf1644d 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -829,7 +829,8 @@ int  xfs_iomap_write_unwritten(  	xfs_inode_t	*ip,  	xfs_off_t	offset, -	xfs_off_t	count) +	xfs_off_t	count, +	bool		update_isize)  {  	xfs_mount_t	*mp = ip->i_mount;  	xfs_fileoff_t	offset_fsb; @@ -840,6 +841,7 @@ xfs_iomap_write_unwritten(  	xfs_trans_t	*tp;  	xfs_bmbt_irec_t imap;  	struct xfs_defer_ops dfops; +	struct inode	*inode = VFS_I(ip);  	xfs_fsize_t	i_size;  	uint		resblks;  	int		error; @@ -899,7 +901,8 @@ xfs_iomap_write_unwritten(  		i_size = XFS_FSB_TO_B(mp, offset_fsb + count_fsb);  		if (i_size > offset + count)  			i_size = offset + count; - +		if (update_isize && i_size > i_size_read(inode)) +			i_size_write(inode, i_size);  		i_size = xfs_new_eof(ip, i_size);  		if (i_size) {  			ip->i_d.di_size = i_size; diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h index 00db3ecea084..ee535065c5d0 100644 --- a/fs/xfs/xfs_iomap.h +++ b/fs/xfs/xfs_iomap.h @@ -27,7 +27,7 @@ int xfs_iomap_write_direct(struct xfs_inode *, xfs_off_t, size_t,  			struct xfs_bmbt_irec *, int);  int xfs_iomap_write_allocate(struct xfs_inode *, int, xfs_off_t,  			struct xfs_bmbt_irec *); -int xfs_iomap_write_unwritten(struct xfs_inode *, xfs_off_t, xfs_off_t); +int xfs_iomap_write_unwritten(struct xfs_inode *, xfs_off_t, xfs_off_t, bool);  void xfs_bmbt_to_iomap(struct xfs_inode *, struct iomap *,  		struct xfs_bmbt_irec *); diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index c5107c7bc4bf..dc95a49d62e7 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -2515,7 +2515,7 @@ next_lv:  				if (lv)  					vecp = lv->lv_iovecp;  			} -			if (record_cnt == 0 && ordered == false) { +			if (record_cnt == 0 && !ordered) {  				if (!lv)  					return 0;  				break; diff --git a/fs/xfs/xfs_message.h b/fs/xfs/xfs_message.h index 85401155750e..34447dca97d1 100644 --- a/fs/xfs/xfs_message.h +++ b/fs/xfs/xfs_message.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  #ifndef __XFS_MESSAGE_H  #define __XFS_MESSAGE_H 1 diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index ea7d4b4e50d0..e9727d0a541a 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -704,7 +704,7 @@ xfs_mountfs(  	xfs_set_maxicount(mp);  	/* enable fail_at_unmount as default */ -	mp->m_fail_unmount = 1; +	mp->m_fail_unmount = true;  	error = xfs_sysfs_init(&mp->m_kobj, &xfs_mp_ktype, NULL, mp->m_fsname);  	if (error) diff --git a/fs/xfs/xfs_ondisk.h b/fs/xfs/xfs_ondisk.h index 0c381d71b242..0492436a053f 100644 --- a/fs/xfs/xfs_ondisk.h +++ b/fs/xfs/xfs_ondisk.h @@ -134,7 +134,7 @@ xfs_check_ondisk_structs(void)  	XFS_CHECK_STRUCT_SIZE(struct xfs_icreate_log,		28);  	XFS_CHECK_STRUCT_SIZE(struct xfs_ictimestamp,		8);  	XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format_32,	52); -	XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format_64,	56); +	XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format,	56);  	XFS_CHECK_STRUCT_SIZE(struct xfs_qoff_logformat,	20);  	XFS_CHECK_STRUCT_SIZE(struct xfs_trans_header,		16);  } diff --git a/fs/xfs/xfs_pnfs.c b/fs/xfs/xfs_pnfs.c index 2f2dc3c09ad0..aa6c5c193f45 100644 --- a/fs/xfs/xfs_pnfs.c +++ b/fs/xfs/xfs_pnfs.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0  /*   * Copyright (c) 2014 Christoph Hellwig.   */ @@ -274,7 +275,7 @@ xfs_fs_commit_blocks(  					(end - 1) >> PAGE_SHIFT);  		WARN_ON_ONCE(error); -		error = xfs_iomap_write_unwritten(ip, start, length); +		error = xfs_iomap_write_unwritten(ip, start, length, false);  		if (error)  			goto out_drop_iolock;  	} diff --git a/fs/xfs/xfs_pnfs.h b/fs/xfs/xfs_pnfs.h index b587cb99b2b7..bf45951e28fe 100644 --- a/fs/xfs/xfs_pnfs.h +++ b/fs/xfs/xfs_pnfs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  #ifndef _XFS_PNFS_H  #define _XFS_PNFS_H 1 diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c index 3246815c24d6..37e603bf1591 100644 --- a/fs/xfs/xfs_reflink.c +++ b/fs/xfs/xfs_reflink.c @@ -736,7 +736,13 @@ xfs_reflink_end_cow(  	/* If there is a hole at end_fsb - 1 go to the previous extent */  	if (!xfs_iext_lookup_extent(ip, ifp, end_fsb - 1, &idx, &got) ||  	    got.br_startoff > end_fsb) { -		ASSERT(idx > 0); +		/* +		 * In case of racing, overlapping AIO writes no COW extents +		 * might be left by the time I/O completes for the loser of +		 * the race.  In that case we are done. +		 */ +		if (idx <= 0) +			goto out_cancel;  		xfs_iext_get_extent(ifp, --idx, &got);  	} @@ -809,6 +815,7 @@ next_extent:  out_defer:  	xfs_defer_cancel(&dfops); +out_cancel:  	xfs_trans_cancel(tp);  	xfs_iunlock(ip, XFS_ILOCK_EXCL);  out: diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index c996f4ae4a5f..f663022353c0 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1637,7 +1637,7 @@ xfs_fs_fill_super(  	/* version 5 superblocks support inode version counters. */  	if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5) -		sb->s_flags |= MS_I_VERSION; +		sb->s_flags |= SB_I_VERSION;  	if (mp->m_flags & XFS_MOUNT_DAX) {  		xfs_warn(mp, @@ -1654,6 +1654,16 @@ xfs_fs_fill_super(  		"DAX and reflink have not been tested together!");  	} +	if (mp->m_flags & XFS_MOUNT_DISCARD) { +		struct request_queue *q = bdev_get_queue(sb->s_bdev); + +		if (!blk_queue_discard(q)) { +			xfs_warn(mp, "mounting with \"discard\" option, but " +					"the device does not support discard"); +			mp->m_flags &= ~XFS_MOUNT_DISCARD; +		} +	} +  	if (xfs_sb_version_hasrmapbt(&mp->m_sb)) {  		if (mp->m_sb.sb_rblocks) {  			xfs_alert(mp, |