~ubuntu-branches/ubuntu/utopic/xfsprogs/utopic-proposed

« back to all changes in this revision

Viewing changes to repair/incore_ext.c

  • Committer: Bazaar Package Importer
  • Author(s): Nathan Scott
  • Date: 2002-04-13 09:45:06 UTC
  • Revision ID: james.westby@ubuntu.com-20020413094506-t8dhemv41gkeg4kx
Tags: 2.0.3-1
New upstream bugfix release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
 
3
 * 
 
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.
 
7
 * 
 
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.
 
11
 * 
 
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.
 
18
 * 
 
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.
 
22
 * 
 
23
 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
 
24
 * Mountain View, CA  94043, or:
 
25
 * 
 
26
 * http://www.sgi.com 
 
27
 * 
 
28
 * For further information regarding this notice, see: 
 
29
 * 
 
30
 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
 
31
 */
 
32
 
 
33
#include <libxfs.h>
 
34
#include "avl.h"
 
35
#include "globals.h"
 
36
#include "incore.h"
 
37
#include "agheader.h"
 
38
#include "protos.h"
 
39
#include "err_protos.h"
 
40
#include "avl64.h"
 
41
#define ALLOC_NUM_EXTS          100
 
42
 
 
43
/*
 
44
 * paranoia -- account for any weird padding, 64/32-bit alignment, etc.
 
45
 */
 
46
typedef struct extent_alloc_rec  {
 
47
        ba_rec_t                alloc_rec;
 
48
        extent_tree_node_t      extents[ALLOC_NUM_EXTS];
 
49
} extent_alloc_rec_t;
 
50
 
 
51
typedef struct rt_extent_alloc_rec  {
 
52
        ba_rec_t                alloc_rec;
 
53
        rt_extent_tree_node_t   extents[ALLOC_NUM_EXTS];
 
54
} rt_extent_alloc_rec_t;
 
55
 
 
56
/*
 
57
 * note:  there are 4 sets of incore things handled here:
 
58
 * block bitmaps, extent trees, uncertain inode list,
 
59
 * and inode tree.  The tree-based code uses the AVL
 
60
 * tree package used by the IRIX kernel VM code
 
61
 * (sys/avl.h).  The inode list code uses the same records
 
62
 * as the inode tree code for convenience.  The bitmaps
 
63
 * and bitmap operators are mostly macros defined in incore.h.
 
64
 * There are one of everything per AG except for extent
 
65
 * trees.  There's one duplicate extent tree, one bno and
 
66
 * one bcnt extent tree per AG.  Not all of the above exist
 
67
 * through all phases.  The duplicate extent tree gets trashed
 
68
 * at the end of phase 4.  The bno/bcnt trees don't appear until
 
69
 * phase 5.  The uncertain inode list goes away at the end of
 
70
 * phase 3.  The inode tree and bno/bnct trees go away after phase 5.
 
71
 */
 
72
typedef struct ext_flist_s  {
 
73
        extent_tree_node_t      *list;
 
74
        int                     cnt;
 
75
} ext_flist_t;
 
76
 
 
77
static ext_flist_t ext_flist;
 
78
 
 
79
typedef struct rt_ext_flist_s  {
 
80
        rt_extent_tree_node_t   *list;
 
81
        int                     cnt;
 
82
} rt_ext_flist_t;
 
83
 
 
84
static rt_ext_flist_t rt_ext_flist;
 
85
 
 
86
static avl64tree_desc_t *rt_ext_tree_ptr;       /* dup extent tree for rt */
 
87
 
 
88
static avltree_desc_t   **extent_tree_ptrs;     /* array of extent tree ptrs */
 
89
                                                /* one per ag for dups */
 
90
static avltree_desc_t   **extent_bno_ptrs;      /*
 
91
                                                 * array of extent tree ptrs
 
92
                                                 * one per ag for free extents
 
93
                                                 * sorted by starting block
 
94
                                                 * number
 
95
                                                 */
 
96
static avltree_desc_t   **extent_bcnt_ptrs;     /*
 
97
                                                 * array of extent tree ptrs
 
98
                                                 * one per ag for free extents
 
99
                                                 * sorted by size
 
100
                                                 */
 
101
 
 
102
/*
 
103
 * list of allocated "blocks" for easy freeing later
 
104
 */
 
105
static ba_rec_t         *ba_list;
 
106
static ba_rec_t         *rt_ba_list;
 
107
 
 
108
/*
 
109
 * extent tree stuff is avl trees of duplicate extents,
 
110
 * sorted in order by block number.  there is one tree per ag.
 
111
 */
 
112
 
 
113
static extent_tree_node_t *
 
114
mk_extent_tree_nodes(xfs_agblock_t new_startblock,
 
115
        xfs_extlen_t new_blockcount, extent_state_t new_state)
 
