Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8add71ca authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Dave Chinner
Browse files

xfs: factor out a xfs_update_prealloc_flags() helper



This logic is duplicated in xfs_file_fallocate and xfs_ioc_space, and
we'll need another copy of it for pNFS block support.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent 4d949021
Loading
Loading
Loading
Loading
+42 −22
Original line number Original line Diff line number Diff line
@@ -127,6 +127,42 @@ xfs_iozero(
	return (-status);
	return (-status);
}
}


int
xfs_update_prealloc_flags(
	struct xfs_inode	*ip,
	enum xfs_prealloc_flags	flags)
{
	struct xfs_trans	*tp;
	int			error;

	tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_WRITEID);
	error = xfs_trans_reserve(tp, &M_RES(ip->i_mount)->tr_writeid, 0, 0);
	if (error) {
		xfs_trans_cancel(tp, 0);
		return error;
	}

	xfs_ilock(ip, XFS_ILOCK_EXCL);
	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);

	if (!(flags & XFS_PREALLOC_INVISIBLE)) {
		ip->i_d.di_mode &= ~S_ISUID;
		if (ip->i_d.di_mode & S_IXGRP)
			ip->i_d.di_mode &= ~S_ISGID;
		xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
	}

	if (flags & XFS_PREALLOC_SET)
		ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC;
	if (flags & XFS_PREALLOC_CLEAR)
		ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC;

	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
	if (flags & XFS_PREALLOC_SYNC)
		xfs_trans_set_sync(tp);
	return xfs_trans_commit(tp, 0);
}

/*
/*
 * Fsync operations on directories are much simpler than on regular files,
 * Fsync operations on directories are much simpler than on regular files,
 * as there is no file data to flush, and thus also no need for explicit
 * as there is no file data to flush, and thus also no need for explicit
@@ -784,8 +820,8 @@ xfs_file_fallocate(
{
{
	struct inode		*inode = file_inode(file);
	struct inode		*inode = file_inode(file);
	struct xfs_inode	*ip = XFS_I(inode);
	struct xfs_inode	*ip = XFS_I(inode);
	struct xfs_trans	*tp;
	long			error;
	long			error;
	enum xfs_prealloc_flags	flags = 0;
	loff_t			new_size = 0;
	loff_t			new_size = 0;


	if (!S_ISREG(inode->i_mode))
	if (!S_ISREG(inode->i_mode))
@@ -822,6 +858,8 @@ xfs_file_fallocate(
		if (error)
		if (error)
			goto out_unlock;
			goto out_unlock;
	} else {
	} else {
		flags |= XFS_PREALLOC_SET;

		if (!(mode & FALLOC_FL_KEEP_SIZE) &&
		if (!(mode & FALLOC_FL_KEEP_SIZE) &&
		    offset + len > i_size_read(inode)) {
		    offset + len > i_size_read(inode)) {
			new_size = offset + len;
			new_size = offset + len;
@@ -839,28 +877,10 @@ xfs_file_fallocate(
			goto out_unlock;
			goto out_unlock;
	}
	}


	tp = xfs_trans_alloc(ip->i_mount, XFS_TRANS_WRITEID);
	error = xfs_trans_reserve(tp, &M_RES(ip->i_mount)->tr_writeid, 0, 0);
	if (error) {
		xfs_trans_cancel(tp, 0);
		goto out_unlock;
	}

	xfs_ilock(ip, XFS_ILOCK_EXCL);
	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
	ip->i_d.di_mode &= ~S_ISUID;
	if (ip->i_d.di_mode & S_IXGRP)
		ip->i_d.di_mode &= ~S_ISGID;

	if (!(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE)))
		ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC;

	xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);

	if (file->f_flags & O_DSYNC)
	if (file->f_flags & O_DSYNC)
		xfs_trans_set_sync(tp);
		flags |= XFS_PREALLOC_SYNC;
	error = xfs_trans_commit(tp, 0);

	error = xfs_update_prealloc_flags(ip, flags);
	if (error)
	if (error)
		goto out_unlock;
		goto out_unlock;


+9 −0
Original line number Original line Diff line number Diff line
@@ -377,6 +377,15 @@ int xfs_droplink(struct xfs_trans *, struct xfs_inode *);
int		xfs_bumplink(struct xfs_trans *, struct xfs_inode *);
int		xfs_bumplink(struct xfs_trans *, struct xfs_inode *);


/* from xfs_file.c */
/* from xfs_file.c */
enum xfs_prealloc_flags {
	XFS_PREALLOC_SET	= (1 << 1),
	XFS_PREALLOC_CLEAR	= (1 << 2),
	XFS_PREALLOC_SYNC	= (1 << 3),
	XFS_PREALLOC_INVISIBLE	= (1 << 4),
};

int		xfs_update_prealloc_flags(struct xfs_inode *,
			enum xfs_prealloc_flags);
int		xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t);
int		xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t);
int		xfs_iozero(struct xfs_inode *, loff_t, size_t);
int		xfs_iozero(struct xfs_inode *, loff_t, size_t);


