aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2015-02-15 19:59:50 -0500
committerDave Chinner <david@fromorbit.com>2015-02-15 19:59:50 -0500
commit781355c6e5ae87908de27dec3380a34918c33eee (patch)
tree9c747dd4207fae358368c3217d5e71f7d3a0af38
parent527851124d10f9c50b1c578e0a56fcd49922422d (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.c14
-rw-r--r--fs/xfs/xfs_ioctl.c9
-rw-r--r--fs/xfs/xfs_iops.c11
-rw-r--r--fs/xfs/xfs_pnfs.c30
-rw-r--r--fs/xfs/xfs_pnfs.h7
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
896out_unlock: 906out_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
727out_unlock: 732out_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 */
31int
32xfs_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);
8int xfs_fs_commit_blocks(struct inode *inode, struct iomap *maps, int nr_maps, 8int xfs_fs_commit_blocks(struct inode *inode, struct iomap *maps, int nr_maps,
9 struct iattr *iattr); 9 struct iattr *iattr);
10
11int xfs_break_layouts(struct inode *inode, uint *iolock);
12#else
13static 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 */