diff options
author | Dave Chinner <dchinner@redhat.com> | 2013-04-03 01:11:20 -0400 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2013-04-27 12:51:56 -0400 |
commit | f5f3d9b0161633e8943520e83df634ad540b3b7f (patch) | |
tree | bd1a014fd6472904e53d7680e5692b49431ca6ab /fs/xfs/xfs_dir2_block.c | |
parent | f948dd76dde021c050c7c35720dc066a8b9a5e35 (diff) |
xfs: add CRC checks to block format directory blocks
Now that directory buffers are made from a single struct xfs_buf, we
can add CRC calculation and checking callbacks. While there, add all
the fields to the on disk structures for future functionality such
as d_type support, uuids, block numbers, owner inode, etc.
To distinguish between the different on disk formats, change the
magic numbers for the new format directory blocks.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Ben Myers <bpm@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_dir2_block.c')
-rw-r--r-- | fs/xfs/xfs_dir2_block.c | 132 |
1 files changed, 94 insertions, 38 deletions
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c index 12afe07a91d7..79a3f1b2bc7d 100644 --- a/fs/xfs/xfs_dir2_block.c +++ b/fs/xfs/xfs_dir2_block.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. | 2 | * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. |
3 | * Copyright (c) 2013 Red Hat, Inc. | ||
3 | * All Rights Reserved. | 4 | * All Rights Reserved. |
4 | * | 5 | * |
5 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -28,11 +29,13 @@ | |||
28 | #include "xfs_dinode.h" | 29 | #include "xfs_dinode.h" |
29 | #include "xfs_inode.h" | 30 | #include "xfs_inode.h" |
30 | #include "xfs_inode_item.h" | 31 | #include "xfs_inode_item.h" |
32 | #include "xfs_buf_item.h" | ||
31 | #include "xfs_dir2.h" | 33 | #include "xfs_dir2.h" |
32 | #include "xfs_dir2_format.h" | 34 | #include "xfs_dir2_format.h" |
33 | #include "xfs_dir2_priv.h" | 35 | #include "xfs_dir2_priv.h" |
34 | #include "xfs_error.h" | 36 | #include "xfs_error.h" |
35 | #include "xfs_trace.h" | 37 | #include "xfs_trace.h" |
38 | #include "xfs_cksum.h" | ||
36 | 39 | ||
37 | /* | 40 | /* |
38 | * Local function prototypes. | 41 | * Local function prototypes. |
@@ -56,44 +59,74 @@ xfs_dir_startup(void) | |||
56 | xfs_dir_hash_dotdot = xfs_da_hashname((unsigned char *)"..", 2); | 59 | xfs_dir_hash_dotdot = xfs_da_hashname((unsigned char *)"..", 2); |
57 | } | 60 | } |
58 | 61 | ||
59 | static void | 62 | static bool |
60 | xfs_dir2_block_verify( | 63 | xfs_dir3_block_verify( |
61 | struct xfs_buf *bp) | 64 | struct xfs_buf *bp) |
62 | { | 65 | { |
63 | struct xfs_mount *mp = bp->b_target->bt_mount; | 66 | struct xfs_mount *mp = bp->b_target->bt_mount; |
64 | struct xfs_dir2_data_hdr *hdr = bp->b_addr; | 67 | struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; |
65 | int block_ok = 0; | 68 | |
66 | 69 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | |
67 | block_ok = hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC); | 70 | if (hdr3->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) |
68 | block_ok = block_ok && __xfs_dir2_data_check(NULL, bp) == 0; | 71 | return false; |
69 | 72 | if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid)) | |
70 | if (!block_ok) { | 73 | return false; |
71 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, hdr); | 74 | if (be64_to_cpu(hdr3->blkno) != bp->b_bn) |
72 | xfs_buf_ioerror(bp, EFSCORRUPTED); | 75 | return false; |
76 | } else { | ||
77 | if (hdr3->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) | ||
78 | return false; | ||
73 | } | 79 | } |
80 | if (__xfs_dir2_data_check(NULL, bp)) | ||
81 | return false; | ||
82 | return true; | ||
74 | } | 83 | } |
75 | 84 | ||
76 | static void | 85 | static void |
77 | xfs_dir2_block_read_verify( | 86 | xfs_dir3_block_read_verify( |
78 | struct xfs_buf *bp) | 87 | struct xfs_buf *bp) |
79 | { | 88 | { |
80 | xfs_dir2_block_verify(bp); | 89 | struct xfs_mount *mp = bp->b_target->bt_mount; |
90 | |||
91 | if ((xfs_sb_version_hascrc(&mp->m_sb) && | ||
92 | !xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), | ||
93 | XFS_DIR3_DATA_CRC_OFF)) || | ||
94 | !xfs_dir3_block_verify(bp)) { | ||
95 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
96 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
97 | } | ||
81 | } | 98 | } |
82 | 99 | ||
83 | static void | 100 | static void |
84 | xfs_dir2_block_write_verify( | 101 | xfs_dir3_block_write_verify( |
85 | struct xfs_buf *bp) | 102 | struct xfs_buf *bp) |
86 | { | 103 | { |
87 | xfs_dir2_block_verify(bp); | 104 | struct xfs_mount *mp = bp->b_target->bt_mount; |
105 | struct xfs_buf_log_item *bip = bp->b_fspriv; | ||
106 | struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; | ||
107 | |||
108 | if (!xfs_dir3_block_verify(bp)) { | ||
109 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); | ||
110 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
111 | return; | ||
112 | } | ||
113 | |||
114 | if (!xfs_sb_version_hascrc(&mp->m_sb)) | ||
115 | return; | ||
116 | |||
117 | if (bip) | ||
118 | hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); | ||
119 | |||
120 | xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), XFS_DIR3_DATA_CRC_OFF); | ||
88 | } | 121 | } |
89 | 122 | ||
90 | const struct xfs_buf_ops xfs_dir2_block_buf_ops = { | 123 | const struct xfs_buf_ops xfs_dir3_block_buf_ops = { |
91 | .verify_read = xfs_dir2_block_read_verify, | 124 | .verify_read = xfs_dir3_block_read_verify, |
92 | .verify_write = xfs_dir2_block_write_verify, | 125 | .verify_write = xfs_dir3_block_write_verify, |
93 | }; | 126 | }; |
94 | 127 | ||
95 | static int | 128 | static int |
96 | xfs_dir2_block_read( | 129 | xfs_dir3_block_read( |
97 | struct xfs_trans *tp, | 130 | struct xfs_trans *tp, |
98 | struct xfs_inode *dp, | 131 | struct xfs_inode *dp, |
99 | struct xfs_buf **bpp) | 132 | struct xfs_buf **bpp) |
@@ -101,7 +134,29 @@ xfs_dir2_block_read( | |||
101 | struct xfs_mount *mp = dp->i_mount; | 134 | struct xfs_mount *mp = dp->i_mount; |
102 | 135 | ||
103 | return xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, bpp, | 136 | return xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, bpp, |
104 | XFS_DATA_FORK, &xfs_dir2_block_buf_ops); | 137 | XFS_DATA_FORK, &xfs_dir3_block_buf_ops); |
138 | } | ||
139 | |||
140 | static void | ||
141 | xfs_dir3_block_init( | ||
142 | struct xfs_mount *mp, | ||
143 | struct xfs_buf *bp, | ||
144 | struct xfs_inode *dp) | ||
145 | { | ||
146 | struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; | ||
147 | |||
148 | bp->b_ops = &xfs_dir3_block_buf_ops; | ||
149 | |||
150 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | ||
151 | memset(hdr3, 0, sizeof(*hdr3)); | ||
152 | hdr3->magic = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC); | ||
153 | hdr3->blkno = cpu_to_be64(bp->b_bn); | ||
154 | hdr3->owner = cpu_to_be64(dp->i_ino); | ||
155 | uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid); | ||
156 | return; | ||
157 | |||
158 | } | ||
159 | hdr3->magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC); | ||
105 | } | 160 | } |
106 | 161 | ||
107 | static void | 162 | static void |
@@ -121,7 +176,7 @@ xfs_dir2_block_need_space( | |||
121 | struct xfs_dir2_data_unused *enddup = NULL; | 176 | struct xfs_dir2_data_unused *enddup = NULL; |
122 | 177 | ||
123 | *compact = 0; | 178 | *compact = 0; |
124 | bf = hdr->bestfree; | 179 | bf = xfs_dir3_data_bestfree_p(hdr); |
125 | 180 | ||
126 | /* | 181 | /* |
127 | * If there are stale entries we'll use one for the leaf. | 182 | * If there are stale entries we'll use one for the leaf. |
@@ -303,7 +358,7 @@ xfs_dir2_block_addname( | |||
303 | mp = dp->i_mount; | 358 | mp = dp->i_mount; |
304 | 359 | ||
305 | /* Read the (one and only) directory block into bp. */ | 360 | /* Read the (one and only) directory block into bp. */ |
306 | error = xfs_dir2_block_read(tp, dp, &bp); | 361 | error = xfs_dir3_block_read(tp, dp, &bp); |
307 | if (error) | 362 | if (error) |
308 | return error; | 363 | return error; |
309 | 364 | ||
@@ -531,7 +586,7 @@ xfs_dir2_block_getdents( | |||
531 | if (xfs_dir2_dataptr_to_db(mp, *offset) > mp->m_dirdatablk) | 586 | if (xfs_dir2_dataptr_to_db(mp, *offset) > mp->m_dirdatablk) |
532 | return 0; | 587 | return 0; |
533 | 588 | ||
534 | error = xfs_dir2_block_read(NULL, dp, &bp); | 589 | error = xfs_dir3_block_read(NULL, dp, &bp); |
535 | if (error) | 590 | if (error) |
536 | return error; | 591 | return error; |
537 | 592 | ||
@@ -546,7 +601,7 @@ xfs_dir2_block_getdents( | |||
546 | * Set up values for the loop. | 601 | * Set up values for the loop. |
547 | */ | 602 | */ |
548 | btp = xfs_dir2_block_tail_p(mp, hdr); | 603 | btp = xfs_dir2_block_tail_p(mp, hdr); |
549 | ptr = (char *)(hdr + 1); | 604 | ptr = (char *)xfs_dir3_data_entry_p(hdr); |
550 | endptr = (char *)xfs_dir2_block_leaf_p(btp); | 605 | endptr = (char *)xfs_dir2_block_leaf_p(btp); |
551 | 606 | ||
552 | /* | 607 | /* |
@@ -711,7 +766,7 @@ xfs_dir2_block_lookup_int( | |||
711 | tp = args->trans; | 766 | tp = args->trans; |
712 | mp = dp->i_mount; | 767 | mp = dp->i_mount; |
713 | 768 | ||
714 | error = xfs_dir2_block_read(tp, dp, &bp); | 769 | error = xfs_dir3_block_read(tp, dp, &bp); |
715 | if (error) | 770 | if (error) |
716 | return error; | 771 | return error; |
717 | 772 | ||
@@ -974,9 +1029,12 @@ xfs_dir2_leaf_to_block( | |||
974 | * These will show up in the leaf bests table. | 1029 | * These will show up in the leaf bests table. |
975 | */ | 1030 | */ |
976 | while (dp->i_d.di_size > mp->m_dirblksize) { | 1031 | while (dp->i_d.di_size > mp->m_dirblksize) { |
1032 | int hdrsz; | ||
1033 | |||
1034 | hdrsz = xfs_dir3_data_hdr_size(xfs_sb_version_hascrc(&mp->m_sb)); | ||
977 | bestsp = xfs_dir2_leaf_bests_p(ltp); | 1035 | bestsp = xfs_dir2_leaf_bests_p(ltp); |
978 | if (be16_to_cpu(bestsp[be32_to_cpu(ltp->bestcount) - 1]) == | 1036 | if (be16_to_cpu(bestsp[be32_to_cpu(ltp->bestcount) - 1]) == |
979 | mp->m_dirblksize - (uint)sizeof(*hdr)) { | 1037 | mp->m_dirblksize - hdrsz) { |
980 | if ((error = | 1038 | if ((error = |
981 | xfs_dir2_leaf_trim_data(args, lbp, | 1039 | xfs_dir2_leaf_trim_data(args, lbp, |
982 | (xfs_dir2_db_t)(be32_to_cpu(ltp->bestcount) - 1)))) | 1040 | (xfs_dir2_db_t)(be32_to_cpu(ltp->bestcount) - 1)))) |
@@ -1014,8 +1072,8 @@ xfs_dir2_leaf_to_block( | |||
1014 | /* | 1072 | /* |
1015 | * Start converting it to block form. | 1073 | * Start converting it to block form. |
1016 | */ | 1074 | */ |
1017 | dbp->b_ops = &xfs_dir2_block_buf_ops; | 1075 | xfs_dir3_block_init(mp, dbp, dp); |
1018 | hdr->magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC); | 1076 | |
1019 | needlog = 1; | 1077 | needlog = 1; |
1020 | needscan = 0; | 1078 | needscan = 0; |
1021 | /* | 1079 | /* |
@@ -1137,16 +1195,16 @@ xfs_dir2_sf_to_block( | |||
1137 | return error; | 1195 | return error; |
1138 | } | 1196 | } |
1139 | /* | 1197 | /* |
1140 | * Initialize the data block. | 1198 | * Initialize the data block, then convert it to block format. |
1141 | */ | 1199 | */ |
1142 | error = xfs_dir2_data_init(args, blkno, &bp); | 1200 | error = xfs_dir3_data_init(args, blkno, &bp); |
1143 | if (error) { | 1201 | if (error) { |
1144 | kmem_free(sfp); | 1202 | kmem_free(sfp); |
1145 | return error; | 1203 | return error; |
1146 | } | 1204 | } |
1147 | bp->b_ops = &xfs_dir2_block_buf_ops; | 1205 | xfs_dir3_block_init(mp, bp, dp); |
1148 | hdr = bp->b_addr; | 1206 | hdr = bp->b_addr; |
1149 | hdr->magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC); | 1207 | |
1150 | /* | 1208 | /* |
1151 | * Compute size of block "tail" area. | 1209 | * Compute size of block "tail" area. |
1152 | */ | 1210 | */ |
@@ -1156,7 +1214,7 @@ xfs_dir2_sf_to_block( | |||
1156 | * The whole thing is initialized to free by the init routine. | 1214 | * The whole thing is initialized to free by the init routine. |
1157 | * Say we're using the leaf and tail area. | 1215 | * Say we're using the leaf and tail area. |
1158 | */ | 1216 | */ |
1159 | dup = (xfs_dir2_data_unused_t *)(hdr + 1); | 1217 | dup = xfs_dir3_data_unused_p(hdr); |
1160 | needlog = needscan = 0; | 1218 | needlog = needscan = 0; |
1161 | xfs_dir2_data_use_free(tp, bp, dup, mp->m_dirblksize - i, i, &needlog, | 1219 | xfs_dir2_data_use_free(tp, bp, dup, mp->m_dirblksize - i, i, &needlog, |
1162 | &needscan); | 1220 | &needscan); |
@@ -1178,8 +1236,7 @@ xfs_dir2_sf_to_block( | |||
1178 | /* | 1236 | /* |
1179 | * Create entry for . | 1237 | * Create entry for . |
1180 | */ | 1238 | */ |
1181 | dep = (xfs_dir2_data_entry_t *) | 1239 | dep = xfs_dir3_data_dot_entry_p(hdr); |
1182 | ((char *)hdr + XFS_DIR2_DATA_DOT_OFFSET); | ||
1183 | dep->inumber = cpu_to_be64(dp->i_ino); | 1240 | dep->inumber = cpu_to_be64(dp->i_ino); |
1184 | dep->namelen = 1; | 1241 | dep->namelen = 1; |
1185 | dep->name[0] = '.'; | 1242 | dep->name[0] = '.'; |
@@ -1192,8 +1249,7 @@ xfs_dir2_sf_to_block( | |||
1192 | /* | 1249 | /* |
1193 | * Create entry for .. | 1250 | * Create entry for .. |
1194 | */ | 1251 | */ |
1195 | dep = (xfs_dir2_data_entry_t *) | 1252 | dep = xfs_dir3_data_dotdot_entry_p(hdr); |
1196 | ((char *)hdr + XFS_DIR2_DATA_DOTDOT_OFFSET); | ||
1197 | dep->inumber = cpu_to_be64(xfs_dir2_sf_get_parent_ino(sfp)); | 1253 | dep->inumber = cpu_to_be64(xfs_dir2_sf_get_parent_ino(sfp)); |
1198 | dep->namelen = 2; | 1254 | dep->namelen = 2; |
1199 | dep->name[0] = dep->name[1] = '.'; | 1255 | dep->name[0] = dep->name[1] = '.'; |
@@ -1203,7 +1259,7 @@ xfs_dir2_sf_to_block( | |||
1203 | blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot); | 1259 | blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot); |
1204 | blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp, | 1260 | blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp, |
1205 | (char *)dep - (char *)hdr)); | 1261 | (char *)dep - (char *)hdr)); |
1206 | offset = XFS_DIR2_DATA_FIRST_OFFSET; | 1262 | offset = xfs_dir3_data_first_offset(hdr); |
1207 | /* | 1263 | /* |
1208 | * Loop over existing entries, stuff them in. | 1264 | * Loop over existing entries, stuff them in. |
1209 | */ | 1265 | */ |