Commit 27b31deb authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'xfs-6.10-fixes-5' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull xfs fixes from Chandan Babu:

 - Always free only post-EOF delayed allocations for files with the
   XFS_DIFLAG_PREALLOC or APPEND flags set.

 - Do not align cow fork delalloc to cowextsz hint when running low on
   space.

 - Allow zero-size symlinks and directories as long as the link count is
   zero.

 - Change XFS_IOC_EXCHANGE_RANGE to be a _IOW only ioctl. This was ioctl
   was introduced during v6.10 developement cycle.

 - xfs_init_new_inode() now creates an attribute fork on a newly created
   inode even if ATTR feature flag is not enabled.

* tag 'xfs-6.10-fixes-5' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
  xfs: honor init_xattrs in xfs_init_new_inode for !ATTR fs
  xfs: fix direction in XFS_IOC_EXCHANGE_RANGE
  xfs: allow unlinked symlinks and dirs with zero size
  xfs: restrict when we try to align cow fork delalloc to cowextsz hints
  xfs: fix freeing speculative preallocations for preallocated files
parents ebe70b3a 673cd885
Loading
Loading
Loading
Loading
+27 −4
Original line number Diff line number Diff line
@@ -4058,20 +4058,32 @@ xfs_bmapi_reserve_delalloc(
	xfs_extlen_t		indlen;
	uint64_t		fdblocks;
	int			error;
	xfs_fileoff_t		aoff = off;
	xfs_fileoff_t		aoff;
	bool			use_cowextszhint =
					whichfork == XFS_COW_FORK && !prealloc;

retry:
	/*
	 * Cap the alloc length. Keep track of prealloc so we know whether to
	 * tag the inode before we return.
	 */
	aoff = off;
	alen = XFS_FILBLKS_MIN(len + prealloc, XFS_MAX_BMBT_EXTLEN);
	if (!eof)
		alen = XFS_FILBLKS_MIN(alen, got->br_startoff - aoff);
	if (prealloc && alen >= len)
		prealloc = alen - len;

	/* Figure out the extent size, adjust alen */
	if (whichfork == XFS_COW_FORK) {
	/*
	 * If we're targetting the COW fork but aren't creating a speculative
	 * posteof preallocation, try to expand the reservation to align with
	 * the COW extent size hint if there's sufficient free space.
	 *
	 * Unlike the data fork, the CoW cancellation functions will free all
	 * the reservations at inactivation, so we don't require that every
	 * delalloc reservation have a dirty pagecache.
	 */
	if (use_cowextszhint) {
		struct xfs_bmbt_irec	prev;
		xfs_extlen_t		extsz = xfs_get_cowextsz_hint(ip);

@@ -4090,7 +4102,7 @@ xfs_bmapi_reserve_delalloc(
	 */
	error = xfs_quota_reserve_blkres(ip, alen);
	if (error)
		return error;
		goto out;

	/*
	 * Split changing sb for alen and indlen since they could be coming
@@ -4140,6 +4152,17 @@ xfs_bmapi_reserve_delalloc(
out_unreserve_quota:
	if (XFS_IS_QUOTA_ON(mp))
		xfs_quota_unreserve_blkres(ip, alen);
out:
	if (error == -ENOSPC || error == -EDQUOT) {
		trace_xfs_delalloc_enospc(ip, off, len);

		if (prealloc || use_cowextszhint) {
			/* retry without any preallocation */
			use_cowextszhint = false;
			prealloc = 0;
			goto retry;
		}
	}
	return error;
}

+1 −1
Original line number Diff line number Diff line
@@ -996,7 +996,7 @@ struct xfs_getparents_by_handle {
#define XFS_IOC_FSGEOMETRY	     _IOR ('X', 126, struct xfs_fsop_geom)
#define XFS_IOC_BULKSTAT	     _IOR ('X', 127, struct xfs_bulkstat_req)
#define XFS_IOC_INUMBERS	     _IOR ('X', 128, struct xfs_inumbers_req)
#define XFS_IOC_EXCHANGE_RANGE	     _IOWR('X', 129, struct xfs_exchange_range)
#define XFS_IOC_EXCHANGE_RANGE	     _IOW ('X', 129, struct xfs_exchange_range)
/*	XFS_IOC_GETFSUUID ---------- deprecated 140	 */


+18 −5
Original line number Diff line number Diff line
@@ -379,10 +379,13 @@ xfs_dinode_verify_fork(
		/*
		 * A directory small enough to fit in the inode must be stored
		 * in local format.  The directory sf <-> extents conversion
		 * code updates the directory size accordingly.
		 * code updates the directory size accordingly.  Directories
		 * being truncated have zero size and are not subject to this
		 * check.
		 */
		if (S_ISDIR(mode)) {
			if (be64_to_cpu(dip->di_size) <= fork_size &&
			if (dip->di_size &&
			    be64_to_cpu(dip->di_size) <= fork_size &&
			    fork_format != XFS_DINODE_FMT_LOCAL)
				return __this_address;
		}
@@ -528,9 +531,19 @@ xfs_dinode_verify(
	if (mode && xfs_mode_to_ftype(mode) == XFS_DIR3_FT_UNKNOWN)
		return __this_address;

	/* No zero-length symlinks/dirs. */
	if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0)
	/*
	 * No zero-length symlinks/dirs unless they're unlinked and hence being
	 * inactivated.
	 */
	if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0) {
		if (dip->di_version > 1) {
			if (dip->di_nlink)
				return __this_address;
		} else {
			if (dip->di_onlink)
				return __this_address;
		}
	}

	fa = xfs_dinode_verify_nrext64(mp, dip);
	if (fa)
+22 −8
Original line number Diff line number Diff line
@@ -486,13 +486,11 @@ xfs_bmap_punch_delalloc_range(

/*
 * Test whether it is appropriate to check an inode for and free post EOF
 * blocks. The 'force' parameter determines whether we should also consider
 * regular files that are marked preallocated or append-only.
 * blocks.
 */
bool
xfs_can_free_eofblocks(
	struct xfs_inode	*ip,
	bool			force)
	struct xfs_inode	*ip)
{
	struct xfs_bmbt_irec	imap;
	struct xfs_mount	*mp = ip->i_mount;
@@ -526,11 +524,11 @@ xfs_can_free_eofblocks(
		return false;

	/*
	 * Do not free real preallocated or append-only files unless the file
	 * has delalloc blocks and we are forced to remove them.
	 * Only free real extents for inodes with persistent preallocations or
	 * the append-only flag.
	 */
	if (ip->i_diflags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND))
		if (!force || ip->i_delayed_blks == 0)
		if (ip->i_delayed_blks == 0)
			return false;

	/*
@@ -584,6 +582,22 @@ xfs_free_eofblocks(
	/* Wait on dio to ensure i_size has settled. */
	inode_dio_wait(VFS_I(ip));

	/*
	 * For preallocated files only free delayed allocations.
	 *
	 * Note that this means we also leave speculative preallocations in
	 * place for preallocated files.
	 */
	if (ip->i_diflags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) {
		if (ip->i_delayed_blks) {
			xfs_bmap_punch_delalloc_range(ip,
				round_up(XFS_ISIZE(ip), mp->m_sb.sb_blocksize),
				LLONG_MAX);
		}
		xfs_inode_clear_eofblocks_tag(ip);
		return 0;
	}

	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
	if (error) {
		ASSERT(xfs_is_shutdown(mp));
@@ -891,7 +905,7 @@ xfs_prepare_shift(
	 * Trim eofblocks to avoid shifting uninitialized post-eof preallocation
	 * into the accessible region of the file.
	 */
	if (xfs_can_free_eofblocks(ip, true)) {
	if (xfs_can_free_eofblocks(ip)) {
		error = xfs_free_eofblocks(ip);
		if (error)
			return error;
+1 −1
Original line number Diff line number Diff line
@@ -63,7 +63,7 @@ int xfs_insert_file_space(struct xfs_inode *, xfs_off_t offset,
				xfs_off_t len);

/* EOF block manipulation functions */
bool	xfs_can_free_eofblocks(struct xfs_inode *ip, bool force);
bool	xfs_can_free_eofblocks(struct xfs_inode *ip);
int	xfs_free_eofblocks(struct xfs_inode *ip);

int	xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip,
Loading