116
{
 
117
        int i;
 
118
        extent_tree_node_t *new;
 
119
        extent_alloc_rec_t *rec;
 
120
 
 
121
        if (ext_flist.cnt == 0)  {
 
122
                ASSERT(ext_flist.list == NULL);
 
123
 
 
124
                if ((rec = malloc(sizeof(extent_alloc_rec_t))) == NULL)
 
125
                        do_error("couldn't allocate new extent descriptors.\n");
 
126
 
 
127
                record_allocation(&rec->alloc_rec, ba_list);
 
128
 
 
129
                new = &rec->extents[0];
 
130
 
 
131
                for (i = 0; i < ALLOC_NUM_EXTS; i++)  {
 
132
                        new->avl_node.avl_nextino = (avlnode_t *)
 
133
                                                        ext_flist.list;
 
134
                        ext_flist.list = new;
 
135
                        ext_flist.cnt++;
 
136
                        new++;
 
137
                }
 
138
        }
 
139
 
 
140
        ASSERT(ext_flist.list != NULL);
 
141
 
 
142
        new = ext_flist.list;
 
143
        ext_flist.list = (extent_tree_node_t *) new->avl_node.avl_nextino;
 
144
        ext_flist.cnt--;
 
145
        new->avl_node.avl_nextino = NULL;
 
146
 
 
147
        /* initialize node */
 
148
 
 
149
        new->ex_startblock = new_startblock;
 
150
        new->ex_blockcount = new_blockcount;
 
151
        new->ex_state = new_state;
 
152
        new->next = NULL;
 
153
 
 
154
        return(new);
 
155
}
 
156
 
 
157
void
 
158
release_extent_tree_node(extent_tree_node_t *node)
 
159
{
 
160
        node->avl_node.avl_nextino = (avlnode_t *) ext_flist.list;
 
161
        ext_flist.list = node;
 
162
        ext_flist.cnt++;
 
163
 
 
164
        return;
 
165
}
 
166
 
 
167
/*
 
168
 * routines to recycle all nodes in a tree.  it walks the tree
 
169
 * and puts all nodes back on the free list so the nodes can be
 
170
 * reused.  the duplicate and bno/bcnt extent trees for each AG
 
171
 * are recycled after they're no longer needed to save memory
 
172
 */
 
173
void
 
174
release_extent_tree(avltree_desc_t *tree)
 
175
{
 
176
        extent_tree_node_t      *ext;
 
177
        extent_tree_node_t      *tmp;
 
178
        extent_tree_node_t      *lext;
 
179
        extent_tree_node_t      *ltmp;
 
180
 
 
181
        if (tree->avl_firstino == NULL)
 
182
                return;
 
183
 
 
184
        ext = (extent_tree_node_t *) tree->avl_firstino;
 
185
 
 
186
        while (ext != NULL)  {
 
187
                tmp = (extent_tree_node_t *) ext->avl_node.avl_nextino;
 
188
 
 
189
                /*
 
190
                 * ext->next is guaranteed to be set only in bcnt trees
 
191
                 */
 
192
                if (ext->next != NULL)  {
 
193
                        lext = ext->next;
 
194
                        while (lext != NULL)  {
 
195
                                ltmp = lext->next;
 
196
                                release_extent_tree_node(lext);
 
197
                                lext = ltmp;
 
198
                        }
 
199
                }
 
200
 
 
201
                release_extent_tree_node(ext);
 
202
                ext = tmp;
 
203
        }
 
204
 
 
205
        tree->avl_root = tree->avl_firstino = NULL;
 
206
 
 
207
        return;
 
208
}
 
209
 
 
210
/*
 
211
 * top-level (visible) routines
 
212
 */
 
213
void
 
214
release_dup_extent_tree(xfs_agnumber_t agno)
 
215
{
 
216
        release_extent_tree(extent_tree_ptrs[agno]);
 
217
 
 
218
        return;
 
219
}
 
220
 
 
221
void
 
222
release_agbno_extent_tree(xfs_agnumber_t agno)
 
223
{
 
224
        release_extent_tree(extent_bno_ptrs[agno]);
 
225
 
 
226
        return;
 
227
}
 
228
 
 
229
void
 
230
release_agbcnt_extent_tree(xfs_agnumber_t agno)
 
231
{
 
232
        release_extent_tree(extent_bcnt_ptrs[agno]);
 
233
 
 
234
        return;
 
235
}
 
236
 
 
237
/*
 
238
 * the next 4 routines manage the trees of free extents -- 2 trees
 
239
 * per AG.  The first tree is sorted by block number.  The second
 
240
 * tree is sorted by extent size.  This is the bno tree.
 
241
 */
 
242
void
 
243
add_bno_extent(xfs_agnumber_t agno, xfs_agblock_t startblock,
 
244
                xfs_extlen_t blockcount)
 
245
{
 
246
        extent_tree_node_t *ext;
 
247
 
 
248
        ASSERT(extent_bno_ptrs != NULL);
 
249
        ASSERT(extent_bno_ptrs[agno] != NULL);
 
250
 
 
251
        ext = mk_extent_tree_nodes(startblock, blockcount, XR_E_FREE);
 
252
 
 
253
        if (avl_insert(extent_bno_ptrs[agno], (avlnode_t *) ext) == NULL)  {
 
254
                do_error("xfs_repair:  duplicate bno extent range\n");
 
255
        }
 
256
}
 
257
 
 
258
extent_tree_node_t *
 
259
findfirst_bno_extent(xfs_agnumber_t agno)
 
