aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_dir2_data.c
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2013-01-29 04:48:30 -0500
committerJiri Kosina <jkosina@suse.cz>2013-01-29 04:48:30 -0500
commit617677295b53a40d0e54aac4cbbc216ffbc755dd (patch)
tree51b9e87213243ed5efff252c8e8d8fec4eebc588 /fs/xfs/xfs_dir2_data.c
parent5c8d1b68e01a144813e38795fe6dbe7ebb506131 (diff)
parent6abb7c25775b7fb2225ad0508236d63ca710e65f (diff)
Merge branch 'master' into for-next
Conflicts: drivers/devfreq/exynos4_bus.c Sync with Linus' tree to be able to apply patches that are against newer code (mvneta).
Diffstat (limited to 'fs/xfs/xfs_dir2_data.c')
-rw-r--r--fs/xfs/xfs_dir2_data.c170
1 files changed, 138 insertions, 32 deletions
diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c
index 44ffd4d6bc91..ffcf1774152e 100644
--- a/fs/xfs/xfs_dir2_data.c
+++ b/fs/xfs/xfs_dir2_data.c
@@ -34,14 +34,13 @@
34STATIC xfs_dir2_data_free_t * 34STATIC xfs_dir2_data_free_t *
35xfs_dir2_data_freefind(xfs_dir2_data_hdr_t *hdr, xfs_dir2_data_unused_t *dup); 35xfs_dir2_data_freefind(xfs_dir2_data_hdr_t *hdr, xfs_dir2_data_unused_t *dup);
36 36
37#ifdef DEBUG
38/* 37/*
39 * Check the consistency of the data block. 38 * Check the consistency of the data block.
40 * The input can also be a block-format directory. 39 * The input can also be a block-format directory.
41 * Pop an assert if we find anything bad. 40 * Return 0 is the buffer is good, otherwise an error.
42 */ 41 */
43void 42int
44xfs_dir2_data_check( 43__xfs_dir2_data_check(
45 struct xfs_inode *dp, /* incore inode pointer */ 44 struct xfs_inode *dp, /* incore inode pointer */
46 struct xfs_buf *bp) /* data block's buffer */ 45 struct xfs_buf *bp) /* data block's buffer */
47{ 46{
@@ -64,18 +63,23 @@ xfs_dir2_data_check(
64 int stale; /* count of stale leaves */ 63 int stale; /* count of stale leaves */
65 struct xfs_name name; 64 struct xfs_name name;
66 65
67 mp = dp->i_mount; 66 mp = bp->b_target->bt_mount;
68 hdr = bp->b_addr; 67 hdr = bp->b_addr;
69 bf = hdr->bestfree; 68 bf = hdr->bestfree;
70 p = (char *)(hdr + 1); 69 p = (char *)(hdr + 1);
71 70
72 if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) { 71 switch (hdr->magic) {
72 case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC):
73 btp = xfs_dir2_block_tail_p(mp, hdr); 73 btp = xfs_dir2_block_tail_p(mp, hdr);
74 lep = xfs_dir2_block_leaf_p(btp); 74 lep = xfs_dir2_block_leaf_p(btp);
75 endp = (char *)lep; 75 endp = (char *)lep;
76 } else { 76 break;
77 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC)); 77 case cpu_to_be32(XFS_DIR2_DATA_MAGIC):
78 endp = (char *)hdr + mp->m_dirblksize; 78 endp = (char *)hdr + mp->m_dirblksize;
79 break;
80 default:
81 XFS_ERROR_REPORT("Bad Magic", XFS_ERRLEVEL_LOW, mp);
82 return EFSCORRUPTED;
79 } 83 }
80 84
81 count = lastfree = freeseen = 0; 85 count = lastfree = freeseen = 0;
@@ -83,19 +87,22 @@ xfs_dir2_data_check(
83 * Account for zero bestfree entries. 87 * Account for zero bestfree entries.
84 */ 88 */
85 if (!bf[0].length) { 89 if (!bf[0].length) {
86 ASSERT(!bf[0].offset); 90 XFS_WANT_CORRUPTED_RETURN(!bf[0].offset);
87 freeseen |= 1 << 0; 91 freeseen |= 1 << 0;
88 } 92 }
89 if (!bf[1].length) { 93 if (!bf[1].length) {
90 ASSERT(!bf[1].offset); 94 XFS_WANT_CORRUPTED_RETURN(!bf[1].offset);
91 freeseen |= 1 << 1; 95 freeseen |= 1 << 1;
92 } 96 }
93 if (!bf[2].length) { 97 if (!bf[2].length) {
94 ASSERT(!bf[2].offset); 98 XFS_WANT_CORRUPTED_RETURN(!bf[2].offset);
95 freeseen |= 1 << 2; 99 freeseen |= 1 << 2;
96 } 100 }
97 ASSERT(be16_to_cpu(bf[0].length) >= be16_to_cpu(bf[1].length)); 101
98 ASSERT(be16_to_cpu(bf[1].length) >= be16_to_cpu(bf[2].length)); 102 XFS_WANT_CORRUPTED_RETURN(be16_to_cpu(bf[0].length) >=
103 be16_to_cpu(bf[1].length));
104 XFS_WANT_CORRUPTED_RETURN(be16_to_cpu(bf[1].length) >=
105 be16_to_cpu(bf[2].length));
99 /* 106 /*
100 * Loop over the data/unused entries. 107 * Loop over the data/unused entries.
101 */ 108 */
@@ -107,17 +114,20 @@ xfs_dir2_data_check(
107 * doesn't need to be there. 114 * doesn't need to be there.
108 */ 115 */
109 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { 116 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
110 ASSERT(lastfree == 0); 117 XFS_WANT_CORRUPTED_RETURN(lastfree == 0);
111 ASSERT(be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) == 118 XFS_WANT_CORRUPTED_RETURN(
112 (char *)dup - (char *)hdr); 119 be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) ==
120 (char *)dup - (char *)hdr);
113 dfp = xfs_dir2_data_freefind(hdr, dup); 121 dfp = xfs_dir2_data_freefind(hdr, dup);
114 if (dfp) { 122 if (dfp) {
115 i = (int)(dfp - bf); 123 i = (int)(dfp - bf);
116 ASSERT((freeseen & (1 << i)) == 0); 124 XFS_WANT_CORRUPTED_RETURN(
125 (freeseen & (1 << i)) == 0);
117 freeseen |= 1 << i; 126 freeseen |= 1 << i;
118 } else { 127 } else {
119 ASSERT(be16_to_cpu(dup->length) <= 128 XFS_WANT_CORRUPTED_RETURN(
120 be16_to_cpu(bf[2].length)); 129 be16_to_cpu(dup->length) <=
130 be16_to_cpu(bf[2].length));
121 } 131 }
122 p += be16_to_cpu(dup->length); 132 p += be16_to_cpu(dup->length);
123 lastfree = 1; 133 lastfree = 1;
@@ -130,10 +140,12 @@ xfs_dir2_data_check(
130 * The linear search is crude but this is DEBUG code. 140 * The linear search is crude but this is DEBUG code.
131 */ 141 */
132 dep = (xfs_dir2_data_entry_t *)p; 142 dep = (xfs_dir2_data_entry_t *)p;
133 ASSERT(dep->namelen != 0); 143 XFS_WANT_CORRUPTED_RETURN(dep->namelen != 0);
134 ASSERT(xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)) == 0); 144 XFS_WANT_CORRUPTED_RETURN(
135 ASSERT(be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)) == 145 !xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)));
136 (char *)dep - (char *)hdr); 146 XFS_WANT_CORRUPTED_RETURN(
147 be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)) ==
148 (char *)dep - (char *)hdr);
137 count++; 149 count++;
138 lastfree = 0; 150 lastfree = 0;
139 if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) { 151 if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) {
@@ -148,27 +160,122 @@ xfs_dir2_data_check(
148 be32_to_cpu(lep[i].hashval) == hash) 160 be32_to_cpu(lep[i].hashval) == hash)
149 break; 161 break;
150 } 162 }
151 ASSERT(i < be32_to_cpu(btp->count)); 163 XFS_WANT_CORRUPTED_RETURN(i < be32_to_cpu(btp->count));
152 } 164 }
153 p += xfs_dir2_data_entsize(dep->namelen); 165 p += xfs_dir2_data_entsize(dep->namelen);
154 } 166 }
155 /* 167 /*
156 * Need to have seen all the entries and all the bestfree slots. 168 * Need to have seen all the entries and all the bestfree slots.
157 */ 169 */
158 ASSERT(freeseen == 7); 170 XFS_WANT_CORRUPTED_RETURN(freeseen == 7);
159 if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) { 171 if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) {
160 for (i = stale = 0; i < be32_to_cpu(btp->count); i++) { 172 for (i = stale = 0; i < be32_to_cpu(btp->count); i++) {
161 if (lep[i].address == 173 if (lep[i].address ==
162 cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) 174 cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
163 stale++; 175 stale++;
164 if (i > 0) 176 if (i > 0)
165 ASSERT(be32_to_cpu(lep[i].hashval) >= be32_to_cpu(lep[i - 1].hashval)); 177 XFS_WANT_CORRUPTED_RETURN(
178 be32_to_cpu(lep[i].hashval) >=
179 be32_to_cpu(lep[i - 1].hashval));
166 } 180 }
167 ASSERT(count == be32_to_cpu(btp->count) - be32_to_cpu(btp->stale)); 181 XFS_WANT_CORRUPTED_RETURN(count ==
168 ASSERT(stale == be32_to_cpu(btp->stale)); 182 be32_to_cpu(btp->count) - be32_to_cpu(btp->stale));
183 XFS_WANT_CORRUPTED_RETURN(stale == be32_to_cpu(btp->stale));
169 } 184 }
185 return 0;
186}
187
188static void
189xfs_dir2_data_verify(
190 struct xfs_buf *bp)
191{
192 struct xfs_mount *mp = bp->b_target->bt_mount;
193 struct xfs_dir2_data_hdr *hdr = bp->b_addr;
194 int block_ok = 0;
195
196 block_ok = hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC);
197 block_ok = block_ok && __xfs_dir2_data_check(NULL, bp) == 0;
198
199 if (!block_ok) {
200 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, hdr);
201 xfs_buf_ioerror(bp, EFSCORRUPTED);
202 }
203}
204
205/*
206 * Readahead of the first block of the directory when it is opened is completely
207 * oblivious to the format of the directory. Hence we can either get a block
208 * format buffer or a data format buffer on readahead.
209 */
210static void
211xfs_dir2_data_reada_verify(
212 struct xfs_buf *bp)
213{
214 struct xfs_mount *mp = bp->b_target->bt_mount;
215 struct xfs_dir2_data_hdr *hdr = bp->b_addr;
216
217 switch (hdr->magic) {
218 case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC):
219 bp->b_ops = &xfs_dir2_block_buf_ops;
220 bp->b_ops->verify_read(bp);
221 return;
222 case cpu_to_be32(XFS_DIR2_DATA_MAGIC):
223 xfs_dir2_data_verify(bp);
224 return;
225 default:
226 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, hdr);
227 xfs_buf_ioerror(bp, EFSCORRUPTED);
228 break;
229 }
230}
231
232static void
233xfs_dir2_data_read_verify(
234 struct xfs_buf *bp)
235{
236 xfs_dir2_data_verify(bp);
237}
238
239static void
240xfs_dir2_data_write_verify(
241 struct xfs_buf *bp)
242{
243 xfs_dir2_data_verify(bp);
244}
245
246const struct xfs_buf_ops xfs_dir2_data_buf_ops = {
247 .verify_read = xfs_dir2_data_read_verify,
248 .verify_write = xfs_dir2_data_write_verify,
249};
250
251static const struct xfs_buf_ops xfs_dir2_data_reada_buf_ops = {
252 .verify_read = xfs_dir2_data_reada_verify,
253 .verify_write = xfs_dir2_data_write_verify,
254};
255
256
257int
258xfs_dir2_data_read(
259 struct xfs_trans *tp,
260 struct xfs_inode *dp,
261 xfs_dablk_t bno,
262 xfs_daddr_t mapped_bno,
263 struct xfs_buf **bpp)
264{
265 return xfs_da_read_buf(tp, dp, bno, mapped_bno, bpp,
266 XFS_DATA_FORK, &xfs_dir2_data_buf_ops);
267}
268
269int
270xfs_dir2_data_readahead(
271 struct xfs_trans *tp,
272 struct xfs_inode *dp,
273 xfs_dablk_t bno,
274 xfs_daddr_t mapped_bno)
275{
276 return xfs_da_reada_buf(tp, dp, bno, mapped_bno,
277 XFS_DATA_FORK, &xfs_dir2_data_reada_buf_ops);
170} 278}
171#endif
172 279
173/* 280/*
174 * Given a data block and an unused entry from that block, 281 * Given a data block and an unused entry from that block,
@@ -409,10 +516,9 @@ xfs_dir2_data_init(
409 */ 516 */
410 error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, blkno), -1, &bp, 517 error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, blkno), -1, &bp,
411 XFS_DATA_FORK); 518 XFS_DATA_FORK);
412 if (error) { 519 if (error)
413 return error; 520 return error;
414 } 521 bp->b_ops = &xfs_dir2_data_buf_ops;
415 ASSERT(bp != NULL);
416 522
417 /* 523 /*
418 * Initialize the header. 524 * Initialize the header.