diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/xfs/xfs_dir2_block.c | 22 | ||||
-rw-r--r-- | fs/xfs/xfs_dir2_data.c | 73 | ||||
-rw-r--r-- | fs/xfs/xfs_dir2_priv.h | 4 |
3 files changed, 68 insertions, 31 deletions
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c index 25ce409487be..57351b868861 100644 --- a/fs/xfs/xfs_dir2_block.c +++ b/fs/xfs/xfs_dir2_block.c | |||
@@ -56,6 +56,26 @@ xfs_dir_startup(void) | |||
56 | xfs_dir_hash_dotdot = xfs_da_hashname((unsigned char *)"..", 2); | 56 | xfs_dir_hash_dotdot = xfs_da_hashname((unsigned char *)"..", 2); |
57 | } | 57 | } |
58 | 58 | ||
59 | static void | ||
60 | xfs_dir2_block_verify( | ||
61 | struct xfs_buf *bp) | ||
62 | { | ||
63 | struct xfs_mount *mp = bp->b_target->bt_mount; | ||
64 | struct xfs_dir2_data_hdr *hdr = bp->b_addr; | ||
65 | int block_ok = 0; | ||
66 | |||
67 | block_ok = hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC); | ||
68 | block_ok = block_ok && __xfs_dir2_data_check(NULL, bp) == 0; | ||
69 | |||
70 | if (!block_ok) { | ||
71 | XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, hdr); | ||
72 | xfs_buf_ioerror(bp, EFSCORRUPTED); | ||
73 | } | ||
74 | |||
75 | bp->b_iodone = NULL; | ||
76 | xfs_buf_ioend(bp, 0); | ||
77 | } | ||
78 | |||
59 | static int | 79 | static int |
60 | xfs_dir2_block_read( | 80 | xfs_dir2_block_read( |
61 | struct xfs_trans *tp, | 81 | struct xfs_trans *tp, |
@@ -65,7 +85,7 @@ xfs_dir2_block_read( | |||
65 | struct xfs_mount *mp = dp->i_mount; | 85 | struct xfs_mount *mp = dp->i_mount; |
66 | 86 | ||
67 | return xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, bpp, | 87 | return xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, bpp, |
68 | XFS_DATA_FORK, NULL); | 88 | XFS_DATA_FORK, xfs_dir2_block_verify); |
69 | } | 89 | } |
70 | 90 | ||
71 | static void | 91 | static void |
diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c index 44ffd4d6bc91..cb117234e32e 100644 --- a/fs/xfs/xfs_dir2_data.c +++ b/fs/xfs/xfs_dir2_data.c | |||
@@ -34,14 +34,13 @@ | |||
34 | STATIC xfs_dir2_data_free_t * | 34 | STATIC xfs_dir2_data_free_t * |
35 | xfs_dir2_data_freefind(xfs_dir2_data_hdr_t *hdr, xfs_dir2_data_unused_t *dup); | 35 | xfs_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 | */ |
43 | void | 42 | int |
44 | xfs_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,30 @@ 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; | ||
170 | } | 186 | } |
171 | #endif | ||
172 | 187 | ||
173 | /* | 188 | /* |
174 | * Given a data block and an unused entry from that block, | 189 | * Given a data block and an unused entry from that block, |
diff --git a/fs/xfs/xfs_dir2_priv.h b/fs/xfs/xfs_dir2_priv.h index 3523d3e15aa8..93b8f66ae788 100644 --- a/fs/xfs/xfs_dir2_priv.h +++ b/fs/xfs/xfs_dir2_priv.h | |||
@@ -41,10 +41,12 @@ extern int xfs_dir2_leaf_to_block(struct xfs_da_args *args, | |||
41 | 41 | ||
42 | /* xfs_dir2_data.c */ | 42 | /* xfs_dir2_data.c */ |
43 | #ifdef DEBUG | 43 | #ifdef DEBUG |
44 | extern void xfs_dir2_data_check(struct xfs_inode *dp, struct xfs_buf *bp); | 44 | #define xfs_dir2_data_check(dp,bp) __xfs_dir2_data_check(dp, bp); |
45 | #else | 45 | #else |
46 | #define xfs_dir2_data_check(dp,bp) | 46 | #define xfs_dir2_data_check(dp,bp) |
47 | #endif | 47 | #endif |
48 | extern int __xfs_dir2_data_check(struct xfs_inode *dp, struct xfs_buf *bp); | ||
49 | |||
48 | extern struct xfs_dir2_data_free * | 50 | extern struct xfs_dir2_data_free * |
49 | xfs_dir2_data_freeinsert(struct xfs_dir2_data_hdr *hdr, | 51 | xfs_dir2_data_freeinsert(struct xfs_dir2_data_hdr *hdr, |
50 | struct xfs_dir2_data_unused *dup, int *loghead); | 52 | struct xfs_dir2_data_unused *dup, int *loghead); |