]>
Commit | Line | Data |
---|---|---|
2bd0ea18 | 1 | /* |
da23017d NS |
2 | * Copyright (c) 2000-2002,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 | ||
2556c98b BN |
19 | #ifndef XFS_REPAIR_INCORE_H |
20 | #define XFS_REPAIR_INCORE_H | |
21 | ||
22 | #include "avl.h" | |
79872d6e BN |
23 | |
24 | ||
2bd0ea18 NS |
25 | /* |
26 | * contains definition information. implementation (code) | |
27 | * is spread out in separate files. | |
28 | */ | |
29 | ||
2bd0ea18 | 30 | /* |
8961bfde | 31 | * block map -- track state of each filesystem block. |
2bd0ea18 | 32 | */ |
2bd0ea18 | 33 | |
8961bfde BN |
34 | void init_bmaps(xfs_mount_t *mp); |
35 | void reset_bmaps(xfs_mount_t *mp); | |
36 | void free_bmaps(xfs_mount_t *mp); | |
37 | ||
38 | void set_bmap_ext(xfs_agnumber_t agno, xfs_agblock_t agbno, | |
39 | xfs_extlen_t blen, int state); | |
40 | int get_bmap_ext(xfs_agnumber_t agno, xfs_agblock_t agbno, | |
41 | xfs_agblock_t maxbno, xfs_extlen_t *blen); | |
42 | ||
5a35bf2c DC |
43 | void set_rtbmap(xfs_rtblock_t bno, int state); |
44 | int get_rtbmap(xfs_rtblock_t bno); | |
8961bfde BN |
45 | |
46 | static inline void | |
47 | set_bmap(xfs_agnumber_t agno, xfs_agblock_t agbno, int state) | |
48 | { | |
49 | set_bmap_ext(agno, agbno, 1, state); | |
50 | } | |
51 | ||
52 | static inline int | |
53 | get_bmap(xfs_agnumber_t agno, xfs_agblock_t agbno) | |
54 | { | |
55 | return get_bmap_ext(agno, agbno, agbno + 1, NULL); | |
56 | } | |
2bd0ea18 NS |
57 | |
58 | /* | |
59 | * extent tree definitions | |
60 | * right now, there are 3 trees per AG, a bno tree, a bcnt tree | |
61 | * and a tree for dup extents. If the code is modified in the | |
62 | * future to use an extent tree instead of a bitmask for tracking | |
63 | * fs blocks, then we could lose the dup extent tree if we labelled | |
64 | * each extent with the inode that owned it. | |
65 | */ | |
66 | ||
67 | typedef unsigned char extent_state_t; | |
68 | ||
69 | typedef struct extent_tree_node { | |
70 | avlnode_t avl_node; | |
71 | xfs_agblock_t ex_startblock; /* starting block (agbno) */ | |
72 | xfs_extlen_t ex_blockcount; /* number of blocks in extent */ | |
73 | extent_state_t ex_state; /* see state flags below */ | |
74 | ||
75 | struct extent_tree_node *next; /* for bcnt extent lists */ | |
b87887d4 | 76 | struct extent_tree_node *last; /* for bcnt extent list anchors */ |
2bd0ea18 NS |
77 | #if 0 |
78 | xfs_ino_t ex_inode; /* owner, NULL if free or */ | |
79 | /* multiply allocated */ | |
80 | #endif | |
81 | } extent_tree_node_t; | |
82 | ||
83 | typedef struct rt_extent_tree_node { | |
84 | avlnode_t avl_node; | |
5a35bf2c | 85 | xfs_rtblock_t rt_startblock; /* starting realtime block */ |
2bd0ea18 NS |
86 | xfs_extlen_t rt_blockcount; /* number of blocks in extent */ |
87 | extent_state_t rt_state; /* see state flags below */ | |
88 | ||
89 | #if 0 | |
90 | xfs_ino_t ex_inode; /* owner, NULL if free or */ | |
91 | /* multiply allocated */ | |
92 | #endif | |
93 | } rt_extent_tree_node_t; | |
94 | ||
95 | /* extent states, prefix with XR_ to avoid conflict with buffer cache defines */ | |
96 | ||
97 | #define XR_E_UNKNOWN 0 /* unknown state */ | |
98 | #define XR_E_FREE1 1 /* free block (marked by one fs space tree) */ | |
99 | #define XR_E_FREE 2 /* free block (marked by both fs space trees) */ | |
100 | #define XR_E_INUSE 3 /* extent used by file/dir data or metadata */ | |
101 | #define XR_E_INUSE_FS 4 /* extent used by fs ag header or log */ | |
102 | #define XR_E_MULT 5 /* extent is multiply referenced */ | |
103 | #define XR_E_INO 6 /* extent used by inodes (inode blocks) */ | |
104 | #define XR_E_FS_MAP 7 /* extent used by fs space/inode maps */ | |
0f94fa4b DW |
105 | #define XR_E_INUSE1 8 /* used block (marked by rmap btree) */ |
106 | #define XR_E_INUSE_FS1 9 /* used by fs ag header or log (rmap btree) */ | |
107 | #define XR_E_INO1 10 /* used by inodes (marked by rmap btree) */ | |
108 | #define XR_E_FS_MAP1 11 /* used by fs space/inode maps (rmap btree) */ | |
18c44aa9 | 109 | #define XR_E_REFC 12 /* used by fs ag reference count btree */ |
13ef9674 DW |
110 | #define XR_E_COW 13 /* leftover cow extent */ |
111 | #define XR_E_BAD_STATE 14 | |
1e77098c | 112 | |
2bd0ea18 NS |
113 | /* separate state bit, OR'ed into high (4th) bit of ex_state field */ |
114 | ||
115 | #define XR_E_WRITTEN 0x8 /* extent has been written out, can't reclaim */ | |
116 | #define good_state(state) (((state) & (~XR_E_WRITTEN)) >= XR_E_UNKNOWN && \ | |
117 | ((state) & (~XR_E_WRITTEN) < XF_E_BAD_STATE)) | |
118 | #define written(state) ((state) & XR_E_WRITTEN) | |
119 | #define set_written(state) (state) &= XR_E_WRITTEN | |
120 | ||
121 | /* | |
122 | * bno extent tree functions | |
123 | */ | |
124 | void | |
125 | add_bno_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, | |
126 | xfs_extlen_t blockcount); | |
127 | ||
128 | extent_tree_node_t * | |
129 | findfirst_bno_extent(xfs_agnumber_t agno); | |
130 | ||
131 | extent_tree_node_t * | |
132 | find_bno_extent(xfs_agnumber_t agno, xfs_agblock_t agbno); | |
133 | ||
134 | extent_tree_node_t * | |
135 | findfirst_bno_extent(xfs_agnumber_t agno); | |
136 | ||
137 | #define findnext_bno_extent(exent_ptr) \ | |
138 | ((extent_tree_node_t *) ((exent_ptr)->avl_node.avl_nextino)) | |
139 | ||
140 | void | |
141 | get_bno_extent(xfs_agnumber_t agno, extent_tree_node_t *ext); | |
142 | ||
143 | /* | |
144 | * bcnt tree functions | |
145 | */ | |
146 | void | |
147 | add_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, | |
148 | xfs_extlen_t blockcount); | |
149 | ||
150 | extent_tree_node_t * | |
151 | findfirst_bcnt_extent(xfs_agnumber_t agno); | |
152 | ||
153 | extent_tree_node_t * | |
154 | find_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t agbno); | |
155 | ||
156 | extent_tree_node_t * | |
157 | findbiggest_bcnt_extent(xfs_agnumber_t agno); | |
158 | ||
159 | extent_tree_node_t * | |
160 | findnext_bcnt_extent(xfs_agnumber_t agno, extent_tree_node_t *ext); | |
161 | ||
162 | extent_tree_node_t * | |
163 | get_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, | |
164 | xfs_extlen_t blockcount); | |
165 | ||
166 | /* | |
167 | * duplicate extent tree functions | |
168 | */ | |
2bd0ea18 | 169 | |
79872d6e BN |
170 | int add_dup_extent(xfs_agnumber_t agno, xfs_agblock_t startblock, |
171 | xfs_extlen_t blockcount); | |
172 | int search_dup_extent(xfs_agnumber_t agno, | |
173 | xfs_agblock_t start_agbno, xfs_agblock_t end_agbno); | |
5a35bf2c | 174 | void add_rt_dup_extent(xfs_rtblock_t startblock, |
2bd0ea18 NS |
175 | xfs_extlen_t blockcount); |
176 | ||
177 | int search_rt_dup_extent(xfs_mount_t *mp, | |
5a35bf2c | 178 | xfs_rtblock_t bno); |
2bd0ea18 NS |
179 | |
180 | /* | |
181 | * extent/tree recyling and deletion routines | |
182 | */ | |
183 | ||
184 | /* | |
185 | * return an extent node to the extent node free list | |
186 | */ | |
187 | void release_extent_tree_node(extent_tree_node_t *node); | |
188 | ||
189 | /* | |
190 | * recycle all the nodes in the per-AG tree | |
191 | */ | |
192 | void release_dup_extent_tree(xfs_agnumber_t agno); | |
193 | void release_agbno_extent_tree(xfs_agnumber_t agno); | |
194 | void release_agbcnt_extent_tree(xfs_agnumber_t agno); | |
195 | ||
196 | /* | |
197 | * realtime duplicate extent tree - this one actually frees the memory | |
198 | */ | |
199 | void free_rt_dup_extent_tree(xfs_mount_t *mp); | |
200 | ||
c1f7a46c | 201 | void incore_ext_init(xfs_mount_t *); |
2bd0ea18 NS |
202 | /* |
203 | * per-AG extent trees shutdown routine -- all (bno, bcnt and dup) | |
204 | * at once. this one actually frees the memory instead of just recyling | |
205 | * the nodes. | |
206 | */ | |
207 | void incore_ext_teardown(xfs_mount_t *mp); | |
c1f7a46c BN |
208 | void incore_ino_init(xfs_mount_t *); |
209 | ||
52cb19dc CH |
210 | int count_bno_extents(xfs_agnumber_t); |
211 | int count_bno_extents_blocks(xfs_agnumber_t, uint *); | |
212 | int count_bcnt_extents(xfs_agnumber_t); | |
213 | ||
2bd0ea18 NS |
214 | /* |
215 | * inode definitions | |
216 | */ | |
217 | ||
218 | /* inode types */ | |
219 | ||
220 | #define XR_INO_UNKNOWN 0 /* unknown */ | |
221 | #define XR_INO_DIR 1 /* directory */ | |
222 | #define XR_INO_RTDATA 2 /* realtime file */ | |
223 | #define XR_INO_RTBITMAP 3 /* realtime bitmap inode */ | |
224 | #define XR_INO_RTSUM 4 /* realtime summary inode */ | |
225 | #define XR_INO_DATA 5 /* regular file */ | |
226 | #define XR_INO_SYMLINK 6 /* symlink */ | |
227 | #define XR_INO_CHRDEV 7 /* character device */ | |
228 | #define XR_INO_BLKDEV 8 /* block device */ | |
229 | #define XR_INO_SOCK 9 /* socket */ | |
230 | #define XR_INO_FIFO 10 /* fifo */ | |
231 | #define XR_INO_MOUNTPOINT 11 /* mountpoint */ | |
232 | ||
233 | /* inode allocation tree */ | |
234 | ||
235 | /* | |
236 | * Inodes in the inode allocation trees are allocated in chunks. | |
237 | * Those groups can be easily duplicated in our trees. | |
238 | * Disconnected inodes are harder. We can do one of two | |
239 | * things in that case: if we know the inode allocation btrees | |
240 | * are good, then we can disallow directory references to unknown | |
241 | * inode chunks. If the inode allocation trees have been trashed or | |
242 | * we feel like being aggressive, then as we hit unknown inodes, | |
243 | * we can search on the disk for all contiguous inodes and see if | |
244 | * they fit into chunks. Before putting them into the inode tree, | |
245 | * we can scan each inode starting at the earliest inode to see which | |
246 | * ones are good. This protects us from the pathalogical case of | |
247 | * inodes appearing in user-data. We still may have to mark the | |
248 | * inodes as "possibly fake" so that if a file claims the blocks, | |
249 | * we decide to believe the inodes, especially if they're not | |
250 | * connected. | |
251 | */ | |
252 | ||
253 | #define PLIST_CHUNK_SIZE 4 | |
254 | ||
255 | typedef xfs_ino_t parent_entry_t; | |
256 | ||
0f012a4c BN |
257 | struct nlink_ops; |
258 | ||
2bd0ea18 | 259 | typedef struct parent_list { |
14f8b681 | 260 | uint64_t pmask; |
2bd0ea18 NS |
261 | parent_entry_t *pentries; |
262 | #ifdef DEBUG | |
263 | short cnt; | |
264 | #endif | |
265 | } parent_list_t; | |
266 | ||
edfb350c | 267 | union ino_nlink { |
14f8b681 DW |
268 | uint8_t *un8; |
269 | uint16_t *un16; | |
270 | uint32_t *un32; | |
edfb350c CH |
271 | }; |
272 | ||
0f012a4c | 273 | typedef struct ino_ex_data { |
14f8b681 DW |
274 | uint64_t ino_reached; /* bit == 1 if reached */ |
275 | uint64_t ino_processed; /* reference checked bit mask */ | |
2bd0ea18 | 276 | parent_list_t *parents; |
edfb350c | 277 | union ino_nlink counted_nlinks;/* counted nlinks in P6 */ |
0f012a4c | 278 | } ino_ex_data_t; |
2bd0ea18 NS |
279 | |
280 | typedef struct ino_tree_node { | |
281 | avlnode_t avl_node; | |
282 | xfs_agino_t ino_startnum; /* starting inode # */ | |
283 | xfs_inofree_t ir_free; /* inode free bit mask */ | |
14f8b681 DW |
284 | uint64_t ir_sparse; /* sparse inode bitmask */ |
285 | uint64_t ino_confirmed; /* confirmed bitmask */ | |
286 | uint64_t ino_isa_dir; /* bit == 1 if a directory */ | |
287 | uint64_t ino_was_rl; /* bit == 1 if reflink flag set */ | |
288 | uint64_t ino_is_rl; /* bit == 1 if reflink flag should be set */ | |
289 | uint8_t nlink_size; | |
edfb350c | 290 | union ino_nlink disk_nlinks; /* on-disk nlinks, set in P3 */ |
2bd0ea18 | 291 | union { |
0f012a4c BN |
292 | ino_ex_data_t *ex_data; /* phases 6,7 */ |
293 | parent_list_t *plist; /* phases 2-5 */ | |
2bd0ea18 | 294 | } ino_un; |
14f8b681 | 295 | uint8_t *ftypes; /* phases 3,6 */ |
2bd0ea18 NS |
296 | } ino_tree_node_t; |
297 | ||
14f8b681 DW |
298 | #define INOS_PER_IREC (sizeof(uint64_t) * NBBY) |
299 | #define IREC_MASK(i) ((uint64_t)1 << (i)) | |
f4ef1178 | 300 | |
0f012a4c | 301 | void add_ino_ex_data(xfs_mount_t *mp); |
2bd0ea18 NS |
302 | |
303 | /* | |
304 | * return an inode record to the free inode record pool | |
305 | */ | |
306 | void free_inode_rec(xfs_agnumber_t agno, ino_tree_node_t *ino_rec); | |
307 | ||
308 | /* | |
309 | * get pulls the inode record from the good inode tree | |
310 | */ | |
1ae311d5 LC |
311 | void get_inode_rec(struct xfs_mount *mp, xfs_agnumber_t agno, |
312 | ino_tree_node_t *ino_rec); | |
2bd0ea18 | 313 | |
1e77098c | 314 | extern avltree_desc_t **inode_tree_ptrs; |
1b9f3650 CM |
315 | |
316 | static inline int | |
317 | get_inode_offset(struct xfs_mount *mp, xfs_ino_t ino, ino_tree_node_t *irec) | |
318 | { | |
319 | return XFS_INO_TO_AGINO(mp, ino) - irec->ino_startnum; | |
320 | } | |
78a0dc91 | 321 | static inline ino_tree_node_t * |
1e77098c MV |
322 | findfirst_inode_rec(xfs_agnumber_t agno) |
323 | { | |
324 | return((ino_tree_node_t *) inode_tree_ptrs[agno]->avl_firstino); | |
325 | } | |
78a0dc91 | 326 | static inline ino_tree_node_t * |
1ae311d5 | 327 | find_inode_rec(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t ino) |
1e77098c | 328 | { |
1ae311d5 LC |
329 | /* |
330 | * Is the AG inside the file system | |
331 | */ | |
332 | if (agno >= mp->m_sb.sb_agcount) | |
333 | return NULL; | |
1e77098c MV |
334 | return((ino_tree_node_t *) |
335 | avl_findrange(inode_tree_ptrs[agno], ino)); | |
336 | } | |
1ae311d5 | 337 | void find_inode_rec_range(struct xfs_mount *mp, xfs_agnumber_t agno, |
2bd0ea18 NS |
338 | xfs_agino_t start_ino, xfs_agino_t end_ino, |
339 | ino_tree_node_t **first, ino_tree_node_t **last); | |
340 | ||
341 | /* | |
342 | * set inode states -- setting an inode to used or free also | |
343 | * automatically marks it as "existing". Note -- all the inode | |
344 | * add/set/get routines assume a valid inode number. | |
345 | */ | |
1ae311d5 LC |
346 | ino_tree_node_t *set_inode_used_alloc(struct xfs_mount *mp, xfs_agnumber_t agno, |
347 | xfs_agino_t ino); | |
348 | ino_tree_node_t *set_inode_free_alloc(struct xfs_mount *mp, xfs_agnumber_t agno, | |
349 | xfs_agino_t ino); | |
2bd0ea18 NS |
350 | |
351 | void print_inode_list(xfs_agnumber_t agno); | |
352 | void print_uncertain_inode_list(xfs_agnumber_t agno); | |
353 | ||
354 | /* | |
355 | * separate trees for uncertain inodes (they may not exist). | |
356 | */ | |
357 | ino_tree_node_t *findfirst_uncertain_inode_rec(xfs_agnumber_t agno); | |
2d9475a4 NS |
358 | ino_tree_node_t *find_uncertain_inode_rec(xfs_agnumber_t agno, |
359 | xfs_agino_t ino); | |
2bd0ea18 NS |
360 | void add_inode_uncertain(xfs_mount_t *mp, |
361 | xfs_ino_t ino, int free); | |
aaca101b DC |
362 | void add_aginode_uncertain(struct xfs_mount *mp, |
363 | xfs_agnumber_t agno, | |
2bd0ea18 | 364 | xfs_agino_t agino, int free); |
1ae311d5 LC |
365 | void get_uncertain_inode_rec(struct xfs_mount *mp, |
366 | xfs_agnumber_t agno, | |
2bd0ea18 NS |
367 | ino_tree_node_t *ino_rec); |
368 | void clear_uncertain_ino_cache(xfs_agnumber_t agno); | |
369 | ||
370 | /* | |
371 | * return next in-order inode tree node. takes an "ino_tree_node_t *" | |
372 | */ | |
373 | #define next_ino_rec(ino_node_ptr) \ | |
374 | ((ino_tree_node_t *) ((ino_node_ptr)->avl_node.avl_nextino)) | |
375 | /* | |
376 | * return the next linked inode (forward avl tree link)-- meant to be used | |
377 | * by linked list routines (uncertain inode routines/records) | |
378 | */ | |
379 | #define next_link_rec(ino_node_ptr) \ | |
380 | ((ino_tree_node_t *) ((ino_node_ptr)->avl_node.avl_forw)) | |
381 | ||
01159bd2 BF |
382 | /* |
383 | * finobt helpers | |
384 | */ | |
c77c41ee BF |
385 | |
386 | static inline bool | |
387 | inode_rec_has_free(struct ino_tree_node *ino_rec) | |
388 | { | |
389 | /* must have real, allocated inodes for finobt */ | |
390 | return ino_rec->ir_free & ~ino_rec->ir_sparse; | |
391 | } | |
392 | ||
01159bd2 BF |
393 | static inline ino_tree_node_t * |
394 | findfirst_free_inode_rec(xfs_agnumber_t agno) | |
395 | { | |
396 | ino_tree_node_t *ino_rec; | |
397 | ||
398 | ino_rec = findfirst_inode_rec(agno); | |
399 | ||
c77c41ee | 400 | while (ino_rec && !inode_rec_has_free(ino_rec)) |
01159bd2 BF |
401 | ino_rec = next_ino_rec(ino_rec); |
402 | ||
403 | return ino_rec; | |
404 | } | |
405 | ||
406 | static inline ino_tree_node_t * | |
407 | next_free_ino_rec(ino_tree_node_t *ino_rec) | |
408 | { | |
409 | ino_rec = next_ino_rec(ino_rec); | |
410 | ||
c77c41ee | 411 | while (ino_rec && !inode_rec_has_free(ino_rec)) |
01159bd2 BF |
412 | ino_rec = next_ino_rec(ino_rec); |
413 | ||
414 | return ino_rec; | |
415 | } | |
416 | ||
2bd0ea18 | 417 | /* |
f4ef1178 CH |
418 | * Has an inode been processed for phase 6 (reference count checking)? |
419 | * | |
420 | * add_inode_refchecked() is set on an inode when it gets traversed | |
421 | * during the reference count phase (6). It's set so that if the inode | |
422 | * is a directory, it's traversed (and it's links counted) only once. | |
2bd0ea18 | 423 | */ |
f4ef1178 CH |
424 | static inline void add_inode_refchecked(struct ino_tree_node *irec, int offset) |
425 | { | |
426 | irec->ino_un.ex_data->ino_processed |= IREC_MASK(offset); | |
427 | } | |
2bd0ea18 | 428 | |
f4ef1178 CH |
429 | static inline int is_inode_refchecked(struct ino_tree_node *irec, int offset) |
430 | { | |
431 | return (irec->ino_un.ex_data->ino_processed & IREC_MASK(offset)) != 0; | |
432 | } | |
2bd0ea18 NS |
433 | |
434 | /* | |
f4ef1178 | 435 | * set/test is inode known to be valid (although perhaps corrupt) |
2bd0ea18 | 436 | */ |
f4ef1178 CH |
437 | static inline void set_inode_confirmed(struct ino_tree_node *irec, int offset) |
438 | { | |
439 | irec->ino_confirmed |= IREC_MASK(offset); | |
440 | } | |
2bd0ea18 | 441 | |
f4ef1178 CH |
442 | static inline int is_inode_confirmed(struct ino_tree_node *irec, int offset) |
443 | { | |
444 | return (irec->ino_confirmed & IREC_MASK(offset)) != 0; | |
445 | } | |
2bd0ea18 NS |
446 | |
447 | /* | |
f4ef1178 | 448 | * set/clear/test is inode a directory inode |
2bd0ea18 | 449 | */ |
f4ef1178 CH |
450 | static inline void set_inode_isadir(struct ino_tree_node *irec, int offset) |
451 | { | |
452 | irec->ino_isa_dir |= IREC_MASK(offset); | |
453 | } | |
2bd0ea18 | 454 | |
f4ef1178 CH |
455 | static inline void clear_inode_isadir(struct ino_tree_node *irec, int offset) |
456 | { | |
457 | irec->ino_isa_dir &= ~IREC_MASK(offset); | |
458 | } | |
2bd0ea18 | 459 | |
f4ef1178 CH |
460 | static inline int inode_isadir(struct ino_tree_node *irec, int offset) |
461 | { | |
462 | return (irec->ino_isa_dir & IREC_MASK(offset)) != 0; | |
463 | } | |
2bd0ea18 NS |
464 | |
465 | /* | |
466 | * set/clear/test is inode free or used | |
467 | */ | |
f4ef1178 CH |
468 | static inline void set_inode_free(struct ino_tree_node *irec, int offset) |
469 | { | |
470 | set_inode_confirmed(irec, offset); | |
471 | irec->ir_free |= XFS_INOBT_MASK(offset); | |
2bd0ea18 | 472 | |
f4ef1178 | 473 | } |
56b2de80 | 474 | |
f4ef1178 CH |
475 | static inline void set_inode_used(struct ino_tree_node *irec, int offset) |
476 | { | |
477 | set_inode_confirmed(irec, offset); | |
478 | irec->ir_free &= ~XFS_INOBT_MASK(offset); | |
479 | } | |
2bd0ea18 | 480 | |
f4ef1178 CH |
481 | static inline int is_inode_free(struct ino_tree_node *irec, int offset) |
482 | { | |
483 | return (irec->ir_free & XFS_INOBT_MASK(offset)) != 0; | |
484 | } | |
2bd0ea18 | 485 | |
c749bd55 BF |
486 | /* |
487 | * set/test is inode sparse (not physically allocated) | |
488 | */ | |
489 | static inline void set_inode_sparse(struct ino_tree_node *irec, int offset) | |
490 | { | |
491 | irec->ir_sparse |= XFS_INOBT_MASK(offset); | |
492 | } | |
493 | ||
494 | static inline bool is_inode_sparse(struct ino_tree_node *irec, int offset) | |
495 | { | |
496 | return irec->ir_sparse & XFS_INOBT_MASK(offset); | |
497 | } | |
498 | ||
7e174ec7 DW |
499 | /* |
500 | * set/clear/test was inode marked as reflinked | |
501 | */ | |
502 | static inline void set_inode_was_rl(struct ino_tree_node *irec, int offset) | |
503 | { | |
504 | irec->ino_was_rl |= IREC_MASK(offset); | |
505 | } | |
506 | ||
507 | static inline void clear_inode_was_rl(struct ino_tree_node *irec, int offset) | |
508 | { | |
509 | irec->ino_was_rl &= ~IREC_MASK(offset); | |
510 | } | |
511 | ||
512 | static inline int inode_was_rl(struct ino_tree_node *irec, int offset) | |
513 | { | |
514 | return (irec->ino_was_rl & IREC_MASK(offset)) != 0; | |
515 | } | |
516 | ||
517 | /* | |
518 | * set/clear/test should inode be marked as reflinked | |
519 | */ | |
520 | static inline void set_inode_is_rl(struct ino_tree_node *irec, int offset) | |
521 | { | |
522 | irec->ino_is_rl |= IREC_MASK(offset); | |
523 | } | |
524 | ||
525 | static inline void clear_inode_is_rl(struct ino_tree_node *irec, int offset) | |
526 | { | |
527 | irec->ino_is_rl &= ~IREC_MASK(offset); | |
528 | } | |
529 | ||
530 | static inline int inode_is_rl(struct ino_tree_node *irec, int offset) | |
531 | { | |
532 | return (irec->ino_is_rl & IREC_MASK(offset)) != 0; | |
533 | } | |
534 | ||
2bd0ea18 NS |
535 | /* |
536 | * add_inode_reached() is set on inode I only if I has been reached | |
537 | * by an inode P claiming to be the parent and if I is a directory, | |
538 | * the .. link in the I says that P is I's parent. | |
539 | * | |
540 | * add_inode_ref() is called every time a link to an inode is | |
541 | * detected and drop_inode_ref() is called every time a link to | |
542 | * an inode that we've counted is removed. | |
543 | */ | |
edfb350c CH |
544 | void add_inode_ref(struct ino_tree_node *irec, int offset); |
545 | void drop_inode_ref(struct ino_tree_node *irec, int offset); | |
14f8b681 | 546 | uint32_t num_inode_references(struct ino_tree_node *irec, int offset); |
2bd0ea18 | 547 | |
14f8b681 DW |
548 | void set_inode_disk_nlinks(struct ino_tree_node *irec, int offset, uint32_t nlinks); |
549 | uint32_t get_inode_disk_nlinks(struct ino_tree_node *irec, int offset); | |
1e77098c | 550 | |
f4ef1178 | 551 | static inline int is_inode_reached(struct ino_tree_node *irec, int offset) |
1e77098c | 552 | { |
f4ef1178 CH |
553 | ASSERT(irec->ino_un.ex_data != NULL); |
554 | return (irec->ino_un.ex_data->ino_reached & IREC_MASK(offset)) != 0; | |
1e77098c MV |
555 | } |
556 | ||
f4ef1178 | 557 | static inline void add_inode_reached(struct ino_tree_node *irec, int offset) |
1e77098c | 558 | { |
f4ef1178 CH |
559 | add_inode_ref(irec, offset); |
560 | irec->ino_un.ex_data->ino_reached |= IREC_MASK(offset); | |
0f012a4c BN |
561 | } |
562 | ||
aaca101b DC |
563 | /* |
564 | * get/set inode filetype. Only used if the superblock feature bit is set | |
565 | * which allocates irec->ftypes. | |
566 | */ | |
567 | static inline void | |
568 | set_inode_ftype(struct ino_tree_node *irec, | |
569 | int ino_offset, | |
14f8b681 | 570 | uint8_t ftype) |
aaca101b DC |
571 | { |
572 | if (irec->ftypes) | |
573 | irec->ftypes[ino_offset] = ftype; | |
574 | } | |
575 | ||
14f8b681 | 576 | static inline uint8_t |
aaca101b DC |
577 | get_inode_ftype( |
578 | struct ino_tree_node *irec, | |
579 | int ino_offset) | |
580 | { | |
581 | if (!irec->ftypes) | |
582 | return XFS_DIR3_FT_UNKNOWN; | |
583 | return irec->ftypes[ino_offset]; | |
584 | } | |
585 | ||
2bd0ea18 NS |
586 | /* |
587 | * set/get inode number of parent -- works for directory inodes only | |
588 | */ | |
589 | void set_inode_parent(ino_tree_node_t *irec, int ino_offset, | |
590 | xfs_ino_t ino); | |
2bd0ea18 NS |
591 | xfs_ino_t get_inode_parent(ino_tree_node_t *irec, int ino_offset); |
592 | ||
2e162270 ES |
593 | /* |
594 | * Allocate extra inode data | |
595 | */ | |
596 | void alloc_ex_data(ino_tree_node_t *irec); | |
597 | ||
2bd0ea18 NS |
598 | /* |
599 | * bmap cursor for tracking and fixing bmap btrees. All xfs btrees number | |
600 | * the levels with 0 being the leaf and every level up being 1 greater. | |
601 | */ | |
602 | ||
603 | #define XR_MAX_BMLEVELS 10 /* XXX - rcc need to verify number */ | |
604 | ||
605 | typedef struct bm_level_state { | |
5a35bf2c DC |
606 | xfs_fsblock_t fsbno; |
607 | xfs_fsblock_t left_fsbno; | |
608 | xfs_fsblock_t right_fsbno; | |
14f8b681 DW |
609 | uint64_t first_key; |
610 | uint64_t last_key; | |
2bd0ea18 NS |
611 | /* |
612 | int level; | |
14f8b681 | 613 | uint64_t prev_last_key; |
2bd0ea18 NS |
614 | xfs_buf_t *bp; |
615 | xfs_bmbt_block_t *block; | |
616 | */ | |
617 | } bm_level_state_t; | |
618 | ||
619 | typedef struct bm_cursor { | |
620 | int num_levels; | |
621 | xfs_ino_t ino; | |
622 | xfs_dinode_t *dip; | |
623 | bm_level_state_t level[XR_MAX_BMLEVELS]; | |
624 | } bmap_cursor_t; | |
625 | ||
626 | void init_bm_cursor(bmap_cursor_t *cursor, int num_level); | |
2556c98b | 627 | |
ac9a3f73 BF |
628 | /* |
629 | * On-disk inobt record helpers. The sparse inode record format has a single | |
630 | * byte freecount. The older format has a 32-bit freecount and thus byte | |
631 | * conversion is necessary. | |
632 | */ | |
633 | ||
634 | static inline int | |
635 | inorec_get_freecount( | |
636 | struct xfs_mount *mp, | |
637 | struct xfs_inobt_rec *rp) | |
638 | { | |
639 | if (xfs_sb_version_hassparseinodes(&mp->m_sb)) | |
640 | return rp->ir_u.sp.ir_freecount; | |
641 | return be32_to_cpu(rp->ir_u.f.ir_freecount); | |
642 | } | |
643 | ||
644 | static inline void | |
645 | inorec_set_freecount( | |
646 | struct xfs_mount *mp, | |
647 | struct xfs_inobt_rec *rp, | |
648 | int freecount) | |
649 | { | |
650 | if (xfs_sb_version_hassparseinodes(&mp->m_sb)) | |
651 | rp->ir_u.sp.ir_freecount = freecount; | |
652 | else | |
653 | rp->ir_u.f.ir_freecount = cpu_to_be32(freecount); | |
654 | } | |
655 | ||
2556c98b | 656 | #endif /* XFS_REPAIR_INCORE_H */ |