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