+12 −38
Original line number Original line Diff line number Diff line
@@ -606,11 +606,8 @@ xfs_ioc_space(
	unsigned int		cmd,
	unsigned int		cmd,
	xfs_flock64_t		*bf)
	xfs_flock64_t		*bf)
{
{
	struct xfs_mount	*mp = ip->i_mount;
	struct xfs_trans	*tp;
	struct iattr		iattr;
	struct iattr		iattr;
	bool			setprealloc = false;
	enum xfs_prealloc_flags	flags = 0;
	bool			clrprealloc = false;
	int			error;
	int			error;


	/*
	/*
@@ -630,6 +627,11 @@ xfs_ioc_space(
	if (!S_ISREG(inode->i_mode))
	if (!S_ISREG(inode->i_mode))
		return -EINVAL;
		return -EINVAL;


	if (filp->f_flags & O_DSYNC)
		flags |= XFS_PREALLOC_SYNC;
	if (ioflags & XFS_IO_INVIS)	
		flags |= XFS_PREALLOC_INVISIBLE;

	error = mnt_want_write_file(filp);
	error = mnt_want_write_file(filp);
	if (error)
	if (error)
		return error;
		return error;
@@ -673,25 +675,23 @@ xfs_ioc_space(
	}
	}


	if (bf->l_start < 0 ||
	if (bf->l_start < 0 ||
	    bf->l_start > mp->m_super->s_maxbytes ||
	    bf->l_start > inode->i_sb->s_maxbytes ||
	    bf->l_start + bf->l_len < 0 ||
	    bf->l_start + bf->l_len < 0 ||
	    bf->l_start + bf->l_len >= mp->m_super->s_maxbytes) {
	    bf->l_start + bf->l_len >= inode->i_sb->s_maxbytes) {
		error = -EINVAL;
		error = -EINVAL;
		goto out_unlock;
		goto out_unlock;
	}
	}


	switch (cmd) {
	switch (cmd) {
	case XFS_IOC_ZERO_RANGE:
	case XFS_IOC_ZERO_RANGE:
		flags |= XFS_PREALLOC_SET;
		error = xfs_zero_file_space(ip, bf->l_start, bf->l_len);
		error = xfs_zero_file_space(ip, bf->l_start, bf->l_len);
		if (!error)
			setprealloc = true;
		break;
		break;
	case XFS_IOC_RESVSP:
	case XFS_IOC_RESVSP:
	case XFS_IOC_RESVSP64:
	case XFS_IOC_RESVSP64:
		flags |= XFS_PREALLOC_SET;
		error = xfs_alloc_file_space(ip, bf->l_start, bf->l_len,
		error = xfs_alloc_file_space(ip, bf->l_start, bf->l_len,
						XFS_BMAPI_PREALLOC);
						XFS_BMAPI_PREALLOC);
		if (!error)
			setprealloc = true;
		break;
		break;
	case XFS_IOC_UNRESVSP:
	case XFS_IOC_UNRESVSP:
	case XFS_IOC_UNRESVSP64:
	case XFS_IOC_UNRESVSP64:
@@ -701,6 +701,7 @@ xfs_ioc_space(
	case XFS_IOC_ALLOCSP64:
	case XFS_IOC_ALLOCSP64:
	case XFS_IOC_FREESP:
	case XFS_IOC_FREESP:
	case XFS_IOC_FREESP64:
	case XFS_IOC_FREESP64:
		flags |= XFS_PREALLOC_CLEAR;
		if (bf->l_start > XFS_ISIZE(ip)) {
		if (bf->l_start > XFS_ISIZE(ip)) {
			error = xfs_alloc_file_space(ip, XFS_ISIZE(ip),
			error = xfs_alloc_file_space(ip, XFS_ISIZE(ip),
					bf->l_start - XFS_ISIZE(ip), 0);
					bf->l_start - XFS_ISIZE(ip), 0);
@@ -712,8 +713,6 @@ xfs_ioc_space(
		iattr.ia_size = bf->l_start;
		iattr.ia_size = bf->l_start;


		error = xfs_setattr_size(ip, &iattr);
		error = xfs_setattr_size(ip, &iattr);
		if (!error)
			clrprealloc = true;
		break;
		break;
	default:
	default:
		ASSERT(0);
		ASSERT(0);
@@ -723,32 +722,7 @@ xfs_ioc_space(
	if (error)
	if (error)
		goto out_unlock;
		goto out_unlock;


	tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID);
	error = xfs_update_prealloc_flags(ip, flags);
	error = xfs_trans_reserve(tp, &M_RES(mp)->tr_writeid, 0, 0);
	if (error) {
		xfs_trans_cancel(tp, 0);
		goto out_unlock;
	}

	xfs_ilock(ip, XFS_ILOCK_EXCL);
	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);

	if (!(ioflags & XFS_IO_INVIS)) {
		ip->i_d.di_mode &= ~S_ISUID;
		if (ip->i_d.di_mode & S_IXGRP)
			ip->i_d.di_mode &= ~S_ISGID;
		xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
	}

	if (setprealloc)
		ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC;
	else if (clrprealloc)
		ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC;

	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
	if (filp->f_flags & O_DSYNC)
		xfs_trans_set_sync(tp);
	error = xfs_trans_commit(tp, 0);


out_unlock:
out_unlock:
	xfs_iunlock(ip, XFS_IOLOCK_EXCL);
	xfs_iunlock(ip, XFS_IOLOCK_EXCL);