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:
parent
527851124d
commit
781355c6e5
5 changed files with 64 additions and 7 deletions
|
@ -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 @@ restart:
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
error = xfs_setattr_size(ip, iattr);
|
||||
xfs_iunlock(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, iolock);
|
||||
} else {
|
||||
error = xfs_setattr_nonsize(ip, iattr, 0);
|
||||
}
|
||||
|
|
|
@ -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,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 */
|
||||
|
|
Loading…
Reference in a new issue