diff options
author | Christoph Hellwig <hch@lst.de> | 2015-02-15 19:59:50 -0500 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2015-02-15 19:59:50 -0500 |
commit | 781355c6e5ae87908de27dec3380a34918c33eee (patch) | |
tree | 9c747dd4207fae358368c3217d5e71f7d3a0af38 | |
parent | 527851124d10f9c50b1c578e0a56fcd49922422d (diff) |
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>
-rw-r--r-- | fs/xfs/xfs_file.c | 14 | ||||
-rw-r--r-- | fs/xfs/xfs_ioctl.c | 9 | ||||
-rw-r--r-- | fs/xfs/xfs_iops.c | 11 | ||||
-rw-r--r-- | fs/xfs/xfs_pnfs.c | 30 | ||||
-rw-r--r-- | fs/xfs/xfs_pnfs.h | 7 |
5 files changed, 64 insertions, 7 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 712d312d8e3e..56dcfce8d7d6 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include "xfs_trace.h" | 36 | #include "xfs_trace.h" |
37 | #include "xfs_log.h" | 37 | #include "xfs_log.h" |
38 | #include "xfs_icache.h" | 38 | #include "xfs_icache.h" |
39 | #include "xfs_pnfs.h" | ||
39 | 40 | ||
40 | #include <linux/aio.h> | 41 | #include <linux/aio.h> |
41 | #include <linux/dcache.h> | 42 | #include <linux/dcache.h> |
@@ -554,6 +555,10 @@ restart: | |||
554 | if (error) | 555 | if (error) |
555 | return error; | 556 | return error; |
556 | 557 | ||
558 | error = xfs_break_layouts(inode, iolock); | ||
559 | if (error) | ||
560 | return error; | ||
561 | |||
557 | /* | 562 | /* |
558 | * If the offset is beyond the size of the file, we need to zero any | 563 | * If the offset is beyond the size of the file, we need to zero any |
559 | * blocks that fall between the existing EOF and the start of this | 564 | * blocks that fall between the existing EOF and the start of this |
@@ -822,6 +827,7 @@ xfs_file_fallocate( | |||
822 | struct xfs_inode *ip = XFS_I(inode); | 827 | struct xfs_inode *ip = XFS_I(inode); |
823 | long error; | 828 | long error; |
824 | enum xfs_prealloc_flags flags = 0; | 829 | enum xfs_prealloc_flags flags = 0; |
830 | uint iolock = XFS_IOLOCK_EXCL; | ||
825 | loff_t new_size = 0; | 831 | loff_t new_size = 0; |
826 | 832 | ||
827 | if (!S_ISREG(inode->i_mode)) | 833 | if (!S_ISREG(inode->i_mode)) |
@@ -830,7 +836,11 @@ xfs_file_fallocate( | |||
830 | FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE)) | 836 | FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE)) |
831 | return -EOPNOTSUPP; | 837 | return -EOPNOTSUPP; |
832 | 838 | ||
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 | |||
834 | if (mode & FALLOC_FL_PUNCH_HOLE) { | 844 | if (mode & FALLOC_FL_PUNCH_HOLE) { |
835 | error = xfs_free_file_space(ip, offset, len); | 845 | error = xfs_free_file_space(ip, offset, len); |
836 | if (error) | 846 | if (error) |
@@ -894,7 +904,7 @@ xfs_file_fallocate( | |||
894 | } | 904 | } |
895 | 905 | ||
896 | out_unlock: | 906 | out_unlock: |
897 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 907 | xfs_iunlock(ip, iolock); |
898 | return error; | 908 | return error; |
899 | } | 909 | } |
900 | 910 | ||
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index f7afb86c9148..bf70a2affb05 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include "xfs_icache.h" | 39 | #include "xfs_icache.h" |
40 | #include "xfs_symlink.h" | 40 | #include "xfs_symlink.h" |
41 | #include "xfs_trans.h" | 41 | #include "xfs_trans.h" |
42 | #include "xfs_pnfs.h" | ||
42 | 43 | ||
43 | #include <linux/capability.h> | 44 | #include <linux/capability.h> |
44 | #include <linux/dcache.h> | 45 | #include <linux/dcache.h> |
@@ -608,6 +609,7 @@ xfs_ioc_space( | |||
608 | { | 609 | { |
609 | struct iattr iattr; | 610 | struct iattr iattr; |
610 | enum xfs_prealloc_flags flags = 0; | 611 | enum xfs_prealloc_flags flags = 0; |
612 | uint iolock = XFS_IOLOCK_EXCL; | ||
611 | int error; | 613 | int error; |
612 | 614 | ||
613 | /* | 615 | /* |
@@ -636,7 +638,10 @@ xfs_ioc_space( | |||
636 | if (error) | 638 | if (error) |
637 | return error; | 639 | return error; |
638 | 640 | ||
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; | ||
640 | 645 | ||
641 | switch (bf->l_whence) { | 646 | switch (bf->l_whence) { |
642 | case 0: /*SEEK_SET*/ | 647 | case 0: /*SEEK_SET*/ |
@@ -725,7 +730,7 @@ xfs_ioc_space( | |||
725 | error = xfs_update_prealloc_flags(ip, flags); | 730 | error = xfs_update_prealloc_flags(ip, flags); |
726 | 731 | ||
727 | out_unlock: | 732 | out_unlock: |
728 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 733 | xfs_iunlock(ip, iolock); |
729 | mnt_drop_write_file(filp); | 734 | mnt_drop_write_file(filp); |
730 | return error; | 735 | return error; |
731 | } | 736 | } |
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index e5e2ea0d0b25..d919ad7b16bf 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include "xfs_da_btree.h" | 37 | #include "xfs_da_btree.h" |
38 | #include "xfs_dir2.h" | 38 | #include "xfs_dir2.h" |
39 | #include "xfs_trans_space.h" | 39 | #include "xfs_trans_space.h" |
40 | #include "xfs_pnfs.h" | ||
40 | 41 | ||
41 | #include <linux/capability.h> | 42 | #include <linux/capability.h> |
42 | #include <linux/xattr.h> | 43 | #include <linux/xattr.h> |
@@ -979,9 +980,13 @@ xfs_vn_setattr( | |||
979 | int error; | 980 | int error; |
980 | 981 | ||
981 | if (iattr->ia_valid & ATTR_SIZE) { | 982 | if (iattr->ia_valid & ATTR_SIZE) { |
982 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | 983 | uint iolock = XFS_IOLOCK_EXCL; |
983 | error = xfs_setattr_size(ip, iattr); | 984 | |
984 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 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); | ||
985 | } else { | 990 | } else { |
986 | error = xfs_setattr_nonsize(ip, iattr, 0); | 991 | error = xfs_setattr_nonsize(ip, iattr, 0); |
987 | } | 992 | } |
diff --git a/fs/xfs/xfs_pnfs.c b/fs/xfs/xfs_pnfs.c index 89912b34f184..4b33ef112400 100644 --- a/fs/xfs/xfs_pnfs.c +++ b/fs/xfs/xfs_pnfs.c | |||
@@ -19,6 +19,36 @@ | |||
19 | #include "xfs_pnfs.h" | 19 | #include "xfs_pnfs.h" |
20 | 20 | ||
21 | /* | 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 | |||
51 | /* | ||
22 | * Get a unique ID including its location so that the client can identify | 52 | * Get a unique ID including its location so that the client can identify |
23 | * the exported device. | 53 | * the exported device. |
24 | */ | 54 | */ |
diff --git a/fs/xfs/xfs_pnfs.h b/fs/xfs/xfs_pnfs.h index 0d91255a89ae..b7fbfce660f6 100644 --- a/fs/xfs/xfs_pnfs.h +++ b/fs/xfs/xfs_pnfs.h | |||
@@ -7,5 +7,12 @@ int xfs_fs_map_blocks(struct inode *inode, loff_t offset, u64 length, | |||
7 | struct iomap *iomap, bool write, u32 *device_generation); | 7 | struct iomap *iomap, bool write, u32 *device_generation); |
8 | int xfs_fs_commit_blocks(struct inode *inode, struct iomap *maps, int nr_maps, | 8 | int xfs_fs_commit_blocks(struct inode *inode, struct iomap *maps, int nr_maps, |
9 | struct iattr *iattr); | 9 | 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 | } | ||
10 | #endif /* CONFIG_NFSD_PNFS */ | 17 | #endif /* CONFIG_NFSD_PNFS */ |
11 | #endif /* _XFS_PNFS_H */ | 18 | #endif /* _XFS_PNFS_H */ |