260
{
 
261
        ASSERT(extent_bno_ptrs != NULL);
 
262
        ASSERT(extent_bno_ptrs[agno] != NULL);
 
263
 
 
264
        return((extent_tree_node_t *) extent_bno_ptrs[agno]->avl_firstino);
 
265
}
 
266
 
 
267
extent_tree_node_t *
 
268
find_bno_extent(xfs_agnumber_t agno, xfs_agblock_t startblock)
 
269
{
 
270
        ASSERT(extent_bno_ptrs != NULL);
 
271
        ASSERT(extent_bno_ptrs[agno] != NULL);
 
272
 
 
273
        return((extent_tree_node_t *) avl_find(extent_bno_ptrs[agno],
 
274
                                                startblock));
 
275
}
 
276
 
 
277
/*
 
278
 * delete a node that's in the tree (pointer obtained by a find routine)
 
279
 */
 
280
void
 
281
get_bno_extent(xfs_agnumber_t agno, extent_tree_node_t *ext)
 
282
{
 
283
        ASSERT(extent_bno_ptrs != NULL);
 
284
        ASSERT(extent_bno_ptrs[agno] != NULL);
 
285
 
 
286
        avl_delete(extent_bno_ptrs[agno], &ext->avl_node);
 
287
 
 
288
        return;
 
289
}
 
290
 
 
291
/*
 
292
 * normalizing constant for bcnt size -> address conversion (see avl ops)
 
293
 * used by the AVL tree code to convert sizes and must be used when
 
294
 * doing an AVL search in the tree (e.g. avl_findrange(s))
 
295
 */
 
296
#define MAXBCNT         0xFFFFFFFF
 
297
#define BCNT_ADDR(cnt)  ((unsigned int) MAXBCNT - (cnt))
 
298
 
 
299
/*
 
300
 * the next 4 routines manage the trees of free extents -- 2 trees
 
301
 * per AG.  The first tree is sorted by block number.  The second
 
302
 * tree is sorted by extent size.  This is the bcnt tree.
 
303
 */
 
304
void
 
305
add_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t startblock,
 
306
                xfs_extlen_t blockcount)
 
307
{
 
308
        extent_tree_node_t *ext, *prev, *current, *top;
 
309
        xfs_agblock_t           tmp_startblock;
 
310
        xfs_extlen_t            tmp_blockcount;
 
311
        extent_state_t          tmp_state;
 
312
 
 
313
        ASSERT(extent_bcnt_ptrs != NULL);
 
314
        ASSERT(extent_bcnt_ptrs[agno] != NULL);
 
315
 
 
316
        ext = mk_extent_tree_nodes(startblock, blockcount, XR_E_FREE);
 
317
 
 
318
        ASSERT(ext->next == NULL);
 
319
 
 
320
#ifdef XR_BCNT_TRACE
 
321
        fprintf(stderr, "adding bcnt: agno = %d, start = %u, count = %u\n",
 
322
                        agno, startblock, blockcount);
 
323
#endif
 
324
        if ((current = (extent_tree_node_t *) avl_find(extent_bcnt_ptrs[agno],
 
325
                                                        blockcount)) != NULL)  {
 
326
                /*
 
327
                 * avl tree code doesn't handle dups so insert
 
328
                 * onto linked list in increasing startblock order
 
329
                 */
 
330
                top = prev = current;
 
331
                while (current != NULL &&
 
332
                                startblock > current->ex_startblock)  {
 
333
                        prev = current;
 
334
                        current = current->next;
 
335
                }
 
336
 
 
337
                if (top == current)  {
 
338
                        ASSERT(top == prev);
 
339
                        /*
 
340
                         * swap the values of to-be-inserted element
 
341
                         * and the values of the head of the list.
 
342
                         * then insert as the 2nd element on the list.
 
343
                         *
 
344
                         * see the comment in get_bcnt_extent()
 
345
                         * as to why we have to do this.
 
346
                         */
 
347
                        tmp_startblock = top->ex_startblock;
 
348
                        tmp_blockcount = top->ex_blockcount;
 
349
                        tmp_state = top->ex_state;
 
350
 
 
351
                        top->ex_startblock = ext->ex_startblock;
 
352
                        top->ex_blockcount = ext->ex_blockcount;
 
353
                        top->ex_state = ext->ex_state;
 
354
 
 
355
                        ext->ex_startblock = tmp_startblock;
 
356
                        ext->ex_blockcount = tmp_blockcount;
 
357
                        ext->ex_state = tmp_state;
 
358
 
 
359
                        current = top->next;
 
360
                        prev = top;
 
361
                }
 
362
 
 
363
                prev->next = ext;
 
364
                ext->next = current;
 
365
 
 
366
                return;
 
367
        }
 
368
 
 
369
        if (avl_insert(extent_bcnt_ptrs[agno], (avlnode_t *) ext) == NULL)  {
 
370
                do_error("xfs_repair:  duplicate bno extent range\n");
 
371
        }
 
372
 
 
373
        return;
 
374
}
 
375
 
 
376
extent_tree_node_t *
 
377
findfirst_bcnt_extent(xfs_agnumber_t agno)
 
