diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-12 19:13:41 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-12 19:13:41 -0400 |
commit | e0ea4045bce3cee84e35746fb98946ca36781248 (patch) | |
tree | 71409476f4b9acb0b441de1bdb51bf035f1fc5ad | |
parent | 48efe453e6b29561f78a1df55c7f58375259cb8c (diff) | |
parent | 08474ed639e971e9d5a877cf7aba7ef91d847ae9 (diff) |
Merge tag 'xfs-for-linus-v3.12-rc1-2' of git://oss.sgi.com/xfs/xfs
Pull xfs update #2 from Ben Myers:
"Here we have defrag support for v5 superblock, a number of bugfixes
and a cleanup or two.
- defrag support for CRC filesystems
- fix endian worning in xlog_recover_get_buf_lsn
- fixes for sparse warnings
- fix for assert in xfs_dir3_leaf_hdr_from_disk
- fix for log recovery of remote symlinks
- fix for log recovery of btree root splits
- fixes formemory allocation failures with ACLs
- fix for assert in xfs_buf_item_relse
- fix for assert in xfs_inode_buf_verify
- fix an assignment in an assert that should be a test in
xfs_bmbt_change_owner
- remove dead code in xlog_recover_inode_pass2"
* tag 'xfs-for-linus-v3.12-rc1-2' of git://oss.sgi.com/xfs/xfs:
xfs: remove dead code from xlog_recover_inode_pass2
xfs: = vs == typo in ASSERT()
xfs: don't assert fail on bad inode numbers
xfs: aborted buf items can be in the AIL.
xfs: factor all the kmalloc-or-vmalloc fallback allocations
xfs: fix memory allocation failures with ACLs
xfs: ensure we copy buffer type in da btree root splits
xfs: set remote symlink buffer type for recovery
xfs: recovery of swap extents operations for CRC filesystems
xfs: swap extents operations for CRC filesystems
xfs: check magic numbers in dir3 leaf verifier first
xfs: fix some minor sparse warnings
xfs: fix endian warning in xlog_recover_get_buf_lsn()
-rw-r--r-- | fs/xfs/kmem.c | 15 | ||||
-rw-r--r-- | fs/xfs/kmem.h | 9 | ||||
-rw-r--r-- | fs/xfs/xfs_acl.c | 12 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap.c | 2 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap_btree.c | 44 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap_btree.h | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_bmap_util.c | 69 | ||||
-rw-r--r-- | fs/xfs/xfs_btree.c | 170 | ||||
-rw-r--r-- | fs/xfs/xfs_btree.h | 19 | ||||
-rw-r--r-- | fs/xfs/xfs_buf_item.c | 24 | ||||
-rw-r--r-- | fs/xfs/xfs_da_btree.c | 1 | ||||
-rw-r--r-- | fs/xfs/xfs_dir2_leaf.c | 20 | ||||
-rw-r--r-- | fs/xfs/xfs_dquot_item.c | 3 | ||||
-rw-r--r-- | fs/xfs/xfs_extent_busy.c | 3 | ||||
-rw-r--r-- | fs/xfs/xfs_icache.c | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_icache.h | 4 | ||||
-rw-r--r-- | fs/xfs/xfs_inode_buf.c | 10 | ||||
-rw-r--r-- | fs/xfs/xfs_inode_buf.h | 18 | ||||
-rw-r--r-- | fs/xfs/xfs_ioctl.c | 36 | ||||
-rw-r--r-- | fs/xfs/xfs_ioctl32.c | 18 | ||||
-rw-r--r-- | fs/xfs/xfs_itable.c | 7 | ||||
-rw-r--r-- | fs/xfs/xfs_log.c | 3 | ||||
-rw-r--r-- | fs/xfs/xfs_log_format.h | 8 | ||||
-rw-r--r-- | fs/xfs/xfs_log_recover.c | 122 | ||||
-rw-r--r-- | fs/xfs/xfs_symlink.c | 2 |
25 files changed, 461 insertions, 166 deletions
diff --git a/fs/xfs/kmem.c b/fs/xfs/kmem.c index 4a7286c1dc80..a02cfb9e3bce 100644 --- a/fs/xfs/kmem.c +++ b/fs/xfs/kmem.c | |||
@@ -27,8 +27,6 @@ | |||
27 | 27 | ||
28 | /* | 28 | /* |
29 | * Greedy allocation. May fail and may return vmalloced memory. | 29 | * Greedy allocation. May fail and may return vmalloced memory. |
30 | * | ||
31 | * Must be freed using kmem_free_large. | ||
32 | */ | 30 | */ |
33 | void * | 31 | void * |
34 | kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize) | 32 | kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize) |
@@ -36,7 +34,7 @@ kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize) | |||
36 | void *ptr; | 34 | void *ptr; |
37 | size_t kmsize = maxsize; | 35 | size_t kmsize = maxsize; |
38 | 36 | ||
39 | while (!(ptr = kmem_zalloc_large(kmsize))) { | 37 | while (!(ptr = vzalloc(kmsize))) { |
40 | if ((kmsize >>= 1) <= minsize) | 38 | if ((kmsize >>= 1) <= minsize) |
41 | kmsize = minsize; | 39 | kmsize = minsize; |
42 | } | 40 | } |
@@ -75,6 +73,17 @@ kmem_zalloc(size_t size, xfs_km_flags_t flags) | |||
75 | return ptr; | 73 | return ptr; |
76 | } | 74 | } |
77 | 75 | ||
76 | void * | ||
77 | kmem_zalloc_large(size_t size, xfs_km_flags_t flags) | ||
78 | { | ||
79 | void *ptr; | ||
80 | |||
81 | ptr = kmem_zalloc(size, flags | KM_MAYFAIL); | ||
82 | if (ptr) | ||
83 | return ptr; | ||
84 | return vzalloc(size); | ||
85 | } | ||
86 | |||
78 | void | 87 | void |
79 | kmem_free(const void *ptr) | 88 | kmem_free(const void *ptr) |
80 | { | 89 | { |
diff --git a/fs/xfs/kmem.h b/fs/xfs/kmem.h index b2f2620f9a87..3a7371cab508 100644 --- a/fs/xfs/kmem.h +++ b/fs/xfs/kmem.h | |||
@@ -57,17 +57,10 @@ kmem_flags_convert(xfs_km_flags_t flags) | |||
57 | 57 | ||
58 | extern void *kmem_alloc(size_t, xfs_km_flags_t); | 58 | extern void *kmem_alloc(size_t, xfs_km_flags_t); |
59 | extern void *kmem_zalloc(size_t, xfs_km_flags_t); | 59 | extern void *kmem_zalloc(size_t, xfs_km_flags_t); |
60 | extern void *kmem_zalloc_large(size_t size, xfs_km_flags_t); | ||
60 | extern void *kmem_realloc(const void *, size_t, size_t, xfs_km_flags_t); | 61 | extern void *kmem_realloc(const void *, size_t, size_t, xfs_km_flags_t); |
61 | extern void kmem_free(const void *); | 62 | extern void kmem_free(const void *); |
62 | 63 | ||
63 | static inline void *kmem_zalloc_large(size_t size) | ||
64 | { | ||
65 | return vzalloc(size); | ||
66 | } | ||
67 | static inline void kmem_free_large(void *ptr) | ||
68 | { | ||
69 | vfree(ptr); | ||
70 | } | ||
71 | 64 | ||
72 | extern void *kmem_zalloc_greedy(size_t *, size_t, size_t); | 65 | extern void *kmem_zalloc_greedy(size_t *, size_t, size_t); |
73 | 66 | ||
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 69518960b2ba..0e2f37efedd0 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c | |||
@@ -152,7 +152,7 @@ xfs_get_acl(struct inode *inode, int type) | |||
152 | * go out to the disk. | 152 | * go out to the disk. |
153 | */ | 153 | */ |
154 | len = XFS_ACL_MAX_SIZE(ip->i_mount); | 154 | len = XFS_ACL_MAX_SIZE(ip->i_mount); |
155 | xfs_acl = kzalloc(len, GFP_KERNEL); | 155 | xfs_acl = kmem_zalloc_large(len, KM_SLEEP); |
156 | if (!xfs_acl) | 156 | if (!xfs_acl) |
157 | return ERR_PTR(-ENOMEM); | 157 | return ERR_PTR(-ENOMEM); |
158 | 158 | ||
@@ -175,10 +175,10 @@ xfs_get_acl(struct inode *inode, int type) | |||
175 | if (IS_ERR(acl)) | 175 | if (IS_ERR(acl)) |
176 | goto out; | 176 | goto out; |
177 | 177 | ||
178 | out_update_cache: | 178 | out_update_cache: |
179 | set_cached_acl(inode, type, acl); | 179 | set_cached_acl(inode, type, acl); |
180 | out: | 180 | out: |
181 | kfree(xfs_acl); | 181 | kmem_free(xfs_acl); |
182 | return acl; | 182 | return acl; |
183 | } | 183 | } |
184 | 184 | ||
@@ -209,7 +209,7 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
209 | struct xfs_acl *xfs_acl; | 209 | struct xfs_acl *xfs_acl; |
210 | int len = XFS_ACL_MAX_SIZE(ip->i_mount); | 210 | int len = XFS_ACL_MAX_SIZE(ip->i_mount); |
211 | 211 | ||
212 | xfs_acl = kzalloc(len, GFP_KERNEL); | 212 | xfs_acl = kmem_zalloc_large(len, KM_SLEEP); |
213 | if (!xfs_acl) | 213 | if (!xfs_acl) |
214 | return -ENOMEM; | 214 | return -ENOMEM; |
215 | 215 | ||
@@ -222,7 +222,7 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
222 | error = -xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl, | 222 | error = -xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl, |
223 | len, ATTR_ROOT); | 223 | len, ATTR_ROOT); |
224 | 224 | ||
225 | kfree(xfs_acl); | 225 | kmem_free(xfs_acl); |
226 | } else { | 226 | } else { |
227 | /* | 227 | /* |
228 | * A NULL ACL argument means we want to remove the ACL. | 228 | * A NULL ACL argument means we want to remove the ACL. |
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 92b830901d60..f47e65c30be6 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -4450,7 +4450,7 @@ xfs_bmapi_write( | |||
4450 | { | 4450 | { |
4451 | struct xfs_mount *mp = ip->i_mount; | 4451 | struct xfs_mount *mp = ip->i_mount; |
4452 | struct xfs_ifork *ifp; | 4452 | struct xfs_ifork *ifp; |
4453 | struct xfs_bmalloca bma = { 0 }; /* args for xfs_bmap_alloc */ | 4453 | struct xfs_bmalloca bma = { NULL }; /* args for xfs_bmap_alloc */ |
4454 | xfs_fileoff_t end; /* end of mapped file region */ | 4454 | xfs_fileoff_t end; /* end of mapped file region */ |
4455 | int eof; /* after the end of extents */ | 4455 | int eof; /* after the end of extents */ |
4456 | int error; /* error return */ | 4456 | int error; /* error return */ |
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index cf3bc76710c3..bb8de8e399c4 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c | |||
@@ -925,3 +925,47 @@ xfs_bmdr_maxrecs( | |||
925 | return blocklen / sizeof(xfs_bmdr_rec_t); | 925 | return blocklen / sizeof(xfs_bmdr_rec_t); |
926 | return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t)); | 926 | return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t)); |
927 | } | 927 | } |
928 | |||
929 | /* | ||
930 | * Change the owner of a btree format fork fo the inode passed in. Change it to | ||
931 | * the owner of that is passed in so that we can change owners before or after | ||
932 | * we switch forks between inodes. The operation that the caller is doing will | ||
933 | * determine whether is needs to change owner before or after the switch. | ||
934 | * | ||
935 | * For demand paged transactional modification, the fork switch should be done | ||
936 | * after reading in all the blocks, modifying them and pinning them in the | ||
937 | * transaction. For modification when the buffers are already pinned in memory, | ||
938 | * the fork switch can be done before changing the owner as we won't need to | ||
939 | * validate the owner until the btree buffers are unpinned and writes can occur | ||
940 | * again. | ||
941 | * | ||
942 | * For recovery based ownership change, there is no transactional context and | ||
943 | * so a buffer list must be supplied so that we can record the buffers that we | ||
944 | * modified for the caller to issue IO on. | ||
945 | */ | ||
946 | int | ||
947 | xfs_bmbt_change_owner( | ||
948 | struct xfs_trans *tp, | ||
949 | struct xfs_inode *ip, | ||
950 | int whichfork, | ||
951 | xfs_ino_t new_owner, | ||
952 | struct list_head *buffer_list) | ||
953 | { | ||
954 | struct xfs_btree_cur *cur; | ||
955 | int error; | ||
956 | |||
957 | ASSERT(tp || buffer_list); | ||
958 | ASSERT(!(tp && buffer_list)); | ||
959 | if (whichfork == XFS_DATA_FORK) | ||
960 | ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_BTREE); | ||
961 | else | ||
962 | ASSERT(ip->i_d.di_aformat == XFS_DINODE_FMT_BTREE); | ||
963 | |||
964 | cur = xfs_bmbt_init_cursor(ip->i_mount, tp, ip, whichfork); | ||
965 | if (!cur) | ||
966 | return ENOMEM; | ||
967 | |||
968 | error = xfs_btree_change_owner(cur, new_owner, buffer_list); | ||
969 | xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); | ||
970 | return error; | ||
971 | } | ||
diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h index 1b726d626941..e367461a638e 100644 --- a/fs/xfs/xfs_bmap_btree.h +++ b/fs/xfs/xfs_bmap_btree.h | |||
@@ -236,6 +236,10 @@ extern int xfs_bmbt_get_maxrecs(struct xfs_btree_cur *, int level); | |||
236 | extern int xfs_bmdr_maxrecs(struct xfs_mount *, int blocklen, int leaf); | 236 | extern int xfs_bmdr_maxrecs(struct xfs_mount *, int blocklen, int leaf); |
237 | extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf); | 237 | extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf); |
238 | 238 | ||
239 | extern int xfs_bmbt_change_owner(struct xfs_trans *tp, struct xfs_inode *ip, | ||
240 | int whichfork, xfs_ino_t new_owner, | ||
241 | struct list_head *buffer_list); | ||
242 | |||
239 | extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *, | 243 | extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *, |
240 | struct xfs_trans *, struct xfs_inode *, int); | 244 | struct xfs_trans *, struct xfs_inode *, int); |
241 | 245 | ||
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c index 541d59f5e658..97f952caea74 100644 --- a/fs/xfs/xfs_bmap_util.c +++ b/fs/xfs/xfs_bmap_util.c | |||
@@ -612,13 +612,9 @@ xfs_getbmap( | |||
612 | 612 | ||
613 | if (bmv->bmv_count > ULONG_MAX / sizeof(struct getbmapx)) | 613 | if (bmv->bmv_count > ULONG_MAX / sizeof(struct getbmapx)) |
614 | return XFS_ERROR(ENOMEM); | 614 | return XFS_ERROR(ENOMEM); |
615 | out = kmem_zalloc(bmv->bmv_count * sizeof(struct getbmapx), KM_MAYFAIL); | 615 | out = kmem_zalloc_large(bmv->bmv_count * sizeof(struct getbmapx), 0); |
616 | if (!out) { | 616 | if (!out) |
617 | out = kmem_zalloc_large(bmv->bmv_count * | 617 | return XFS_ERROR(ENOMEM); |
618 | sizeof(struct getbmapx)); | ||
619 | if (!out) | ||
620 | return XFS_ERROR(ENOMEM); | ||
621 | } | ||
622 | 618 | ||
623 | xfs_ilock(ip, XFS_IOLOCK_SHARED); | 619 | xfs_ilock(ip, XFS_IOLOCK_SHARED); |
624 | if (whichfork == XFS_DATA_FORK && !(iflags & BMV_IF_DELALLOC)) { | 620 | if (whichfork == XFS_DATA_FORK && !(iflags & BMV_IF_DELALLOC)) { |
@@ -754,10 +750,7 @@ xfs_getbmap( | |||
754 | break; | 750 | break; |
755 | } | 751 | } |
756 | 752 | ||
757 | if (is_vmalloc_addr(out)) | 753 | kmem_free(out); |
758 | kmem_free_large(out); | ||
759 | else | ||
760 | kmem_free(out); | ||
761 | return error; | 754 | return error; |
762 | } | 755 | } |
763 | 756 | ||
@@ -1789,14 +1782,6 @@ xfs_swap_extents( | |||
1789 | int taforkblks = 0; | 1782 | int taforkblks = 0; |
1790 | __uint64_t tmp; | 1783 | __uint64_t tmp; |
1791 | 1784 | ||
1792 | /* | ||
1793 | * We have no way of updating owner information in the BMBT blocks for | ||
1794 | * each inode on CRC enabled filesystems, so to avoid corrupting the | ||
1795 | * this metadata we simply don't allow extent swaps to occur. | ||
1796 | */ | ||
1797 | if (xfs_sb_version_hascrc(&mp->m_sb)) | ||
1798 | return XFS_ERROR(EINVAL); | ||
1799 | |||
1800 | tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL); | 1785 | tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL); |
1801 | if (!tempifp) { | 1786 | if (!tempifp) { |
1802 | error = XFS_ERROR(ENOMEM); | 1787 | error = XFS_ERROR(ENOMEM); |
@@ -1920,6 +1905,42 @@ xfs_swap_extents( | |||
1920 | goto out_trans_cancel; | 1905 | goto out_trans_cancel; |
1921 | } | 1906 | } |
1922 | 1907 | ||
1908 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); | ||
1909 | xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); | ||
1910 | |||
1911 | /* | ||
1912 | * Before we've swapped the forks, lets set the owners of the forks | ||
1913 | * appropriately. We have to do this as we are demand paging the btree | ||
1914 | * buffers, and so the validation done on read will expect the owner | ||
1915 | * field to be correctly set. Once we change the owners, we can swap the | ||
1916 | * inode forks. | ||
1917 | * | ||
1918 | * Note the trickiness in setting the log flags - we set the owner log | ||
1919 | * flag on the opposite inode (i.e. the inode we are setting the new | ||
1920 | * owner to be) because once we swap the forks and log that, log | ||
1921 | * recovery is going to see the fork as owned by the swapped inode, | ||
1922 | * not the pre-swapped inodes. | ||
1923 | */ | ||
1924 | src_log_flags = XFS_ILOG_CORE; | ||
1925 | target_log_flags = XFS_ILOG_CORE; | ||
1926 | if (ip->i_d.di_version == 3 && | ||
1927 | ip->i_d.di_format == XFS_DINODE_FMT_BTREE) { | ||
1928 | target_log_flags |= XFS_ILOG_DOWNER; | ||
1929 | error = xfs_bmbt_change_owner(tp, ip, XFS_DATA_FORK, | ||
1930 | tip->i_ino, NULL); | ||
1931 | if (error) | ||
1932 | goto out_trans_cancel; | ||
1933 | } | ||
1934 | |||
1935 | if (tip->i_d.di_version == 3 && | ||
1936 | tip->i_d.di_format == XFS_DINODE_FMT_BTREE) { | ||
1937 | src_log_flags |= XFS_ILOG_DOWNER; | ||
1938 | error = xfs_bmbt_change_owner(tp, tip, XFS_DATA_FORK, | ||
1939 | ip->i_ino, NULL); | ||
1940 | if (error) | ||
1941 | goto out_trans_cancel; | ||
1942 | } | ||
1943 | |||
1923 | /* | 1944 | /* |
1924 | * Swap the data forks of the inodes | 1945 | * Swap the data forks of the inodes |
1925 | */ | 1946 | */ |
@@ -1957,7 +1978,6 @@ xfs_swap_extents( | |||
1957 | tip->i_delayed_blks = ip->i_delayed_blks; | 1978 | tip->i_delayed_blks = ip->i_delayed_blks; |
1958 | ip->i_delayed_blks = 0; | 1979 | ip->i_delayed_blks = 0; |
1959 | 1980 | ||
1960 | src_log_flags = XFS_ILOG_CORE; | ||
1961 | switch (ip->i_d.di_format) { | 1981 | switch (ip->i_d.di_format) { |
1962 | case XFS_DINODE_FMT_EXTENTS: | 1982 | case XFS_DINODE_FMT_EXTENTS: |
1963 | /* If the extents fit in the inode, fix the | 1983 | /* If the extents fit in the inode, fix the |
@@ -1971,11 +1991,12 @@ xfs_swap_extents( | |||
1971 | src_log_flags |= XFS_ILOG_DEXT; | 1991 | src_log_flags |= XFS_ILOG_DEXT; |
1972 | break; | 1992 | break; |
1973 | case XFS_DINODE_FMT_BTREE: | 1993 | case XFS_DINODE_FMT_BTREE: |
1994 | ASSERT(ip->i_d.di_version < 3 || | ||
1995 | (src_log_flags & XFS_ILOG_DOWNER)); | ||
1974 | src_log_flags |= XFS_ILOG_DBROOT; | 1996 | src_log_flags |= XFS_ILOG_DBROOT; |
1975 | break; | 1997 | break; |
1976 | } | 1998 | } |
1977 | 1999 | ||
1978 | target_log_flags = XFS_ILOG_CORE; | ||
1979 | switch (tip->i_d.di_format) { | 2000 | switch (tip->i_d.di_format) { |
1980 | case XFS_DINODE_FMT_EXTENTS: | 2001 | case XFS_DINODE_FMT_EXTENTS: |
1981 | /* If the extents fit in the inode, fix the | 2002 | /* If the extents fit in the inode, fix the |
@@ -1990,13 +2011,11 @@ xfs_swap_extents( | |||
1990 | break; | 2011 | break; |
1991 | case XFS_DINODE_FMT_BTREE: | 2012 | case XFS_DINODE_FMT_BTREE: |
1992 | target_log_flags |= XFS_ILOG_DBROOT; | 2013 | target_log_flags |= XFS_ILOG_DBROOT; |
2014 | ASSERT(tip->i_d.di_version < 3 || | ||
2015 | (target_log_flags & XFS_ILOG_DOWNER)); | ||
1993 | break; | 2016 | break; |
1994 | } | 2017 | } |
1995 | 2018 | ||
1996 | |||
1997 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); | ||
1998 | xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); | ||
1999 | |||
2000 | xfs_trans_log_inode(tp, ip, src_log_flags); | 2019 | xfs_trans_log_inode(tp, ip, src_log_flags); |
2001 | xfs_trans_log_inode(tp, tip, target_log_flags); | 2020 | xfs_trans_log_inode(tp, tip, target_log_flags); |
2002 | 2021 | ||
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c index 7a2b4da3c0db..5690e102243d 100644 --- a/fs/xfs/xfs_btree.c +++ b/fs/xfs/xfs_btree.c | |||
@@ -855,6 +855,41 @@ xfs_btree_readahead( | |||
855 | return xfs_btree_readahead_sblock(cur, lr, block); | 855 | return xfs_btree_readahead_sblock(cur, lr, block); |
856 | } | 856 | } |
857 | 857 | ||
858 | STATIC xfs_daddr_t | ||
859 | xfs_btree_ptr_to_daddr( | ||
860 | struct xfs_btree_cur *cur, | ||
861 | union xfs_btree_ptr *ptr) | ||
862 | { | ||
863 | if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { | ||
864 | ASSERT(ptr->l != cpu_to_be64(NULLDFSBNO)); | ||
865 | |||
866 | return XFS_FSB_TO_DADDR(cur->bc_mp, be64_to_cpu(ptr->l)); | ||
867 | } else { | ||
868 | ASSERT(cur->bc_private.a.agno != NULLAGNUMBER); | ||
869 | ASSERT(ptr->s != cpu_to_be32(NULLAGBLOCK)); | ||
870 | |||
871 | return XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_private.a.agno, | ||
872 | be32_to_cpu(ptr->s)); | ||
873 | } | ||
874 | } | ||
875 | |||
876 | /* | ||
877 | * Readahead @count btree blocks at the given @ptr location. | ||
878 | * | ||
879 | * We don't need to care about long or short form btrees here as we have a | ||
880 | * method of converting the ptr directly to a daddr available to us. | ||
881 | */ | ||
882 | STATIC void | ||
883 | xfs_btree_readahead_ptr( | ||
884 | struct xfs_btree_cur *cur, | ||
885 | union xfs_btree_ptr *ptr, | ||
886 | xfs_extlen_t count) | ||
887 | { | ||
888 | xfs_buf_readahead(cur->bc_mp->m_ddev_targp, | ||
889 | xfs_btree_ptr_to_daddr(cur, ptr), | ||
890 | cur->bc_mp->m_bsize * count, cur->bc_ops->buf_ops); | ||
891 | } | ||
892 | |||
858 | /* | 893 | /* |
859 | * Set the buffer for level "lev" in the cursor to bp, releasing | 894 | * Set the buffer for level "lev" in the cursor to bp, releasing |
860 | * any previous buffer. | 895 | * any previous buffer. |
@@ -1073,24 +1108,6 @@ xfs_btree_buf_to_ptr( | |||
1073 | } | 1108 | } |
1074 | } | 1109 | } |
1075 | 1110 | ||
1076 | STATIC xfs_daddr_t | ||
1077 | xfs_btree_ptr_to_daddr( | ||
1078 | struct xfs_btree_cur *cur, | ||
1079 | union xfs_btree_ptr *ptr) | ||
1080 | { | ||
1081 | if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { | ||
1082 | ASSERT(ptr->l != cpu_to_be64(NULLDFSBNO)); | ||
1083 | |||
1084 | return XFS_FSB_TO_DADDR(cur->bc_mp, be64_to_cpu(ptr->l)); | ||
1085 | } else { | ||
1086 | ASSERT(cur->bc_private.a.agno != NULLAGNUMBER); | ||
1087 | ASSERT(ptr->s != cpu_to_be32(NULLAGBLOCK)); | ||
1088 | |||
1089 | return XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_private.a.agno, | ||
1090 | be32_to_cpu(ptr->s)); | ||
1091 | } | ||
1092 | } | ||
1093 | |||
1094 | STATIC void | 1111 | STATIC void |
1095 | xfs_btree_set_refs( | 1112 | xfs_btree_set_refs( |
1096 | struct xfs_btree_cur *cur, | 1113 | struct xfs_btree_cur *cur, |
@@ -3869,3 +3886,120 @@ xfs_btree_get_rec( | |||
3869 | *stat = 1; | 3886 | *stat = 1; |
3870 | return 0; | 3887 | return 0; |
3871 | } | 3888 | } |
3889 | |||
3890 | /* | ||
3891 | * Change the owner of a btree. | ||
3892 | * | ||
3893 | * The mechanism we use here is ordered buffer logging. Because we don't know | ||
3894 | * how many buffers were are going to need to modify, we don't really want to | ||
3895 | * have to make transaction reservations for the worst case of every buffer in a | ||
3896 | * full size btree as that may be more space that we can fit in the log.... | ||
3897 | * | ||
3898 | * We do the btree walk in the most optimal manner possible - we have sibling | ||
3899 | * pointers so we can just walk all the blocks on each level from left to right | ||
3900 | * in a single pass, and then move to the next level and do the same. We can | ||
3901 | * also do readahead on the sibling pointers to get IO moving more quickly, | ||
3902 | * though for slow disks this is unlikely to make much difference to performance | ||
3903 | * as the amount of CPU work we have to do before moving to the next block is | ||
3904 | * relatively small. | ||
3905 | * | ||
3906 | * For each btree block that we load, modify the owner appropriately, set the | ||
3907 | * buffer as an ordered buffer and log it appropriately. We need to ensure that | ||
3908 | * we mark the region we change dirty so that if the buffer is relogged in | ||
3909 | * a subsequent transaction the changes we make here as an ordered buffer are | ||
3910 | * correctly relogged in that transaction. If we are in recovery context, then | ||
3911 | * just queue the modified buffer as delayed write buffer so the transaction | ||
3912 | * recovery completion writes the changes to disk. | ||
3913 | */ | ||
3914 | static int | ||
3915 | xfs_btree_block_change_owner( | ||
3916 | struct xfs_btree_cur *cur, | ||
3917 | int level, | ||
3918 | __uint64_t new_owner, | ||
3919 | struct list_head *buffer_list) | ||
3920 | { | ||
3921 | struct xfs_btree_block *block; | ||
3922 | struct xfs_buf *bp; | ||
3923 | union xfs_btree_ptr rptr; | ||
3924 | |||
3925 | /* do right sibling readahead */ | ||
3926 | xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA); | ||
3927 | |||
3928 | /* modify the owner */ | ||
3929 | block = xfs_btree_get_block(cur, level, &bp); | ||
3930 | if (cur->bc_flags & XFS_BTREE_LONG_PTRS) | ||
3931 | block->bb_u.l.bb_owner = cpu_to_be64(new_owner); | ||
3932 | else | ||
3933 | block->bb_u.s.bb_owner = cpu_to_be32(new_owner); | ||
3934 | |||
3935 | /* | ||
3936 | * If the block is a root block hosted in an inode, we might not have a | ||
3937 | * buffer pointer here and we shouldn't attempt to log the change as the | ||
3938 | * information is already held in the inode and discarded when the root | ||
3939 | * block is formatted into the on-disk inode fork. We still change it, | ||
3940 | * though, so everything is consistent in memory. | ||
3941 | */ | ||
3942 | if (bp) { | ||
3943 | if (cur->bc_tp) { | ||
3944 | xfs_trans_ordered_buf(cur->bc_tp, bp); | ||
3945 | xfs_btree_log_block(cur, bp, XFS_BB_OWNER); | ||
3946 | } else { | ||
3947 | xfs_buf_delwri_queue(bp, buffer_list); | ||
3948 | } | ||
3949 | } else { | ||
3950 | ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE); | ||
3951 | ASSERT(level == cur->bc_nlevels - 1); | ||
3952 | } | ||
3953 | |||
3954 | /* now read rh sibling block for next iteration */ | ||
3955 | xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB); | ||
3956 | if (xfs_btree_ptr_is_null(cur, &rptr)) | ||
3957 | return ENOENT; | ||
3958 | |||
3959 | return xfs_btree_lookup_get_block(cur, level, &rptr, &block); | ||
3960 | } | ||
3961 | |||
3962 | int | ||
3963 | xfs_btree_change_owner( | ||
3964 | struct xfs_btree_cur *cur, | ||
3965 | __uint64_t new_owner, | ||
3966 | struct list_head *buffer_list) | ||
3967 | { | ||
3968 | union xfs_btree_ptr lptr; | ||
3969 | int level; | ||
3970 | struct xfs_btree_block *block = NULL; | ||
3971 | int error = 0; | ||
3972 | |||
3973 | cur->bc_ops->init_ptr_from_cur(cur, &lptr); | ||
3974 | |||
3975 | /* for each level */ | ||
3976 | for (level = cur->bc_nlevels - 1; level >= 0; level--) { | ||
3977 | /* grab the left hand block */ | ||
3978 | error = xfs_btree_lookup_get_block(cur, level, &lptr, &block); | ||
3979 | if (error) | ||
3980 | return error; | ||
3981 | |||
3982 | /* readahead the left most block for the next level down */ | ||
3983 | if (level > 0) { | ||
3984 | union xfs_btree_ptr *ptr; | ||
3985 | |||
3986 | ptr = xfs_btree_ptr_addr(cur, 1, block); | ||
3987 | xfs_btree_readahead_ptr(cur, ptr, 1); | ||
3988 | |||
3989 | /* save for the next iteration of the loop */ | ||
3990 | lptr = *ptr; | ||
3991 | } | ||
3992 | |||
3993 | /* for each buffer in the level */ | ||
3994 | do { | ||
3995 | error = xfs_btree_block_change_owner(cur, level, | ||
3996 | new_owner, | ||
3997 | buffer_list); | ||
3998 | } while (!error); | ||
3999 | |||
4000 | if (error != ENOENT) | ||
4001 | return error; | ||
4002 | } | ||
4003 | |||
4004 | return 0; | ||
4005 | } | ||
diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h index c8473c7ef45e..06729b67ad58 100644 --- a/fs/xfs/xfs_btree.h +++ b/fs/xfs/xfs_btree.h | |||
@@ -121,15 +121,18 @@ union xfs_btree_rec { | |||
121 | /* | 121 | /* |
122 | * For logging record fields. | 122 | * For logging record fields. |
123 | */ | 123 | */ |
124 | #define XFS_BB_MAGIC 0x01 | 124 | #define XFS_BB_MAGIC (1 << 0) |
125 | #define XFS_BB_LEVEL 0x02 | 125 | #define XFS_BB_LEVEL (1 << 1) |
126 | #define XFS_BB_NUMRECS 0x04 | 126 | #define XFS_BB_NUMRECS (1 << 2) |
127 | #define XFS_BB_LEFTSIB 0x08 | 127 | #define XFS_BB_LEFTSIB (1 << 3) |
128 | #define XFS_BB_RIGHTSIB 0x10 | 128 | #define XFS_BB_RIGHTSIB (1 << 4) |
129 | #define XFS_BB_BLKNO 0x20 | 129 | #define XFS_BB_BLKNO (1 << 5) |
130 | #define XFS_BB_LSN (1 << 6) | ||
131 | #define XFS_BB_UUID (1 << 7) | ||
132 | #define XFS_BB_OWNER (1 << 8) | ||
130 | #define XFS_BB_NUM_BITS 5 | 133 | #define XFS_BB_NUM_BITS 5 |
131 | #define XFS_BB_ALL_BITS ((1 << XFS_BB_NUM_BITS) - 1) | 134 | #define XFS_BB_ALL_BITS ((1 << XFS_BB_NUM_BITS) - 1) |
132 | #define XFS_BB_NUM_BITS_CRC 8 | 135 | #define XFS_BB_NUM_BITS_CRC 9 |
133 | #define XFS_BB_ALL_BITS_CRC ((1 << XFS_BB_NUM_BITS_CRC) - 1) | 136 | #define XFS_BB_ALL_BITS_CRC ((1 << XFS_BB_NUM_BITS_CRC) - 1) |
134 | 137 | ||
135 | /* | 138 | /* |
@@ -442,6 +445,8 @@ int xfs_btree_new_iroot(struct xfs_btree_cur *, int *, int *); | |||
442 | int xfs_btree_insert(struct xfs_btree_cur *, int *); | 445 | int xfs_btree_insert(struct xfs_btree_cur *, int *); |
443 | int xfs_btree_delete(struct xfs_btree_cur *, int *); | 446 | int xfs_btree_delete(struct xfs_btree_cur *, int *); |
444 | int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *); | 447 | int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *); |
448 | int xfs_btree_change_owner(struct xfs_btree_cur *cur, __uint64_t new_owner, | ||
449 | struct list_head *buffer_list); | ||
445 | 450 | ||
446 | /* | 451 | /* |
447 | * btree block CRC helpers | 452 | * btree block CRC helpers |
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 3a944b198e35..88c5ea75ebf6 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c | |||
@@ -613,13 +613,27 @@ xfs_buf_item_unlock( | |||
613 | } | 613 | } |
614 | } | 614 | } |
615 | } | 615 | } |
616 | if (clean || aborted) { | 616 | |
617 | if (atomic_dec_and_test(&bip->bli_refcount)) { | 617 | /* |
618 | ASSERT(!aborted || XFS_FORCED_SHUTDOWN(lip->li_mountp)); | 618 | * Clean buffers, by definition, cannot be in the AIL. However, aborted |
619 | * buffers may be dirty and hence in the AIL. Therefore if we are | ||
620 | * aborting a buffer and we've just taken the last refernce away, we | ||
621 | * have to check if it is in the AIL before freeing it. We need to free | ||
622 | * it in this case, because an aborted transaction has already shut the | ||
623 | * filesystem down and this is the last chance we will have to do so. | ||
624 | */ | ||
625 | if (atomic_dec_and_test(&bip->bli_refcount)) { | ||
626 | if (clean) | ||
627 | xfs_buf_item_relse(bp); | ||
628 | else if (aborted) { | ||
629 | ASSERT(XFS_FORCED_SHUTDOWN(lip->li_mountp)); | ||
630 | if (lip->li_flags & XFS_LI_IN_AIL) { | ||
631 | xfs_trans_ail_delete(lip->li_ailp, lip, | ||
632 | SHUTDOWN_LOG_IO_ERROR); | ||
633 | } | ||
619 | xfs_buf_item_relse(bp); | 634 | xfs_buf_item_relse(bp); |
620 | } | 635 | } |
621 | } else | 636 | } |
622 | atomic_dec(&bip->bli_refcount); | ||
623 | 637 | ||
624 | if (!(flags & XFS_BLI_HOLD)) | 638 | if (!(flags & XFS_BLI_HOLD)) |
625 | xfs_buf_relse(bp); | 639 | xfs_buf_relse(bp); |
diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index d4e59a4ff59f..069537c845e5 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/fs/xfs/xfs_da_btree.c | |||
@@ -635,6 +635,7 @@ xfs_da3_root_split( | |||
635 | xfs_trans_log_buf(tp, bp, 0, size - 1); | 635 | xfs_trans_log_buf(tp, bp, 0, size - 1); |
636 | 636 | ||
637 | bp->b_ops = blk1->bp->b_ops; | 637 | bp->b_ops = blk1->bp->b_ops; |
638 | xfs_trans_buf_copy_type(bp, blk1->bp); | ||
638 | blk1->bp = bp; | 639 | blk1->bp = bp; |
639 | blk1->blkno = blkno; | 640 | blk1->blkno = blkno; |
640 | 641 | ||
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c index 08984eeee159..1021c8356d08 100644 --- a/fs/xfs/xfs_dir2_leaf.c +++ b/fs/xfs/xfs_dir2_leaf.c | |||
@@ -180,6 +180,11 @@ xfs_dir3_leaf_check_int( | |||
180 | return true; | 180 | return true; |
181 | } | 181 | } |
182 | 182 | ||
183 | /* | ||
184 | * We verify the magic numbers before decoding the leaf header so that on debug | ||
185 | * kernels we don't get assertion failures in xfs_dir3_leaf_hdr_from_disk() due | ||
186 | * to incorrect magic numbers. | ||
187 | */ | ||
183 | static bool | 188 | static bool |
184 | xfs_dir3_leaf_verify( | 189 | xfs_dir3_leaf_verify( |
185 | struct xfs_buf *bp, | 190 | struct xfs_buf *bp, |
@@ -191,24 +196,25 @@ xfs_dir3_leaf_verify( | |||
191 | 196 | ||
192 | ASSERT(magic == XFS_DIR2_LEAF1_MAGIC || magic == XFS_DIR2_LEAFN_MAGIC); | 197 | ASSERT(magic == XFS_DIR2_LEAF1_MAGIC || magic == XFS_DIR2_LEAFN_MAGIC); |
193 | 198 | ||
194 | xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); | ||
195 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | 199 | if (xfs_sb_version_hascrc(&mp->m_sb)) { |
196 | struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr; | 200 | struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr; |
201 | __uint16_t magic3; | ||
197 | 202 | ||
198 | if ((magic == XFS_DIR2_LEAF1_MAGIC && | 203 | magic3 = (magic == XFS_DIR2_LEAF1_MAGIC) ? XFS_DIR3_LEAF1_MAGIC |
199 | leafhdr.magic != XFS_DIR3_LEAF1_MAGIC) || | 204 | : XFS_DIR3_LEAFN_MAGIC; |
200 | (magic == XFS_DIR2_LEAFN_MAGIC && | ||
201 | leafhdr.magic != XFS_DIR3_LEAFN_MAGIC)) | ||
202 | return false; | ||
203 | 205 | ||
206 | if (leaf3->info.hdr.magic != cpu_to_be16(magic3)) | ||
207 | return false; | ||
204 | if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_uuid)) | 208 | if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_uuid)) |
205 | return false; | 209 | return false; |
206 | if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn) | 210 | if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn) |
207 | return false; | 211 | return false; |
208 | } else { | 212 | } else { |
209 | if (leafhdr.magic != magic) | 213 | if (leaf->hdr.info.magic != cpu_to_be16(magic)) |
210 | return false; | 214 | return false; |
211 | } | 215 | } |
216 | |||
217 | xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf); | ||
212 | return xfs_dir3_leaf_check_int(mp, &leafhdr, leaf); | 218 | return xfs_dir3_leaf_check_int(mp, &leafhdr, leaf); |
213 | } | 219 | } |
214 | 220 | ||
diff --git a/fs/xfs/xfs_dquot_item.c b/fs/xfs/xfs_dquot_item.c index 60c6e1f12695..e838d84b4e85 100644 --- a/fs/xfs/xfs_dquot_item.c +++ b/fs/xfs/xfs_dquot_item.c | |||
@@ -142,7 +142,8 @@ xfs_qm_dqunpin_wait( | |||
142 | STATIC uint | 142 | STATIC uint |
143 | xfs_qm_dquot_logitem_push( | 143 | xfs_qm_dquot_logitem_push( |
144 | struct xfs_log_item *lip, | 144 | struct xfs_log_item *lip, |
145 | struct list_head *buffer_list) | 145 | struct list_head *buffer_list) __releases(&lip->li_ailp->xa_lock) |
146 | __acquires(&lip->li_ailp->xa_lock) | ||
146 | { | 147 | { |
147 | struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; | 148 | struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; |
148 | struct xfs_buf *bp = NULL; | 149 | struct xfs_buf *bp = NULL; |
diff --git a/fs/xfs/xfs_extent_busy.c b/fs/xfs/xfs_extent_busy.c index 86f559f6e5d3..e43708e2f080 100644 --- a/fs/xfs/xfs_extent_busy.c +++ b/fs/xfs/xfs_extent_busy.c | |||
@@ -160,7 +160,8 @@ xfs_extent_busy_update_extent( | |||
160 | struct xfs_extent_busy *busyp, | 160 | struct xfs_extent_busy *busyp, |
161 | xfs_agblock_t fbno, | 161 | xfs_agblock_t fbno, |
162 | xfs_extlen_t flen, | 162 | xfs_extlen_t flen, |
163 | bool userdata) | 163 | bool userdata) __releases(&pag->pagb_lock) |
164 | __acquires(&pag->pagb_lock) | ||
164 | { | 165 | { |
165 | xfs_agblock_t fend = fbno + flen; | 166 | xfs_agblock_t fend = fbno + flen; |
166 | xfs_agblock_t bbno = busyp->bno; | 167 | xfs_agblock_t bbno = busyp->bno; |
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index 73b62a24ceac..193206ba4358 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c | |||
@@ -48,7 +48,7 @@ STATIC void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp, | |||
48 | /* | 48 | /* |
49 | * Allocate and initialise an xfs_inode. | 49 | * Allocate and initialise an xfs_inode. |
50 | */ | 50 | */ |
51 | STATIC struct xfs_inode * | 51 | struct xfs_inode * |
52 | xfs_inode_alloc( | 52 | xfs_inode_alloc( |
53 | struct xfs_mount *mp, | 53 | struct xfs_mount *mp, |
54 | xfs_ino_t ino) | 54 | xfs_ino_t ino) |
@@ -98,7 +98,7 @@ xfs_inode_free_callback( | |||
98 | kmem_zone_free(xfs_inode_zone, ip); | 98 | kmem_zone_free(xfs_inode_zone, ip); |
99 | } | 99 | } |
100 | 100 | ||
101 | STATIC void | 101 | void |
102 | xfs_inode_free( | 102 | xfs_inode_free( |
103 | struct xfs_inode *ip) | 103 | struct xfs_inode *ip) |
104 | { | 104 | { |
diff --git a/fs/xfs/xfs_icache.h b/fs/xfs/xfs_icache.h index 456f0144e1b6..9ed68bb750f5 100644 --- a/fs/xfs/xfs_icache.h +++ b/fs/xfs/xfs_icache.h | |||
@@ -42,6 +42,10 @@ struct xfs_eofblocks { | |||
42 | int xfs_iget(struct xfs_mount *mp, struct xfs_trans *tp, xfs_ino_t ino, | 42 | int xfs_iget(struct xfs_mount *mp, struct xfs_trans *tp, xfs_ino_t ino, |
43 | uint flags, uint lock_flags, xfs_inode_t **ipp); | 43 | uint flags, uint lock_flags, xfs_inode_t **ipp); |
44 | 44 | ||
45 | /* recovery needs direct inode allocation capability */ | ||
46 | struct xfs_inode * xfs_inode_alloc(struct xfs_mount *mp, xfs_ino_t ino); | ||
47 | void xfs_inode_free(struct xfs_inode *ip); | ||
48 | |||
45 | void xfs_reclaim_worker(struct work_struct *work); | 49 | void xfs_reclaim_worker(struct work_struct *work); |
46 | 50 | ||
47 | int xfs_reclaim_inodes(struct xfs_mount *mp, int mode); | 51 | int xfs_reclaim_inodes(struct xfs_mount *mp, int mode); |
diff --git a/fs/xfs/xfs_inode_buf.c b/fs/xfs/xfs_inode_buf.c index e011d597f12f..63382d37f565 100644 --- a/fs/xfs/xfs_inode_buf.c +++ b/fs/xfs/xfs_inode_buf.c | |||
@@ -53,9 +53,8 @@ xfs_inobp_check( | |||
53 | i * mp->m_sb.sb_inodesize); | 53 | i * mp->m_sb.sb_inodesize); |
54 | if (!dip->di_next_unlinked) { | 54 | if (!dip->di_next_unlinked) { |
55 | xfs_alert(mp, | 55 | xfs_alert(mp, |
56 | "Detected bogus zero next_unlinked field in incore inode buffer 0x%p.", | 56 | "Detected bogus zero next_unlinked field in inode %d buffer 0x%llx.", |
57 | bp); | 57 | i, (long long)bp->b_bn); |
58 | ASSERT(dip->di_next_unlinked); | ||
59 | } | 58 | } |
60 | } | 59 | } |
61 | } | 60 | } |
@@ -106,11 +105,10 @@ xfs_inode_buf_verify( | |||
106 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_HIGH, | 105 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_HIGH, |
107 | mp, dip); | 106 | mp, dip); |
108 | #ifdef DEBUG | 107 | #ifdef DEBUG |
109 | xfs_emerg(mp, | 108 | xfs_alert(mp, |
110 | "bad inode magic/vsn daddr %lld #%d (magic=%x)", | 109 | "bad inode magic/vsn daddr %lld #%d (magic=%x)", |
111 | (unsigned long long)bp->b_bn, i, | 110 | (unsigned long long)bp->b_bn, i, |
112 | be16_to_cpu(dip->di_magic)); | 111 | be16_to_cpu(dip->di_magic)); |
113 | ASSERT(0); | ||
114 | #endif | 112 | #endif |
115 | } | 113 | } |
116 | } | 114 | } |
@@ -196,7 +194,7 @@ xfs_imap_to_bp( | |||
196 | return 0; | 194 | return 0; |
197 | } | 195 | } |
198 | 196 | ||
199 | STATIC void | 197 | void |
200 | xfs_dinode_from_disk( | 198 | xfs_dinode_from_disk( |
201 | xfs_icdinode_t *to, | 199 | xfs_icdinode_t *to, |
202 | xfs_dinode_t *from) | 200 | xfs_dinode_t *from) |
diff --git a/fs/xfs/xfs_inode_buf.h b/fs/xfs/xfs_inode_buf.h index 599e6c0ca2a9..abba0ae8cf2d 100644 --- a/fs/xfs/xfs_inode_buf.h +++ b/fs/xfs/xfs_inode_buf.h | |||
@@ -32,17 +32,17 @@ struct xfs_imap { | |||
32 | ushort im_boffset; /* inode offset in block in bytes */ | 32 | ushort im_boffset; /* inode offset in block in bytes */ |
33 | }; | 33 | }; |
34 | 34 | ||
35 | int xfs_imap_to_bp(struct xfs_mount *, struct xfs_trans *, | 35 | int xfs_imap_to_bp(struct xfs_mount *, struct xfs_trans *, |
36 | struct xfs_imap *, struct xfs_dinode **, | 36 | struct xfs_imap *, struct xfs_dinode **, |
37 | struct xfs_buf **, uint, uint); | 37 | struct xfs_buf **, uint, uint); |
38 | int xfs_iread(struct xfs_mount *, struct xfs_trans *, | 38 | int xfs_iread(struct xfs_mount *, struct xfs_trans *, |
39 | struct xfs_inode *, uint); | 39 | struct xfs_inode *, uint); |
40 | void xfs_dinode_calc_crc(struct xfs_mount *, struct xfs_dinode *); | 40 | void xfs_dinode_calc_crc(struct xfs_mount *, struct xfs_dinode *); |
41 | void xfs_dinode_to_disk(struct xfs_dinode *, | 41 | void xfs_dinode_to_disk(struct xfs_dinode *to, struct xfs_icdinode *from); |
42 | struct xfs_icdinode *); | 42 | void xfs_dinode_from_disk(struct xfs_icdinode *to, struct xfs_dinode *from); |
43 | 43 | ||
44 | #if defined(DEBUG) | 44 | #if defined(DEBUG) |
45 | void xfs_inobp_check(struct xfs_mount *, struct xfs_buf *); | 45 | void xfs_inobp_check(struct xfs_mount *, struct xfs_buf *); |
46 | #else | 46 | #else |
47 | #define xfs_inobp_check(mp, bp) | 47 | #define xfs_inobp_check(mp, bp) |
48 | #endif /* DEBUG */ | 48 | #endif /* DEBUG */ |
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index bdebc21078d7..668e8f4ccf5e 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c | |||
@@ -71,7 +71,7 @@ xfs_find_handle( | |||
71 | int hsize; | 71 | int hsize; |
72 | xfs_handle_t handle; | 72 | xfs_handle_t handle; |
73 | struct inode *inode; | 73 | struct inode *inode; |
74 | struct fd f = {0}; | 74 | struct fd f = {NULL}; |
75 | struct path path; | 75 | struct path path; |
76 | int error; | 76 | int error; |
77 | struct xfs_inode *ip; | 77 | struct xfs_inode *ip; |
@@ -456,12 +456,9 @@ xfs_attrlist_by_handle( | |||
456 | if (IS_ERR(dentry)) | 456 | if (IS_ERR(dentry)) |
457 | return PTR_ERR(dentry); | 457 | return PTR_ERR(dentry); |
458 | 458 | ||
459 | kbuf = kmem_zalloc(al_hreq.buflen, KM_SLEEP | KM_MAYFAIL); | 459 | kbuf = kmem_zalloc_large(al_hreq.buflen, KM_SLEEP); |
460 | if (!kbuf) { | 460 | if (!kbuf) |
461 | kbuf = kmem_zalloc_large(al_hreq.buflen); | 461 | goto out_dput; |
462 | if (!kbuf) | ||
463 | goto out_dput; | ||
464 | } | ||
465 | 462 | ||
466 | cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; | 463 | cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; |
467 | error = -xfs_attr_list(XFS_I(dentry->d_inode), kbuf, al_hreq.buflen, | 464 | error = -xfs_attr_list(XFS_I(dentry->d_inode), kbuf, al_hreq.buflen, |
@@ -472,12 +469,9 @@ xfs_attrlist_by_handle( | |||
472 | if (copy_to_user(al_hreq.buffer, kbuf, al_hreq.buflen)) | 469 | if (copy_to_user(al_hreq.buffer, kbuf, al_hreq.buflen)) |
473 | error = -EFAULT; | 470 | error = -EFAULT; |
474 | 471 | ||
475 | out_kfree: | 472 | out_kfree: |
476 | if (is_vmalloc_addr(kbuf)) | 473 | kmem_free(kbuf); |
477 | kmem_free_large(kbuf); | 474 | out_dput: |
478 | else | ||
479 | kmem_free(kbuf); | ||
480 | out_dput: | ||
481 | dput(dentry); | 475 | dput(dentry); |
482 | return error; | 476 | return error; |
483 | } | 477 | } |
@@ -495,12 +489,9 @@ xfs_attrmulti_attr_get( | |||
495 | 489 | ||
496 | if (*len > XATTR_SIZE_MAX) | 490 | if (*len > XATTR_SIZE_MAX) |
497 | return EINVAL; | 491 | return EINVAL; |
498 | kbuf = kmem_zalloc(*len, KM_SLEEP | KM_MAYFAIL); | 492 | kbuf = kmem_zalloc_large(*len, KM_SLEEP); |
499 | if (!kbuf) { | 493 | if (!kbuf) |
500 | kbuf = kmem_zalloc_large(*len); | 494 | return ENOMEM; |
501 | if (!kbuf) | ||
502 | return ENOMEM; | ||
503 | } | ||
504 | 495 | ||
505 | error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags); | 496 | error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags); |
506 | if (error) | 497 | if (error) |
@@ -509,11 +500,8 @@ xfs_attrmulti_attr_get( | |||
509 | if (copy_to_user(ubuf, kbuf, *len)) | 500 | if (copy_to_user(ubuf, kbuf, *len)) |
510 | error = EFAULT; | 501 | error = EFAULT; |
511 | 502 | ||
512 | out_kfree: | 503 | out_kfree: |
513 | if (is_vmalloc_addr(kbuf)) | 504 | kmem_free(kbuf); |
514 | kmem_free_large(kbuf); | ||
515 | else | ||
516 | kmem_free(kbuf); | ||
517 | return error; | 505 | return error; |
518 | } | 506 | } |
519 | 507 | ||
diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c index d3ab9534307f..f671f7e472ac 100644 --- a/fs/xfs/xfs_ioctl32.c +++ b/fs/xfs/xfs_ioctl32.c | |||
@@ -371,12 +371,9 @@ xfs_compat_attrlist_by_handle( | |||
371 | return PTR_ERR(dentry); | 371 | return PTR_ERR(dentry); |
372 | 372 | ||
373 | error = -ENOMEM; | 373 | error = -ENOMEM; |
374 | kbuf = kmem_zalloc(al_hreq.buflen, KM_SLEEP | KM_MAYFAIL); | 374 | kbuf = kmem_zalloc_large(al_hreq.buflen, KM_SLEEP); |
375 | if (!kbuf) { | 375 | if (!kbuf) |
376 | kbuf = kmem_zalloc_large(al_hreq.buflen); | 376 | goto out_dput; |
377 | if (!kbuf) | ||
378 | goto out_dput; | ||
379 | } | ||
380 | 377 | ||
381 | cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; | 378 | cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; |
382 | error = -xfs_attr_list(XFS_I(dentry->d_inode), kbuf, al_hreq.buflen, | 379 | error = -xfs_attr_list(XFS_I(dentry->d_inode), kbuf, al_hreq.buflen, |
@@ -387,12 +384,9 @@ xfs_compat_attrlist_by_handle( | |||
387 | if (copy_to_user(compat_ptr(al_hreq.buffer), kbuf, al_hreq.buflen)) | 384 | if (copy_to_user(compat_ptr(al_hreq.buffer), kbuf, al_hreq.buflen)) |
388 | error = -EFAULT; | 385 | error = -EFAULT; |
389 | 386 | ||
390 | out_kfree: | 387 | out_kfree: |
391 | if (is_vmalloc_addr(kbuf)) | 388 | kmem_free(kbuf); |
392 | kmem_free_large(kbuf); | 389 | out_dput: |
393 | else | ||
394 | kmem_free(kbuf); | ||
395 | out_dput: | ||
396 | dput(dentry); | 390 | dput(dentry); |
397 | return error; | 391 | return error; |
398 | } | 392 | } |
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index b93e14b86754..084b3e1741fd 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c | |||
@@ -495,7 +495,7 @@ xfs_bulkstat( | |||
495 | /* | 495 | /* |
496 | * Done, we're either out of filesystem or space to put the data. | 496 | * Done, we're either out of filesystem or space to put the data. |
497 | */ | 497 | */ |
498 | kmem_free_large(irbuf); | 498 | kmem_free(irbuf); |
499 | *ubcountp = ubelem; | 499 | *ubcountp = ubelem; |
500 | /* | 500 | /* |
501 | * Found some inodes, return them now and return the error next time. | 501 | * Found some inodes, return them now and return the error next time. |
@@ -541,8 +541,9 @@ xfs_bulkstat_single( | |||
541 | * at the expense of the error case. | 541 | * at the expense of the error case. |
542 | */ | 542 | */ |
543 | 543 | ||
544 | ino = (xfs_ino_t)*lastinop; | 544 | ino = *lastinop; |
545 | error = xfs_bulkstat_one(mp, ino, buffer, sizeof(xfs_bstat_t), 0, &res); | 545 | error = xfs_bulkstat_one(mp, ino, buffer, sizeof(xfs_bstat_t), |
546 | NULL, &res); | ||
546 | if (error) { | 547 | if (error) { |
547 | /* | 548 | /* |
548 | * Special case way failed, do it the "long" way | 549 | * Special case way failed, do it the "long" way |
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index 5372d58ef93a..a2dea108071a 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c | |||
@@ -257,7 +257,8 @@ xlog_grant_head_wait( | |||
257 | struct xlog *log, | 257 | struct xlog *log, |
258 | struct xlog_grant_head *head, | 258 | struct xlog_grant_head *head, |
259 | struct xlog_ticket *tic, | 259 | struct xlog_ticket *tic, |
260 | int need_bytes) | 260 | int need_bytes) __releases(&head->lock) |
261 | __acquires(&head->lock) | ||
261 | { | 262 | { |
262 | list_add_tail(&tic->t_queue, &head->waiters); | 263 | list_add_tail(&tic->t_queue, &head->waiters); |
263 | 264 | ||
diff --git a/fs/xfs/xfs_log_format.h b/fs/xfs/xfs_log_format.h index 31e3a06c4644..ca7e28a8ed31 100644 --- a/fs/xfs/xfs_log_format.h +++ b/fs/xfs/xfs_log_format.h | |||
@@ -474,6 +474,8 @@ typedef struct xfs_inode_log_format_64 { | |||
474 | #define XFS_ILOG_ADATA 0x040 /* log i_af.if_data */ | 474 | #define XFS_ILOG_ADATA 0x040 /* log i_af.if_data */ |
475 | #define XFS_ILOG_AEXT 0x080 /* log i_af.if_extents */ | 475 | #define XFS_ILOG_AEXT 0x080 /* log i_af.if_extents */ |
476 | #define XFS_ILOG_ABROOT 0x100 /* log i_af.i_broot */ | 476 | #define XFS_ILOG_ABROOT 0x100 /* log i_af.i_broot */ |
477 | #define XFS_ILOG_DOWNER 0x200 /* change the data fork owner on replay */ | ||
478 | #define XFS_ILOG_AOWNER 0x400 /* change the attr fork owner on replay */ | ||
477 | 479 | ||
478 | 480 | ||
479 | /* | 481 | /* |
@@ -487,7 +489,8 @@ typedef struct xfs_inode_log_format_64 { | |||
487 | #define XFS_ILOG_NONCORE (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \ | 489 | #define XFS_ILOG_NONCORE (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \ |
488 | XFS_ILOG_DBROOT | XFS_ILOG_DEV | \ | 490 | XFS_ILOG_DBROOT | XFS_ILOG_DEV | \ |
489 | XFS_ILOG_UUID | XFS_ILOG_ADATA | \ | 491 | XFS_ILOG_UUID | XFS_ILOG_ADATA | \ |
490 | XFS_ILOG_AEXT | XFS_ILOG_ABROOT) | 492 | XFS_ILOG_AEXT | XFS_ILOG_ABROOT | \ |
493 | XFS_ILOG_DOWNER | XFS_ILOG_AOWNER) | ||
491 | 494 | ||
492 | #define XFS_ILOG_DFORK (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \ | 495 | #define XFS_ILOG_DFORK (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \ |
493 | XFS_ILOG_DBROOT) | 496 | XFS_ILOG_DBROOT) |
@@ -499,7 +502,8 @@ typedef struct xfs_inode_log_format_64 { | |||
499 | XFS_ILOG_DEXT | XFS_ILOG_DBROOT | \ | 502 | XFS_ILOG_DEXT | XFS_ILOG_DBROOT | \ |
500 | XFS_ILOG_DEV | XFS_ILOG_UUID | \ | 503 | XFS_ILOG_DEV | XFS_ILOG_UUID | \ |
501 | XFS_ILOG_ADATA | XFS_ILOG_AEXT | \ | 504 | XFS_ILOG_ADATA | XFS_ILOG_AEXT | \ |
502 | XFS_ILOG_ABROOT | XFS_ILOG_TIMESTAMP) | 505 | XFS_ILOG_ABROOT | XFS_ILOG_TIMESTAMP | \ |
506 | XFS_ILOG_DOWNER | XFS_ILOG_AOWNER) | ||
503 | 507 | ||
504 | static inline int xfs_ilog_fbroot(int w) | 508 | static inline int xfs_ilog_fbroot(int w) |
505 | { | 509 | { |
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 7c0c1fdc728b..dabda9521b4b 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c | |||
@@ -2014,7 +2014,7 @@ xlog_recover_get_buf_lsn( | |||
2014 | case XFS_ATTR3_RMT_MAGIC: | 2014 | case XFS_ATTR3_RMT_MAGIC: |
2015 | return be64_to_cpu(((struct xfs_attr3_rmt_hdr *)blk)->rm_lsn); | 2015 | return be64_to_cpu(((struct xfs_attr3_rmt_hdr *)blk)->rm_lsn); |
2016 | case XFS_SB_MAGIC: | 2016 | case XFS_SB_MAGIC: |
2017 | return be64_to_cpu(((struct xfs_sb *)blk)->sb_lsn); | 2017 | return be64_to_cpu(((struct xfs_dsb *)blk)->sb_lsn); |
2018 | default: | 2018 | default: |
2019 | break; | 2019 | break; |
2020 | } | 2020 | } |
@@ -2629,6 +2629,82 @@ out_release: | |||
2629 | return error; | 2629 | return error; |
2630 | } | 2630 | } |
2631 | 2631 | ||
2632 | /* | ||
2633 | * Inode fork owner changes | ||
2634 | * | ||
2635 | * If we have been told that we have to reparent the inode fork, it's because an | ||
2636 | * extent swap operation on a CRC enabled filesystem has been done and we are | ||
2637 | * replaying it. We need to walk the BMBT of the appropriate fork and change the | ||
2638 | * owners of it. | ||
2639 | * | ||
2640 | * The complexity here is that we don't have an inode context to work with, so | ||
2641 | * after we've replayed the inode we need to instantiate one. This is where the | ||
2642 | * fun begins. | ||
2643 | * | ||
2644 | * We are in the middle of log recovery, so we can't run transactions. That | ||
2645 | * means we cannot use cache coherent inode instantiation via xfs_iget(), as | ||
2646 | * that will result in the corresponding iput() running the inode through | ||
2647 | * xfs_inactive(). If we've just replayed an inode core that changes the link | ||
2648 | * count to zero (i.e. it's been unlinked), then xfs_inactive() will run | ||
2649 | * transactions (bad!). | ||
2650 | * | ||
2651 | * So, to avoid this, we instantiate an inode directly from the inode core we've | ||
2652 | * just recovered. We have the buffer still locked, and all we really need to | ||
2653 | * instantiate is the inode core and the forks being modified. We can do this | ||
2654 | * manually, then run the inode btree owner change, and then tear down the | ||
2655 | * xfs_inode without having to run any transactions at all. | ||
2656 | * | ||
2657 | * Also, because we don't have a transaction context available here but need to | ||
2658 | * gather all the buffers we modify for writeback so we pass the buffer_list | ||
2659 | * instead for the operation to use. | ||
2660 | */ | ||
2661 | |||
2662 | STATIC int | ||
2663 | xfs_recover_inode_owner_change( | ||
2664 | struct xfs_mount *mp, | ||
2665 | struct xfs_dinode *dip, | ||
2666 | struct xfs_inode_log_format *in_f, | ||
2667 | struct list_head *buffer_list) | ||
2668 | { | ||
2669 | struct xfs_inode *ip; | ||
2670 | int error; | ||
2671 | |||
2672 | ASSERT(in_f->ilf_fields & (XFS_ILOG_DOWNER|XFS_ILOG_AOWNER)); | ||
2673 | |||
2674 | ip = xfs_inode_alloc(mp, in_f->ilf_ino); | ||
2675 | if (!ip) | ||
2676 | return ENOMEM; | ||
2677 | |||
2678 | /* instantiate the inode */ | ||
2679 | xfs_dinode_from_disk(&ip->i_d, dip); | ||
2680 | ASSERT(ip->i_d.di_version >= 3); | ||
2681 | |||
2682 | error = xfs_iformat_fork(ip, dip); | ||
2683 | if (error) | ||
2684 | goto out_free_ip; | ||
2685 | |||
2686 | |||
2687 | if (in_f->ilf_fields & XFS_ILOG_DOWNER) { | ||
2688 | ASSERT(in_f->ilf_fields & XFS_ILOG_DBROOT); | ||
2689 | error = xfs_bmbt_change_owner(NULL, ip, XFS_DATA_FORK, | ||
2690 | ip->i_ino, buffer_list); | ||
2691 | if (error) | ||
2692 | goto out_free_ip; | ||
2693 | } | ||
2694 | |||
2695 | if (in_f->ilf_fields & XFS_ILOG_AOWNER) { | ||
2696 | ASSERT(in_f->ilf_fields & XFS_ILOG_ABROOT); | ||
2697 | error = xfs_bmbt_change_owner(NULL, ip, XFS_ATTR_FORK, | ||
2698 | ip->i_ino, buffer_list); | ||
2699 | if (error) | ||
2700 | goto out_free_ip; | ||
2701 | } | ||
2702 | |||
2703 | out_free_ip: | ||
2704 | xfs_inode_free(ip); | ||
2705 | return error; | ||
2706 | } | ||
2707 | |||
2632 | STATIC int | 2708 | STATIC int |
2633 | xlog_recover_inode_pass2( | 2709 | xlog_recover_inode_pass2( |
2634 | struct xlog *log, | 2710 | struct xlog *log, |
@@ -2681,8 +2757,7 @@ xlog_recover_inode_pass2( | |||
2681 | error = bp->b_error; | 2757 | error = bp->b_error; |
2682 | if (error) { | 2758 | if (error) { |
2683 | xfs_buf_ioerror_alert(bp, "xlog_recover_do..(read#2)"); | 2759 | xfs_buf_ioerror_alert(bp, "xlog_recover_do..(read#2)"); |
2684 | xfs_buf_relse(bp); | 2760 | goto out_release; |
2685 | goto error; | ||
2686 | } | 2761 | } |
2687 | ASSERT(in_f->ilf_fields & XFS_ILOG_CORE); | 2762 | ASSERT(in_f->ilf_fields & XFS_ILOG_CORE); |
2688 | dip = (xfs_dinode_t *)xfs_buf_offset(bp, in_f->ilf_boffset); | 2763 | dip = (xfs_dinode_t *)xfs_buf_offset(bp, in_f->ilf_boffset); |
@@ -2692,30 +2767,31 @@ xlog_recover_inode_pass2( | |||
2692 | * like an inode! | 2767 | * like an inode! |
2693 | */ | 2768 | */ |
2694 | if (unlikely(dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))) { | 2769 | if (unlikely(dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))) { |
2695 | xfs_buf_relse(bp); | ||
2696 | xfs_alert(mp, | 2770 | xfs_alert(mp, |
2697 | "%s: Bad inode magic number, dip = 0x%p, dino bp = 0x%p, ino = %Ld", | 2771 | "%s: Bad inode magic number, dip = 0x%p, dino bp = 0x%p, ino = %Ld", |
2698 | __func__, dip, bp, in_f->ilf_ino); | 2772 | __func__, dip, bp, in_f->ilf_ino); |
2699 | XFS_ERROR_REPORT("xlog_recover_inode_pass2(1)", | 2773 | XFS_ERROR_REPORT("xlog_recover_inode_pass2(1)", |
2700 | XFS_ERRLEVEL_LOW, mp); | 2774 | XFS_ERRLEVEL_LOW, mp); |
2701 | error = EFSCORRUPTED; | 2775 | error = EFSCORRUPTED; |
2702 | goto error; | 2776 | goto out_release; |
2703 | } | 2777 | } |
2704 | dicp = item->ri_buf[1].i_addr; | 2778 | dicp = item->ri_buf[1].i_addr; |
2705 | if (unlikely(dicp->di_magic != XFS_DINODE_MAGIC)) { | 2779 | if (unlikely(dicp->di_magic != XFS_DINODE_MAGIC)) { |
2706 | xfs_buf_relse(bp); | ||
2707 | xfs_alert(mp, | 2780 | xfs_alert(mp, |
2708 | "%s: Bad inode log record, rec ptr 0x%p, ino %Ld", | 2781 | "%s: Bad inode log record, rec ptr 0x%p, ino %Ld", |
2709 | __func__, item, in_f->ilf_ino); | 2782 | __func__, item, in_f->ilf_ino); |
2710 | XFS_ERROR_REPORT("xlog_recover_inode_pass2(2)", | 2783 | XFS_ERROR_REPORT("xlog_recover_inode_pass2(2)", |
2711 | XFS_ERRLEVEL_LOW, mp); | 2784 | XFS_ERRLEVEL_LOW, mp); |
2712 | error = EFSCORRUPTED; | 2785 | error = EFSCORRUPTED; |
2713 | goto error; | 2786 | goto out_release; |
2714 | } | 2787 | } |
2715 | 2788 | ||
2716 | /* | 2789 | /* |
2717 | * If the inode has an LSN in it, recover the inode only if it's less | 2790 | * If the inode has an LSN in it, recover the inode only if it's less |
2718 | * than the lsn of the transaction we are replaying. | 2791 | * than the lsn of the transaction we are replaying. Note: we still |
2792 | * need to replay an owner change even though the inode is more recent | ||
2793 | * than the transaction as there is no guarantee that all the btree | ||
2794 | * blocks are more recent than this transaction, too. | ||
2719 | */ | 2795 | */ |
2720 | if (dip->di_version >= 3) { | 2796 | if (dip->di_version >= 3) { |
2721 | xfs_lsn_t lsn = be64_to_cpu(dip->di_lsn); | 2797 | xfs_lsn_t lsn = be64_to_cpu(dip->di_lsn); |
@@ -2723,7 +2799,7 @@ xlog_recover_inode_pass2( | |||
2723 | if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) { | 2799 | if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) { |
2724 | trace_xfs_log_recover_inode_skip(log, in_f); | 2800 | trace_xfs_log_recover_inode_skip(log, in_f); |
2725 | error = 0; | 2801 | error = 0; |
2726 | goto out_release; | 2802 | goto out_owner_change; |
2727 | } | 2803 | } |
2728 | } | 2804 | } |
2729 | 2805 | ||
@@ -2745,10 +2821,9 @@ xlog_recover_inode_pass2( | |||
2745 | dicp->di_flushiter < (DI_MAX_FLUSH >> 1)) { | 2821 | dicp->di_flushiter < (DI_MAX_FLUSH >> 1)) { |
2746 | /* do nothing */ | 2822 | /* do nothing */ |
2747 | } else { | 2823 | } else { |
2748 | xfs_buf_relse(bp); | ||
2749 | trace_xfs_log_recover_inode_skip(log, in_f); | 2824 | trace_xfs_log_recover_inode_skip(log, in_f); |
2750 | error = 0; | 2825 | error = 0; |
2751 | goto error; | 2826 | goto out_release; |
2752 | } | 2827 | } |
2753 | } | 2828 | } |
2754 | 2829 | ||
@@ -2760,13 +2835,12 @@ xlog_recover_inode_pass2( | |||
2760 | (dicp->di_format != XFS_DINODE_FMT_BTREE)) { | 2835 | (dicp->di_format != XFS_DINODE_FMT_BTREE)) { |
2761 | XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(3)", | 2836 | XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(3)", |
2762 | XFS_ERRLEVEL_LOW, mp, dicp); | 2837 | XFS_ERRLEVEL_LOW, mp, dicp); |
2763 | xfs_buf_relse(bp); | ||
2764 | xfs_alert(mp, | 2838 | xfs_alert(mp, |
2765 | "%s: Bad regular inode log record, rec ptr 0x%p, " | 2839 | "%s: Bad regular inode log record, rec ptr 0x%p, " |
2766 | "ino ptr = 0x%p, ino bp = 0x%p, ino %Ld", | 2840 | "ino ptr = 0x%p, ino bp = 0x%p, ino %Ld", |
2767 | __func__, item, dip, bp, in_f->ilf_ino); | 2841 | __func__, item, dip, bp, in_f->ilf_ino); |
2768 | error = EFSCORRUPTED; | 2842 | error = EFSCORRUPTED; |
2769 | goto error; | 2843 | goto out_release; |
2770 | } | 2844 | } |
2771 | } else if (unlikely(S_ISDIR(dicp->di_mode))) { | 2845 | } else if (unlikely(S_ISDIR(dicp->di_mode))) { |
2772 | if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) && | 2846 | if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) && |
@@ -2774,19 +2848,17 @@ xlog_recover_inode_pass2( | |||
2774 | (dicp->di_format != XFS_DINODE_FMT_LOCAL)) { | 2848 | (dicp->di_format != XFS_DINODE_FMT_LOCAL)) { |
2775 | XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(4)", | 2849 | XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(4)", |
2776 | XFS_ERRLEVEL_LOW, mp, dicp); | 2850 | XFS_ERRLEVEL_LOW, mp, dicp); |
2777 | xfs_buf_relse(bp); | ||
2778 | xfs_alert(mp, | 2851 | xfs_alert(mp, |
2779 | "%s: Bad dir inode log record, rec ptr 0x%p, " | 2852 | "%s: Bad dir inode log record, rec ptr 0x%p, " |
2780 | "ino ptr = 0x%p, ino bp = 0x%p, ino %Ld", | 2853 | "ino ptr = 0x%p, ino bp = 0x%p, ino %Ld", |
2781 | __func__, item, dip, bp, in_f->ilf_ino); | 2854 | __func__, item, dip, bp, in_f->ilf_ino); |
2782 | error = EFSCORRUPTED; | 2855 | error = EFSCORRUPTED; |
2783 | goto error; | 2856 | goto out_release; |
2784 | } | 2857 | } |
2785 | } | 2858 | } |
2786 | if (unlikely(dicp->di_nextents + dicp->di_anextents > dicp->di_nblocks)){ | 2859 | if (unlikely(dicp->di_nextents + dicp->di_anextents > dicp->di_nblocks)){ |
2787 | XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(5)", | 2860 | XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(5)", |
2788 | XFS_ERRLEVEL_LOW, mp, dicp); | 2861 | XFS_ERRLEVEL_LOW, mp, dicp); |
2789 | xfs_buf_relse(bp); | ||
2790 | xfs_alert(mp, | 2862 | xfs_alert(mp, |
2791 | "%s: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, " | 2863 | "%s: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, " |
2792 | "dino bp 0x%p, ino %Ld, total extents = %d, nblocks = %Ld", | 2864 | "dino bp 0x%p, ino %Ld, total extents = %d, nblocks = %Ld", |
@@ -2794,29 +2866,27 @@ xlog_recover_inode_pass2( | |||
2794 | dicp->di_nextents + dicp->di_anextents, | 2866 | dicp->di_nextents + dicp->di_anextents, |
2795 | dicp->di_nblocks); | 2867 | dicp->di_nblocks); |
2796 | error = EFSCORRUPTED; | 2868 | error = EFSCORRUPTED; |
2797 | goto error; | 2869 | goto out_release; |
2798 | } | 2870 | } |
2799 | if (unlikely(dicp->di_forkoff > mp->m_sb.sb_inodesize)) { | 2871 | if (unlikely(dicp->di_forkoff > mp->m_sb.sb_inodesize)) { |
2800 | XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(6)", | 2872 | XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(6)", |
2801 | XFS_ERRLEVEL_LOW, mp, dicp); | 2873 | XFS_ERRLEVEL_LOW, mp, dicp); |
2802 | xfs_buf_relse(bp); | ||
2803 | xfs_alert(mp, | 2874 | xfs_alert(mp, |
2804 | "%s: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, " | 2875 | "%s: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, " |
2805 | "dino bp 0x%p, ino %Ld, forkoff 0x%x", __func__, | 2876 | "dino bp 0x%p, ino %Ld, forkoff 0x%x", __func__, |
2806 | item, dip, bp, in_f->ilf_ino, dicp->di_forkoff); | 2877 | item, dip, bp, in_f->ilf_ino, dicp->di_forkoff); |
2807 | error = EFSCORRUPTED; | 2878 | error = EFSCORRUPTED; |
2808 | goto error; | 2879 | goto out_release; |
2809 | } | 2880 | } |
2810 | isize = xfs_icdinode_size(dicp->di_version); | 2881 | isize = xfs_icdinode_size(dicp->di_version); |
2811 | if (unlikely(item->ri_buf[1].i_len > isize)) { | 2882 | if (unlikely(item->ri_buf[1].i_len > isize)) { |
2812 | XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(7)", | 2883 | XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(7)", |
2813 | XFS_ERRLEVEL_LOW, mp, dicp); | 2884 | XFS_ERRLEVEL_LOW, mp, dicp); |
2814 | xfs_buf_relse(bp); | ||
2815 | xfs_alert(mp, | 2885 | xfs_alert(mp, |
2816 | "%s: Bad inode log record length %d, rec ptr 0x%p", | 2886 | "%s: Bad inode log record length %d, rec ptr 0x%p", |
2817 | __func__, item->ri_buf[1].i_len, item); | 2887 | __func__, item->ri_buf[1].i_len, item); |
2818 | error = EFSCORRUPTED; | 2888 | error = EFSCORRUPTED; |
2819 | goto error; | 2889 | goto out_release; |
2820 | } | 2890 | } |
2821 | 2891 | ||
2822 | /* The core is in in-core format */ | 2892 | /* The core is in in-core format */ |
@@ -2842,7 +2912,7 @@ xlog_recover_inode_pass2( | |||
2842 | } | 2912 | } |
2843 | 2913 | ||
2844 | if (in_f->ilf_size == 2) | 2914 | if (in_f->ilf_size == 2) |
2845 | goto write_inode_buffer; | 2915 | goto out_owner_change; |
2846 | len = item->ri_buf[2].i_len; | 2916 | len = item->ri_buf[2].i_len; |
2847 | src = item->ri_buf[2].i_addr; | 2917 | src = item->ri_buf[2].i_addr; |
2848 | ASSERT(in_f->ilf_size <= 4); | 2918 | ASSERT(in_f->ilf_size <= 4); |
@@ -2903,13 +2973,15 @@ xlog_recover_inode_pass2( | |||
2903 | default: | 2973 | default: |
2904 | xfs_warn(log->l_mp, "%s: Invalid flag", __func__); | 2974 | xfs_warn(log->l_mp, "%s: Invalid flag", __func__); |
2905 | ASSERT(0); | 2975 | ASSERT(0); |
2906 | xfs_buf_relse(bp); | ||
2907 | error = EIO; | 2976 | error = EIO; |
2908 | goto error; | 2977 | goto out_release; |
2909 | } | 2978 | } |
2910 | } | 2979 | } |
2911 | 2980 | ||
2912 | write_inode_buffer: | 2981 | out_owner_change: |
2982 | if (in_f->ilf_fields & (XFS_ILOG_DOWNER|XFS_ILOG_AOWNER)) | ||
2983 | error = xfs_recover_inode_owner_change(mp, dip, in_f, | ||
2984 | buffer_list); | ||
2913 | /* re-generate the checksum. */ | 2985 | /* re-generate the checksum. */ |
2914 | xfs_dinode_calc_crc(log->l_mp, dip); | 2986 | xfs_dinode_calc_crc(log->l_mp, dip); |
2915 | 2987 | ||
diff --git a/fs/xfs/xfs_symlink.c b/fs/xfs/xfs_symlink.c index 2f2a7c005be2..f622a97a7e33 100644 --- a/fs/xfs/xfs_symlink.c +++ b/fs/xfs/xfs_symlink.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include "xfs_trans_space.h" | 41 | #include "xfs_trans_space.h" |
42 | #include "xfs_trace.h" | 42 | #include "xfs_trace.h" |
43 | #include "xfs_symlink.h" | 43 | #include "xfs_symlink.h" |
44 | #include "xfs_buf_item.h" | ||
44 | 45 | ||
45 | /* ----- Kernel only functions below ----- */ | 46 | /* ----- Kernel only functions below ----- */ |
46 | STATIC int | 47 | STATIC int |
@@ -363,6 +364,7 @@ xfs_symlink( | |||
363 | pathlen -= byte_cnt; | 364 | pathlen -= byte_cnt; |
364 | offset += byte_cnt; | 365 | offset += byte_cnt; |
365 | 366 | ||
367 | xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF); | ||
366 | xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) - | 368 | xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) - |
367 | (char *)bp->b_addr); | 369 | (char *)bp->b_addr); |
368 | } | 370 | } |