diff options
-rw-r--r-- | fs/xfs/xfs_file.c | 26 | ||||
-rw-r--r-- | fs/xfs/xfs_inode.h | 16 | ||||
-rw-r--r-- | fs/xfs/xfs_ioctl.c | 3 | ||||
-rw-r--r-- | fs/xfs/xfs_iops.c | 6 | ||||
-rw-r--r-- | fs/xfs/xfs_pnfs.c | 12 | ||||
-rw-r--r-- | fs/xfs/xfs_pnfs.h | 5 |
6 files changed, 53 insertions, 15 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 35309bd046be..4774c7172ef4 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -312,7 +312,7 @@ restart: | |||
312 | if (error <= 0) | 312 | if (error <= 0) |
313 | return error; | 313 | return error; |
314 | 314 | ||
315 | error = xfs_break_layouts(inode, iolock); | 315 | error = xfs_break_layouts(inode, iolock, BREAK_WRITE); |
316 | if (error) | 316 | if (error) |
317 | return error; | 317 | return error; |
318 | 318 | ||
@@ -718,6 +718,28 @@ buffered: | |||
718 | return ret; | 718 | return ret; |
719 | } | 719 | } |
720 | 720 | ||
721 | int | ||
722 | xfs_break_layouts( | ||
723 | struct inode *inode, | ||
724 | uint *iolock, | ||
725 | enum layout_break_reason reason) | ||
726 | { | ||
727 | bool retry; | ||
728 | |||
729 | ASSERT(xfs_isilocked(XFS_I(inode), XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL)); | ||
730 | |||
731 | switch (reason) { | ||
732 | case BREAK_UNMAP: | ||
733 | ASSERT(xfs_isilocked(XFS_I(inode), XFS_MMAPLOCK_EXCL)); | ||
734 | /* fall through */ | ||
735 | case BREAK_WRITE: | ||
736 | return xfs_break_leased_layouts(inode, iolock, &retry); | ||
737 | default: | ||
738 | WARN_ON_ONCE(1); | ||
739 | return -EINVAL; | ||
740 | } | ||
741 | } | ||
742 | |||
721 | #define XFS_FALLOC_FL_SUPPORTED \ | 743 | #define XFS_FALLOC_FL_SUPPORTED \ |
722 | (FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | \ | 744 | (FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | \ |
723 | FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE | \ | 745 | FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE | \ |
@@ -744,7 +766,7 @@ xfs_file_fallocate( | |||
744 | return -EOPNOTSUPP; | 766 | return -EOPNOTSUPP; |
745 | 767 | ||
746 | xfs_ilock(ip, iolock); | 768 | xfs_ilock(ip, iolock); |
747 | error = xfs_break_layouts(inode, &iolock); | 769 | error = xfs_break_layouts(inode, &iolock, BREAK_UNMAP); |
748 | if (error) | 770 | if (error) |
749 | goto out_unlock; | 771 | goto out_unlock; |
750 | 772 | ||
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 1eebc53df7d7..e5b849815ce1 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
@@ -379,6 +379,20 @@ static inline void xfs_ifunlock(struct xfs_inode *ip) | |||
379 | >> XFS_ILOCK_SHIFT) | 379 | >> XFS_ILOCK_SHIFT) |
380 | 380 | ||
381 | /* | 381 | /* |
382 | * Layouts are broken in the BREAK_WRITE case to ensure that | ||
383 | * layout-holders do not collide with local writes. Additionally, | ||
384 | * layouts are broken in the BREAK_UNMAP case to make sure the | ||
385 | * layout-holder has a consistent view of the file's extent map. While | ||
386 | * BREAK_WRITE breaks can be satisfied by recalling FL_LAYOUT leases, | ||
387 | * BREAK_UNMAP breaks additionally require waiting for busy dax-pages to | ||
388 | * go idle. | ||
389 | */ | ||
390 | enum layout_break_reason { | ||
391 | BREAK_WRITE, | ||
392 | BREAK_UNMAP, | ||
393 | }; | ||
394 | |||
395 | /* | ||
382 | * For multiple groups support: if S_ISGID bit is set in the parent | 396 | * For multiple groups support: if S_ISGID bit is set in the parent |
383 | * directory, group of new file is set to that of the parent, and | 397 | * directory, group of new file is set to that of the parent, and |
384 | * new subdirectory gets S_ISGID bit from parent. | 398 | * new subdirectory gets S_ISGID bit from parent. |
@@ -443,6 +457,8 @@ enum xfs_prealloc_flags { | |||
443 | 457 | ||
444 | int xfs_update_prealloc_flags(struct xfs_inode *ip, | 458 | int xfs_update_prealloc_flags(struct xfs_inode *ip, |
445 | enum xfs_prealloc_flags flags); | 459 | enum xfs_prealloc_flags flags); |
460 | int xfs_break_layouts(struct inode *inode, uint *iolock, | ||
461 | enum layout_break_reason reason); | ||
446 | 462 | ||
447 | /* from xfs_iops.c */ | 463 | /* from xfs_iops.c */ |
448 | extern void xfs_setup_inode(struct xfs_inode *ip); | 464 | extern void xfs_setup_inode(struct xfs_inode *ip); |
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index 4151fade4bb1..91e73d663099 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c | |||
@@ -39,7 +39,6 @@ | |||
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" | ||
43 | #include "xfs_acl.h" | 42 | #include "xfs_acl.h" |
44 | #include "xfs_btree.h" | 43 | #include "xfs_btree.h" |
45 | #include <linux/fsmap.h> | 44 | #include <linux/fsmap.h> |
@@ -644,7 +643,7 @@ xfs_ioc_space( | |||
644 | return error; | 643 | return error; |
645 | 644 | ||
646 | xfs_ilock(ip, iolock); | 645 | xfs_ilock(ip, iolock); |
647 | error = xfs_break_layouts(inode, &iolock); | 646 | error = xfs_break_layouts(inode, &iolock, BREAK_UNMAP); |
648 | if (error) | 647 | if (error) |
649 | goto out_unlock; | 648 | goto out_unlock; |
650 | 649 | ||
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 138fb36ca875..ce0c1f9466a8 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c | |||
@@ -37,7 +37,6 @@ | |||
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" | ||
41 | #include "xfs_iomap.h" | 40 | #include "xfs_iomap.h" |
42 | 41 | ||
43 | #include <linux/capability.h> | 42 | #include <linux/capability.h> |
@@ -1030,13 +1029,14 @@ xfs_vn_setattr( | |||
1030 | int error; | 1029 | int error; |
1031 | 1030 | ||
1032 | if (iattr->ia_valid & ATTR_SIZE) { | 1031 | if (iattr->ia_valid & ATTR_SIZE) { |
1033 | struct xfs_inode *ip = XFS_I(d_inode(dentry)); | 1032 | struct inode *inode = d_inode(dentry); |
1033 | struct xfs_inode *ip = XFS_I(inode); | ||
1034 | uint iolock; | 1034 | uint iolock; |
1035 | 1035 | ||
1036 | xfs_ilock(ip, XFS_MMAPLOCK_EXCL); | 1036 | xfs_ilock(ip, XFS_MMAPLOCK_EXCL); |
1037 | iolock = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL; | 1037 | iolock = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL; |
1038 | 1038 | ||
1039 | error = xfs_break_layouts(d_inode(dentry), &iolock); | 1039 | error = xfs_break_layouts(inode, &iolock, BREAK_UNMAP); |
1040 | if (error) { | 1040 | if (error) { |
1041 | xfs_iunlock(ip, XFS_MMAPLOCK_EXCL); | 1041 | xfs_iunlock(ip, XFS_MMAPLOCK_EXCL); |
1042 | return error; | 1042 | return error; |
diff --git a/fs/xfs/xfs_pnfs.c b/fs/xfs/xfs_pnfs.c index 6ea7b0b55d02..f44c3599527d 100644 --- a/fs/xfs/xfs_pnfs.c +++ b/fs/xfs/xfs_pnfs.c | |||
@@ -31,17 +31,17 @@ | |||
31 | * rules in the page fault path we don't bother. | 31 | * rules in the page fault path we don't bother. |
32 | */ | 32 | */ |
33 | int | 33 | int |
34 | xfs_break_layouts( | 34 | xfs_break_leased_layouts( |
35 | struct inode *inode, | 35 | struct inode *inode, |
36 | uint *iolock) | 36 | uint *iolock, |
37 | bool *did_unlock) | ||
37 | { | 38 | { |
38 | struct xfs_inode *ip = XFS_I(inode); | 39 | struct xfs_inode *ip = XFS_I(inode); |
39 | int error; | 40 | int error; |
40 | 41 | ||
41 | ASSERT(xfs_isilocked(ip, XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL)); | ||
42 | |||
43 | while ((error = break_layout(inode, false) == -EWOULDBLOCK)) { | 42 | while ((error = break_layout(inode, false) == -EWOULDBLOCK)) { |
44 | xfs_iunlock(ip, *iolock); | 43 | xfs_iunlock(ip, *iolock); |
44 | *did_unlock = true; | ||
45 | error = break_layout(inode, true); | 45 | error = break_layout(inode, true); |
46 | *iolock &= ~XFS_IOLOCK_SHARED; | 46 | *iolock &= ~XFS_IOLOCK_SHARED; |
47 | *iolock |= XFS_IOLOCK_EXCL; | 47 | *iolock |= XFS_IOLOCK_EXCL; |
@@ -121,8 +121,8 @@ xfs_fs_map_blocks( | |||
121 | * Lock out any other I/O before we flush and invalidate the pagecache, | 121 | * Lock out any other I/O before we flush and invalidate the pagecache, |
122 | * and then hand out a layout to the remote system. This is very | 122 | * and then hand out a layout to the remote system. This is very |
123 | * similar to direct I/O, except that the synchronization is much more | 123 | * similar to direct I/O, except that the synchronization is much more |
124 | * complicated. See the comment near xfs_break_layouts for a detailed | 124 | * complicated. See the comment near xfs_break_leased_layouts |
125 | * explanation. | 125 | * for a detailed explanation. |
126 | */ | 126 | */ |
127 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | 127 | xfs_ilock(ip, XFS_IOLOCK_EXCL); |
128 | 128 | ||
diff --git a/fs/xfs/xfs_pnfs.h b/fs/xfs/xfs_pnfs.h index bf45951e28fe..940c6c2ad88c 100644 --- a/fs/xfs/xfs_pnfs.h +++ b/fs/xfs/xfs_pnfs.h | |||
@@ -9,10 +9,11 @@ int xfs_fs_map_blocks(struct inode *inode, loff_t offset, u64 length, | |||
9 | int xfs_fs_commit_blocks(struct inode *inode, struct iomap *maps, int nr_maps, | 9 | int xfs_fs_commit_blocks(struct inode *inode, struct iomap *maps, int nr_maps, |
10 | struct iattr *iattr); | 10 | struct iattr *iattr); |
11 | 11 | ||
12 | int xfs_break_layouts(struct inode *inode, uint *iolock); | 12 | int xfs_break_leased_layouts(struct inode *inode, uint *iolock, |
13 | bool *did_unlock); | ||
13 | #else | 14 | #else |
14 | static inline int | 15 | static inline int |
15 | xfs_break_layouts(struct inode *inode, uint *iolock) | 16 | xfs_break_leased_layouts(struct inode *inode, uint *iolock, bool *did_unlock) |
16 | { | 17 | { |
17 | return 0; | 18 | return 0; |
18 | } | 19 | } |