378
{
 
379
        ASSERT(extent_bcnt_ptrs != NULL);
 
380
        ASSERT(extent_bcnt_ptrs[agno] != NULL);
 
381
 
 
382
        return((extent_tree_node_t *) extent_bcnt_ptrs[agno]->avl_firstino);
 
383
}
 
384
 
 
385
extent_tree_node_t *
 
386
findbiggest_bcnt_extent(xfs_agnumber_t agno)
 
387
{
 
388
        extern avlnode_t *avl_lastino(avlnode_t *root);
 
389
 
 
390
        ASSERT(extent_bcnt_ptrs != NULL);
 
391
        ASSERT(extent_bcnt_ptrs[agno] != NULL);
 
392
 
 
393
        return((extent_tree_node_t *) avl_lastino(extent_bcnt_ptrs[agno]->avl_root));
 
394
}
 
395
 
 
396
extent_tree_node_t *
 
397
findnext_bcnt_extent(xfs_agnumber_t agno, extent_tree_node_t *ext)
 
398
{
 
399
        avlnode_t *nextino;
 
400
 
 
401
        if (ext->next != NULL)  {
 
402
                ASSERT(ext->ex_blockcount == ext->next->ex_blockcount);
 
403
                ASSERT(ext->ex_startblock < ext->next->ex_startblock);
 
404
                return(ext->next);
 
405
        } else  {
 
406
                /*
 
407
                 * have to look at the top of the list to get the
 
408
                 * correct avl_nextino pointer since that pointer
 
409
                 * is maintained and altered by the AVL code.
 
410
                 */
 
411
                nextino = avl_find(extent_bcnt_ptrs[agno], ext->ex_blockcount);
 
412
                ASSERT(nextino != NULL);
 
413
                if (nextino->avl_nextino != NULL)  {
 
414
                        ASSERT(ext->ex_blockcount < ((extent_tree_node_t *)
 
415
                                        nextino->avl_nextino)->ex_blockcount);
 
416
                }
 
417
                return((extent_tree_node_t *) nextino->avl_nextino);
 
418
        }
 
419
}
 
420
 
 
421
/*
 
422
 * this is meant to be called after you walk the bno tree to
 
423
 * determine exactly which extent you want (so you'll know the
 
424
 * desired value for startblock when you call this routine).
 
425
 */
 
426
extent_tree_node_t *
 
427
get_bcnt_extent(xfs_agnumber_t agno, xfs_agblock_t startblock,
 
428
                xfs_extlen_t blockcount)
 
429
{
 
430
        extent_tree_node_t      *ext, *prev, *top;
 
431
        xfs_agblock_t           tmp_startblock;
 
432
        xfs_extlen_t            tmp_blockcount;
 
433
        extent_state_t          tmp_state;
 
434
 
 
435
        prev = NULL;
 
436
        ASSERT(extent_bcnt_ptrs != NULL);
 
437
        ASSERT(extent_bcnt_ptrs[agno] != NULL);
 
438
 
 
439
        if ((ext = (extent_tree_node_t *) avl_find(extent_bcnt_ptrs[agno],
 
440
                                                        blockcount)) == NULL)
 
441
                return(NULL);
 
442
        
 
443
        top = ext;
 
444
 
 
445
        if (ext->next != NULL)  {
 
446
                /*
 
447
                 * pull it off the list
 
448
                 */
 
449
                while (ext != NULL && startblock != ext->ex_startblock)  {
 
450
                        prev = ext;
 
451
                        ext = ext->next;
 
452
                }
 
453
                ASSERT(ext != NULL);
 
454
                if (ext == top)  {
 
455
                        /*
 
456
                         * this node is linked into the tree so we
 
457
                         * swap the core values so we can delete
 
458
                         * the next item on the list instead of
 
459
                         * the head of the list.  This is because
 
460
                         * the rest of the tree undoubtedly has
 
461
                         * pointers to the piece of memory that
 
462
                         * is the head of the list so pulling
 
463
                         * the item out of the list and hence
 
464
                         * the avl tree would be a bad idea.
 
465
                         * 
 
466
                         * (cheaper than the alternative, a tree
 
467
                         * delete of this node followed by a tree
 
468
                         * insert of the next node on the list).
 
469
                         */
 
470
                        tmp_startblock = ext->next->ex_startblock;
 
471
                        tmp_blockcount = ext->next->ex_blockcount;
 
472
                        tmp_state = ext->next->ex_state;
 
473
 
 
474
                        ext->next->ex_startblock = ext->ex_startblock;
 
475
                        ext->next->ex_blockcount = ext->ex_blockcount;
 
476
                        ext->next->ex_state = ext->ex_state;
 
477
 
 
478
                        ext->ex_startblock = tmp_startblock;
 
479
                        ext->ex_blockcount = tmp_blockcount;
 
480
                        ext->ex_state = tmp_state;
 
481
 
 
482
                        ext = ext->next;
 
483
                        prev = top;
 
484
                }
 
485
                /*
 
486
                 * now, a simple list deletion
 
487
                 */
 
488
                prev->next = ext->next;
 
489
                ext->next = NULL;
 
490
        } else  {
 
491
                /*
 
492
                 * no list, just one node.  simply delete
 
493
                 */
 
494
                avl_delete(extent_bcnt_ptrs[agno], &ext->avl_node);
 
495
        }
 
496
 
 
497
        ASSERT(ext->ex_startblock == startblock);
 
498
        ASSERT(ext->ex_blockcount == blockcount);
 
499
        return(ext);
 
500
}
 
