xfs: recall pNFS layouts on conflicting access

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

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
This commit is contained in:
Christoph Hellwig 2015-02-16 11:59:50 +11:00 committed by Dave Chinner
parent 527851124d
commit 781355c6e5
5 changed files with 64 additions and 7 deletions

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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.

View file

@ -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 */