Skip to content

Commit

Permalink
xfs: recall pNFS layouts on conflicting access
Browse files Browse the repository at this point in the history
Recall all outstanding pNFS layouts and truncates, writes and similar extent
list modifying operations.

Signed-off-by: Christoph Hellwig <[email protected]>
Reviewed-by: Dave Chinner <[email protected]>
Signed-off-by: Dave Chinner <[email protected]>
  • Loading branch information
Christoph Hellwig authored and dchinner committed Feb 16, 2015
1 parent 5278511 commit 781355c
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 7 deletions.
14 changes: 12 additions & 2 deletions fs/xfs/xfs_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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))
Expand All @@ -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)
Expand Down Expand Up @@ -894,7 +904,7 @@ xfs_file_fallocate(
}

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

Expand Down
9 changes: 7 additions & 2 deletions fs/xfs/xfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -608,6 +609,7 @@ xfs_ioc_space(
{
struct iattr iattr;
enum xfs_prealloc_flags flags = 0;
uint iolock = XFS_IOLOCK_EXCL;
int error;

/*
Expand Down Expand Up @@ -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*/
Expand Down Expand Up @@ -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;
}
Expand Down
11 changes: 8 additions & 3 deletions fs/xfs/xfs_iops.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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);
}
Expand Down
30 changes: 30 additions & 0 deletions fs/xfs/xfs_pnfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 7 additions & 0 deletions fs/xfs/xfs_pnfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

0 comments on commit 781355c

Please sign in to comment.