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

Commit 781355c6 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Dave Chinner
Browse files

xfs: recall pNFS layouts on conflicting access



Recall all outstanding pNFS layouts and truncates, writes and similar extent
list modifying operations.

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 52785112
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include "xfs_trace.h"
#include "xfs_log.h"
#include "xfs_icache.h"
#include "xfs_pnfs.h"

#include <linux/aio.h>
#include <linux/dcache.h>
@@ -554,6 +555,10 @@ xfs_file_aio_write_checks(
	if (error)
		return error;

	error = xfs_break_layouts(inode, iolock);
	if (error)
		return error;

	/*
	 * If the offset is beyond the size of the file, we need to zero any
	 * blocks that fall between the existing EOF and the start of this
@@ -822,6 +827,7 @@ xfs_file_fallocate(
	struct xfs_inode	*ip = XFS_I(inode);
	long			error;
	enum xfs_prealloc_flags	flags = 0;
	uint			iolock = XFS_IOLOCK_EXCL;
	loff_t			new_size = 0;

	if (!S_ISREG(inode->i_mode))
@@ -830,7 +836,11 @@ xfs_file_fallocate(
		     FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE))
		return -EOPNOTSUPP;

	xfs_ilock(ip, XFS_IOLOCK_EXCL);
	xfs_ilock(ip, iolock);
	error = xfs_break_layouts(inode, &iolock);
	if (error)
		goto out_unlock;

	if (mode & FALLOC_FL_PUNCH_HOLE) {
		error = xfs_free_file_space(ip, offset, len);
		if (error)
@@ -894,7 +904,7 @@ xfs_file_fallocate(
	}

out_unlock:
	xfs_iunlock(ip, XFS_IOLOCK_EXCL);
	xfs_iunlock(ip, iolock);
	return error;
}

+7 −2
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#include "xfs_icache.h"
#include "xfs_symlink.h"
#include "xfs_trans.h"
#include "xfs_pnfs.h"

#include <linux/capability.h>
#include <linux/dcache.h>
@@ -608,6 +609,7 @@ xfs_ioc_space(
{
	struct iattr		iattr;
	enum xfs_prealloc_flags	flags = 0;
	uint			iolock = XFS_IOLOCK_EXCL;
	int			error;

	/*
@@ -636,7 +638,10 @@ xfs_ioc_space(
	if (error)
		return error;

	xfs_ilock(ip, XFS_IOLOCK_EXCL);
	xfs_ilock(ip, iolock);
	error = xfs_break_layouts(inode, &iolock);
	if (error)
		goto out_unlock;

	switch (bf->l_whence) {
	case 0: /*SEEK_SET*/
@@ -725,7 +730,7 @@ xfs_ioc_space(
	error = xfs_update_prealloc_flags(ip, flags);

out_unlock:
	xfs_iunlock(ip, XFS_IOLOCK_EXCL);
	xfs_iunlock(ip, iolock);
	mnt_drop_write_file(filp);
	return error;
}
+8 −3
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include "xfs_da_btree.h"
#include "xfs_dir2.h"
#include "xfs_trans_space.h"
#include "xfs_pnfs.h"

#include <linux/capability.h>
#include <linux/xattr.h>
@@ -979,9 +980,13 @@ xfs_vn_setattr(
	int			error;

	if (iattr->ia_valid & ATTR_SIZE) {
		xfs_ilock(ip, XFS_IOLOCK_EXCL);
		uint		iolock = XFS_IOLOCK_EXCL;

		xfs_ilock(ip, iolock);
		error = xfs_break_layouts(dentry->d_inode, &iolock);
		if (!error)
			error = xfs_setattr_size(ip, iattr);
		xfs_iunlock(ip, XFS_IOLOCK_EXCL);
		xfs_iunlock(ip, iolock);
	} else {
		error = xfs_setattr_nonsize(ip, iattr, 0);
	}
+30 −0
Original line number Diff line number Diff line
@@ -18,6 +18,36 @@
#include "xfs_bit.h"
#include "xfs_pnfs.h"

/*
 * Ensure that we do not have any outstanding pNFS layouts that can be used by
 * clients to directly read from or write to this inode.  This must be called
 * before every operation that can remove blocks from the extent map.
 * Additionally we call it during the write operation, where aren't concerned
 * about exposing unallocated blocks but just want to provide basic
 * synchronization between a local writer and pNFS clients.  mmap writes would
 * also benefit from this sort of synchronization, but due to the tricky locking
 * rules in the page fault path we don't bother.
 */
int
xfs_break_layouts(
	struct inode		*inode,
	uint			*iolock)
{
	struct xfs_inode	*ip = XFS_I(inode);
	int			error;

	ASSERT(xfs_isilocked(ip, XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL));

	while ((error = break_layout(inode, false) == -EWOULDBLOCK)) {
		xfs_iunlock(ip, *iolock);
		error = break_layout(inode, true);
		*iolock = XFS_IOLOCK_EXCL;
		xfs_ilock(ip, *iolock);
	}

	return error;
}

/*
 * Get a unique ID including its location so that the client can identify
 * the exported device.
+7 −0
Original line number Diff line number Diff line
@@ -7,5 +7,12 @@ int xfs_fs_map_blocks(struct inode *inode, loff_t offset, u64 length,
		struct iomap *iomap, bool write, u32 *device_generation);
int xfs_fs_commit_blocks(struct inode *inode, struct iomap *maps, int nr_maps,
		struct iattr *iattr);

int xfs_break_layouts(struct inode *inode, uint *iolock);
#else
static inline int xfs_break_layouts(struct inode *inode, uint *iolock)
{
	return 0;
}
#endif /* CONFIG_NFSD_PNFS */
#endif /* _XFS_PNFS_H */