501
 
 
502
/*
 
503
 * the next 2 routines manage the trees of duplicate extents -- 1 tree
 
504
 * per AG
 
505
 */
 
506
void
 
507
add_dup_extent(xfs_agnumber_t agno, xfs_agblock_t startblock,
 
508
                xfs_extlen_t blockcount)
 
509
{
 
510
        extent_tree_node_t *first, *last, *ext, *next_ext;
 
511
        xfs_agblock_t new_startblock;
 
512
        xfs_extlen_t new_blockcount;
 
513
 
 
514
        ASSERT(agno < glob_agcount);
 
515
 
 
516
#ifdef XR_DUP_TRACE
 
517
        fprintf(stderr, "Adding dup extent - %d/%d %d\n", agno, startblock, blockcount);
 
518
#endif
 
519
        avl_findranges(extent_tree_ptrs[agno], startblock - 1,
 
520
                startblock + blockcount + 1,
 
521
                (avlnode_t **) &first, (avlnode_t **) &last);
 
522
        /*
 
523
         * find adjacent and overlapping extent blocks
 
524
         */
 
525
        if (first == NULL && last == NULL)  {
 
526
                /* nothing, just make and insert new extent */
 
527
 
 
528
                ext = mk_extent_tree_nodes(startblock, blockcount, XR_E_MULT);
 
529
 
 
530
                if (avl_insert(extent_tree_ptrs[agno],
 
531
                                (avlnode_t *) ext) == NULL)  {
 
532
                        do_error("xfs_repair:  duplicate extent range\n");
 
533
                }
 
534
 
 
535
                return;
 
536
        }
 
537
 
 
538
        ASSERT(first != NULL && last != NULL);
 
539
 
 
540
        /*
 
541
         * find the new composite range, delete old extent nodes
 
542
         * as we go
 
543
         */
 
544
        new_startblock = startblock;
 
545
        new_blockcount = blockcount;
 
546
 
 
547
        for (ext = first;
 
548
                ext != (extent_tree_node_t *) last->avl_node.avl_nextino;
 
549
                ext = next_ext)  {
 
550
                /*
 
551
                 * preserve the next inorder node
 
552
                 */
 
553
                next_ext = (extent_tree_node_t *) ext->avl_node.avl_nextino;
 
554
                /*
 
555
                 * just bail if the new extent is contained within an old one
 
556
                 */
 
557
                if (ext->ex_startblock <= startblock && 
 
558
                                ext->ex_blockcount >= blockcount)
 
559
                        return;
 
560
                /*
 
561
                 * now check for overlaps and adjacent extents
 
562
                 */
 
563
                if (ext->ex_startblock + ext->ex_blockcount >= startblock
 
564
                        || ext->ex_startblock <= startblock + blockcount)  {
 
565
 
 
566
                        if (ext->ex_startblock < new_startblock)
 
567
                                new_startblock = ext->ex_startblock;
 
568
 
 
569
                        if (ext->ex_startblock + ext->ex_blockcount >
 
570
                                        new_startblock + new_blockcount)
 
571
                                new_blockcount = ext->ex_startblock +
 
572
                                                        ext->ex_blockcount -
 
573
                                                        new_startblock;
 
574
 
 
575
                        avl_delete(extent_tree_ptrs[agno], (avlnode_t *) ext);
 
576
                        continue;
 
577
                }
 
578
        }
 
579
 
 
580
        ext = mk_extent_tree_nodes(new_startblock, new_blockcount, XR_E_MULT);
 
581
 
 
582
        if (avl_insert(extent_tree_ptrs[agno], (avlnode_t *) ext) == NULL)  {
 
583
                do_error("xfs_repair:  duplicate extent range\n");
 
584
        }
 
585
 
 
586
        return;
 
587
}
 
588
 
 
589
/*
 
590
 * returns 1 if block is a dup, 0 if not
 
591
 */
 
592
/* ARGSUSED */
 
593
int
 
594
search_dup_extent(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agblock_t agbno)
 
595
{
 
596
        ASSERT(agno < glob_agcount);
 
597
 
 
598
        if (avl_findrange(extent_tree_ptrs[agno], agbno) != NULL)
 
599
                return(1);
 
600
 
 
601
        return(0);
 
602
}
 
603
 
 
604
static __psunsigned_t
 
605
avl_ext_start(avlnode_t *node)
 
606
{
 
607
        return((__psunsigned_t)
 
608
                ((extent_tree_node_t *) node)->ex_startblock);
 
609
}
 
610
 
 
611
static __psunsigned_t
 
612
avl_ext_end(avlnode_t *node)
 
613
{
 
614
        return((__psunsigned_t) (
 
615
                ((extent_tree_node_t *) node)->ex_startblock +
 
616
                ((extent_tree_node_t *) node)->ex_blockcount));
 
617
}
 
618
 
 
619
/*
 
620
 * convert size to an address for the AVL tree code -- the bigger the size,
 
621
 * the lower the address so the biggest extent will be first in the tree
 
622
 */
 
