]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/incore.c
xfs_repair: examine all remote attribute blocks
[thirdparty/xfsprogs-dev.git] / repair / incore.c
CommitLineData
2bd0ea18 1/*
da23017d
NS
2 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
dfc130f3 4 *
da23017d
NS
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
2bd0ea18 7 * published by the Free Software Foundation.
dfc130f3 8 *
da23017d
NS
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
dfc130f3 13 *
da23017d
NS
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2bd0ea18
NS
17 */
18
6b803e5a 19#include "libxfs.h"
2bd0ea18 20#include "avl.h"
8961bfde 21#include "btree.h"
2bd0ea18
NS
22#include "globals.h"
23#include "incore.h"
24#include "agheader.h"
25#include "protos.h"
26#include "err_protos.h"
3b6ac903 27#include "threads.h"
2bd0ea18 28
8961bfde
BN
29/*
30 * The following manages the in-core bitmap of the entire filesystem
31 * using extents in a btree.
32 *
33 * The btree items will point to one of the state values below,
34 * rather than storing the value itself in the pointer.
35 */
36static int states[16] =
37 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
38
39static struct btree_root **ag_bmap;
40
41static void
42update_bmap(
43 struct btree_root *bmap,
44 unsigned long offset,
45 xfs_extlen_t blen,
46 void *new_state)
47{
48 unsigned long end = offset + blen;
49 int *cur_state;
50 unsigned long cur_key;
51 int *next_state;
52 unsigned long next_key;
53 int *prev_state;
54
55 cur_state = btree_find(bmap, offset, &cur_key);
56 if (!cur_state)
57 return;
58
59 if (offset == cur_key) {
60 /* if the start is the same as the "item" extent */
61 if (cur_state == new_state)
62 return;
63
64 /*
65 * Note: this may be NULL if we are updating the map for
66 * the superblock.
67 */
68 prev_state = btree_peek_prev(bmap, NULL);
69
70 next_state = btree_peek_next(bmap, &next_key);
71 if (next_key > end) {
72 /* different end */
73 if (new_state == prev_state) {
74 /* #1: prev has same state, move offset up */
75 btree_update_key(bmap, offset, end);
76 return;
77 }
78
79 /* #4: insert new extent after, update current value */
80 btree_update_value(bmap, offset, new_state);
81 btree_insert(bmap, end, cur_state);
82 return;
83 }
84
85 /* same end (and same start) */
86 if (new_state == next_state) {
87 /* next has same state */
88 if (new_state == prev_state) {
89 /* #3: merge prev & next */
90 btree_delete(bmap, offset);
91 btree_delete(bmap, end);
92 return;
93 }
94
95 /* #8: merge next */
96 btree_update_value(bmap, offset, new_state);
97 btree_delete(bmap, end);
98 return;
99 }
100
101 /* same start, same end, next has different state */
102 if (new_state == prev_state) {
103 /* #5: prev has same state */
104 btree_delete(bmap, offset);
105 return;
106 }
107
108 /* #6: update value only */
109 btree_update_value(bmap, offset, new_state);
110 return;
111 }
112
113 /* different start, offset is in the middle of "cur" */
114 prev_state = btree_peek_prev(bmap, NULL);
115 ASSERT(prev_state != NULL);
116 if (prev_state == new_state)
117 return;
118
119 if (end == cur_key) {
120 /* end is at the same point as the current extent */
121 if (new_state == cur_state) {
122 /* #7: move next extent down */
123 btree_update_key(bmap, end, offset);
124 return;
125 }
126
127 /* #9: different start, same end, add new extent */
128 btree_insert(bmap, offset, new_state);
129 return;
130 }
2bd0ea18 131
8961bfde
BN
132 /* #2: insert an extent into the middle of another extent */
133 btree_insert(bmap, offset, new_state);
134 btree_insert(bmap, end, prev_state);
135}
136
137void
138set_bmap_ext(
139 xfs_agnumber_t agno,
140 xfs_agblock_t agbno,
141 xfs_extlen_t blen,
142 int state)
143{
144 update_bmap(ag_bmap[agno], agbno, blen, &states[state]);
145}
146
147int
148get_bmap_ext(
149 xfs_agnumber_t agno,
150 xfs_agblock_t agbno,
151 xfs_agblock_t maxbno,
152 xfs_extlen_t *blen)
153{
154 int *statep;
155 unsigned long key;
156
157 statep = btree_find(ag_bmap[agno], agbno, &key);
158 if (!statep)
159 return -1;
160
161 if (key == agbno) {
162 if (blen) {
163 if (!btree_peek_next(ag_bmap[agno], &key))
164 return -1;
165 *blen = MIN(maxbno, key) - agbno;
166 }
167 return *statep;
168 }
169
170 statep = btree_peek_prev(ag_bmap[agno], NULL);
171 if (!statep)
172 return -1;
173 if (blen)
174 *blen = MIN(maxbno, key) - agbno;
175
176 return *statep;
177}
178
179static uint64_t *rt_bmap;
c1f7a46c 180static size_t rt_bmap_size;
dfc130f3 181
14f8b681 182/* block records fit into uint64_t's units */
8961bfde
BN
183#define XR_BB_UNIT 64 /* number of bits/unit */
184#define XR_BB 4 /* bits per block record */
185#define XR_BB_NUM (XR_BB_UNIT/XR_BB) /* number of records per unit */
186#define XR_BB_MASK 0xF /* block record mask */
187
188/*
189 * these work in real-time extents (e.g. fsbno == rt extent number)
190 */
191int
192get_rtbmap(
5a35bf2c 193 xfs_rtblock_t bno)
8961bfde
BN
194{
195 return (*(rt_bmap + bno / XR_BB_NUM) >>
196 ((bno % XR_BB_NUM) * XR_BB)) & XR_BB_MASK;
197}
198
199void
200set_rtbmap(
5a35bf2c 201 xfs_rtblock_t bno,
8961bfde
BN
202 int state)
203{
204 *(rt_bmap + bno / XR_BB_NUM) =
205 ((*(rt_bmap + bno / XR_BB_NUM) &
14f8b681
DW
206 (~((uint64_t) XR_BB_MASK << ((bno % XR_BB_NUM) * XR_BB)))) |
207 (((uint64_t) state) << ((bno % XR_BB_NUM) * XR_BB)));
8961bfde
BN
208}
209
c1f7a46c
BN
210static void
211reset_rt_bmap(void)
212{
8961bfde
BN
213 if (rt_bmap)
214 memset(rt_bmap, 0x22, rt_bmap_size); /* XR_E_FREE */
c1f7a46c 215}
2bd0ea18 216
c1f7a46c
BN
217static void
218init_rt_bmap(
219 xfs_mount_t *mp)
220{
221 if (mp->m_sb.sb_rextents == 0)
2bd0ea18 222 return;
2bd0ea18 223
c1f7a46c 224 rt_bmap_size = roundup(mp->m_sb.sb_rextents / (NBBY / XR_BB),
14f8b681 225 sizeof(uint64_t));
2bd0ea18 226
14f8b681 227 rt_bmap = memalign(sizeof(uint64_t), rt_bmap_size);
8961bfde 228 if (!rt_bmap) {
c1f7a46c 229 do_error(
5d1b7f0f 230 _("couldn't allocate realtime block map, size = %" PRIu64 "\n"),
c1f7a46c
BN
231 mp->m_sb.sb_rextents);
232 return;
2bd0ea18 233 }
2bd0ea18
NS
234}
235
c1f7a46c
BN
236static void
237free_rt_bmap(xfs_mount_t *mp)
2bd0ea18 238{
8961bfde
BN
239 free(rt_bmap);
240 rt_bmap = NULL;
2bd0ea18
NS
241}
242
2bd0ea18
NS
243
244void
c1f7a46c 245reset_bmaps(xfs_mount_t *mp)
2bd0ea18 246{
c1f7a46c 247 xfs_agnumber_t agno;
8961bfde 248 xfs_agblock_t ag_size;
c1f7a46c 249 int ag_hdr_block;
c1f7a46c
BN
250
251 ag_hdr_block = howmany(4 * mp->m_sb.sb_sectsize, mp->m_sb.sb_blocksize);
8961bfde 252 ag_size = mp->m_sb.sb_agblocks;
c1f7a46c 253
8961bfde
BN
254 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
255 if (agno == mp->m_sb.sb_agcount - 1)
256 ag_size = (xfs_extlen_t)(mp->m_sb.sb_dblocks -
5a35bf2c 257 (xfs_rfsblock_t)mp->m_sb.sb_agblocks * agno);
8961bfde
BN
258#ifdef BTREE_STATS
259 if (btree_find(ag_bmap[agno], 0, NULL)) {
260 printf("ag_bmap[%d] btree stats:\n", i);
261 btree_print_stats(ag_bmap[agno], stdout);
262 }
263#endif
264 /*
265 * We always insert an item for the first block having a
266 * given state. So the code below means:
267 *
268 * block 0..ag_hdr_block-1: XR_E_INUSE_FS
269 * ag_hdr_block..ag_size: XR_E_UNKNOWN
270 * ag_size... XR_E_BAD_STATE
271 */
272 btree_clear(ag_bmap[agno]);
273 btree_insert(ag_bmap[agno], 0, &states[XR_E_INUSE_FS]);
274 btree_insert(ag_bmap[agno],
275 ag_hdr_block, &states[XR_E_UNKNOWN]);
276 btree_insert(ag_bmap[agno], ag_size, &states[XR_E_BAD_STATE]);
2bd0ea18
NS
277 }
278
c1f7a46c 279 if (mp->m_sb.sb_logstart != 0) {
8961bfde
BN
280 set_bmap_ext(XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart),
281 XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart),
282 mp->m_sb.sb_logblocks, XR_E_INUSE_FS);
2bd0ea18
NS
283 }
284
c1f7a46c 285 reset_rt_bmap();
2bd0ea18
NS
286}
287
288void
c1f7a46c 289init_bmaps(xfs_mount_t *mp)
2bd0ea18 290{
8961bfde 291 xfs_agnumber_t i;
2bd0ea18 292
8961bfde
BN
293 ag_bmap = calloc(mp->m_sb.sb_agcount, sizeof(struct btree_root *));
294 if (!ag_bmap)
295 do_error(_("couldn't allocate block map btree roots\n"));
2bd0ea18 296
586f8abf 297 ag_locks = calloc(mp->m_sb.sb_agcount, sizeof(struct aglock));
c1f7a46c
BN
298 if (!ag_locks)
299 do_error(_("couldn't allocate block map locks\n"));
2bd0ea18 300
8961bfde
BN
301 for (i = 0; i < mp->m_sb.sb_agcount; i++) {
302 btree_init(&ag_bmap[i]);
586f8abf 303 pthread_mutex_init(&ag_locks[i].lock, NULL);
2bd0ea18
NS
304 }
305
c1f7a46c
BN
306 init_rt_bmap(mp);
307 reset_bmaps(mp);
2bd0ea18 308}
2bd0ea18
NS
309
310void
c1f7a46c 311free_bmaps(xfs_mount_t *mp)
2bd0ea18 312{
c1f7a46c 313 xfs_agnumber_t i;
2bd0ea18 314
c1f7a46c 315 for (i = 0; i < mp->m_sb.sb_agcount; i++)
8961bfde
BN
316 btree_destroy(ag_bmap[i]);
317 free(ag_bmap);
318 ag_bmap = NULL;
2bd0ea18 319
c1f7a46c 320 free_rt_bmap(mp);
2bd0ea18 321}