]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - repair/incore.h
Revert "3.0.5 release" and some of its preceding commits.
[thirdparty/xfsprogs-dev.git] / repair / incore.h
1 /*
2 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
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
7 * published by the Free Software Foundation.
8 *
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.
13 *
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
17 */
18
19 #ifndef XFS_REPAIR_INCORE_H
20 #define XFS_REPAIR_INCORE_H
21
22 #include "avl.h"
23 /*
24 * contains definition information. implementation (code)
25 * is spread out in separate files.
26 */
27
28 /*
29 * block bit map defs -- track state of each filesystem block.
30 * ba_bmap is an array of bitstrings declared in the globals.h file.
31 * the bitstrings are broken up into 64-bit chunks. one bitstring per AG.
32 */
33 #define BA_BMAP_SIZE(x) (howmany(x, 4))
34
35 void set_bmap_rt(xfs_drfsbno_t numblocks);
36 void set_bmap_log(xfs_mount_t *mp);
37 void set_bmap_fs(xfs_mount_t *mp);
38 void teardown_bmap(xfs_mount_t *mp);
39
40 void teardown_rt_bmap(xfs_mount_t *mp);
41 void teardown_ag_bmap(xfs_mount_t *mp, xfs_agnumber_t agno);
42 void teardown_bmap_finish(xfs_mount_t *mp);
43
44 /* blocks are numbered from zero */
45
46 /* block records fit into __uint64_t's units */
47
48 #define XR_BB_UNIT 64 /* number of bits/unit */
49 #define XR_BB 4 /* bits per block record */
50 #define XR_BB_NUM (XR_BB_UNIT/XR_BB) /* number of records per unit */
51 #define XR_BB_MASK 0xF /* block record mask */
52
53 /*
54 * bitstring ops -- set/get block states, either in filesystem
55 * bno's or in agbno's. turns out that fsbno addressing is
56 * more convenient when dealing with bmap extracted addresses
57 * and agbno addressing is more convenient when dealing with
58 * meta-data extracted addresses. So the fsbno versions use
59 * mtype (which can be one of the block map types above) to
60 * set the correct block map while the agbno versions assume
61 * you want to use the regular block map.
62 */
63
64 #if defined(XR_BMAP_TRACE) || defined(XR_BMAP_DBG)
65 /*
66 * implemented as functions for debugging purposes
67 */
68 int get_agbno_state(xfs_mount_t *mp, xfs_agnumber_t agno,
69 xfs_agblock_t ag_blockno);
70 void set_agbno_state(xfs_mount_t *mp, xfs_agnumber_t agno,
71 xfs_agblock_t ag_blockno, int state);
72
73 int get_fsbno_state(xfs_mount_t *mp, xfs_dfsbno_t blockno);
74 void set_fsbno_state(xfs_mount_t *mp, xfs_dfsbno_t blockno, int state);
75 #else
76 /*
77 * implemented as macros for performance purposes
78 */
79
80 #define get_agbno_state(mp, agno, ag_blockno) \
81 ((int) (*(ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM) \
82 >> (((ag_blockno)%XR_BB_NUM)*XR_BB)) \
83 & XR_BB_MASK)
84 #define set_agbno_state(mp, agno, ag_blockno, state) \
85 *(ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM) = \
86 ((*(ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM) & \
87 (~((__uint64_t) XR_BB_MASK << (((ag_blockno)%XR_BB_NUM)*XR_BB)))) | \
88 (((__uint64_t) (state)) << (((ag_blockno)%XR_BB_NUM)*XR_BB)))
89
90 #define get_fsbno_state(mp, blockno) \
91 get_agbno_state(mp, XFS_FSB_TO_AGNO(mp, (blockno)), \
92 XFS_FSB_TO_AGBNO(mp, (blockno)))
93 #define set_fsbno_state(mp, blockno, state) \
94 set_agbno_state(mp, XFS_FSB_TO_AGNO(mp, (blockno)), \
95 XFS_FSB_TO_AGBNO(mp, (blockno)), (state))
96
97
98 #define get_agbno_rec(mp, agno, ag_blockno) \
99 (*(ba_bmap[(agno)] + (ag_blockno)/XR_BB_NUM))
100 #endif /* XR_BMAP_TRACE */
101
102 /*
103 * these work in real-time extents (e.g. fsbno == rt extent number)
104 */
105 #define get_rtbno_state(mp, fsbno) \
106 ((*(rt_ba_bmap + (fsbno)/XR_BB_NUM) >> \
107 (((fsbno)%XR_BB_NUM)*XR_BB)) & XR_BB_MASK)
108 #define set_rtbno_state(mp, fsbno, state) \
109 *(rt_ba_bmap + (fsbno)/XR_BB_NUM) = \
110 ((*(rt_ba_bmap + (fsbno)/XR_BB_NUM) & \
111 (~((__uint64_t) XR_BB_MASK << (((fsbno)%XR_BB_NUM)*XR_BB)))) | \
112 (((__uint64_t) (state)) << (((fsbno)%XR_BB_NUM)*XR_BB)))
113
114
115 /*
116 * extent tree definitions
117 * right now, there are 3 trees per AG, a bno tree, a bcnt tree
118 * and a tree for dup extents. If the code is modified in the
119 * future to use an extent tree instead of a bitmask for tracking
120 * fs blocks, then we could lose the dup extent tree if we labelled
121 * each extent with the inode that owned it.
122 */
123
124 typedef unsigned char extent_state_t;
125
126 typedef struct extent_tree_node {
127 avlnode_t avl_node;
128 xfs_agblock_t ex_startblock; /* starting block (agbno) */
129 xfs_extlen_t ex_blockcount; /* number of blocks in extent */
130 extent_state_t ex_state; /* see state flags below */
131
132 struct extent_tree_node *next; /* for bcnt extent lists */
133 struct extent_tree_node *last; /* for bcnt extent list anchors */
134 #if 0
135 xfs_ino_t ex_inode; /* owner, NULL if free or */
136 /* multiply allocated */
137 #endif
138 } extent_tree_node_t;
139
140 typedef struct rt_extent_tree_node {
141 avlnode_t avl_node;
142 xfs_drtbno_t rt_startblock; /* starting realtime block */
143 xfs_extlen_t rt_blockcount; /* number of blocks in extent */
144 extent_state_t rt_state; /* see state flags below */
145
146 #if 0
147 xfs_ino_t ex_inode; /* owner, NULL if free or */
148 /* multiply allocated */
149 #endif
150 } rt_extent_tree_node_t;
151
152 /* extent states, prefix with XR_ to avoid conflict with buffer cache defines */
153
154 #define XR_E_UNKNOWN 0 /* unknown state */
155 #define XR_E_FREE1 1 /* free block (marked by one fs space tree) */
156 #define XR_E_FREE 2 /* free block (marked by both fs space trees) */
157 #define XR_E_INUSE 3 /* extent used by file/dir data or metadata */
158 #define XR_E_INUSE_FS 4 /* extent used by fs ag header or log */
159 #define XR_E_MULT 5 /* extent is multiply referenced */
160 #define XR_E_INO 6 /* extent used by inodes (inode blocks) */
161 #define XR_E_FS_MAP 7 /* extent used by fs space/inode maps */
162 #define XR_E_BAD_STATE 8
163
164 /* extent states, in 64 bit word chunks */
165 #define XR_E_UNKNOWN_LL 0x0000000000000000LL
166 #define XR_E_FREE1_LL 0x1111111111111111LL
167 #define XR_E_FREE_LL 0x2222222222222222LL
168 #define XR_E_INUSE_LL 0x3333333333333333LL
169 #define XR_E_INUSE_FS_LL 0x4444444444444444LL
170 #define XR_E_MULT_LL 0x5555555555555555LL
171 #define XR_E_INO_LL 0x6666666666666666LL
172 #define XR_E_FS_MAP_LL 0x7777777777777777LL
173
174 /* separate state bit, OR'ed into high (4th) bit of ex_state field */
175
176 #define XR_E_WRITTEN 0x8 /* extent has been written out, can't reclaim */
177 #define good_state(state) (((state) & (~XR_E_WRITTEN)) >= XR_E_UNKNOWN && \
178 ((state) & (~XR_E_WRITTEN) < XF_E_BAD_STATE))
179 #define written(state) ((state) & XR_E_WRITTEN)
180 #define set_written(state) (state) &= XR_E_WRITTEN
181
182 /*
183 * bno extent tree functions
184 */
185 void
186 add_bno_extent(xfs_agnumber_t agno, xfs_agblock_t startblock,
187 xfs_extlen_t blockcount);
188
189 extent_tree_node_t *
190 findfirst_bno_extent(xfs_agnumber_t agno);
191
192 extent_tree_node_t *
193 find_bno_extent(xfs_agnumber_t agno, xfs_agblock_t agbno);
194
195 extent_tree_node_t *
196 findfirst_bno_extent(xfs_agnumber_t agno);
197
198 #define findnext_bno_extent(exent_ptr) \
199 ((extent_tree_node_t *) ((exent_ptr)->avl_node.avl_nextino))
200
201 void
202 get_bno_extent(xfs_agnumber_t agno, extent_tree_node_t *ext);
203
204 /*
205 * bcnt tree functions
206 */
207 void
208 add_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t startblock,
209 xfs_extlen_t blockcount);
210
211 extent_tree_node_t *
212 findfirst_bcnt_extent(xfs_agnumber_t agno);
213
214 extent_tree_node_t *
215 find_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t agbno);
216
217 extent_tree_node_t *
218 findbiggest_bcnt_extent(xfs_agnumber_t agno);
219
220 extent_tree_node_t *
221 findnext_bcnt_extent(xfs_agnumber_t agno, extent_tree_node_t *ext);
222
223 extent_tree_node_t *
224 get_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t startblock,
225 xfs_extlen_t blockcount);
226
227 /*
228 * duplicate extent tree functions
229 */
230 void add_dup_extent(xfs_agnumber_t agno,
231 xfs_agblock_t startblock,
232 xfs_extlen_t blockcount);
233
234 extern avltree_desc_t **extent_tree_ptrs;
235 /* ARGSUSED */
236 static inline int
237 search_dup_extent(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agblock_t agbno)
238 {
239 ASSERT(agno < glob_agcount);
240
241 if (avl_findrange(extent_tree_ptrs[agno], agbno) != NULL)
242 return(1);
243
244 return(0);
245 }
246
247 void add_rt_dup_extent(xfs_drtbno_t startblock,
248 xfs_extlen_t blockcount);
249
250 int search_rt_dup_extent(xfs_mount_t *mp,
251 xfs_drtbno_t bno);
252
253 /*
254 * extent/tree recyling and deletion routines
255 */
256
257 /*
258 * return an extent node to the extent node free list
259 */
260 void release_extent_tree_node(extent_tree_node_t *node);
261
262 /*
263 * recycle all the nodes in the per-AG tree
264 */
265 void release_dup_extent_tree(xfs_agnumber_t agno);
266 void release_agbno_extent_tree(xfs_agnumber_t agno);
267 void release_agbcnt_extent_tree(xfs_agnumber_t agno);
268
269 /*
270 * realtime duplicate extent tree - this one actually frees the memory
271 */
272 void free_rt_dup_extent_tree(xfs_mount_t *mp);
273
274 /*
275 * per-AG extent trees shutdown routine -- all (bno, bcnt and dup)
276 * at once. this one actually frees the memory instead of just recyling
277 * the nodes.
278 */
279 void incore_ext_teardown(xfs_mount_t *mp);
280
281 /*
282 * inode definitions
283 */
284
285 /* inode types */
286
287 #define XR_INO_UNKNOWN 0 /* unknown */
288 #define XR_INO_DIR 1 /* directory */
289 #define XR_INO_RTDATA 2 /* realtime file */
290 #define XR_INO_RTBITMAP 3 /* realtime bitmap inode */
291 #define XR_INO_RTSUM 4 /* realtime summary inode */
292 #define XR_INO_DATA 5 /* regular file */
293 #define XR_INO_SYMLINK 6 /* symlink */
294 #define XR_INO_CHRDEV 7 /* character device */
295 #define XR_INO_BLKDEV 8 /* block device */
296 #define XR_INO_SOCK 9 /* socket */
297 #define XR_INO_FIFO 10 /* fifo */
298 #define XR_INO_MOUNTPOINT 11 /* mountpoint */
299
300 /* inode allocation tree */
301
302 /*
303 * Inodes in the inode allocation trees are allocated in chunks.
304 * Those groups can be easily duplicated in our trees.
305 * Disconnected inodes are harder. We can do one of two
306 * things in that case: if we know the inode allocation btrees
307 * are good, then we can disallow directory references to unknown
308 * inode chunks. If the inode allocation trees have been trashed or
309 * we feel like being aggressive, then as we hit unknown inodes,
310 * we can search on the disk for all contiguous inodes and see if
311 * they fit into chunks. Before putting them into the inode tree,
312 * we can scan each inode starting at the earliest inode to see which
313 * ones are good. This protects us from the pathalogical case of
314 * inodes appearing in user-data. We still may have to mark the
315 * inodes as "possibly fake" so that if a file claims the blocks,
316 * we decide to believe the inodes, especially if they're not
317 * connected.
318 */
319
320 #define PLIST_CHUNK_SIZE 4
321
322 typedef xfs_ino_t parent_entry_t;
323
324 struct nlink_ops;
325
326 typedef struct parent_list {
327 __uint64_t pmask;
328 parent_entry_t *pentries;
329 #ifdef DEBUG
330 short cnt;
331 #endif
332 } parent_list_t;
333
334 typedef struct ino_ex_data {
335 __uint64_t ino_reached; /* bit == 1 if reached */
336 __uint64_t ino_processed; /* reference checked bit mask */
337 parent_list_t *parents;
338 __uint8_t *counted_nlinks;/* counted nlinks in P6 */
339 } ino_ex_data_t;
340
341 typedef struct ino_tree_node {
342 avlnode_t avl_node;
343 xfs_agino_t ino_startnum; /* starting inode # */
344 xfs_inofree_t ir_free; /* inode free bit mask */
345 __uint64_t ino_confirmed; /* confirmed bitmask */
346 __uint64_t ino_isa_dir; /* bit == 1 if a directory */
347 struct nlink_ops *nlinkops; /* pointer to current nlink ops */
348 __uint8_t *disk_nlinks; /* on-disk nlinks, set in P3 */
349 union {
350 ino_ex_data_t *ex_data; /* phases 6,7 */
351 parent_list_t *plist; /* phases 2-5 */
352 } ino_un;
353 } ino_tree_node_t;
354
355 typedef struct nlink_ops {
356 const int nlink_size;
357 void (*disk_nlink_set)(ino_tree_node_t *, int, __uint32_t);
358 __uint32_t (*disk_nlink_get)(ino_tree_node_t *, int);
359 __uint32_t (*counted_nlink_get)(ino_tree_node_t *, int);
360 __uint32_t (*counted_nlink_inc)(ino_tree_node_t *, int);
361 __uint32_t (*counted_nlink_dec)(ino_tree_node_t *, int);
362 } nlink_ops_t;
363
364
365 #define INOS_PER_IREC (sizeof(__uint64_t) * NBBY)
366 void add_ino_ex_data(xfs_mount_t *mp);
367
368 /*
369 * return an inode record to the free inode record pool
370 */
371 void free_inode_rec(xfs_agnumber_t agno, ino_tree_node_t *ino_rec);
372
373 /*
374 * get pulls the inode record from the good inode tree
375 */
376 void get_inode_rec(xfs_agnumber_t agno, ino_tree_node_t *ino_rec);
377
378 extern avltree_desc_t **inode_tree_ptrs;
379 static inline ino_tree_node_t *
380 findfirst_inode_rec(xfs_agnumber_t agno)
381 {
382 return((ino_tree_node_t *) inode_tree_ptrs[agno]->avl_firstino);
383 }
384 static inline ino_tree_node_t *
385 find_inode_rec(xfs_agnumber_t agno, xfs_agino_t ino)
386 {
387 return((ino_tree_node_t *)
388 avl_findrange(inode_tree_ptrs[agno], ino));
389 }
390 void find_inode_rec_range(xfs_agnumber_t agno,
391 xfs_agino_t start_ino, xfs_agino_t end_ino,
392 ino_tree_node_t **first, ino_tree_node_t **last);
393
394 /*
395 * set inode states -- setting an inode to used or free also
396 * automatically marks it as "existing". Note -- all the inode
397 * add/set/get routines assume a valid inode number.
398 */
399 ino_tree_node_t *set_inode_used_alloc(xfs_agnumber_t agno, xfs_agino_t ino);
400 ino_tree_node_t *set_inode_free_alloc(xfs_agnumber_t agno, xfs_agino_t ino);
401
402 void print_inode_list(xfs_agnumber_t agno);
403 void print_uncertain_inode_list(xfs_agnumber_t agno);
404
405 /*
406 * separate trees for uncertain inodes (they may not exist).
407 */
408 ino_tree_node_t *findfirst_uncertain_inode_rec(xfs_agnumber_t agno);
409 ino_tree_node_t *find_uncertain_inode_rec(xfs_agnumber_t agno,
410 xfs_agino_t ino);
411 void add_inode_uncertain(xfs_mount_t *mp,
412 xfs_ino_t ino, int free);
413 void add_aginode_uncertain(xfs_agnumber_t agno,
414 xfs_agino_t agino, int free);
415 void get_uncertain_inode_rec(xfs_agnumber_t agno,
416 ino_tree_node_t *ino_rec);
417 void clear_uncertain_ino_cache(xfs_agnumber_t agno);
418
419 /*
420 * return next in-order inode tree node. takes an "ino_tree_node_t *"
421 */
422 #define next_ino_rec(ino_node_ptr) \
423 ((ino_tree_node_t *) ((ino_node_ptr)->avl_node.avl_nextino))
424 /*
425 * return the next linked inode (forward avl tree link)-- meant to be used
426 * by linked list routines (uncertain inode routines/records)
427 */
428 #define next_link_rec(ino_node_ptr) \
429 ((ino_tree_node_t *) ((ino_node_ptr)->avl_node.avl_forw))
430
431 /*
432 * Bit manipulations for processed field
433 */
434 #define XFS_INOPROC_MASK(i) ((__uint64_t)1 << (i))
435 #define XFS_INOPROC_MASKN(i,n) ((__uint64_t)((1 << (n)) - 1) << (i))
436
437 #define XFS_INOPROC_IS_PROC(rp, i) \
438 (((rp)->ino_un.ex_data->ino_processed & XFS_INOPROC_MASK((i))) == 0LL \
439 ? 0 : 1)
440 #define XFS_INOPROC_SET_PROC(rp, i) \
441 ((rp)->ino_un.ex_data->ino_processed |= XFS_INOPROC_MASK((i)))
442 /*
443 #define XFS_INOPROC_CLR_PROC(rp, i) \
444 ((rp)->ino_un.ex_data->ino_processed &= ~XFS_INOPROC_MASK((i)))
445 */
446
447 /*
448 * same for ir_confirmed.
449 */
450 #define XFS_INOCF_MASK(i) ((__uint64_t)1 << (i))
451 #define XFS_INOCF_MASKN(i,n) ((__uint64_t)((1 << (n)) - 1) << (i))
452
453 #define XFS_INOCF_IS_CF(rp, i) \
454 (((rp)->ino_confirmed & XFS_INOCF_MASK((i))) == 0LL \
455 ? 0 : 1)
456 #define XFS_INOCF_SET_CF(rp, i) \
457 ((rp)->ino_confirmed |= XFS_INOCF_MASK((i)))
458 #define XFS_INOCF_CLR_CF(rp, i) \
459 ((rp)->ino_confirmed &= ~XFS_INOCF_MASK((i)))
460
461 /*
462 * same for backptr->ino_reached
463 */
464 #define XFS_INO_RCHD_MASK(i) ((__uint64_t)1 << (i))
465
466 #define XFS_INO_RCHD_IS_RCHD(rp, i) \
467 (((rp)->ino_un.ex_data->ino_reached & XFS_INO_RCHD_MASK((i))) == 0LL \
468 ? 0 : 1)
469 #define XFS_INO_RCHD_SET_RCHD(rp, i) \
470 ((rp)->ino_un.ex_data->ino_reached |= XFS_INO_RCHD_MASK((i)))
471 #define XFS_INO_RCHD_CLR_RCHD(rp, i) \
472 ((rp)->ino_un.ex_data->ino_reached &= ~XFS_INO_RCHD_MASK((i)))
473 /*
474 * set/clear/test is inode a directory inode
475 */
476 #define XFS_INO_ISADIR_MASK(i) ((__uint64_t)1 << (i))
477
478 #define inode_isadir(ino_rec, ino_offset) \
479 (((ino_rec)->ino_isa_dir & XFS_INO_ISADIR_MASK((ino_offset))) == 0LL \
480 ? 0 : 1)
481 #define set_inode_isadir(ino_rec, ino_offset) \
482 ((ino_rec)->ino_isa_dir |= XFS_INO_ISADIR_MASK((ino_offset)))
483 #define clear_inode_isadir(ino_rec, ino_offset) \
484 ((ino_rec)->ino_isa_dir &= ~XFS_INO_ISADIR_MASK((ino_offset)))
485
486
487 /*
488 * set/clear/test is inode known to be valid (although perhaps corrupt)
489 */
490 #define clear_inode_confirmed(ino_rec, ino_offset) \
491 XFS_INOCF_CLR_CF((ino_rec), (ino_offset))
492
493 #define set_inode_confirmed(ino_rec, ino_offset) \
494 XFS_INOCF_SET_CF((ino_rec), (ino_offset))
495
496 #define is_inode_confirmed(ino_rec, ino_offset) \
497 XFS_INOCF_IS_CF(ino_rec, ino_offset)
498
499 /*
500 * set/clear/test is inode free or used
501 */
502 #define set_inode_free(ino_rec, ino_offset) \
503 XFS_INOCF_SET_CF((ino_rec), (ino_offset)), \
504 XFS_INOBT_SET_FREE((ino_rec), (ino_offset))
505
506 #define set_inode_used(ino_rec, ino_offset) \
507 XFS_INOCF_SET_CF((ino_rec), (ino_offset)), \
508 XFS_INOBT_CLR_FREE((ino_rec), (ino_offset))
509
510 #define is_inode_used(ino_rec, ino_offset) \
511 !XFS_INOBT_IS_FREE((ino_rec), (ino_offset))
512
513 #define is_inode_free(ino_rec, ino_offset) \
514 XFS_INOBT_IS_FREE((ino_rec), (ino_offset))
515
516 /*
517 * add_inode_reached() is set on inode I only if I has been reached
518 * by an inode P claiming to be the parent and if I is a directory,
519 * the .. link in the I says that P is I's parent.
520 *
521 * add_inode_ref() is called every time a link to an inode is
522 * detected and drop_inode_ref() is called every time a link to
523 * an inode that we've counted is removed.
524 */
525
526 static inline int
527 is_inode_reached(ino_tree_node_t *ino_rec, int ino_offset)
528 {
529 ASSERT(ino_rec->ino_un.ex_data != NULL);
530 return(XFS_INO_RCHD_IS_RCHD(ino_rec, ino_offset));
531 }
532
533 static inline void
534 add_inode_reached(ino_tree_node_t *ino_rec, int ino_offset)
535 {
536 ASSERT(ino_rec->ino_un.ex_data != NULL);
537
538 (*ino_rec->nlinkops->counted_nlink_inc)(ino_rec, ino_offset);
539 XFS_INO_RCHD_SET_RCHD(ino_rec, ino_offset);
540
541 ASSERT(is_inode_reached(ino_rec, ino_offset));
542 }
543
544 static inline void
545 add_inode_ref(ino_tree_node_t *ino_rec, int ino_offset)
546 {
547 ASSERT(ino_rec->ino_un.ex_data != NULL);
548
549 (*ino_rec->nlinkops->counted_nlink_inc)(ino_rec, ino_offset);
550 }
551
552 static inline void
553 drop_inode_ref(ino_tree_node_t *ino_rec, int ino_offset)
554 {
555 ASSERT(ino_rec->ino_un.ex_data != NULL);
556
557 if ((*ino_rec->nlinkops->counted_nlink_dec)(ino_rec, ino_offset) == 0)
558 XFS_INO_RCHD_CLR_RCHD(ino_rec, ino_offset);
559 }
560
561 static inline int
562 is_inode_referenced(ino_tree_node_t *ino_rec, int ino_offset)
563 {
564 ASSERT(ino_rec->ino_un.ex_data != NULL);
565
566 return (*ino_rec->nlinkops->counted_nlink_get)(ino_rec, ino_offset) > 0;
567 }
568
569 static inline __uint32_t
570 num_inode_references(ino_tree_node_t *ino_rec, int ino_offset)
571 {
572 ASSERT(ino_rec->ino_un.ex_data != NULL);
573
574 return (*ino_rec->nlinkops->counted_nlink_get)(ino_rec, ino_offset);
575 }
576
577 static inline void
578 set_inode_disk_nlinks(ino_tree_node_t *ino_rec, int ino_offset, __uint32_t nlinks)
579 {
580 (*ino_rec->nlinkops->disk_nlink_set)(ino_rec, ino_offset, nlinks);
581 }
582
583 static inline __uint32_t
584 get_inode_disk_nlinks(ino_tree_node_t *ino_rec, int ino_offset)
585 {
586 return (*ino_rec->nlinkops->disk_nlink_get)(ino_rec, ino_offset);
587 }
588
589 /*
590 * has an inode been processed for phase 6 (reference count checking)?
591 * add_inode_refchecked() is set on an inode when it gets traversed
592 * during the reference count phase (6). It's set so that if the inode
593 * is a directory, it's traversed (and it's links counted) only once.
594 */
595 #ifndef XR_INO_REF_DEBUG
596 #define add_inode_refchecked(ino, ino_rec, ino_offset) \
597 XFS_INOPROC_SET_PROC((ino_rec), (ino_offset))
598 #define is_inode_refchecked(ino, ino_rec, ino_offset) \
599 (XFS_INOPROC_IS_PROC(ino_rec, ino_offset) != 0LL)
600 #else
601 void add_inode_refchecked(xfs_ino_t ino,
602 ino_tree_node_t *ino_rec, int ino_offset);
603 int is_inode_refchecked(xfs_ino_t ino,
604 ino_tree_node_t *ino_rec, int ino_offset);
605 #endif /* XR_INO_REF_DEBUG */
606
607 /*
608 * set/get inode number of parent -- works for directory inodes only
609 */
610 void set_inode_parent(ino_tree_node_t *irec, int ino_offset,
611 xfs_ino_t ino);
612 xfs_ino_t get_inode_parent(ino_tree_node_t *irec, int ino_offset);
613
614 /*
615 * bmap cursor for tracking and fixing bmap btrees. All xfs btrees number
616 * the levels with 0 being the leaf and every level up being 1 greater.
617 */
618
619 #define XR_MAX_BMLEVELS 10 /* XXX - rcc need to verify number */
620
621 typedef struct bm_level_state {
622 xfs_dfsbno_t fsbno;
623 xfs_dfsbno_t left_fsbno;
624 xfs_dfsbno_t right_fsbno;
625 __uint64_t first_key;
626 __uint64_t last_key;
627 /*
628 int level;
629 __uint64_t prev_last_key;
630 xfs_buf_t *bp;
631 xfs_bmbt_block_t *block;
632 */
633 } bm_level_state_t;
634
635 typedef struct bm_cursor {
636 int num_levels;
637 xfs_ino_t ino;
638 xfs_dinode_t *dip;
639 bm_level_state_t level[XR_MAX_BMLEVELS];
640 } bmap_cursor_t;
641
642 void init_bm_cursor(bmap_cursor_t *cursor, int num_level);
643
644 #endif /* XFS_REPAIR_INCORE_H */