Skip to content

Commit 781355c

Browse files
Christoph Hellwigdchinner
authored andcommitted
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>
1 parent 5278511 commit 781355c

File tree

5 files changed

+64
-7
lines changed

5 files changed

+64
-7
lines changed

fs/xfs/xfs_file.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "xfs_trace.h"
3737
#include "xfs_log.h"
3838
#include "xfs_icache.h"
39+
#include "xfs_pnfs.h"
3940

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

558+
error = xfs_break_layouts(inode, iolock);
559+
if (error)
560+
return error;
561+
557562
/*
558563
* If the offset is beyond the size of the file, we need to zero any
559564
* blocks that fall between the existing EOF and the start of this
@@ -822,6 +827,7 @@ xfs_file_fallocate(
822827
struct xfs_inode *ip = XFS_I(inode);
823828
long error;
824829
enum xfs_prealloc_flags flags = 0;
830+
uint iolock = XFS_IOLOCK_EXCL;
825831
loff_t new_size = 0;
826832

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

833-
xfs_ilock(ip, XFS_IOLOCK_EXCL);
839+
xfs_ilock(ip, iolock);
840+
error = xfs_break_layouts(inode, &iolock);
841+
if (error)
842+
goto out_unlock;
843+
834844
if (mode & FALLOC_FL_PUNCH_HOLE) {
835845
error = xfs_free_file_space(ip, offset, len);
836846
if (error)
@@ -894,7 +904,7 @@ xfs_file_fallocate(
894904
}
895905

896906
out_unlock:
897-
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
907+
xfs_iunlock(ip, iolock);
898908
return error;
899909
}
900910

fs/xfs/xfs_ioctl.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "xfs_icache.h"
4040
#include "xfs_symlink.h"
4141
#include "xfs_trans.h"
42+
#include "xfs_pnfs.h"
4243

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

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

639-
xfs_ilock(ip, XFS_IOLOCK_EXCL);
641+
xfs_ilock(ip, iolock);
642+
error = xfs_break_layouts(inode, &iolock);
643+
if (error)
644+
goto out_unlock;
640645

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

727732
out_unlock:
728-
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
733+
xfs_iunlock(ip, iolock);
729734
mnt_drop_write_file(filp);
730735
return error;
731736
}

fs/xfs/xfs_iops.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "xfs_da_btree.h"
3838
#include "xfs_dir2.h"
3939
#include "xfs_trans_space.h"
40+
#include "xfs_pnfs.h"
4041

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

981982
if (iattr->ia_valid & ATTR_SIZE) {
982-
xfs_ilock(ip, XFS_IOLOCK_EXCL);
983-
error = xfs_setattr_size(ip, iattr);
984-
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
983+
uint iolock = XFS_IOLOCK_EXCL;
984+
985+
xfs_ilock(ip, iolock);
986+
error = xfs_break_layouts(dentry->d_inode, &iolock);
987+
if (!error)
988+
error = xfs_setattr_size(ip, iattr);
989+
xfs_iunlock(ip, iolock);
985990
} else {
986991
error = xfs_setattr_nonsize(ip, iattr, 0);
987992
}

fs/xfs/xfs_pnfs.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,36 @@
1818
#include "xfs_bit.h"
1919
#include "xfs_pnfs.h"
2020

21+
/*
22+
* Ensure that we do not have any outstanding pNFS layouts that can be used by
23+
* clients to directly read from or write to this inode. This must be called
24+
* before every operation that can remove blocks from the extent map.
25+
* Additionally we call it during the write operation, where aren't concerned
26+
* about exposing unallocated blocks but just want to provide basic
27+
* synchronization between a local writer and pNFS clients. mmap writes would
28+
* also benefit from this sort of synchronization, but due to the tricky locking
29+
* rules in the page fault path we don't bother.
30+
*/
31+
int
32+
xfs_break_layouts(
33+
struct inode *inode,
34+
uint *iolock)
35+
{
36+
struct xfs_inode *ip = XFS_I(inode);
37+
int error;
38+
39+
ASSERT(xfs_isilocked(ip, XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL));
40+
41+
while ((error = break_layout(inode, false) == -EWOULDBLOCK)) {
42+
xfs_iunlock(ip, *iolock);
43+
error = break_layout(inode, true);
44+
*iolock = XFS_IOLOCK_EXCL;
45+
xfs_ilock(ip, *iolock);
46+
}
47+
48+
return error;
49+
}
50+
2151
/*
2252
* Get a unique ID including its location so that the client can identify
2353
* the exported device.

fs/xfs/xfs_pnfs.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,12 @@ int xfs_fs_map_blocks(struct inode *inode, loff_t offset, u64 length,
77
struct iomap *iomap, bool write, u32 *device_generation);
88
int xfs_fs_commit_blocks(struct inode *inode, struct iomap *maps, int nr_maps,
99
struct iattr *iattr);
10+
11+
int xfs_break_layouts(struct inode *inode, uint *iolock);
12+
#else
13+
static inline int xfs_break_layouts(struct inode *inode, uint *iolock)
14+
{
15+
return 0;
16+
}
1017
#endif /* CONFIG_NFSD_PNFS */
1118
#endif /* _XFS_PNFS_H */

0 commit comments

Comments
 (0)