623
static __psunsigned_t
 
624
avl_ext_bcnt_start(avlnode_t *node)
 
625
{
 
626
/*
 
627
        return((__psunsigned_t) (BCNT_ADDR(((extent_tree_node_t *)
 
628
                                                node)->ex_blockcount)));
 
629
*/
 
630
        return((__psunsigned_t) ((extent_tree_node_t *)node)->ex_blockcount);
 
631
}
 
632
 
 
633
static __psunsigned_t
 
634
avl_ext_bcnt_end(avlnode_t *node)
 
635
{
 
636
/*
 
637
        return((__psunsigned_t) (BCNT_ADDR(((extent_tree_node_t *)
 
638
                                                node)->ex_blockcount)));
 
639
*/
 
640
        return((__psunsigned_t) ((extent_tree_node_t *)node)->ex_blockcount);
 
641
}
 
642
 
 
643
avlops_t avl_extent_bcnt_tree_ops = {
 
644
        avl_ext_bcnt_start,
 
645
        avl_ext_bcnt_end
 
646
};
 
647
 
 
648
avlops_t avl_extent_tree_ops = {
 
649
        avl_ext_start,
 
650
        avl_ext_end
 
651
};
 
652
 
 
653
/*
 
654
 * for real-time extents -- have to dup code since realtime extent
 
655
 * startblocks can be 64-bit values.
 
656
 */
 
657
static rt_extent_tree_node_t *
 
658
mk_rt_extent_tree_nodes(xfs_drtbno_t new_startblock,
 
659
        xfs_extlen_t new_blockcount, extent_state_t new_state)
 
660
{
 
661
        int i;
 
662
        rt_extent_tree_node_t *new;
 
663
        rt_extent_alloc_rec_t *rec;
 
664
 
 
665
        if (rt_ext_flist.cnt == 0)  {
 
666
                ASSERT(rt_ext_flist.list == NULL);
 
667
 
 
668
                if ((rec = malloc(sizeof(rt_extent_alloc_rec_t))) == NULL)
 
669
                        do_error("couldn't allocate new extent descriptors.\n");
 
670
 
 
671
                record_allocation(&rec->alloc_rec, rt_ba_list);
 
672
 
 
673
                new = &rec->extents[0];
 
674
 
 
675
                for (i = 0; i < ALLOC_NUM_EXTS; i++)  {
 
676
                        new->avl_node.avl_nextino = (avlnode_t *)
 
677
                                                        rt_ext_flist.list;
 
678
                        rt_ext_flist.list = new;
 
679
                        rt_ext_flist.cnt++;
 
680
                        new++;
 
681
                }
 
682
        }
 
683
 
 
684
        ASSERT(rt_ext_flist.list != NULL);
 
685
 
 
686
        new = rt_ext_flist.list;
 
687
        rt_ext_flist.list = (rt_extent_tree_node_t *) new->avl_node.avl_nextino;
 
688
        rt_ext_flist.cnt--;
 
689
        new->avl_node.avl_nextino = NULL;
 
690
 
 
691
        /* initialize node */
 
692
 
 
693
        new->rt_startblock = new_startblock;
 
694
        new->rt_blockcount = new_blockcount;
 
695
        new->rt_state = new_state;
 
696
 
 
697
        return(new);
 
698
}
 
699
 
 
700
#if 0
 
701
void
 
702
release_rt_extent_tree_node(rt_extent_tree_node_t *node)
 
703
{
 
704
        node->avl_node.avl_nextino = (avlnode_t *) rt_ext_flist.list;
 
705
        rt_ext_flist.list = node;
 
706
        rt_ext_flist.cnt++;
 
707
 
 
708
        return;
 
709
}
 
710
 
 
711
void
 
712
release_rt_extent_tree()
 
713
{
 
714
        extent_tree_node_t      *ext;
 
715
        extent_tree_node_t      *tmp;
 
716
        extent_tree_node_t      *lext;
 
717
        extent_tree_node_t      *ltmp;
 
718
        avl64tree_desc_t        *tree;
 
719
 
 
720
        tree = rt_extent_tree_ptr;
 
721
 
 
722
        if (tree->avl_firstino == NULL)
 
723
                return;
 
724
 
 
725
        ext = (extent_tree_node_t *) tree->avl_firstino;
 
726
 
 
727
        while (ext != NULL)  {
 
728
                tmp = (extent_tree_node_t *) ext->avl_node.avl_nextino;
 
729
                release_rt_extent_tree_node(ext);
 
730
                ext = tmp;
 
731
        }
 
732
 
 
733
        tree->avl_root = tree->avl_firstino = NULL;
 
734
 
 
735
        return;
 
736
}
 
737
#endif
 
738
 
 
739
/*
 
740
 * don't need release functions for realtime tree teardown
 
741
 * since we only have one tree, not one per AG
 
742
 */
 
743
/* ARGSUSED */
 
744
void
 
745
free_rt_dup_extent_tree(xfs_mount_t *mp)
 
746
{
 
747
        ASSERT(mp->m_sb.sb_rblocks != 0);
 
748
 
 
749
        free_allocations(rt_ba_list);
 
750
        free(rt_ext_tree_ptr);
 
751
 
 
752
        rt_ba_list = NULL;
 
753
        rt_ext_tree_ptr = NULL;
 
754
 
 
755
        return;
 
756
}
 
