1355d6bb5Sswilcox /* 2355d6bb5Sswilcox * CDDL HEADER START 3355d6bb5Sswilcox * 4355d6bb5Sswilcox * The contents of this file are subject to the terms of the 5*ce37393aSowenr * Common Development and Distribution License (the "License"). 6*ce37393aSowenr * You may not use this file except in compliance with the License. 7355d6bb5Sswilcox * 8355d6bb5Sswilcox * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9355d6bb5Sswilcox * or http://www.opensolaris.org/os/licensing. 10355d6bb5Sswilcox * See the License for the specific language governing permissions 11355d6bb5Sswilcox * and limitations under the License. 12355d6bb5Sswilcox * 13355d6bb5Sswilcox * When distributing Covered Code, include this CDDL HEADER in each 14355d6bb5Sswilcox * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15355d6bb5Sswilcox * If applicable, add the following below this CDDL HEADER, with the 16355d6bb5Sswilcox * fields enclosed by brackets "[]" replaced with your own identifying 17355d6bb5Sswilcox * information: Portions Copyright [yyyy] [name of copyright owner] 18355d6bb5Sswilcox * 19355d6bb5Sswilcox * CDDL HEADER END 20355d6bb5Sswilcox */ 21355d6bb5Sswilcox /* 22*ce37393aSowenr * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23355d6bb5Sswilcox * Use is subject to license terms. 24355d6bb5Sswilcox */ 25355d6bb5Sswilcox 26355d6bb5Sswilcox #pragma ident "%Z%%M% %I% %E% SMI" 27355d6bb5Sswilcox 28355d6bb5Sswilcox /* 29355d6bb5Sswilcox * Keep track of duplicate fragment references (elsewhere called 30355d6bb5Sswilcox * blocks for ancient historical reasons). 31355d6bb5Sswilcox * 32355d6bb5Sswilcox * The duplicates are kept in a binary tree to attempt to minimize 33355d6bb5Sswilcox * search times when checking the block lists of all active inodes 34355d6bb5Sswilcox * for multiple uses. This is opposed to using a simple linear list 35355d6bb5Sswilcox * that is traversed for every block, as is used in the traditional 36355d6bb5Sswilcox * fsck. It can be very time-expensive if there's more than just a 37355d6bb5Sswilcox * very few duplicates, and typically there are either none or lots. 38355d6bb5Sswilcox * 39355d6bb5Sswilcox * For each multiply-claimed fragment, we note all of the claiming 40355d6bb5Sswilcox * inodes and their corresponding logical block numbers. This allows 41355d6bb5Sswilcox * reporting exactly which parts of which files were damaged, which 42355d6bb5Sswilcox * provides at least a chance of recovering the bulk of the data on 43355d6bb5Sswilcox * a seriously-corrupted filesystem. 44355d6bb5Sswilcox */ 45355d6bb5Sswilcox #include <stdio.h> 46355d6bb5Sswilcox #include <stdlib.h> 47355d6bb5Sswilcox #include <unistd.h> 48355d6bb5Sswilcox #include <sys/avl.h> 49355d6bb5Sswilcox #define _KERNEL 50355d6bb5Sswilcox #include <sys/fs/ufs_fsdir.h> /* for struct direct */ 51355d6bb5Sswilcox #undef _KERNEL 52355d6bb5Sswilcox #include <sys/debug.h> 53355d6bb5Sswilcox #include "fsck.h" 54355d6bb5Sswilcox 55355d6bb5Sswilcox #define OFFSETOF(type, elt) ((size_t)(&((type *)NULL)->elt)) 56355d6bb5Sswilcox 57355d6bb5Sswilcox /* 58355d6bb5Sswilcox * For each physical fragment with multiple claimants, the specifics 59355d6bb5Sswilcox * of each claim are recorded. This means there are N+1 AVL trees in 60355d6bb5Sswilcox * use: one for each fragment's claimant table, plus one that orders 61355d6bb5Sswilcox * the fragments themselves. 62355d6bb5Sswilcox * 63355d6bb5Sswilcox * The table of fragments simply has the physical fragment number 64355d6bb5Sswilcox * (pfn) and has the root of the tree of the associated claimants. It 65355d6bb5Sswilcox * is keyed by the pfn and called dup_frags. 66355d6bb5Sswilcox * 67355d6bb5Sswilcox * The subsidiary trees list inodes and logical fragment number (lfn) 68355d6bb5Sswilcox * for each claimant. They are keyed first by inode number and then 69355d6bb5Sswilcox * by lfn. Both are needed, as it is possible for one inode to have 70355d6bb5Sswilcox * multiple claims on the same fragment. 71355d6bb5Sswilcox */ 72355d6bb5Sswilcox 73355d6bb5Sswilcox typedef struct claimant { 74355d6bb5Sswilcox fsck_ino_t cl_inode; 75355d6bb5Sswilcox daddr32_t cl_lfn; 76355d6bb5Sswilcox avl_node_t cl_avl; 77355d6bb5Sswilcox } claimant_t; 78355d6bb5Sswilcox 79355d6bb5Sswilcox typedef struct fragment { 80355d6bb5Sswilcox daddr32_t fr_pfn; 81355d6bb5Sswilcox avl_tree_t fr_claimants; 82355d6bb5Sswilcox avl_node_t fr_avl; 83355d6bb5Sswilcox } fragment_t; 84355d6bb5Sswilcox 85355d6bb5Sswilcox typedef struct reference { 86355d6bb5Sswilcox daddr32_t ref_lfn; 87355d6bb5Sswilcox daddr32_t ref_pfn; 88355d6bb5Sswilcox avl_node_t ref_avl; 89355d6bb5Sswilcox } reference_t; 90355d6bb5Sswilcox 91355d6bb5Sswilcox typedef struct inode_dup { 92355d6bb5Sswilcox fsck_ino_t id_ino; 93355d6bb5Sswilcox avl_tree_t id_fragments; 94355d6bb5Sswilcox avl_node_t id_avl; 95355d6bb5Sswilcox } inode_dup_t; 96355d6bb5Sswilcox 97355d6bb5Sswilcox static avl_tree_t dup_frags; 98355d6bb5Sswilcox 99355d6bb5Sswilcox static void free_invert_frags(avl_tree_t *); 100355d6bb5Sswilcox static void report_dup_lfn_pfn(daddr32_t, daddr32_t, daddr32_t, daddr32_t); 101355d6bb5Sswilcox static inode_dup_t *new_inode_dup(fsck_ino_t); 102355d6bb5Sswilcox static void invert_frags(avl_tree_t *, avl_tree_t *); 103355d6bb5Sswilcox static void report_inode_dups(inode_dup_t *); 104355d6bb5Sswilcox static int by_ino_cmp(const void *, const void *); 105355d6bb5Sswilcox static int by_lfn_cmp(const void *, const void *); 106355d6bb5Sswilcox static claimant_t *alloc_claimant(fsck_ino_t, daddr32_t); 107355d6bb5Sswilcox static fragment_t *alloc_dup(daddr32_t); 108355d6bb5Sswilcox static int claimant_cmp(const void *, const void *); 109355d6bb5Sswilcox static int fragment_cmp(const void *, const void *); 110355d6bb5Sswilcox static int decrement_claimant(fragment_t *, fsck_ino_t, daddr32_t); 111355d6bb5Sswilcox static int increment_claimant(fragment_t *, fsck_ino_t, daddr32_t); 112355d6bb5Sswilcox 113355d6bb5Sswilcox /* 114355d6bb5Sswilcox * Simple accessor function for the outside world so only we need to 115355d6bb5Sswilcox * see and interpret our data structures. 116355d6bb5Sswilcox */ 117355d6bb5Sswilcox int 118355d6bb5Sswilcox have_dups(void) 119355d6bb5Sswilcox { 120355d6bb5Sswilcox return (avl_numnodes(&dup_frags) > 0); 121355d6bb5Sswilcox } 122355d6bb5Sswilcox 123355d6bb5Sswilcox /* 124355d6bb5Sswilcox * Locates, creates, and deletes a record of a duplicate reference. 125355d6bb5Sswilcox * 126355d6bb5Sswilcox * For DB_INCR, returns true if the dup was added to the tree. 127355d6bb5Sswilcox * For DB_DECR, returns true if the dup was in the tree. 128355d6bb5Sswilcox */ 129355d6bb5Sswilcox int 130355d6bb5Sswilcox find_dup_ref(daddr32_t fragno, fsck_ino_t ino, daddr32_t lfn, int flags) 131355d6bb5Sswilcox { 132355d6bb5Sswilcox fragment_t key; 133355d6bb5Sswilcox fragment_t *dup; 134355d6bb5Sswilcox avl_index_t where; 135355d6bb5Sswilcox int added = 0; 136355d6bb5Sswilcox int removed = 0; 137355d6bb5Sswilcox 138355d6bb5Sswilcox if (avl_first(&dup_frags) == NULL) { 139355d6bb5Sswilcox if (flags & DB_CREATE) 140355d6bb5Sswilcox avl_create(&dup_frags, fragment_cmp, 141355d6bb5Sswilcox sizeof (fragment_t), 142355d6bb5Sswilcox OFFSETOF(fragment_t, fr_avl)); 143355d6bb5Sswilcox else 144355d6bb5Sswilcox return (0); 145355d6bb5Sswilcox } 146355d6bb5Sswilcox 147355d6bb5Sswilcox key.fr_pfn = fragno; 148355d6bb5Sswilcox dup = avl_find(&dup_frags, (void *)&key, &where); 149355d6bb5Sswilcox if ((dup == NULL) & (flags & DB_CREATE)) { 150355d6bb5Sswilcox dup = alloc_dup(fragno); 151355d6bb5Sswilcox avl_insert(&dup_frags, (void *)dup, where); 152355d6bb5Sswilcox } 153355d6bb5Sswilcox 154355d6bb5Sswilcox if (dup != NULL) { 155355d6bb5Sswilcox if (flags & DB_INCR) { 156355d6bb5Sswilcox if (debug) 157355d6bb5Sswilcox (void) printf( 158355d6bb5Sswilcox "adding claim by ino %d as lfn %d\n", 159355d6bb5Sswilcox ino, lfn); 160355d6bb5Sswilcox added = increment_claimant(dup, ino, lfn); 161355d6bb5Sswilcox } else if (flags & DB_DECR) { 162355d6bb5Sswilcox /* 163355d6bb5Sswilcox * Note that dup may be invalidated by this call. 164355d6bb5Sswilcox */ 165355d6bb5Sswilcox removed = decrement_claimant(dup, ino, lfn); 166355d6bb5Sswilcox if (debug) 167355d6bb5Sswilcox (void) printf( 168355d6bb5Sswilcox "check for claimant ino %d lfn %d returned %d\n", 169355d6bb5Sswilcox ino, lfn, removed); 170355d6bb5Sswilcox } 171355d6bb5Sswilcox } 172355d6bb5Sswilcox 173355d6bb5Sswilcox return (added || removed || (dup != NULL)); 174355d6bb5Sswilcox } 175355d6bb5Sswilcox 176355d6bb5Sswilcox /* 177355d6bb5Sswilcox * Dump the duplicates table in a relatively user-friendly form. 178355d6bb5Sswilcox * The idea is that the output can be useful when trying to manually 179355d6bb5Sswilcox * work out which block belongs to which of the claiming inodes. 180355d6bb5Sswilcox * 181355d6bb5Sswilcox * What we have is a tree of duplicates indexed by physical 182355d6bb5Sswilcox * fragment number. What we want to report is: 183355d6bb5Sswilcox * 184355d6bb5Sswilcox * Inode %d: 185355d6bb5Sswilcox * Logical Offset 0x%08llx, Physical Fragment %d 186355d6bb5Sswilcox * Logical Offsets 0x%08llx - 0x%08llx, Physical Fragments %d - %d 187355d6bb5Sswilcox * ... 188355d6bb5Sswilcox * Inode %d: 189355d6bb5Sswilcox * Logical Offsets 0x%08llx - 0x%08llx, Physical Fragments %d - %d 190355d6bb5Sswilcox * ... 191355d6bb5Sswilcox */ 192355d6bb5Sswilcox int 193355d6bb5Sswilcox report_dups(int quiet) 194355d6bb5Sswilcox { 195355d6bb5Sswilcox int overlaps; 196355d6bb5Sswilcox inode_dup_t *inode; 197355d6bb5Sswilcox fragment_t *dup; 198355d6bb5Sswilcox avl_tree_t inode_frags; 199355d6bb5Sswilcox 200355d6bb5Sswilcox overlaps = 0; 201355d6bb5Sswilcox ASSERT(have_dups()); 202355d6bb5Sswilcox /* 203355d6bb5Sswilcox * Figure out how many actual dups are still around. 204355d6bb5Sswilcox * This tells us whether or not we can mark the 205355d6bb5Sswilcox * filesystem clean. 206355d6bb5Sswilcox */ 207355d6bb5Sswilcox dup = avl_first(&dup_frags); 208355d6bb5Sswilcox while (dup != NULL) { 209355d6bb5Sswilcox if (avl_numnodes(&dup->fr_claimants) > 1) { 210355d6bb5Sswilcox overlaps++; 211355d6bb5Sswilcox break; 212355d6bb5Sswilcox } 213355d6bb5Sswilcox dup = AVL_NEXT(&dup_frags, dup); 214355d6bb5Sswilcox } 215355d6bb5Sswilcox 216355d6bb5Sswilcox /* 217355d6bb5Sswilcox * Now report on every object that still exists that 218355d6bb5Sswilcox * had *any* dups associated with it. 219355d6bb5Sswilcox */ 220355d6bb5Sswilcox if (!quiet) { 221355d6bb5Sswilcox (void) puts("\nSome blocks that were found to be in " 222355d6bb5Sswilcox "multiple files are still\nassigned to " 223355d6bb5Sswilcox "file(s).\nFragments sorted by inode and " 224355d6bb5Sswilcox "logical offsets:"); 225355d6bb5Sswilcox 226355d6bb5Sswilcox invert_frags(&dup_frags, &inode_frags); 227355d6bb5Sswilcox inode = avl_first(&inode_frags); 228355d6bb5Sswilcox while (inode != NULL) { 229355d6bb5Sswilcox report_inode_dups(inode); 230355d6bb5Sswilcox inode = AVL_NEXT(&inode_frags, inode); 231355d6bb5Sswilcox } 232355d6bb5Sswilcox (void) printf("\n"); 233355d6bb5Sswilcox 234355d6bb5Sswilcox free_invert_frags(&inode_frags); 235355d6bb5Sswilcox } 236355d6bb5Sswilcox 237355d6bb5Sswilcox return (overlaps); 238355d6bb5Sswilcox } 239355d6bb5Sswilcox 240355d6bb5Sswilcox static void 241355d6bb5Sswilcox report_inode_dups(inode_dup_t *inode) 242355d6bb5Sswilcox { 243355d6bb5Sswilcox reference_t *dup; 244355d6bb5Sswilcox daddr32_t first_lfn, last_lfn, first_pfn, last_pfn; 245355d6bb5Sswilcox 246355d6bb5Sswilcox (void) printf("Inode %d:\n", inode->id_ino); 247355d6bb5Sswilcox dup = avl_first(&inode->id_fragments); 248355d6bb5Sswilcox first_lfn = last_lfn = dup->ref_lfn; 249355d6bb5Sswilcox first_pfn = last_pfn = dup->ref_pfn; 250355d6bb5Sswilcox while ((dup = AVL_NEXT(&inode->id_fragments, dup)) != NULL) { 251355d6bb5Sswilcox if (((last_lfn + 1) != dup->ref_lfn) || 252355d6bb5Sswilcox ((last_pfn + 1) != dup->ref_pfn)) { 253355d6bb5Sswilcox report_dup_lfn_pfn(first_lfn, last_lfn, 254355d6bb5Sswilcox first_pfn, last_pfn); 255355d6bb5Sswilcox first_lfn = last_lfn = dup->ref_lfn; 256355d6bb5Sswilcox first_pfn = last_pfn = dup->ref_pfn; 257355d6bb5Sswilcox } 258355d6bb5Sswilcox } 259355d6bb5Sswilcox report_dup_lfn_pfn(first_lfn, last_lfn, first_pfn, last_pfn); 260355d6bb5Sswilcox } 261355d6bb5Sswilcox 262355d6bb5Sswilcox static void 263355d6bb5Sswilcox report_dup_lfn_pfn(daddr32_t first_lfn, daddr32_t last_lfn, 264355d6bb5Sswilcox daddr32_t first_pfn, daddr32_t last_pfn) 265355d6bb5Sswilcox { 266355d6bb5Sswilcox if ((first_lfn == last_lfn) && (first_pfn == last_pfn)) { 267355d6bb5Sswilcox (void) printf( 268355d6bb5Sswilcox " Logical Offset 0x%08llx Physical Fragment %d\n", 269355d6bb5Sswilcox (longlong_t)first_lfn * sblock.fs_fsize, first_pfn); 270355d6bb5Sswilcox } else { 271355d6bb5Sswilcox (void) printf( 272355d6bb5Sswilcox " Logical Offsets 0x%08llx - 0x%08llx, " 273355d6bb5Sswilcox "Physical Fragments %d - %d\n", 274355d6bb5Sswilcox (longlong_t)first_lfn * sblock.fs_fsize, 275355d6bb5Sswilcox (longlong_t)last_lfn * sblock.fs_fsize, 276355d6bb5Sswilcox first_pfn, last_pfn); 277355d6bb5Sswilcox } 278355d6bb5Sswilcox } 279355d6bb5Sswilcox 280355d6bb5Sswilcox /* 281355d6bb5Sswilcox * Given a tree of fragment_ts, each element of which has an integral 282355d6bb5Sswilcox * sub-tree of claimant_ts, produce a tree of inode_dup_ts, each element 283355d6bb5Sswilcox * of which has an integral sub-tree of reference_ts. 284355d6bb5Sswilcox */ 285355d6bb5Sswilcox static void 286355d6bb5Sswilcox invert_frags(avl_tree_t *source, avl_tree_t *target) 287355d6bb5Sswilcox { 288355d6bb5Sswilcox fragment_t *src_frag; 289355d6bb5Sswilcox claimant_t *src_claim; 290355d6bb5Sswilcox inode_dup_t *tgt_inode; 291355d6bb5Sswilcox inode_dup_t tgt_inode_key; 292355d6bb5Sswilcox reference_t *tgt_ref; 293355d6bb5Sswilcox reference_t tgt_ref_key; 294355d6bb5Sswilcox avl_index_t where; 295355d6bb5Sswilcox 296355d6bb5Sswilcox avl_create(target, by_ino_cmp, sizeof (inode_dup_t), 297355d6bb5Sswilcox OFFSETOF(inode_dup_t, id_avl)); 298355d6bb5Sswilcox 299355d6bb5Sswilcox src_frag = avl_first(source); 300355d6bb5Sswilcox while (src_frag != NULL) { 301355d6bb5Sswilcox src_claim = avl_first(&src_frag->fr_claimants); 302355d6bb5Sswilcox while (src_claim != NULL) { 303355d6bb5Sswilcox /* 304355d6bb5Sswilcox * Have we seen this inode before? 305355d6bb5Sswilcox */ 306355d6bb5Sswilcox tgt_inode_key.id_ino = src_claim->cl_inode; 307355d6bb5Sswilcox tgt_inode = avl_find(target, (void *)&tgt_inode_key, 308355d6bb5Sswilcox &where); 309355d6bb5Sswilcox if (tgt_inode == NULL) { 310355d6bb5Sswilcox /* 311355d6bb5Sswilcox * No, so set up a record for it. 312355d6bb5Sswilcox */ 313355d6bb5Sswilcox tgt_inode = new_inode_dup(src_claim->cl_inode); 314355d6bb5Sswilcox avl_insert(target, (void *)tgt_inode, where); 315355d6bb5Sswilcox } 316355d6bb5Sswilcox /* 317355d6bb5Sswilcox * Now, how about this logical fragment? In 318355d6bb5Sswilcox * theory, we should never see a duplicate, since 319355d6bb5Sswilcox * a given lfn only exists once for a given inode. 320355d6bb5Sswilcox * As such, we ignore duplicate hits. 321355d6bb5Sswilcox */ 322355d6bb5Sswilcox tgt_ref_key.ref_lfn = src_claim->cl_lfn; 323355d6bb5Sswilcox tgt_ref = avl_find(&tgt_inode->id_fragments, 324355d6bb5Sswilcox (void *)&tgt_ref_key, &where); 325355d6bb5Sswilcox if (tgt_ref == NULL) { 326355d6bb5Sswilcox /* 327355d6bb5Sswilcox * Haven't seen it, add it. 328355d6bb5Sswilcox */ 329355d6bb5Sswilcox tgt_ref = (reference_t *)malloc( 330355d6bb5Sswilcox sizeof (reference_t)); 331355d6bb5Sswilcox if (tgt_ref == NULL) 332355d6bb5Sswilcox errexit("Out of memory in " 333355d6bb5Sswilcox "invert_frags\n"); 334355d6bb5Sswilcox tgt_ref->ref_lfn = src_claim->cl_lfn; 335355d6bb5Sswilcox tgt_ref->ref_pfn = src_frag->fr_pfn; 336355d6bb5Sswilcox avl_insert(&tgt_inode->id_fragments, 337355d6bb5Sswilcox (void *)tgt_ref, where); 338355d6bb5Sswilcox } 339355d6bb5Sswilcox src_claim = AVL_NEXT(&src_frag->fr_claimants, 340355d6bb5Sswilcox src_claim); 341355d6bb5Sswilcox } 342355d6bb5Sswilcox src_frag = AVL_NEXT(source, src_frag); 343355d6bb5Sswilcox } 344355d6bb5Sswilcox } 345355d6bb5Sswilcox 346355d6bb5Sswilcox /* 347355d6bb5Sswilcox * Discard memory associated with the inverted fragments tree created 348355d6bb5Sswilcox * by report_dups() via invert_frags(). 349355d6bb5Sswilcox */ 350355d6bb5Sswilcox static void 351355d6bb5Sswilcox free_invert_frags(avl_tree_t *tree) 352355d6bb5Sswilcox { 353355d6bb5Sswilcox void *outer = NULL; /* traversal cookie */ 354355d6bb5Sswilcox void *inner; /* traversal cookie */ 355355d6bb5Sswilcox inode_dup_t *inode_dup; 356355d6bb5Sswilcox reference_t *ref_dup; 357355d6bb5Sswilcox 358355d6bb5Sswilcox while ((inode_dup = avl_destroy_nodes(tree, &outer)) != NULL) { 359355d6bb5Sswilcox inner = NULL; 360355d6bb5Sswilcox while ((ref_dup = avl_destroy_nodes(&inode_dup->id_fragments, 361355d6bb5Sswilcox &inner)) != NULL) { 362355d6bb5Sswilcox free((void *)ref_dup); 363355d6bb5Sswilcox } 364355d6bb5Sswilcox avl_destroy(&inode_dup->id_fragments); 365355d6bb5Sswilcox free((void *)inode_dup); 366355d6bb5Sswilcox } 367355d6bb5Sswilcox avl_destroy(tree); 368355d6bb5Sswilcox } 369355d6bb5Sswilcox 370355d6bb5Sswilcox /* 371355d6bb5Sswilcox * Discard all memory allocations associated with the current duplicates 372355d6bb5Sswilcox * table. 373355d6bb5Sswilcox */ 374355d6bb5Sswilcox void 375355d6bb5Sswilcox free_dup_state(void) 376355d6bb5Sswilcox { 377355d6bb5Sswilcox void *dup_cookie = NULL; 378355d6bb5Sswilcox void *claim_cookie; 379355d6bb5Sswilcox fragment_t *fragv; 380355d6bb5Sswilcox claimant_t *claimv; 381355d6bb5Sswilcox 382355d6bb5Sswilcox while ((fragv = avl_destroy_nodes(&dup_frags, &dup_cookie)) != NULL) { 383355d6bb5Sswilcox claim_cookie = NULL; 384355d6bb5Sswilcox while ((claimv = avl_destroy_nodes(&fragv->fr_claimants, 385355d6bb5Sswilcox &claim_cookie)) != NULL) { 386355d6bb5Sswilcox free((void *)claimv); 387355d6bb5Sswilcox } 388355d6bb5Sswilcox avl_destroy(&fragv->fr_claimants); 389355d6bb5Sswilcox free((void *)fragv); 390355d6bb5Sswilcox } 391355d6bb5Sswilcox avl_destroy(&dup_frags); 392355d6bb5Sswilcox } 393355d6bb5Sswilcox 394355d6bb5Sswilcox /* 395355d6bb5Sswilcox * If the given claimant has not been seen before, add it to DUP's 396355d6bb5Sswilcox * list of them. It's not fatal for the same PFN/INODE/LFN to get 397355d6bb5Sswilcox * added twice, because pass1b() will add the same dups that pass1() 398355d6bb5Sswilcox * did, plus one. 399355d6bb5Sswilcox */ 400355d6bb5Sswilcox static int 401355d6bb5Sswilcox increment_claimant(fragment_t *dup, fsck_ino_t ino, daddr32_t lfn) 402355d6bb5Sswilcox { 403355d6bb5Sswilcox avl_index_t where; 404355d6bb5Sswilcox claimant_t *claimant; 405355d6bb5Sswilcox claimant_t key; 406355d6bb5Sswilcox int added = 0; 407355d6bb5Sswilcox 408355d6bb5Sswilcox key.cl_inode = ino; 409355d6bb5Sswilcox key.cl_lfn = lfn; 410355d6bb5Sswilcox claimant = avl_find(&dup->fr_claimants, &key, &where); 411355d6bb5Sswilcox if (claimant == NULL) { 412355d6bb5Sswilcox if (debug) 413355d6bb5Sswilcox (void) printf("inserting claimant\n"); 414355d6bb5Sswilcox claimant = alloc_claimant(ino, lfn); 415355d6bb5Sswilcox avl_insert(&dup->fr_claimants, (void *)claimant, where); 416355d6bb5Sswilcox statemap[ino] |= INCLEAR; 417*ce37393aSowenr /* 418*ce37393aSowenr * If the inode is to be cleared and has zero links then remove 419*ce37393aSowenr * the zero link bit as it will be cleared anyway. If INZLINK 420*ce37393aSowenr * is being removed and it's a directory inode then add the 421*ce37393aSowenr * inode to the orphan directory list. 422*ce37393aSowenr */ 423*ce37393aSowenr if (statemap[ino] & INZLINK) { 424*ce37393aSowenr statemap[ino] &= ~INZLINK; 425*ce37393aSowenr if (statemap[ino] & DSTATE) { 426*ce37393aSowenr add_orphan_dir(ino); 427*ce37393aSowenr } 428*ce37393aSowenr } 429355d6bb5Sswilcox added = 1; 430355d6bb5Sswilcox } 431355d6bb5Sswilcox 432355d6bb5Sswilcox return (added); 433355d6bb5Sswilcox } 434355d6bb5Sswilcox 435355d6bb5Sswilcox /* 436355d6bb5Sswilcox * If the given claimant is on DUP's list, remove it. It is not 437355d6bb5Sswilcox * an error for the claimant to not be on the list. 438355d6bb5Sswilcox */ 439355d6bb5Sswilcox static int 440355d6bb5Sswilcox decrement_claimant(fragment_t *dup, fsck_ino_t ino, daddr32_t lfn) 441355d6bb5Sswilcox { 442355d6bb5Sswilcox avl_index_t where; 443355d6bb5Sswilcox claimant_t *claimant; 444355d6bb5Sswilcox claimant_t key; 445355d6bb5Sswilcox int busy = 0; 446355d6bb5Sswilcox 447355d6bb5Sswilcox key.cl_inode = ino; 448355d6bb5Sswilcox key.cl_lfn = lfn; 449355d6bb5Sswilcox claimant = avl_find(&dup->fr_claimants, &key, &where); 450355d6bb5Sswilcox if (claimant != NULL) { 451355d6bb5Sswilcox avl_remove(&dup->fr_claimants, claimant); 452355d6bb5Sswilcox if (avl_numnodes(&dup->fr_claimants) == 0) { 453355d6bb5Sswilcox avl_destroy(&dup->fr_claimants); 454355d6bb5Sswilcox avl_remove(&dup_frags, (void *)dup); 455355d6bb5Sswilcox free((void *)dup); 456355d6bb5Sswilcox } else { 457355d6bb5Sswilcox busy = 1; 458355d6bb5Sswilcox } 459355d6bb5Sswilcox } 460355d6bb5Sswilcox 461355d6bb5Sswilcox return (busy); 462355d6bb5Sswilcox } 463355d6bb5Sswilcox 464355d6bb5Sswilcox static claimant_t * 465355d6bb5Sswilcox alloc_claimant(fsck_ino_t inode, daddr32_t lfn) 466355d6bb5Sswilcox { 467355d6bb5Sswilcox claimant_t *new = (claimant_t *)malloc(sizeof (claimant_t)); 468355d6bb5Sswilcox 469355d6bb5Sswilcox if (new == NULL) 470355d6bb5Sswilcox errexit("Out of memory in alloc_claimant()\n"); 471355d6bb5Sswilcox 472355d6bb5Sswilcox new->cl_inode = inode; 473355d6bb5Sswilcox new->cl_lfn = lfn; 474355d6bb5Sswilcox 475355d6bb5Sswilcox return (new); 476355d6bb5Sswilcox } 477355d6bb5Sswilcox 478355d6bb5Sswilcox static fragment_t * 479355d6bb5Sswilcox alloc_dup(daddr32_t pfn) 480355d6bb5Sswilcox { 481355d6bb5Sswilcox fragment_t *new = (fragment_t *)malloc(sizeof (fragment_t)); 482355d6bb5Sswilcox 483355d6bb5Sswilcox if (new == NULL) 484355d6bb5Sswilcox errexit("Out of memory in alloc_dup()\n"); 485355d6bb5Sswilcox 486355d6bb5Sswilcox new->fr_pfn = pfn; 487355d6bb5Sswilcox avl_create(&new->fr_claimants, claimant_cmp, sizeof (fragment_t), 488355d6bb5Sswilcox OFFSETOF(claimant_t, cl_avl)); 489355d6bb5Sswilcox 490355d6bb5Sswilcox return (new); 491355d6bb5Sswilcox } 492355d6bb5Sswilcox 493355d6bb5Sswilcox /* 494355d6bb5Sswilcox * Compare two fragment_t instances for avl_find(). It requires a 495355d6bb5Sswilcox * return value of -1/0/1, so we can't just hand back left - right. 496355d6bb5Sswilcox */ 497355d6bb5Sswilcox static int 498355d6bb5Sswilcox fragment_cmp(const void *vlp, const void *vrp) 499355d6bb5Sswilcox { 500355d6bb5Sswilcox const fragment_t *lp = (const fragment_t *)vlp; 501355d6bb5Sswilcox const fragment_t *rp = (const fragment_t *)vrp; 502355d6bb5Sswilcox int cmp = lp->fr_pfn - rp->fr_pfn; 503355d6bb5Sswilcox 504355d6bb5Sswilcox if (cmp < 0) 505355d6bb5Sswilcox cmp = -1; 506355d6bb5Sswilcox else if (cmp > 0) 507355d6bb5Sswilcox cmp = 1; 508355d6bb5Sswilcox 509355d6bb5Sswilcox return (cmp); 510355d6bb5Sswilcox } 511355d6bb5Sswilcox 512355d6bb5Sswilcox /* 513355d6bb5Sswilcox * Compare two claimant_t instances for avl_find(). It requires a 514355d6bb5Sswilcox * return value of -1/0/1, so we can't just hand back left - right. 515355d6bb5Sswilcox */ 516355d6bb5Sswilcox static int 517355d6bb5Sswilcox claimant_cmp(const void *vlp, const void *vrp) 518355d6bb5Sswilcox { 519355d6bb5Sswilcox const claimant_t *lp = (const claimant_t *)vlp; 520355d6bb5Sswilcox const claimant_t *rp = (const claimant_t *)vrp; 521355d6bb5Sswilcox int cmp; 522355d6bb5Sswilcox 523355d6bb5Sswilcox cmp = lp->cl_inode - rp->cl_inode; 524355d6bb5Sswilcox if (cmp == 0) { 525355d6bb5Sswilcox /* 526355d6bb5Sswilcox * lfn < 0 is a wildcard lfn match. 527355d6bb5Sswilcox */ 528355d6bb5Sswilcox if ((lp->cl_lfn >= 0) && (rp->cl_lfn >= 0)) 529355d6bb5Sswilcox cmp = lp->cl_lfn - rp->cl_lfn; 530355d6bb5Sswilcox } 531355d6bb5Sswilcox 532355d6bb5Sswilcox if (cmp < 0) 533355d6bb5Sswilcox cmp = -1; 534355d6bb5Sswilcox else if (cmp > 0) 535355d6bb5Sswilcox cmp = 1; 536355d6bb5Sswilcox 537355d6bb5Sswilcox return (cmp); 538355d6bb5Sswilcox } 539355d6bb5Sswilcox 540355d6bb5Sswilcox static int 541355d6bb5Sswilcox by_ino_cmp(const void *vlp, const void *vrp) 542355d6bb5Sswilcox { 543355d6bb5Sswilcox const inode_dup_t *lp = (const inode_dup_t *)vlp; 544355d6bb5Sswilcox const inode_dup_t *rp = (const inode_dup_t *)vrp; 545355d6bb5Sswilcox int cmp; 546355d6bb5Sswilcox 547355d6bb5Sswilcox cmp = lp->id_ino - rp->id_ino; 548355d6bb5Sswilcox 549355d6bb5Sswilcox if (cmp < 0) 550355d6bb5Sswilcox cmp = -1; 551355d6bb5Sswilcox else if (cmp > 0) 552355d6bb5Sswilcox cmp = 1; 553355d6bb5Sswilcox 554355d6bb5Sswilcox return (cmp); 555355d6bb5Sswilcox } 556355d6bb5Sswilcox 557355d6bb5Sswilcox static int 558355d6bb5Sswilcox by_lfn_cmp(const void *vlp, const void *vrp) 559355d6bb5Sswilcox { 560355d6bb5Sswilcox const reference_t *lp = (const reference_t *)vlp; 561355d6bb5Sswilcox const reference_t *rp = (const reference_t *)vrp; 562355d6bb5Sswilcox int cmp; 563355d6bb5Sswilcox 564355d6bb5Sswilcox cmp = lp->ref_lfn - rp->ref_lfn; 565355d6bb5Sswilcox 566355d6bb5Sswilcox if (cmp < 0) 567355d6bb5Sswilcox cmp = -1; 568355d6bb5Sswilcox else if (cmp > 0) 569355d6bb5Sswilcox cmp = 1; 570355d6bb5Sswilcox 571355d6bb5Sswilcox return (cmp); 572355d6bb5Sswilcox } 573355d6bb5Sswilcox 574355d6bb5Sswilcox static inode_dup_t * 575355d6bb5Sswilcox new_inode_dup(fsck_ino_t inode) 576355d6bb5Sswilcox { 577355d6bb5Sswilcox inode_dup_t *new; 578355d6bb5Sswilcox 579355d6bb5Sswilcox new = (inode_dup_t *)malloc(sizeof (inode_dup_t)); 580355d6bb5Sswilcox if (new == NULL) 581355d6bb5Sswilcox errexit("Out of memory in new_inode_dup\n"); 582355d6bb5Sswilcox new->id_ino = inode; 583355d6bb5Sswilcox avl_create(&new->id_fragments, by_lfn_cmp, sizeof (reference_t), 584355d6bb5Sswilcox OFFSETOF(reference_t, ref_avl)); 585355d6bb5Sswilcox 586355d6bb5Sswilcox return (new); 587355d6bb5Sswilcox } 588