2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
40 #include "err_protos.h"
42 extern avlnode_t
*avl_firstino(avlnode_t
*root
);
45 * array of inode tree ptrs, one per ag
47 static avltree_desc_t
**inode_tree_ptrs
;
50 * ditto for uncertain inodes
52 static avltree_desc_t
**inode_uncertain_tree_ptrs
;
54 #define ALLOC_NUM_INOS 100
56 /* free lists -- inode nodes and extent nodes */
58 typedef struct ino_flist_s
{
59 ino_tree_node_t
*list
;
60 ino_tree_node_t
*last
;
64 static ino_flist_t ino_flist
; /* free list must be initialized before use */
67 * next is the uncertain inode list -- a sorted (in ascending order)
68 * list of inode records sorted on the starting inode number. There
73 * common code for creating inode records for use by trees and lists.
74 * called only from add_inodes and add_inodes_uncertain
76 * IMPORTANT: all inodes (inode records) start off as free and
80 static ino_tree_node_t
*
81 mk_ino_tree_nodes(xfs_agino_t starting_ino
)
87 if (ino_flist
.cnt
== 0) {
88 ASSERT(ino_flist
.list
== NULL
);
90 if ((new = malloc(sizeof(ino_tree_node_t
[ALLOC_NUM_INOS
])))
92 do_error("inode map malloc failed\n");
94 for (i
= 0; i
< ALLOC_NUM_INOS
; i
++) {
95 new->avl_node
.avl_nextino
=
96 (avlnode_t
*) ino_flist
.list
;
103 ASSERT(ino_flist
.list
!= NULL
);
105 new = ino_flist
.list
;
106 ino_flist
.list
= (ino_tree_node_t
*) new->avl_node
.avl_nextino
;
108 node
= &new->avl_node
;
109 node
->avl_nextino
= node
->avl_forw
= node
->avl_back
= NULL
;
111 /* initialize node */
113 new->ino_startnum
= 0;
114 new->ino_confirmed
= 0;
115 new->ino_isa_dir
= 0;
116 new->ir_free
= (xfs_inofree_t
) - 1;
117 new->ino_un
.backptrs
= NULL
;
123 * return inode record to free list, will be initialized when
124 * it gets pulled off list
127 free_ino_tree_node(ino_tree_node_t
*ino_rec
)
129 ino_rec
->avl_node
.avl_nextino
= NULL
;
130 ino_rec
->avl_node
.avl_forw
= NULL
;
131 ino_rec
->avl_node
.avl_back
= NULL
;
133 if (ino_flist
.list
!= NULL
) {
134 ASSERT(ino_flist
.cnt
> 0);
135 ino_rec
->avl_node
.avl_nextino
= (avlnode_t
*) ino_flist
.list
;
137 ASSERT(ino_flist
.cnt
== 0);
138 ino_rec
->avl_node
.avl_nextino
= NULL
;
141 ino_flist
.list
= ino_rec
;
144 if (ino_rec
->ino_un
.backptrs
!= NULL
) {
145 if (full_backptrs
&& ino_rec
->ino_un
.backptrs
->parents
!= NULL
)
146 free(ino_rec
->ino_un
.backptrs
->parents
);
147 if (ino_rec
->ino_un
.plist
!= NULL
)
148 free(ino_rec
->ino_un
.plist
);
155 * last referenced cache for uncertain inodes
157 static ino_tree_node_t
**last_rec
;
160 * ok, the uncertain inodes are a set of trees just like the
161 * good inodes but all starting inode records are (arbitrarily)
162 * aligned on XFS_CHUNK_PER_INODE boundaries to prevent overlaps.
163 * this means we may have partials records in the tree (e.g. records
164 * without 64 confirmed uncertain inodes). Tough.
166 * free is set to 1 if the inode is thought to be free, 0 if used
169 add_aginode_uncertain(xfs_agnumber_t agno
, xfs_agino_t ino
, int free
)
171 ino_tree_node_t
*ino_rec
;
175 ASSERT(agno
< glob_agcount
);
176 ASSERT(last_rec
!= NULL
);
178 s_ino
= rounddown(ino
, XFS_INODES_PER_CHUNK
);
181 * check for a cache hit
183 if (last_rec
[agno
] != NULL
&& last_rec
[agno
]->ino_startnum
== s_ino
) {
184 offset
= ino
- s_ino
;
186 set_inode_free(last_rec
[agno
], offset
);
188 set_inode_used(last_rec
[agno
], offset
);
194 * check to see if record containing inode is already in the tree.
197 if ((ino_rec
= (ino_tree_node_t
*)
198 avl_findrange(inode_uncertain_tree_ptrs
[agno
],
200 ino_rec
= mk_ino_tree_nodes(s_ino
);
201 ino_rec
->ino_startnum
= s_ino
;
203 if (avl_insert(inode_uncertain_tree_ptrs
[agno
],
204 (avlnode_t
*) ino_rec
) == NULL
) {
205 do_error("xfs_repair: add_aginode_uncertain - "
206 "duplicate inode range\n");
211 set_inode_free(ino_rec
, ino
- s_ino
);
213 set_inode_used(ino_rec
, ino
- s_ino
);
218 last_rec
[agno
] = ino_rec
;
224 * like add_aginode_uncertain() only it needs an xfs_mount_t *
225 * to perform the inode number conversion.
228 add_inode_uncertain(xfs_mount_t
*mp
, xfs_ino_t ino
, int free
)
230 add_aginode_uncertain(XFS_INO_TO_AGNO(mp
, ino
),
231 XFS_INO_TO_AGINO(mp
, ino
), free
);
235 * pull the indicated inode record out of the uncertain inode tree
238 get_uncertain_inode_rec(xfs_agnumber_t agno
, ino_tree_node_t
*ino_rec
)
240 ASSERT(inode_tree_ptrs
!= NULL
);
241 ASSERT(inode_tree_ptrs
[agno
] != NULL
);
243 avl_delete(inode_uncertain_tree_ptrs
[agno
], &ino_rec
->avl_node
);
245 ino_rec
->avl_node
.avl_nextino
= NULL
;
246 ino_rec
->avl_node
.avl_forw
= NULL
;
247 ino_rec
->avl_node
.avl_back
= NULL
;
251 findfirst_uncertain_inode_rec(xfs_agnumber_t agno
)
253 return((ino_tree_node_t
*)
254 inode_uncertain_tree_ptrs
[agno
]->avl_firstino
);
258 find_uncertain_inode_rec(xfs_agnumber_t agno
, xfs_agino_t ino
)
260 return((ino_tree_node_t
*)
261 avl_findrange(inode_uncertain_tree_ptrs
[agno
], ino
));
265 clear_uncertain_ino_cache(xfs_agnumber_t agno
)
267 last_rec
[agno
] = NULL
;
274 * next comes the inode trees. One per ag. AVL trees
275 * of inode records, each inode record tracking 64 inodes
278 * set up an inode tree record for a group of inodes that will
279 * include the requested inode.
281 * does NOT error-check for duplicate records. Caller is
282 * responsible for checking that.
284 * ino must be the start of an XFS_INODES_PER_CHUNK (64) inode chunk
286 * Each inode resides in a 64-inode chunk which can be part
287 * one or more chunks (MAX(64, inodes-per-block). The fs allocates
288 * in chunks (as opposed to 1 chunk) when a block can hold more than
289 * one chunk (inodes per block > 64). Allocating in one chunk pieces
290 * causes us problems when it takes more than one fs block to contain
291 * an inode chunk because the chunks can start on *any* block boundary.
292 * So we assume that the caller has a clue because at this level, we
295 static ino_tree_node_t
*
296 add_inode(xfs_agnumber_t agno
, xfs_agino_t ino
)
298 ino_tree_node_t
*ino_rec
;
300 /* no record exists, make some and put them into the tree */
302 ino_rec
= mk_ino_tree_nodes(ino
);
303 ino_rec
->ino_startnum
= ino
;
305 if (avl_insert(inode_tree_ptrs
[agno
],
306 (avlnode_t
*) ino_rec
) == NULL
) {
307 do_warn("xfs_repair: add_inode - duplicate inode range\n");
314 * pull the indicated inode record out of the inode tree
317 get_inode_rec(xfs_agnumber_t agno
, ino_tree_node_t
*ino_rec
)
319 ASSERT(inode_tree_ptrs
!= NULL
);
320 ASSERT(inode_tree_ptrs
[agno
] != NULL
);
322 avl_delete(inode_tree_ptrs
[agno
], &ino_rec
->avl_node
);
324 ino_rec
->avl_node
.avl_nextino
= NULL
;
325 ino_rec
->avl_node
.avl_forw
= NULL
;
326 ino_rec
->avl_node
.avl_back
= NULL
;
330 * free the designated inode record (return it to the free pool)
334 free_inode_rec(xfs_agnumber_t agno
, ino_tree_node_t
*ino_rec
)
336 free_ino_tree_node(ino_rec
);
342 * returns the inode record desired containing the inode
343 * returns NULL if inode doesn't exist. The tree-based find
344 * routines do NOT pull records out of the tree.
347 find_inode_rec(xfs_agnumber_t agno
, xfs_agino_t ino
)
349 return((ino_tree_node_t
*)
350 avl_findrange(inode_tree_ptrs
[agno
], ino
));
354 find_inode_rec_range(xfs_agnumber_t agno
, xfs_agino_t start_ino
,
355 xfs_agino_t end_ino
, ino_tree_node_t
**first
,
356 ino_tree_node_t
**last
)
358 *first
= *last
= NULL
;
360 avl_findranges(inode_tree_ptrs
[agno
], start_ino
,
361 end_ino
, (avlnode_t
**) first
, (avlnode_t
**) last
);
366 * if ino doesn't exist, it must be properly aligned -- on a
367 * filesystem block boundary or XFS_INODES_PER_CHUNK boundary,
368 * whichever alignment is larger.
371 set_inode_used_alloc(xfs_agnumber_t agno
, xfs_agino_t ino
)
373 ino_tree_node_t
*ino_rec
;
376 * check alignment -- the only way to detect this
377 * is too see if the chunk overlaps another chunk
378 * already in the tree
380 ino_rec
= add_inode(agno
, ino
);
382 ASSERT(ino_rec
!= NULL
);
383 ASSERT(ino
>= ino_rec
->ino_startnum
&&
384 ino
- ino_rec
->ino_startnum
< XFS_INODES_PER_CHUNK
);
386 set_inode_used(ino_rec
, ino
- ino_rec
->ino_startnum
);
392 set_inode_free_alloc(xfs_agnumber_t agno
, xfs_agino_t ino
)
394 ino_tree_node_t
*ino_rec
;
396 ino_rec
= add_inode(agno
, ino
);
398 ASSERT(ino_rec
!= NULL
);
399 ASSERT(ino
>= ino_rec
->ino_startnum
&&
400 ino
- ino_rec
->ino_startnum
< XFS_INODES_PER_CHUNK
);
402 set_inode_free(ino_rec
, ino
- ino_rec
->ino_startnum
);
408 findfirst_inode_rec(xfs_agnumber_t agno
)
410 return((ino_tree_node_t
*) inode_tree_ptrs
[agno
]->avl_firstino
);
414 print_inode_list_int(xfs_agnumber_t agno
, int uncertain
)
416 ino_tree_node_t
*ino_rec
;
419 fprintf(stderr
, "good inode list is --\n");
420 ino_rec
= findfirst_inode_rec(agno
);
422 fprintf(stderr
, "uncertain inode list is --\n");
423 ino_rec
= findfirst_uncertain_inode_rec(agno
);
426 if (ino_rec
== NULL
) {
427 fprintf(stderr
, "agno %d -- no inodes\n", agno
);
431 printf("agno %d\n", agno
);
433 while(ino_rec
!= NULL
) {
435 "\tptr = %lx, start = 0x%x, free = 0x%llx, confirmed = 0x%llx\n",
436 (unsigned long)ino_rec
,
437 ino_rec
->ino_startnum
,
438 (unsigned long long)ino_rec
->ir_free
,
439 (unsigned long long)ino_rec
->ino_confirmed
);
440 if (ino_rec
->ino_startnum
== 0)
442 ino_rec
= next_ino_rec(ino_rec
);
447 print_inode_list(xfs_agnumber_t agno
)
449 print_inode_list_int(agno
, 0);
453 print_uncertain_inode_list(xfs_agnumber_t agno
)
455 print_inode_list_int(agno
, 1);
459 * set parent -- use a bitmask and a packed array. The bitmask
460 * indicate which inodes have an entry in the array. An inode that
461 * is the Nth bit set in the mask is stored in the Nth location in
462 * the array where N starts at 0.
465 set_inode_parent(ino_tree_node_t
*irec
, int offset
, xfs_ino_t parent
)
473 ASSERT(full_backptrs
== 0);
475 if (irec
->ino_un
.plist
== NULL
) {
477 (parent_list_t
*)malloc(sizeof(parent_list_t
));
478 if (!irec
->ino_un
.plist
)
479 do_error("couldn't malloc parent list table\n");
481 irec
->ino_un
.plist
->pmask
= 1LL << offset
;
482 irec
->ino_un
.plist
->pentries
=
483 (xfs_ino_t
*)memalign(sizeof(xfs_ino_t
), sizeof(xfs_ino_t
));
484 if (!irec
->ino_un
.plist
->pentries
)
485 do_error("couldn't memalign pentries table\n");
487 irec
->ino_un
.plist
->cnt
= 1;
489 irec
->ino_un
.plist
->pentries
[0] = parent
;
494 if (irec
->ino_un
.plist
->pmask
& (1LL << offset
)) {
498 for (i
= 0; i
< offset
; i
++) {
499 if (irec
->ino_un
.plist
->pmask
& bitmask
)
504 ASSERT(target
< irec
->ino_un
.plist
->cnt
);
506 irec
->ino_un
.plist
->pentries
[target
] = parent
;
514 for (i
= 0; i
< XFS_INODES_PER_CHUNK
; i
++) {
515 if (irec
->ino_un
.plist
->pmask
& bitmask
) {
525 ASSERT(cnt
== irec
->ino_un
.plist
->cnt
);
527 ASSERT(cnt
>= target
);
529 tmp
= (xfs_ino_t
*)memalign(sizeof(xfs_ino_t
), (cnt
+ 1) * sizeof(xfs_ino_t
));
531 do_error("couldn't memalign pentries table\n");
533 (void) bcopy(irec
->ino_un
.plist
->pentries
, tmp
,
534 target
* sizeof(parent_entry_t
));
537 (void) bcopy(irec
->ino_un
.plist
->pentries
+ target
,
539 (cnt
- target
) * sizeof(parent_entry_t
));
541 free(irec
->ino_un
.plist
->pentries
);
543 irec
->ino_un
.plist
->pentries
= tmp
;
546 irec
->ino_un
.plist
->cnt
++;
548 irec
->ino_un
.plist
->pentries
[target
] = parent
;
549 irec
->ino_un
.plist
->pmask
|= (1LL << offset
);
556 * not needed for now since we don't set the parent info
557 * until phase 4 -- at which point we know that the directory
558 * inode won't be going away -- so we won't ever need to clear
559 * directory parent data that we set.
562 clear_inode_parent(ino_tree_node_t
*irec
, int offset
)
564 ASSERT(full_backptrs
== 0);
565 ASSERT(irec
->ino_un
.plist
!= NULL
);
572 get_inode_parent(ino_tree_node_t
*irec
, int offset
)
580 ptbl
= irec
->ino_un
.backptrs
->parents
;
582 ptbl
= irec
->ino_un
.plist
;
584 if (ptbl
->pmask
& (1LL << offset
)) {
588 for (i
= 0; i
< offset
; i
++) {
589 if (ptbl
->pmask
& bitmask
)
594 ASSERT(target
< ptbl
->cnt
);
596 return(ptbl
->pentries
[target
]);
603 * code that deals with the inode descriptor appendages -- the back
604 * pointers, link counts and reached bits for phase 6 and phase 7.
608 add_inode_reached(ino_tree_node_t
*ino_rec
, int ino_offset
)
610 ASSERT(ino_rec
->ino_un
.backptrs
!= NULL
);
612 ino_rec
->ino_un
.backptrs
->nlinks
[ino_offset
]++;
613 XFS_INO_RCHD_SET_RCHD(ino_rec
, ino_offset
);
615 ASSERT(is_inode_reached(ino_rec
, ino_offset
));
621 is_inode_reached(ino_tree_node_t
*ino_rec
, int ino_offset
)
623 ASSERT(ino_rec
->ino_un
.backptrs
!= NULL
);
624 return(XFS_INO_RCHD_IS_RCHD(ino_rec
, ino_offset
));
628 add_inode_ref(ino_tree_node_t
*ino_rec
, int ino_offset
)
630 ASSERT(ino_rec
->ino_un
.backptrs
!= NULL
);
632 ino_rec
->ino_un
.backptrs
->nlinks
[ino_offset
]++;
638 drop_inode_ref(ino_tree_node_t
*ino_rec
, int ino_offset
)
640 ASSERT(ino_rec
->ino_un
.backptrs
!= NULL
);
641 ASSERT(ino_rec
->ino_un
.backptrs
->nlinks
[ino_offset
] > 0);
643 if (--ino_rec
->ino_un
.backptrs
->nlinks
[ino_offset
] == 0)
644 XFS_INO_RCHD_CLR_RCHD(ino_rec
, ino_offset
);
650 is_inode_referenced(ino_tree_node_t
*ino_rec
, int ino_offset
)
652 ASSERT(ino_rec
->ino_un
.backptrs
!= NULL
);
653 return(ino_rec
->ino_un
.backptrs
->nlinks
[ino_offset
] > 0);
657 num_inode_references(ino_tree_node_t
*ino_rec
, int ino_offset
)
659 ASSERT(ino_rec
->ino_un
.backptrs
!= NULL
);
660 return(ino_rec
->ino_un
.backptrs
->nlinks
[ino_offset
]);
664 static backptrs_t
*bptrs
;
665 static int bptrs_index
;
666 #define BPTR_ALLOC_NUM 1000
673 if (bptrs_index
== BPTR_ALLOC_NUM
) {
674 ASSERT(bptrs
== NULL
);
676 if ((bptrs
= malloc(sizeof(backptrs_t
[BPTR_ALLOC_NUM
])))
678 do_error("couldn't malloc ino rec backptrs.\n");
684 ASSERT(bptrs
!= NULL
);
686 bptr
= &bptrs
[bptrs_index
];
689 if (bptrs_index
== BPTR_ALLOC_NUM
)
692 bzero(bptr
, sizeof(backptrs_t
));
703 if ((ptr
= malloc(sizeof(backptrs_t
))) == NULL
)
704 do_error("could not malloc back pointer table\n");
706 bzero(ptr
, sizeof(backptrs_t
));
712 add_ino_backptrs(xfs_mount_t
*mp
)
717 #endif /* XR_BCKPTR_DBG */
718 ino_tree_node_t
*ino_rec
;
722 for (i
= 0; i
< mp
->m_sb
.sb_agcount
; i
++) {
723 ino_rec
= findfirst_inode_rec(i
);
725 while (ino_rec
!= NULL
) {
726 tmp
= ino_rec
->ino_un
.plist
;
727 ino_rec
->ino_un
.backptrs
= get_backptr();
728 ino_rec
->ino_un
.backptrs
->parents
= tmp
;
733 for (j
= 0; j
< XFS_INODES_PER_CHUNK
; j
++) {
734 ino
= XFS_AGINO_TO_INO(mp
, i
,
735 ino_rec
->ino_startnum
+ j
);
736 if (ino
== 25165846) {
737 do_warn("THERE 1 !!!\n");
739 if (tmp
->pentries
[j
] != 0) {
742 "inode %llu - parent %llu\n",
745 if (ino
== 25165846) {
746 do_warn("THERE!!!\n");
753 "ERROR - count = %d, counted %d\n",
757 #endif /* XR_BCKPTR_DBG */
758 ino_rec
= next_ino_rec(ino_rec
);
767 static __psunsigned_t
768 avl_ino_start(avlnode_t
*node
)
770 return((__psunsigned_t
) ((ino_tree_node_t
*) node
)->ino_startnum
);
773 static __psunsigned_t
774 avl_ino_end(avlnode_t
*node
)
776 return((__psunsigned_t
) (
777 ((ino_tree_node_t
*) node
)->ino_startnum
+
778 XFS_INODES_PER_CHUNK
));
781 avlops_t avl_ino_tree_ops
= {
787 incore_ino_init(xfs_mount_t
*mp
)
790 int agcount
= mp
->m_sb
.sb_agcount
;
792 if ((inode_tree_ptrs
= malloc(agcount
*
793 sizeof(avltree_desc_t
*))) == NULL
)
794 do_error("couldn't malloc inode tree descriptor table\n");
795 if ((inode_uncertain_tree_ptrs
= malloc(agcount
*
796 sizeof(avltree_desc_t
*))) == NULL
)
797 do_error("couldn't malloc uncertain ino tree descriptor table\n");
799 for (i
= 0; i
< agcount
; i
++) {
800 if ((inode_tree_ptrs
[i
] =
801 malloc(sizeof(avltree_desc_t
))) == NULL
)
802 do_error("couldn't malloc inode tree descriptor\n");
803 if ((inode_uncertain_tree_ptrs
[i
] =
804 malloc(sizeof(avltree_desc_t
))) == NULL
)
806 "couldn't malloc uncertain ino tree descriptor\n");
808 for (i
= 0; i
< agcount
; i
++) {
809 avl_init_tree(inode_tree_ptrs
[i
], &avl_ino_tree_ops
);
810 avl_init_tree(inode_uncertain_tree_ptrs
[i
], &avl_ino_tree_ops
);
814 ino_flist
.list
= NULL
;
816 if ((last_rec
= malloc(sizeof(ino_tree_node_t
*) * agcount
)) == NULL
)
817 do_error("couldn't malloc uncertain inode cache area\n");
819 bzero(last_rec
, sizeof(ino_tree_node_t
*) * agcount
);
826 #ifdef XR_INO_REF_DEBUG
828 add_inode_refchecked(xfs_ino_t ino
, ino_tree_node_t
*ino_rec
, int ino_offset
)
830 XFS_INOPROC_SET_PROC((ino_rec
), (ino_offset
));
832 ASSERT(is_inode_refchecked(ino
, ino_rec
, ino_offset
));
838 is_inode_refchecked(xfs_ino_t ino
, ino_tree_node_t
*ino_rec
, int ino_offset
)
840 return(XFS_INOPROC_IS_PROC(ino_rec
, ino_offset
) == 0LL ? 0 : 1);
842 #endif /* XR_INO_REF_DEBUG */