757
 
 
758
/*
 
759
 * add a duplicate real-time extent
 
760
 */
 
761
void
 
762
add_rt_dup_extent(xfs_drtbno_t startblock, xfs_extlen_t blockcount)
 
763
{
 
764
        rt_extent_tree_node_t *first, *last, *ext, *next_ext;
 
765
        xfs_drtbno_t new_startblock;
 
766
        xfs_extlen_t new_blockcount;
 
767
 
 
768
        avl64_findranges(rt_ext_tree_ptr, startblock - 1,
 
769
                startblock + blockcount + 1,
 
770
                (avl64node_t **) &first, (avl64node_t **) &last);
 
771
        /*
 
772
         * find adjacent and overlapping extent blocks
 
773
         */
 
774
        if (first == NULL && last == NULL)  {
 
775
                /* nothing, just make and insert new extent */
 
776
 
 
777
                ext = mk_rt_extent_tree_nodes(startblock,
 
778
                                blockcount, XR_E_MULT);
 
779
 
 
780
                if (avl64_insert(rt_ext_tree_ptr,
 
781
                                (avl64node_t *) ext) == NULL)  {
 
782
                        do_error("xfs_repair:  duplicate extent range\n");
 
783
                }
 
784
 
 
785
                return;
 
786
        }
 
787
 
 
788
        ASSERT(first != NULL && last != NULL);
 
789
 
 
790
        /*
 
791
         * find the new composite range, delete old extent nodes
 
792
         * as we go
 
793
         */
 
794
        new_startblock = startblock;
 
795
        new_blockcount = blockcount;
 
796
 
 
797
        for (ext = first;
 
798
                ext != (rt_extent_tree_node_t *) last->avl_node.avl_nextino;
 
799
                ext = next_ext)  {
 
800
                /*
 
801
                 * preserve the next inorder node
 
802
                 */
 
803
                next_ext = (rt_extent_tree_node_t *) ext->avl_node.avl_nextino;
 
804
                /*
 
805
                 * just bail if the new extent is contained within an old one
 
806
                 */
 
807
                if (ext->rt_startblock <= startblock && 
 
808
                                ext->rt_blockcount >= blockcount)
 
809
                        return;
 
810
                /*
 
811
                 * now check for overlaps and adjacent extents
 
812
                 */
 
813
                if (ext->rt_startblock + ext->rt_blockcount >= startblock
 
814
                        || ext->rt_startblock <= startblock + blockcount)  {
 
815
 
 
816
                        if (ext->rt_startblock < new_startblock)
 
817
                                new_startblock = ext->rt_startblock;
 
818
 
 
819
                        if (ext->rt_startblock + ext->rt_blockcount >
 
820
                                        new_startblock + new_blockcount)
 
821
                                new_blockcount = ext->rt_startblock +
 
822
                                                        ext->rt_blockcount -
 
823
                                                        new_startblock;
 
824
 
 
825
                        avl64_delete(rt_ext_tree_ptr, (avl64node_t *) ext);
 
826
                        continue;
 
827
                }
 
828
        }
 
829
 
 
830
        ext = mk_rt_extent_tree_nodes(new_startblock,
 
831
                                new_blockcount, XR_E_MULT);
 
832
 
 
833
        if (avl64_insert(rt_ext_tree_ptr, (avl64node_t *) ext) == NULL)  {
 
834
                do_error("xfs_repair:  duplicate extent range\n");
 
835
        }
 
836
 
 
837
        return;
 
838
}
 
839
 
 
840
/*
 
841
 * returns 1 if block is a dup, 0 if not
 
842
 */
 
843
/* ARGSUSED */
 
844
int
 
845
search_rt_dup_extent(xfs_mount_t *mp, xfs_drtbno_t bno)
 
846
{
 
847
        if (avl64_findrange(rt_ext_tree_ptr, bno) != NULL)
 
848
                return(1);
 
849
 
 
850
        return(0);
 
851
}
 
852
 
 
853
static __uint64_t
 
854
avl64_rt_ext_start(avl64node_t *node)
 
855
{
 
856
        return(((rt_extent_tree_node_t *) node)->rt_startblock);
 
857
}
 
858
 
 
859
static __uint64_t
 
860
avl64_ext_end(avl64node_t *node)
 
861
{
 
862
        return(((rt_extent_tree_node_t *) node)->rt_startblock +
 
863
                ((rt_extent_tree_node_t *) node)->rt_blockcount);
 
864
}
 
865
 
 
866
avl64ops_t avl64_extent_tree_ops = {
 
867
        avl64_rt_ext_start,
 
868
        avl64_ext_end
 
869
};
 
870
 
 
871
void
 
872
incore_ext_init(xfs_mount_t *mp)
 
