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

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
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_log.h" #include "xfs_log.h"
#include "xfs_icache.h" #include "xfs_icache.h"
#include "xfs_pnfs.h"
#include <linux/aio.h> #include <linux/aio.h>
#include <linux/dcache.h> #include <linux/dcache.h>
...@@ -554,6 +555,10 @@ xfs_file_aio_write_checks( ...@@ -554,6 +555,10 @@ xfs_file_aio_write_checks(
if (error) if (error)
return 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 * 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 * blocks that fall between the existing EOF and the start of this
...@@ -822,6 +827,7 @@ xfs_file_fallocate( ...@@ -822,6 +827,7 @@ xfs_file_fallocate(
struct xfs_inode *ip = XFS_I(inode); struct xfs_inode *ip = XFS_I(inode);
long error; long error;
enum xfs_prealloc_flags flags = 0; enum xfs_prealloc_flags flags = 0;
uint iolock = XFS_IOLOCK_EXCL;
loff_t new_size = 0; loff_t new_size = 0;
if (!S_ISREG(inode->i_mode)) if (!S_ISREG(inode->i_mode))
...@@ -830,7 +836,11 @@ xfs_file_fallocate( ...@@ -830,7 +836,11 @@ xfs_file_fallocate(
FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE)) FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE))
return -EOPNOTSUPP; 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) { if (mode & FALLOC_FL_PUNCH_HOLE) {
error = xfs_free_file_space(ip, offset, len); error = xfs_free_file_space(ip, offset, len);
if (error) if (error)
...@@ -894,7 +904,7 @@ xfs_file_fallocate( ...@@ -894,7 +904,7 @@ xfs_file_fallocate(
} }
out_unlock: out_unlock:
xfs_iunlock(ip, XFS_IOLOCK_EXCL); xfs_iunlock(ip, iolock);
return error; return error;
} }
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include "xfs_icache.h" #include "xfs_icache.h"
#include "xfs_symlink.h" #include "xfs_symlink.h"
#include "xfs_trans.h" #include "xfs_trans.h"
#include "xfs_pnfs.h"
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/dcache.h> #include <linux/dcache.h>
...@@ -608,6 +609,7 @@ xfs_ioc_space( ...@@ -608,6 +609,7 @@ xfs_ioc_space(
{ {
struct iattr iattr; struct iattr iattr;
enum xfs_prealloc_flags flags = 0; enum xfs_prealloc_flags flags = 0;
uint iolock = XFS_IOLOCK_EXCL;
int error; int error;
/* /*
...@@ -636,7 +638,10 @@ xfs_ioc_space( ...@@ -636,7 +638,10 @@ xfs_ioc_space(
if (error) if (error)
return 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) { switch (bf->l_whence) {
case 0: /*SEEK_SET*/ case 0: /*SEEK_SET*/
...@@ -725,7 +730,7 @@ xfs_ioc_space( ...@@ -725,7 +730,7 @@ xfs_ioc_space(
error = xfs_update_prealloc_flags(ip, flags); error = xfs_update_prealloc_flags(ip, flags);
out_unlock: out_unlock:
xfs_iunlock(ip, XFS_IOLOCK_EXCL); xfs_iunlock(ip, iolock);
mnt_drop_write_file(filp); mnt_drop_write_file(filp);
return error; return error;
} }
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "xfs_da_btree.h" #include "xfs_da_btree.h"
#include "xfs_dir2.h" #include "xfs_dir2.h"
#include "xfs_trans_space.h" #include "xfs_trans_space.h"
#include "xfs_pnfs.h"
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/xattr.h> #include <linux/xattr.h>
...@@ -979,9 +980,13 @@ xfs_vn_setattr( ...@@ -979,9 +980,13 @@ xfs_vn_setattr(
int error; int error;
if (iattr->ia_valid & ATTR_SIZE) { if (iattr->ia_valid & ATTR_SIZE) {
xfs_ilock(ip, XFS_IOLOCK_EXCL); uint iolock = XFS_IOLOCK_EXCL;
error = xfs_setattr_size(ip, iattr);
xfs_iunlock(ip, 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, iolock);
} else { } else {
error = xfs_setattr_nonsize(ip, iattr, 0); error = xfs_setattr_nonsize(ip, iattr, 0);
} }
......
...@@ -18,6 +18,36 @@ ...@@ -18,6 +18,36 @@
#include "xfs_bit.h" #include "xfs_bit.h"
#include "xfs_pnfs.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 * Get a unique ID including its location so that the client can identify
* the exported device. * the exported device.
......
...@@ -7,5 +7,12 @@ int xfs_fs_map_blocks(struct inode *inode, loff_t offset, u64 length, ...@@ -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); struct iomap *iomap, bool write, u32 *device_generation);
int xfs_fs_commit_blocks(struct inode *inode, struct iomap *maps, int nr_maps, int xfs_fs_commit_blocks(struct inode *inode, struct iomap *maps, int nr_maps,
struct iattr *iattr); 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 /* CONFIG_NFSD_PNFS */
#endif /* _XFS_PNFS_H */ #endif /* _XFS_PNFS_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment