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 | } |