873
{
 
874
        int i;
 
875
        xfs_agnumber_t agcount = mp->m_sb.sb_agcount;
 
876
 
 
877
        ba_list = NULL;
 
878
        rt_ba_list = NULL;
 
879
 
 
880
        if ((extent_tree_ptrs = malloc(agcount *
 
881
                                        sizeof(avltree_desc_t *))) == NULL)
 
882
                do_error("couldn't malloc dup extent tree descriptor table\n");
 
883
 
 
884
        if ((extent_bno_ptrs = malloc(agcount *
 
885
                                        sizeof(avltree_desc_t *))) == NULL)
 
886
                do_error("couldn't malloc free by-bno extent tree descriptor table\n");
 
887
 
 
888
        if ((extent_bcnt_ptrs = malloc(agcount *
 
889
                                        sizeof(avltree_desc_t *))) == NULL)
 
890
                do_error("couldn't malloc free by-bcnt extent tree descriptor table\n");
 
891
 
 
892
        for (i = 0; i < agcount; i++)  {
 
893
                if ((extent_tree_ptrs[i] =
 
894
                                malloc(sizeof(avltree_desc_t))) == NULL)
 
895
                        do_error("couldn't malloc dup extent tree descriptor\n");
 
896
                if ((extent_bno_ptrs[i] =
 
897
                                malloc(sizeof(avltree_desc_t))) == NULL)
 
898
                        do_error("couldn't malloc bno extent tree descriptor\n");
 
899
                if ((extent_bcnt_ptrs[i] =
 
900
                                malloc(sizeof(avltree_desc_t))) == NULL)
 
901
                        do_error("couldn't malloc bcnt extent tree descriptor\n");
 
902
        }
 
903
 
 
904
        for (i = 0; i < agcount; i++)  {
 
905
                avl_init_tree(extent_tree_ptrs[i], &avl_extent_tree_ops);
 
906
                avl_init_tree(extent_bno_ptrs[i], &avl_extent_tree_ops);
 
907
                avl_init_tree(extent_bcnt_ptrs[i], &avl_extent_bcnt_tree_ops);
 
908
        }
 
909
 
 
910
        if ((rt_ext_tree_ptr = malloc(sizeof(avltree_desc_t))) == NULL)
 
911
                do_error("couldn't malloc dup rt extent tree descriptor\n");
 
912
 
 
913
        avl64_init_tree(rt_ext_tree_ptr, &avl64_extent_tree_ops);
 
914
 
 
915
        ext_flist.cnt = 0;
 
916
        ext_flist.list = NULL;
 
917
 
 
918
        return;
 
919
}
 
920
 
 
921
/*
 
922
 * this routine actually frees all the memory used to track per-AG trees
 
923
 */
 
924
void
 
925
incore_ext_teardown(xfs_mount_t *mp)
 
926
{
 
927
        xfs_agnumber_t i;
 
928
 
 
929
        free_allocations(ba_list);
 
930
 
 
931
        for (i = 0; i < mp->m_sb.sb_agcount; i++)  {
 
932
                free(extent_tree_ptrs[i]);
 
933
                free(extent_bno_ptrs[i]);
 
934
                free(extent_bcnt_ptrs[i]);
 
935
        }
 
936
 
 
937
        free(extent_bcnt_ptrs);
 
938
        free(extent_bno_ptrs);
 
939
        free(extent_tree_ptrs);
 
940
 
 
941
        extent_bcnt_ptrs = extent_bno_ptrs = extent_tree_ptrs = NULL;
 
942
 
 
943
        return;
 
944
}
 
945
 
 
946
int
 
947
count_extents(xfs_agnumber_t agno, avltree_desc_t *tree, int whichtree)
 
948
{
 
949
        extent_tree_node_t *node;
 
950
        int i = 0;
 
951
 
 
952
        node = (extent_tree_node_t *) tree->avl_firstino;
 
953
 
 
954
        while (node != NULL)  {
 
955
                i++;
 
956
                if (whichtree)
 
957
                        node = findnext_bcnt_extent(agno, node);
 
958
                else
 
959
                        node = findnext_bno_extent(node);
 
960
        }
 
961
 
 
962
        return(i);
 
963
}
 
964
 
 
965
int
 
966
count_bno_extents_blocks(xfs_agnumber_t agno, uint *numblocks)
 
967
{
 
968
        __uint64_t nblocks;
 
969
        extent_tree_node_t *node;
 
970
        int i = 0;
 
971
 
 
972
        ASSERT(agno < glob_agcount);
 
973
 
 
974
        nblocks = 0;
 
975
 
 
976
        node = (extent_tree_node_t *) extent_bno_ptrs[agno]->avl_firstino;
 
977
 
 
978
        while (node != NULL) {
 
979
                nblocks += node->ex_blockcount;
 
980
                i++;
 
981
                node = findnext_bno_extent(node);
 
982
        }
 
983
 
 
984
        *numblocks = nblocks;
 
985
        return(i);
 
986
}
 
987
 
 
988
int
 
989
count_bno_extents(xfs_agnumber_t agno)
 
990
{
 
991
        ASSERT(agno < glob_agcount);
 
992
        return(count_extents(agno, extent_bno_ptrs[agno], 0));
 
993
}
 
994
 
 
995
int
 
996
count_bcnt_extents(xfs_agnumber_t agno)
 
997
{
 
998
        ASSERT(agno < glob_agcount);
 
999
        return(count_extents(agno, extent_bcnt_ptrs[agno], 1));
 
1000
}