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

« back to all changes in this revision

Viewing changes to repair/dir.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 "agheader.h"
 
37
#include "incore.h"
 
38
#include "protos.h"
 
39
#include "err_protos.h"
 
40
#include "dinode.h"
 
41
#include "dir.h"
 
42
#include "bmap.h"
 
43
 
 
44
#if XFS_DIR_LEAF_MAPSIZE >= XFS_ATTR_LEAF_MAPSIZE
 
45
#define XR_DA_LEAF_MAPSIZE      XFS_DIR_LEAF_MAPSIZE
 
46
#else
 
47
#define XR_DA_LEAF_MAPSIZE      XFS_ATTR_LEAF_MAPSIZE
 
48
#endif
 
49
 
 
50
 
 
51
 
 
52
typedef struct da_hole_map  {
 
53
        int     lost_holes;
 
54
        int     num_holes;
 
55
        struct {
 
56
                int     base;
 
57
                int     size;
 
58
        } hentries[XR_DA_LEAF_MAPSIZE];
 
59
} da_hole_map_t;
 
60
 
 
61
/*
 
62
 * takes a name and length (name need not be null-terminated)
 
63
 * and returns 1 if the name contains a '/' or a \0, returns 0
 
64
 * otherwise
 
65
 */
 
66
int
 
67
namecheck(char *name, int length)
 
68
{
 
69
        char *c;
 
70
        int i;
 
71
 
 
72
        ASSERT(length < MAXNAMELEN);
 
73
 
 
74
        for (c = name, i = 0; i < length; i++, c++)  {
 
75
                if (*c == '/' || *c == '\0')
 
76
                        return(1);
 
77
        }
 
78
 
 
79
        return(0);
 
80
}
 
81
 
 
82
/*
 
83
 * this routine performs inode discovery and tries to fix things
 
84
 * in place.  available redundancy -- inode data size should match
 
85
 * used directory space in inode.  returns number of valid directory
 
86
 * entries.  a non-zero return value means the directory is bogus
 
87
 * and should be blasted.
 
88
 */
 
89
/* ARGSUSED */
 
90
int
 
91
process_shortform_dir(
 
92
        xfs_mount_t     *mp,
 
93
        xfs_ino_t       ino,
 
94
        xfs_dinode_t    *dip,
 
95
        int             ino_discovery,
 
96
        int             *dino_dirty,    /* out - 1 if dinode buffer dirty? */
 
97
        xfs_ino_t       *parent,        /* out - NULLFSINO if entry doesn't exist */
 
98
        char            *dirname,       /* directory pathname */
 
99
        int             *repair)        /* out - 1 if dir was fixed up */
 
100
{
 
101
        xfs_dir_shortform_t     *sf;
 
102
        xfs_dir_sf_entry_t      *sf_entry, *next_sfe, *tmp_sfe;
 
103
        xfs_ino_t               lino;
 
104
        int                     max_size;
 
105
        __int64_t               ino_dir_size;
 
106
        int                     num_entries;
 
107
        int                     ino_off;
 
108
        int                     namelen;
 
109
        int                     i;
 
110
        int                     junkit;
 
111
        int                     tmp_len;
 
112
        int                     tmp_elen;
 
113
        int                     bad_sfnamelen;
 
114
        ino_tree_node_t         *irec_p;
 
115
        char                    name[MAXNAMELEN + 1];
 
116
 
 
117
#ifdef XR_DIR_TRACE
 
118
        fprintf(stderr, "process_shortform_dir - inode %llu\n", ino);
 
119
#endif
 
120
 
 
121
        sf = &dip->di_u.di_dirsf;
 
122
 
 
123
        max_size = XFS_DFORK_DSIZE_ARCH(dip, mp, ARCH_CONVERT);
 
124
        num_entries = INT_GET(sf->hdr.count, ARCH_CONVERT);
 
125
        ino_dir_size = INT_GET(dip->di_core.di_size, ARCH_CONVERT);
 
126
        *repair = 0;
 
127
 
 
128
        ASSERT(ino_dir_size <= max_size);
 
129
 
 
130
        /*
 
131
         * check for bad entry count
 
132
         */
 
133
        if (num_entries * sizeof(xfs_dir_sf_entry_t) + sizeof(xfs_dir_sf_hdr_t)
 
134
                        > max_size || num_entries == 0)
 
135
                num_entries = 0xFF;
 
136
 
 
137
        /*
 
138
         * run through entries, stop at first bad entry, don't need
 
139
         * to check for .. since that's encoded in its own field
 
140
         */
 
141
        sf_entry = next_sfe = &sf->list[0];
 
142
        for (i = 0; i < num_entries && ino_dir_size >
 
143
                                (__psint_t)next_sfe - (__psint_t)sf; i++)  {
 
144
                tmp_sfe = NULL;
 
145
                sf_entry = next_sfe;
 
146
                junkit = 0;
 
147
                bad_sfnamelen = 0;
 
148
                XFS_DIR_SF_GET_DIRINO_ARCH(&sf_entry->inumber, &lino, ARCH_CONVERT);
 
149
 
 
150
                /*
 
151
                 * if entry points to self, junk it since only '.' or '..'
 
152
                 * should do that and shortform dirs don't contain either
 
153
                 * entry.  if inode number is invalid, trash entry.
 
154
                 * if entry points to special inodes, trash it.
 
155
                 * if inode is unknown but number is valid,
 
156
                 * add it to the list of uncertain inodes.  don't
 
157
                 * have to worry about an entry pointing to a
 
158
                 * deleted lost+found inode because the entry was
 
159
                 * deleted at the same time that the inode was cleared.
 
160
                 */
 
161
                if (lino == ino)  {
 
162
                        junkit = 1;
 
163
                } else if (verify_inum(mp, lino))  {
 
164
                        /*
 
165
                         * junk the entry, mark lino as NULL since it's bad
 
166
                         */
 
167
                        do_warn("invalid inode number %llu in directory %llu\n",
 
168
                                lino, ino);
 
169
                        lino = NULLFSINO;
 
170
                        junkit = 1;
 
171
                } else if (lino == mp->m_sb.sb_rbmino)  {
 
172
                        do_warn(
 
173
        "entry in shorform dir %llu references realtime bitmap inode %llu\n",
 
174
                                ino, lino);
 
175
                        junkit = 1;
 
176
                } else if (lino == mp->m_sb.sb_rsumino)  {
 
177
                        do_warn(
 
178
        "entry in shorform dir %llu references realtime summary inode %llu\n",
 
179
                                ino, lino);
 
180
                        junkit = 1;
 
181
                } else if (lino == mp->m_sb.sb_uquotino)  {
 
182
                        do_warn(
 
183
        "entry in shorform dir %llu references user quota inode %llu\n",
 
184
                                ino, lino);
 
185
                        junkit = 1;
 
186
                } else if (lino == mp->m_sb.sb_gquotino)  {
 
187
                        do_warn(
 
188
        "entry in shorform dir %llu references group quota inode %llu\n",
 
189
                                ino, lino);
 
190
                        junkit = 1;
 
191
                } else if ((irec_p = find_inode_rec(XFS_INO_TO_AGNO(mp, lino),
 
192
                                        XFS_INO_TO_AGINO(mp, lino))) != NULL)  {
 
193
                        /*
 
194
                         * if inode is marked free and we're in inode
 
195
                         * discovery mode, leave the entry alone for now.
 
196
                         * if the inode turns out to be used, we'll figure
 
197
                         * that out when we scan it.  If the inode really
 
198
                         * is free, we'll hit this code again in phase 4
 
199
                         * after we've finished inode discovery and blow
 
200
                         * out the entry then.
 
201
                         */
 
202
                        ino_off = XFS_INO_TO_AGINO(mp, lino) -
 
203
                                irec_p->ino_startnum;
 
204
                        ASSERT(is_inode_confirmed(irec_p, ino_off));
 
205
 
 
206
                        if (!ino_discovery && is_inode_free(irec_p, ino_off))  {
 
207
                                do_warn(
 
208
        "entry references free inode %llu in shortform directory %llu\n",
 
209
                                        lino, ino);
 
210
                                junkit = 1;
 
211
                        }
 
212
                } else if (ino_discovery) {
 
213
                        /*
 
214
                         * put the inode on the uncertain list.  we'll
 
215
                         * pull the inode off the list and check it later.
 
216
                         * if the inode turns out be bogus, we'll delete
 
217
                         * this entry in phase 6.
 
218
                         */
 
219
                        add_inode_uncertain(mp, lino, 0);
 
220
                } else  {
 
221
                        /*
 
222
                         * blow the entry out.  we know about all
 
223
                         * undiscovered entries now (past inode discovery
 
224
                         * phase) so this is clearly a bogus entry.
 
225
                         */
 
226
                        do_warn(
 
227
        "entry references non-existent inode %llu in shortform dir %llu\n",
 
228
                                        lino, ino);
 
229
                        junkit = 1;
 
230
                }
 
231
 
 
232
                namelen = sf_entry->namelen;
 
233
 
 
234
                if (namelen == 0)  {
 
235
                        /*
 
236
                         * if we're really lucky, this is
 
237
                         * the last entry in which case we
 
238
                         * can use the dir size to set the
 
239
                         * namelen value.  otherwise, forget
 
240
                         * it because we're not going to be
 
241
                         * able to find the next entry.
 
242
                         */
 
243
                        bad_sfnamelen = 1;
 
244
 
 
245
                        if (i == num_entries - 1)  {
 
246
                                namelen = ino_dir_size -
 
247
                                        ((__psint_t) &sf_entry->name[0] -
 
248
                                         (__psint_t) sf);
 
249
                                if (!no_modify)  {
 
250
                                        do_warn(
 
251
                "zero length entry in shortform dir %llu, resetting to %d\n",
 
252
                                                ino, namelen);
 
253
                                        sf_entry->namelen = namelen;
 
254
                                } else  {
 
255
                                        do_warn(
 
256
                "zero length entry in shortform dir %llu, would set to %d\n",
 
257
                                                ino, namelen);
 
258
                                }
 
259
                        } else  {
 
260
                                do_warn(
 
261
        "zero length entry in shortform dir %llu",
 
262
                                        ino);
 
263
                                if (!no_modify)
 
264
                                        do_warn(", junking %d entries\n",
 
265
                                                num_entries - i);
 
266
                                else
 
267
                                        do_warn(", would junk %d entries\n",
 
268
                                                num_entries - i);
 
269
                                /*
 
270
                                 * don't process the rest of the directory,
 
271
                                 * break out of processing looop
 
272
                                 */
 
273
                                break;
 
274
                        }
 
275
                } else if ((__psint_t) sf_entry - (__psint_t) sf +
 
276
                                + XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry)
 
277
                                > ino_dir_size)  {
 
278
                        bad_sfnamelen = 1;
 
279
 
 
280
                        if (i == num_entries - 1)  {
 
281
                                namelen = ino_dir_size -
 
282
                                        ((__psint_t) &sf_entry->name[0] -
 
283
                                         (__psint_t) sf);
 
284
                                do_warn(
 
285
        "size of last entry overflows space left in in shortform dir %llu, ",
 
286
                                        ino);
 
287
                                if (!no_modify)  {
 
288
                                        do_warn("resetting to %d\n",
 
289
                                                namelen);
 
290
                                        sf_entry->namelen = namelen;
 
291
                                        *dino_dirty = 1;
 
292
                                } else  {
 
293
                                        do_warn("would reset to %d\n",
 
294
                                                namelen);
 
295
                                }
 
296
                        } else  {
 
297
                                do_warn(
 
298
        "size of entry #%d overflows space left in in shortform dir %llu\n",
 
299
                                        i, ino);
 
300
                                if (!no_modify)  {
 
301
                                        if (i == num_entries - 1)
 
302
                                                do_warn("junking entry #%d\n",
 
303
                                                        i);
 
304
                                        else
 
305
                                                do_warn(
 
306
                                                "junking %d entries\n",
 
307
                                                        num_entries - i);
 
308
                                } else  {
 
309
                                        if (i == num_entries - 1)
 
310
                                                do_warn(
 
311
                                                "would junk entry #%d\n",
 
312
                                                        i);
 
313
                                        else
 
314
                                                do_warn(
 
315
                                                "would junk %d entries\n",
 
316
                                                        num_entries - i);
 
317
                                }
 
318
 
 
319
                                break;
 
320
                        }
 
321
                }
 
322
 
 
323
                /*
 
324
                 * check for illegal chars in name.
 
325
                 * no need to check for bad length because
 
326
                 * the length value is stored in a byte
 
327
                 * so it can't be too big, it can only wrap
 
328
                 */
 
329
                if (namecheck((char *)&sf_entry->name[0], namelen))  {
 
330
                        /*
 
331
                         * junk entry
 
332
                         */
 
333
                        do_warn(
 
334
                "entry contains illegal character in shortform dir %llu\n",
 
335
                                ino);
 
336
                        junkit = 1;
 
337
                }
 
338
 
 
339
                /*
 
340
                 * junk the entry by copying up the rest of the
 
341
                 * fork over the current entry and decrementing
 
342
                 * the entry count.  if we're in no_modify mode,
 
343
                 * just issue the warning instead.  then continue
 
344
                 * the loop with the next_sfe pointer set to the
 
345
                 * correct place in the fork and other counters
 
346
                 * properly set to reflect the deletion if it
 
347
                 * happened.
 
348
                 */
 
349
                if (junkit)  {
 
350
                        bcopy(sf_entry->name, name, namelen);
 
351
                        name[namelen] = '\0';
 
352
 
 
353
                        if (!no_modify)  {
 
354
                                tmp_elen = XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry);
 
355
                                INT_MOD(dip->di_core.di_size, ARCH_CONVERT, -(tmp_elen));
 
356
                                ino_dir_size -= tmp_elen;
 
357
 
 
358
                                tmp_sfe = (xfs_dir_sf_entry_t *)
 
359
                                        ((__psint_t) sf_entry + tmp_elen);
 
360
                                tmp_len = max_size - ((__psint_t) tmp_sfe
 
361
                                                        - (__psint_t) sf);
 
362
 
 
363
                                memmove(sf_entry, tmp_sfe, tmp_len);
 
364
 
 
365
                                INT_MOD(sf->hdr.count, ARCH_CONVERT, -1);
 
366
                                num_entries--;
 
367
                                bzero((void *) ((__psint_t) sf_entry + tmp_len),
 
368
                                        tmp_elen);
 
369
 
 
370
                                /*
 
371
                                 * reset the tmp value to the current
 
372
                                 * pointer so we'll process the entry
 
373
                                 * we just moved up
 
374
                                 */
 
375
                                tmp_sfe = sf_entry;
 
376
 
 
377
                                /*
 
378
                                 * WARNING:  drop the index i by one
 
379
                                 * so it matches the decremented count
 
380
                                 * for accurate comparisons later
 
381
                                 */
 
382
                                i--;
 
383
 
 
384
                                *dino_dirty = 1;
 
385
                                *repair = 1;
 
386
 
 
387
                                do_warn(
 
388
                        "junking entry \"%s\" in directory inode %llu\n",
 
389
                                        name, ino);
 
390
                        } else  {
 
391
                                do_warn(
 
392
                "would have junked entry \"%s\" in directory inode %llu\n",
 
393
                                        name, ino);
 
394
                        }
 
395
                }
 
396
 
 
397
                /*
 
398
                 * go onto next entry unless we've just junked an
 
399
                 * entry in which the current entry pointer points
 
400
                 * to an unprocessed entry.  have to take into zero-len
 
401
                 * entries into account in no modify mode since we
 
402
                 * calculate size based on next_sfe.
 
403
                 */
 
404
                next_sfe = (tmp_sfe == NULL)
 
405
                        ? (xfs_dir_sf_entry_t *) ((__psint_t) sf_entry
 
406
                                + ((!bad_sfnamelen)
 
407
                                        ? XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry)
 
408
                                        : sizeof(xfs_dir_sf_entry_t) - 1
 
409
                                                + namelen))
 
410
                        : tmp_sfe;
 
411
        }
 
412
 
 
413
        /* sync up sizes and entry counts */
 
414
 
 
415
        if (INT_GET(sf->hdr.count, ARCH_CONVERT) != i)  {
 
416
                if (no_modify)  {
 
417
do_warn("would have corrected entry count in directory %llu from %d to %d\n",
 
418
                        ino, INT_GET(sf->hdr.count, ARCH_CONVERT), i);
 
419
                } else  {
 
420
do_warn("corrected entry count in directory %llu, was %d, now %d\n",
 
421
                        ino, INT_GET(sf->hdr.count, ARCH_CONVERT), i);
 
422
                        INT_SET(sf->hdr.count, ARCH_CONVERT, i);
 
423
                        *dino_dirty = 1;
 
424
                        *repair = 1;
 
425
                }
 
426
        }
 
427
 
 
428
        if ((__psint_t) next_sfe - (__psint_t) sf != ino_dir_size)  {
 
429
                if (no_modify)  {
 
430
                        do_warn(
 
431
                "would have corrected directory %llu size from %lld to %lld\n",
 
432
                                ino, (__int64_t) ino_dir_size,
 
433
                        (__int64_t)((__psint_t) next_sfe - (__psint_t) sf));
 
434
                } else  {
 
435
                        do_warn(
 
436
                        "corrected directory %llu size, was %lld, now %lld\n",
 
437
                                ino, (__int64_t) ino_dir_size,
 
438
                        (__int64_t)((__psint_t) next_sfe - (__psint_t) sf));
 
439
 
 
440
                        INT_SET(dip->di_core.di_size, ARCH_CONVERT, (xfs_fsize_t)
 
441
                                        ((__psint_t) next_sfe - (__psint_t) sf));
 
442
                        *dino_dirty = 1;
 
443
                        *repair = 1;
 
444
                }
 
445
        }
 
446
        /*
 
447
         * check parent (..) entry
 
448
         */
 
449
        XFS_DIR_SF_GET_DIRINO_ARCH(&sf->hdr.parent, parent, ARCH_CONVERT);
 
450
 
 
451
        /*
 
452
         * if parent entry is bogus, null it out.  we'll fix it later .
 
453
         */
 
454
        if (verify_inum(mp, *parent))  {
 
455
                *parent = NULLFSINO;
 
456
 
 
457
                do_warn(
 
458
        "bogus .. inode number (%llu) in directory inode %llu,",
 
459
                                *parent, ino);
 
460
                if (!no_modify)  {
 
461
                        do_warn("clearing inode number\n");
 
462
 
 
463
                        XFS_DIR_SF_PUT_DIRINO_ARCH(parent, &sf->hdr.parent, ARCH_CONVERT);
 
464
                        *dino_dirty = 1;
 
465
                        *repair = 1;
 
466
                } else  {
 
467
                        do_warn("would clear inode number\n");
 
468
                }
 
469
        } else if (ino == mp->m_sb.sb_rootino && ino != *parent) {
 
470
                /*
 
471
                 * root directories must have .. == .
 
472
                 */
 
473
                if (!no_modify)  {
 
474
                        do_warn(
 
475
        "corrected root directory %llu .. entry, was %llu, now %llu\n",
 
476
                                ino, *parent, ino);
 
477
                        *parent = ino;
 
478
                        XFS_DIR_SF_PUT_DIRINO_ARCH(parent, &sf->hdr.parent, ARCH_CONVERT);
 
479
                        *dino_dirty = 1;
 
480
                        *repair = 1;
 
481
                } else  {
 
482
                        do_warn(
 
483
        "would have corrected root directory %llu .. entry from %llu to %llu\n",
 
484
                                ino, *parent, ino);
 
485
                }
 
486
        } else if (ino == *parent && ino != mp->m_sb.sb_rootino)  {
 
487
                /*
 
488
                 * likewise, non-root directories can't have .. pointing
 
489
                 * to .
 
490
                 */
 
491
                *parent = NULLFSINO;
 
492
                do_warn("bad .. entry in dir ino %llu, points to self,",
 
493
                        ino);
 
494
                if (!no_modify)  {
 
495
                        do_warn(" clearing inode number\n");
 
496
 
 
497
                        XFS_DIR_SF_PUT_DIRINO_ARCH(parent, &sf->hdr.parent, ARCH_CONVERT);
 
498
                        *dino_dirty = 1;
 
499
                        *repair = 1;
 
500
                } else  {
 
501
                        do_warn(" would clear inode number\n");
 
502
                }
 
503
        }
 
504
 
 
505
        return(0);
 
506
}
 
507
 
 
508
/*
 
509
 * freespace map for directory leaf blocks (1 bit per byte)
 
510
 * 1 == used, 0 == free
 
511
 */
 
512
static da_freemap_t dir_freemap[DA_BMAP_SIZE];
 
513
 
 
514
#if 0
 
515
unsigned char *
 
516
alloc_da_freemap(xfs_mount_t *mp)
 
517
{
 
518
        unsigned char *freemap;
 
519
 
 
520
        if ((freemap = malloc(mp->m_sb.sb_blocksize)) == NULL)
 
521
                return(NULL);
 
522
 
 
523
        bzero(freemap, mp->m_sb.sb_blocksize/NBBY);
 
524
 
 
525
        return(freemap);
 
526
}
 
527
#endif
 
528
 
 
529
void
 
530
init_da_freemap(da_freemap_t *dir_freemap)
 
531
{
 
532
        bzero(dir_freemap, sizeof(da_freemap_t) * DA_BMAP_SIZE);
 
533
}
 
534
 
 
535
/*
 
536
 * sets directory freemap, returns 1 if there is a conflict
 
537
 * returns 0 if everything's good.  the range [start, stop) is set.
 
538
 * right now, we just use the static array since only one directory
 
539
 * block will be processed at once even though the interface allows
 
540
 * you to pass in arbitrary da_freemap_t array's.
 
541
 *
 
542
 * Within a char, the lowest bit of the char represents the byte with
 
543
 * the smallest address
 
544
 */
 
545
int
 
546
set_da_freemap(xfs_mount_t *mp, da_freemap_t *map, int start, int stop)
 
547
{
 
548
        const da_freemap_t mask = 0x1;
 
549
        int i;
 
550
 
 
551
        if (start > stop)  {
 
552
                /*
 
553
                 * allow == relation since [x, x) claims 1 byte
 
554
                 */
 
555
                do_warn("bad range claimed [%d, %d) in da block\n",
 
556
                        start, stop);
 
557
                return(1);
 
558
        }
 
559
 
 
560
        if (stop > mp->m_sb.sb_blocksize)  {
 
561
                do_warn(
 
562
                "byte range end [%d %d) in da block larger than blocksize %d\n",
 
563
                        start, stop, mp->m_sb.sb_blocksize);
 
564
                return(1);
 
565
        }
 
566
 
 
567
        for (i = start; i < stop; i ++)  {
 
568
                if (map[i / NBBY] & (mask << i % NBBY))  {
 
569
                        do_warn("multiply claimed byte %d in da block\n", i);
 
570
                        return(1);
 
571
                }
 
572
                map[i / NBBY] |= (mask << i % NBBY);
 
573
        }
 
574
 
 
575
        return(0);
 
576
}
 
577
 
 
578
/*
 
579
 * returns 0 if holemap is consistent with reality (as expressed by
 
580
 * the da_freemap_t).  returns 1 if there's a conflict.
 
581
 */
 
582
int
 
583
verify_da_freemap(xfs_mount_t *mp, da_freemap_t *map, da_hole_map_t *holes,
 
584
                        xfs_ino_t ino, xfs_dablk_t da_bno)
 
585
{
 
586
        int i, j, start, len;
 
587
        const da_freemap_t mask = 0x1;
 
588
 
 
589
        for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; i++)  {
 
590
                if (holes->hentries[i].size == 0)
 
591
                        continue;
 
592
                
 
593
                start = holes->hentries[i].base;
 
594
                len = holes->hentries[i].size;
 
595
 
 
596
                if (start >= mp->m_sb.sb_blocksize ||
 
597
                                start + len > mp->m_sb.sb_blocksize)  {
 
598
                        do_warn(
 
599
        "hole (start %d, len %d) out of range, block %d, dir ino %llu\n",
 
600
                                start, len, da_bno, ino);
 
601
                        return(1);
 
602
                }
 
603
 
 
604
                for (j = start; j < start + len; j++)  {
 
605
                        if ((map[j / NBBY] & (mask << (j % NBBY))) != 0)  {
 
606
                                /*
 
607
                                 * bad news -- hole claims a used byte is free
 
608
                                 */
 
609
                                do_warn(
 
610
                "hole claims used byte %d, block %d, dir ino %llu\n",
 
611
                                        j, da_bno, ino);
 
612
                                return(1);
 
613
                        }
 
614
                }
 
615
        }
 
616
 
 
617
        return(0);
 
618
}
 
619
 
 
620
void
 
621
process_da_freemap(xfs_mount_t *mp, da_freemap_t *map, da_hole_map_t *holes)
 
622
{
 
623
        int i, j, in_hole, start, length, smallest, num_holes;
 
624
        const da_freemap_t mask = 0x1;
 
625
 
 
626
        num_holes = in_hole = start = length = 0;
 
627
 
 
628
        for (i = 0; i < mp->m_sb.sb_blocksize; i++)  {
 
629
                if ((map[i / NBBY] & (mask << (i % NBBY))) == 0)  {
 
630
                        /*
 
631
                         * byte is free (unused)
 
632
                         */
 
633
                        if (in_hole == 1)
 
634
                                continue;
 
635
                        /*
 
636
                         * start of a new hole
 
637
                         */
 
638
                        in_hole = 1;
 
639
                        start = i;
 
640
                } else  {
 
641
                        /*
 
642
                         * byte is used
 
643
                         */
 
644
                        if (in_hole == 0)
 
645
                                continue;
 
646
                        /*
 
647
                         * end of a hole
 
648
                         */
 
649
                        in_hole = 0;
 
650
                        /*
 
651
                         * if the hole disappears, throw it away
 
652
                         */
 
653
                        length = i - start;
 
654
 
 
655
                        if (length <= 0)
 
656
                                continue;
 
657
 
 
658
                        num_holes++;
 
659
 
 
660
                        for (smallest = j = 0; j < XR_DA_LEAF_MAPSIZE; j++)  {
 
661
                                if (holes->hentries[j].size <
 
662
                                                holes->hentries[smallest].size)
 
663
                                        smallest = j;
 
664
 
 
665
                        }
 
666
                        if (length > holes->hentries[smallest].size)  {
 
667
                                holes->hentries[smallest].base = start;
 
668
                                holes->hentries[smallest].size = length;
 
669
                        }
 
670
                }
 
671
        }
 
672
 
 
673
        /*
 
674
         * see if we have a big hole at the end
 
675
         */
 
676
        if (in_hole == 1)  {
 
677
                /*
 
678
                 * duplicate of hole placement code above
 
679
                 */
 
680
                length = i - start;
 
681
 
 
682
                if (length > 0)  {
 
683
                        num_holes++;
 
684
 
 
685
                        for (smallest = j = 0; j < XR_DA_LEAF_MAPSIZE; j++)  {
 
686
                                if (holes->hentries[j].size <
 
687
                                                holes->hentries[smallest].size)
 
688
                                        smallest = j;
 
689
 
 
690
                        }
 
691
                        if (length > holes->hentries[smallest].size)  {
 
692
                                holes->hentries[smallest].base = start;
 
693
                                holes->hentries[smallest].size = length;
 
694
                        }
 
695
                }
 
696
        }
 
697
 
 
698
        holes->lost_holes = MAX(num_holes - XR_DA_LEAF_MAPSIZE, 0);
 
699
        holes->num_holes = num_holes;
 
700
 
 
701
        return;
 
702
}
 
703
 
 
704
/*
 
705
 * returns 1 if the hole info doesn't match, 0 if it does
 
706
 */
 
707
/* ARGSUSED */
 
708
int
 
709
compare_da_freemaps(xfs_mount_t *mp, da_hole_map_t *holemap,
 
710
                        da_hole_map_t *block_hmap, int entries,
 
711
                        xfs_ino_t ino, xfs_dablk_t da_bno)
 
712
{
 
713
        int i, k, res, found;
 
714
 
 
715
        res = 0;
 
716
 
 
717
        /*
 
718
         * we chop holemap->lost_holes down to being two-valued
 
719
         * value (1 or 0) for the test  because the filesystem
 
720
         * value is two-valued
 
721
         */
 
722
        if ((holemap->lost_holes > 0 ? 1 : 0) != block_hmap->lost_holes)  {
 
723
                if (verbose)  {
 
724
                        do_warn(
 
725
                "- derived hole value %d, saw %d, block %d, dir ino %llu\n",
 
726
                                holemap->lost_holes, block_hmap->lost_holes,
 
727
                                da_bno, ino);
 
728
                        res = 1;
 
729
                } else
 
730
                        return(1);
 
731
        }
 
732
 
 
733
        for (i = 0; i < entries; i++)  {
 
734
                for (found = k = 0; k < entries; k++)  {
 
735
                        if (holemap->hentries[i].base ==
 
736
                                        block_hmap->hentries[k].base
 
737
                                        && holemap->hentries[i].size ==
 
738
                                        block_hmap->hentries[k].size)  
 
739
                                found = 1;
 
740
                }
 
741
                if (!found)  {
 
742
                        if (verbose)  {
 
743
                                do_warn(
 
744
"- derived hole (base %d, size %d) in block %d, dir inode %llu not found\n",
 
745
                                        holemap->hentries[i].base,
 
746
                                        holemap->hentries[i].size,
 
747
                                        da_bno, ino);
 
748
                                res = 1;
 
749
                        } else
 
750
                                return(1);
 
751
                }
 
752
        }
 
753
 
 
754
        return(res);
 
755
}
 
756
 
 
757
#if 0
 
758
void
 
759
test(xfs_mount_t *mp)
 
760
{
 
761
        int i = 0;
 
762
        da_hole_map_t   holemap;
 
763
 
 
764
        init_da_freemap(dir_freemap);
 
765
        bzero(&holemap, sizeof(da_hole_map_t));
 
766
 
 
767
        set_da_freemap(mp, dir_freemap, 0, 50);
 
768
        set_da_freemap(mp, dir_freemap, 100, 126);
 
769
        set_da_freemap(mp, dir_freemap, 126, 129);
 
770
        set_da_freemap(mp, dir_freemap, 130, 131);
 
771
        set_da_freemap(mp, dir_freemap, 150, 160);
 
772
        process_da_freemap(mp, dir_freemap, &holemap);
 
773
 
 
774
        return;
 
775
}
 
776
#endif
 
777
 
 
778
 
 
779
/*
 
780
 * walk tree from root to the left-most leaf block reading in
 
781
 * blocks and setting up cursor.  passes back file block number of the
 
782
 * left-most leaf block if successful (bno).  returns 1 if successful,
 
783
 * 0 if unsuccessful.
 
784
 */
 
785
int
 
786
traverse_int_dablock(xfs_mount_t        *mp,
 
787
                da_bt_cursor_t          *da_cursor,
 
788
                xfs_dablk_t             *rbno,
 
789
                int                     whichfork)
 
790
{
 
791
        xfs_dablk_t             bno;
 
792
        int                     i;
 
793
        xfs_da_intnode_t        *node;
 
794
        xfs_dfsbno_t            fsbno;
 
795
        xfs_buf_t               *bp;
 
796
 
 
797
        /*
 
798
         * traverse down left-side of tree until we hit the
 
799
         * left-most leaf block setting up the btree cursor along
 
800
         * the way.
 
801
         */
 
802
        bno = 0;
 
803
        i = -1;
 
804
        node = NULL;
 
805
        da_cursor->active = 0;
 
806
 
 
807
        do {
 
808
                /*
 
809
                 * read in each block along the way and set up cursor
 
810
                 */
 
811
                fsbno = blkmap_get(da_cursor->blkmap, bno);
 
812
 
 
813
                if (fsbno == NULLDFSBNO)
 
814
                        goto error_out;
 
815
 
 
816
                bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
 
817
                                XFS_FSB_TO_BB(mp, 1), 0);
 
818
                if (!bp) {
 
819
                        if (whichfork == XFS_DATA_FORK)
 
820
                                do_warn("can't read block %u (fsbno %llu) for "
 
821
                                        "directory inode %llu\n",
 
822
                                        bno, fsbno, da_cursor->ino);
 
823
                        else
 
824
                                do_warn("can't read block %u (fsbno %llu) for "
 
825
                                        "attrbute fork of inode %llu\n",
 
826
                                        bno, fsbno, da_cursor->ino);
 
827
                        goto error_out;
 
828
                }
 
829
 
 
830
                node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp);
 
831
 
 
832
                if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC)  {
 
833
                        do_warn("bad dir/attr magic number in inode %llu, file "
 
834
                                "bno = %u, fsbno = %llu\n", da_cursor->ino, bno, fsbno);
 
835
                        libxfs_putbuf(bp);
 
836
                        goto error_out;
 
837
                }
 
838
                if (INT_GET(node->hdr.count, ARCH_CONVERT) > XFS_DA_NODE_ENTRIES(mp))  {
 
839
                        do_warn("bad record count in inode %llu, count = %d, max = %d\n",
 
840
                                da_cursor->ino, INT_GET(node->hdr.count, ARCH_CONVERT),
 
841
                                XFS_DA_NODE_ENTRIES(mp));
 
842
                        libxfs_putbuf(bp);
 
843
                        goto error_out;
 
844
                }
 
845
 
 
846
                /*
 
847
                 * maintain level counter
 
848
                 */
 
849
                if (i == -1)
 
850
                        i = da_cursor->active = INT_GET(node->hdr.level, ARCH_CONVERT);
 
851
                else  {
 
852
                        if (INT_GET(node->hdr.level, ARCH_CONVERT) == i - 1)  {
 
853
                                i--;
 
854
                        } else  {
 
855
                                if (whichfork == XFS_DATA_FORK) 
 
856
                                        do_warn("bad directory btree for directory "
 
857
                                                "inode %llu\n", da_cursor->ino);
 
858
                                else
 
859
                                        do_warn("bad attribute fork btree for "
 
860
                                                "inode %llu\n", da_cursor->ino);
 
861
                                libxfs_putbuf(bp);
 
862
                                goto error_out;
 
863
                        }
 
864
                }
 
865
 
 
866
                da_cursor->level[i].hashval =
 
867
                                INT_GET(node->btree[0].hashval, ARCH_CONVERT);
 
868
                da_cursor->level[i].bp = bp;
 
869
                da_cursor->level[i].bno = bno;
 
870
                da_cursor->level[i].index = 0;
 
871
#ifdef XR_DIR_TRACE
 
872
                da_cursor->level[i].n = XFS_BUF_TO_DA_INTNODE(bp);
 
873
#endif
 
874
 
 
875
                /*
 
876
                 * set up new bno for next level down
 
877
                 */
 
878
                bno = INT_GET(node->btree[0].before, ARCH_CONVERT);
 
879
        } while(node != NULL && i > 1);
 
880
 
 
881
        /*
 
882
         * now return block number and get out
 
883
         */
 
884
        *rbno = da_cursor->level[0].bno = bno;
 
885
        return(1);
 
886
 
 
887
error_out:
 
888
        while (i > 1 && i <= da_cursor->active)  {
 
889
                libxfs_putbuf(da_cursor->level[i].bp);
 
890
                i++;
 
891
        }
 
892
 
 
893
        return(0);
 
894
}
 
895
 
 
896
/*
 
897
 * blow out buffer for this level and all the rest above as well
 
898
 * if error == 0, we are not expecting to encounter any unreleased
 
899
 * buffers (e.g. if we do, it's a mistake).  if error == 1, we're
 
900
 * in an error-handling case so unreleased buffers may exist.
 
901
 */
 
902
void
 
903
release_da_cursor_int(xfs_mount_t       *mp,
 
904
                        da_bt_cursor_t  *cursor,
 
905
                        int             prev_level,
 
906
                        int             error)
 
907
{
 
908
        int     level = prev_level + 1;
 
909
 
 
910
        if (cursor->level[level].bp != NULL)  {
 
911
                if (!error)  {
 
912
                        do_warn("release_da_cursor_int got unexpected non-null bp, "
 
913
                                "dabno = %u\n", cursor->level[level].bno);
 
914
                }
 
915
                ASSERT(error != 0);
 
916
 
 
917
                libxfs_putbuf(cursor->level[level].bp);
 
918
                cursor->level[level].bp = NULL;
 
919
        }
 
920
 
 
921
        if (level < cursor->active)
 
922
                release_da_cursor_int(mp, cursor, level, error);
 
923
 
 
924
        return;
 
925
}
 
926
 
 
927
void
 
928
release_da_cursor(xfs_mount_t   *mp,
 
929
                da_bt_cursor_t  *cursor,
 
930
                int             prev_level)
 
931
{
 
932
        release_da_cursor_int(mp, cursor, prev_level, 0);
 
933
}
 
934
 
 
935
void
 
936
err_release_da_cursor(xfs_mount_t       *mp,
 
937
                        da_bt_cursor_t  *cursor,
 
938
                        int             prev_level)
 
939
{
 
940
        release_da_cursor_int(mp, cursor, prev_level, 1);
 
941
}
 
942
 
 
943
/*
 
944
 * like traverse_int_dablock only it does far less checking
 
945
 * and doesn't maintain the cursor.  Just gets you to the
 
946
 * leftmost block in the directory.  returns the fsbno
 
947
 * of that block if successful, NULLDFSBNO if not.
 
948
 */
 
949
xfs_dfsbno_t
 
950
get_first_dblock_fsbno(xfs_mount_t      *mp,
 
951
                        xfs_ino_t       ino,
 
952
                        xfs_dinode_t    *dino)
 
953
{
 
954
        xfs_dablk_t             bno;
 
955
        int                     i;
 
956
        xfs_da_intnode_t        *node;
 
957
        xfs_dfsbno_t            fsbno;
 
958
        xfs_buf_t               *bp;
 
959
 
 
960
        /*
 
961
         * traverse down left-side of tree until we hit the
 
962
         * left-most leaf block setting up the btree cursor along
 
963
         * the way.
 
964
         */
 
965
        bno = 0;
 
966
        i = -1;
 
967
        node = NULL;
 
968
 
 
969
        fsbno = get_bmapi(mp, dino, ino, bno, XFS_DATA_FORK);
 
970
 
 
971
        if (fsbno == NULLDFSBNO)  {
 
972
                do_warn("bmap of block #%u of inode %llu failed\n",
 
973
                        bno, ino);
 
974
                return(fsbno);
 
975
        }
 
976
 
 
977
        if (INT_GET(dino->di_core.di_size, ARCH_CONVERT) <= XFS_LBSIZE(mp))
 
978
                return(fsbno);
 
979
 
 
980
        do {
 
981
                /*
 
982
                 * walk down left side of btree, release buffers as you
 
983
                 * go.  if the root block is a leaf (single-level btree),
 
984
                 * just return it.
 
985
                 * 
 
986
                 */
 
987
 
 
988
                bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
 
989
                                XFS_FSB_TO_BB(mp, 1), 0);
 
990
                if (!bp) {
 
991
                        do_warn("can't read block %u (fsbno %llu) for directory "
 
992
                                "inode %llu\n", bno, fsbno, ino);
 
993
                        return(NULLDFSBNO);
 
994
                }
 
995
 
 
996
                node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp);
 
997
 
 
998
                if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC)  {
 
999
                        do_warn("bad dir/attr magic number in inode %llu, file "
 
1000
                                "bno = %u, fsbno = %llu\n", ino, bno, fsbno);
 
1001
                        libxfs_putbuf(bp);
 
1002
                        return(NULLDFSBNO);
 
1003
                }
 
1004
 
 
1005
                if (i == -1)
 
1006
                        i = INT_GET(node->hdr.level, ARCH_CONVERT);
 
1007
                bno = INT_GET(node->btree[0].before, ARCH_CONVERT);
 
1008
 
 
1009
                libxfs_putbuf(bp);
 
1010
 
 
1011
                fsbno = get_bmapi(mp, dino, ino, bno, XFS_DATA_FORK);
 
1012
 
 
1013
                if (fsbno == NULLDFSBNO)  {
 
1014
                        do_warn("bmap of block #%u of inode %llu failed\n", bno, ino);
 
1015
                        return(NULLDFSBNO);
 
1016
                }
 
1017
 
 
1018
                i--;
 
1019
        } while(i > 0);
 
1020
 
 
1021
        return(fsbno);
 
1022
}
 
1023
 
 
1024
/*
 
1025
 * make sure that all entries in all blocks along the right side of
 
1026
 * of the tree are used and hashval's are consistent.  level is the
 
1027
 * level of the descendent block.  returns 0 if good (even if it had
 
1028
 * to be fixed up), and 1 if bad.  The right edge of the tree is
 
1029
 * technically a block boundary.  this routine should be used then
 
1030
 * instead of verify_da_path().
 
1031
 */
 
1032
int
 
1033
verify_final_da_path(xfs_mount_t        *mp,
 
1034
                da_bt_cursor_t          *cursor,
 
1035
                const int               p_level)
 
1036
{
 
1037
        xfs_da_intnode_t        *node;
 
1038
        int                     bad = 0;
 
1039
        int                     entry;
 
1040
        int                     this_level = p_level + 1;
 
1041
 
 
1042
#ifdef XR_DIR_TRACE
 
1043
        fprintf(stderr, "in verify_final_da_path, this_level = %d\n",
 
1044
                this_level);
 
1045
#endif
 
1046
        /*
 
1047
         * the index should point to the next "unprocessed" entry
 
1048
         * in the block which should be the final (rightmost) entry
 
1049
         */
 
1050
        entry = cursor->level[this_level].index;
 
1051
        node = (xfs_da_intnode_t *)XFS_BUF_PTR(cursor->level[this_level].bp);
 
1052
        /*
 
1053
         * check internal block consistency on this level -- ensure
 
1054
         * that all entries are used, encountered and expected hashvals
 
1055
         * match, etc.
 
1056
         */
 
1057
        if (entry != INT_GET(node->hdr.count, ARCH_CONVERT) - 1)  {
 
1058
                do_warn("directory/attribute block used/count inconsistency - %d/%hu\n",
 
1059
                        entry, INT_GET(node->hdr.count, ARCH_CONVERT));
 
1060
                bad++;
 
1061
        }
 
1062
        /*
 
1063
         * hash values monotonically increasing ???
 
1064
         */
 
1065
        if (cursor->level[this_level].hashval >=
 
1066
                                INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) {
 
1067
                do_warn("directory/attribute block hashvalue inconsistency, "
 
1068
                        "expected > %u / saw %u\n", cursor->level[this_level].hashval,
 
1069
                        INT_GET(node->btree[entry].hashval, ARCH_CONVERT));
 
1070
                bad++;
 
1071
        }
 
1072
        if (INT_GET(node->hdr.info.forw, ARCH_CONVERT) != 0)  {
 
1073
                do_warn("bad directory/attribute forward block pointer, expected 0, "
 
1074
                        "saw %u\n", INT_GET(node->hdr.info.forw, ARCH_CONVERT));
 
1075
                bad++;
 
1076
        }
 
1077
        if (bad) {
 
1078
                do_warn("bad directory block in dir ino %llu\n", cursor->ino);
 
1079
                return(1);
 
1080
        }
 
1081
        /*
 
1082
         * keep track of greatest block # -- that gets
 
1083
         * us the length of the directory
 
1084
         */
 
1085
        if (cursor->level[this_level].bno > cursor->greatest_bno)
 
1086
                cursor->greatest_bno = cursor->level[this_level].bno;
 
1087
 
 
1088
        /*
 
1089
         * ok, now check descendant block number against this level
 
1090
         */
 
1091
        if (cursor->level[p_level].bno !=
 
1092
                        INT_GET(node->btree[entry].before, ARCH_CONVERT))  {
 
1093
#ifdef XR_DIR_TRACE
 
1094
                fprintf(stderr, "bad directory btree pointer, child bno should be %d, "
 
1095
                        "block bno is %d, hashval is %u\n",
 
1096
                        INT_GET(node->btree[entry].before, ARCH_CONVERT),
 
1097
                        cursor->level[p_level].bno,
 
1098
                        cursor->level[p_level].hashval);
 
1099
                fprintf(stderr, "verify_final_da_path returns 1 (bad) #1a\n");
 
1100
#endif
 
1101
                return(1);
 
1102
        }
 
1103
 
 
1104
        if (cursor->level[p_level].hashval !=
 
1105
                                INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) {
 
1106
                if (!no_modify)  {
 
1107
                        do_warn("correcting bad hashval in non-leaf dir/attr block\n");
 
1108
                        do_warn("\tin (level %d) in inode %llu.\n",
 
1109
                                this_level, cursor->ino);
 
1110
                        INT_SET(node->btree[entry].hashval, ARCH_CONVERT,
 
1111
                                cursor->level[p_level].hashval);
 
1112
                        cursor->level[this_level].dirty++;
 
1113
                } else  {
 
1114
                        do_warn("would correct bad hashval in non-leaf dir/attr "
 
1115
                                "block\n\tin (level %d) in inode %llu.\n",
 
1116
                                this_level, cursor->ino);
 
1117
                }
 
1118
        }
 
1119
 
 
1120
        /*
 
1121
         * release/write buffer
 
1122
         */
 
1123
        ASSERT(cursor->level[this_level].dirty == 0 ||
 
1124
                (cursor->level[this_level].dirty && !no_modify));
 
1125
 
 
1126
        if (cursor->level[this_level].dirty && !no_modify)
 
1127
                libxfs_writebuf(cursor->level[this_level].bp, 0);
 
1128
        else
 
1129
                libxfs_putbuf(cursor->level[this_level].bp);
 
1130
 
 
1131
        cursor->level[this_level].bp = NULL;
 
1132
 
 
1133
        /*
 
1134
         * bail out if this is the root block (top of tree)
 
1135
         */
 
1136
        if (this_level >= cursor->active)  {
 
1137
#ifdef XR_DIR_TRACE
 
1138
                fprintf(stderr, "verify_final_da_path returns 0 (ok)\n");
 
1139
#endif
 
1140
                return(0);
 
1141
        }
 
1142
        /*
 
1143
         * set hashvalue to correctl reflect the now-validated
 
1144
         * last entry in this block and continue upwards validation
 
1145
         */
 
1146
        cursor->level[this_level].hashval =
 
1147
                        INT_GET(node->btree[entry].hashval, ARCH_CONVERT);
 
1148
        return(verify_final_da_path(mp, cursor, this_level));
 
1149
}
 
1150
 
 
1151
/*
 
1152
 * Verifies the path from a descendant block up to the root.
 
1153
 * Should be called when the descendant level traversal hits
 
1154
 * a block boundary before crossing the boundary (reading in a new
 
1155
 * block).
 
1156
 *
 
1157
 * the directory/attr btrees work differently to the other fs btrees.
 
1158
 * each interior block contains records that are <hashval, bno>
 
1159
 * pairs.  The bno is a file bno, not a filesystem bno.  The last
 
1160
 * hashvalue in the block <bno> will be <hashval>.  BUT unlike
 
1161
 * the freespace btrees, the *last* value in each block gets
 
1162
 * propagated up the tree instead of the first value in each block.
 
1163
 * that is, the interior records point to child blocks and the *greatest*
 
1164
 * hash value contained by the child block is the one the block above
 
1165
 * uses as the key for the child block.
 
1166
 *
 
1167
 * level is the level of the descendent block.  returns 0 if good,
 
1168
 * and 1 if bad.  The descendant block may be a leaf block.
 
1169
 *
 
1170
 * the invariant here is that the values in the cursor for the
 
1171
 * levels beneath this level (this_level) and the cursor index
 
1172
 * for this level *must* be valid.
 
1173
 *
 
1174
 * that is, the hashval/bno info is accurate for all
 
1175
 * DESCENDANTS and match what the node[index] information
 
1176
 * for the current index in the cursor for this level.
 
1177
 *
 
1178
 * the index values in the cursor for the descendant level
 
1179
 * are allowed to be off by one as they will reflect the
 
1180
 * next entry at those levels to be processed.
 
1181
 *
 
1182
 * the hashvalue for the current level can't be set until
 
1183
 * we hit the last entry in the block so, it's garbage
 
1184
 * until set by this routine.
 
1185
 *
 
1186
 * bno and bp for the current block/level are always valid
 
1187
 * since they have to be set so we can get a buffer for the
 
1188
 * block.
 
1189
 */
 
1190
int
 
1191
verify_da_path(xfs_mount_t      *mp,
 
1192
        da_bt_cursor_t          *cursor,
 
1193
        const int               p_level)
 
1194
{
 
1195
        xfs_da_intnode_t        *node;
 
1196
        xfs_da_intnode_t        *newnode;
 
1197
        xfs_dfsbno_t            fsbno;
 
1198
        xfs_dablk_t             dabno;
 
1199
        xfs_buf_t               *bp;
 
1200
        int                     bad;
 
1201
        int                     entry;
 
1202
        int                     this_level = p_level + 1;
 
1203
 
 
1204
        /*
 
1205
         * index is currently set to point to the entry that
 
1206
         * should be processed now in this level.
 
1207
         */
 
1208
        entry = cursor->level[this_level].index;
 
1209
        node = (xfs_da_intnode_t *)XFS_BUF_PTR(cursor->level[this_level].bp);
 
1210
 
 
1211
        /*
 
1212
         * if this block is out of entries, validate this
 
1213
         * block and move on to the next block.
 
1214
         * and update cursor value for said level
 
1215
         */
 
1216
        if (entry >= INT_GET(node->hdr.count, ARCH_CONVERT))  {
 
1217
                /*
 
1218
                 * update the hash value for this level before
 
1219
                 * validating it.  bno value should be ok since
 
1220
                 * it was set when the block was first read in.
 
1221
                 */
 
1222
                cursor->level[this_level].hashval = 
 
1223
                                INT_GET(node->btree[entry - 1].hashval, ARCH_CONVERT);
 
1224
 
 
1225
                /*
 
1226
                 * keep track of greatest block # -- that gets
 
1227
                 * us the length of the directory
 
1228
                 */
 
1229
                if (cursor->level[this_level].bno > cursor->greatest_bno)
 
1230
                        cursor->greatest_bno = cursor->level[this_level].bno;
 
1231
 
 
1232
                /*
 
1233
                 * validate the path for the current used-up block
 
1234
                 * before we trash it
 
1235
                 */
 
1236
                if (verify_da_path(mp, cursor, this_level))
 
1237
                        return(1);
 
1238
                /*
 
1239
                 * ok, now get the next buffer and check sibling pointers
 
1240
                 */
 
1241
                dabno = INT_GET(node->hdr.info.forw, ARCH_CONVERT);
 
1242
                ASSERT(dabno != 0);
 
1243
                fsbno = blkmap_get(cursor->blkmap, dabno);
 
1244
 
 
1245
                if (fsbno == NULLDFSBNO) {
 
1246
                        do_warn("can't get map info for block %u of directory "
 
1247
                                "inode %llu\n", dabno, cursor->ino);
 
1248
                        return(1);
 
1249
                }
 
1250
 
 
1251
                bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
 
1252
                                XFS_FSB_TO_BB(mp, 1), 0);
 
1253
                if (!bp) {
 
1254
                        do_warn("can't read block %u (%llu) for directory inode %llu\n",
 
1255
                                dabno, fsbno, cursor->ino);
 
1256
                        return(1);
 
1257
                }
 
1258
 
 
1259
                newnode = (xfs_da_intnode_t *)XFS_BUF_PTR(bp);
 
1260
                /*
 
1261
                 * verify magic number and back pointer, sanity-check
 
1262
                 * entry count, verify level
 
1263
                 */
 
1264
                bad = 0;
 
1265
                if (INT_GET(newnode->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC)  {
 
1266
                        do_warn("bad magic number %x in block %u (%llu) for directory "
 
1267
                                "inode %llu\n",
 
1268
                                INT_GET(newnode->hdr.info.magic, ARCH_CONVERT),
 
1269
                                dabno, fsbno, cursor->ino);
 
1270
                        bad++;
 
1271
                }
 
1272
                if (INT_GET(newnode->hdr.info.back, ARCH_CONVERT) !=
 
1273
                                                cursor->level[this_level].bno)  {
 
1274
                        do_warn("bad back pointer in block %u (%llu) for directory "
 
1275
                                "inode %llu\n", dabno, fsbno, cursor->ino);
 
1276
                        bad++;
 
1277
                }
 
1278
                if (INT_GET(newnode->hdr.count, ARCH_CONVERT) >
 
1279
                                                XFS_DA_NODE_ENTRIES(mp))  {
 
1280
                        do_warn("entry count %d too large in block %u (%llu) for "
 
1281
                                "directory inode %llu\n",
 
1282
                                INT_GET(newnode->hdr.count, ARCH_CONVERT),
 
1283
                                dabno, fsbno, cursor->ino);
 
1284
                        bad++;
 
1285
                }
 
1286
                if (INT_GET(newnode->hdr.level, ARCH_CONVERT) != this_level)  {
 
1287
                        do_warn("bad level %d in block %u (%llu) for directory inode "
 
1288
                                "%llu\n", INT_GET(newnode->hdr.level, ARCH_CONVERT),
 
1289
                                dabno, fsbno, cursor->ino);
 
1290
                        bad++;
 
1291
                }
 
1292
                if (bad)  {
 
1293
#ifdef XR_DIR_TRACE
 
1294
                        fprintf(stderr, "verify_da_path returns 1 (bad) #4\n");
 
1295
#endif
 
1296
                        libxfs_putbuf(bp);
 
1297
                        return(1);
 
1298
                }
 
1299
                /*
 
1300
                 * update cursor, write out the *current* level if
 
1301
                 * required.  don't write out the descendant level
 
1302
                 */
 
1303
                ASSERT(cursor->level[this_level].dirty == 0 ||
 
1304
                        (cursor->level[this_level].dirty && !no_modify));
 
1305
 
 
1306
                if (cursor->level[this_level].dirty && !no_modify)
 
1307
                        libxfs_writebuf(cursor->level[this_level].bp, 0);
 
1308
                else
 
1309
                        libxfs_putbuf(cursor->level[this_level].bp);
 
1310
                cursor->level[this_level].bp = bp;
 
1311
                cursor->level[this_level].dirty = 0;
 
1312
                cursor->level[this_level].bno = dabno;
 
1313
                cursor->level[this_level].hashval =
 
1314
                        INT_GET(newnode->btree[0].hashval, ARCH_CONVERT);
 
1315
#ifdef XR_DIR_TRACE
 
1316
                cursor->level[this_level].n = newnode;
 
1317
#endif
 
1318
                node = newnode;
 
1319
 
 
1320
                entry = cursor->level[this_level].index = 0;
 
1321
        }
 
1322
        /*
 
1323
         * ditto for block numbers
 
1324
         */
 
1325
        if (cursor->level[p_level].bno !=
 
1326
                        INT_GET(node->btree[entry].before, ARCH_CONVERT))  {
 
1327
#ifdef XR_DIR_TRACE
 
1328
                fprintf(stderr, "bad directory btree pointer, child bno should be %d, "
 
1329
                        "block bno is %d, hashval is %u\n",
 
1330
                        INT_GET(node->btree[entry].before, ARCH_CONVERT),
 
1331
                        cursor->level[p_level].bno,
 
1332
                        cursor->level[p_level].hashval);
 
1333
                fprintf(stderr, "verify_da_path returns 1 (bad) #1a\n");
 
1334
#endif
 
1335
                return(1);
 
1336
        }
 
1337
        /*
 
1338
         * ok, now validate last hashvalue in the descendant
 
1339
         * block against the hashval in the current entry
 
1340
         */
 
1341
        if (cursor->level[p_level].hashval !=
 
1342
                        INT_GET(node->btree[entry].hashval, ARCH_CONVERT))  {
 
1343
                if (!no_modify)  {
 
1344
                        do_warn("correcting bad hashval in interior dir/attr block\n");
 
1345
                        do_warn("\tin (level %d) in inode %llu.\n",
 
1346
                                this_level, cursor->ino);
 
1347
                        INT_SET(node->btree[entry].hashval, ARCH_CONVERT,
 
1348
                                cursor->level[p_level].hashval);
 
1349
                        cursor->level[this_level].dirty++;
 
1350
                } else  {
 
1351
                        do_warn("would correct bad hashval in interior dir/attr "
 
1352
                                "block\n\tin (level %d) in inode %llu.\n",
 
1353
                                this_level, cursor->ino);
 
1354
                }
 
1355
        }
 
1356
        /*
 
1357
         * increment index for this level to point to next entry
 
1358
         * (which should point to the next descendant block)
 
1359
         */
 
1360
        cursor->level[this_level].index++;
 
1361
#ifdef XR_DIR_TRACE
 
1362
        fprintf(stderr, "verify_da_path returns 0 (ok)\n");
 
1363
#endif
 
1364
        return(0);
 
1365
}
 
1366
 
 
1367
#if 0
 
1368
/*
 
1369
 * handles junking directory leaf block entries that have zero lengths
 
1370
 * buf_dirty is an in/out, set to 1 if the leaf was modified.
 
1371
 * we do NOT initialize it to zero if nothing happened because it
 
1372
 * may be already set by the caller.  Assumes that the block
 
1373
 * has been compacted before calling this routine.
 
1374
 */
 
1375
void
 
1376
junk_zerolen_dir_leaf_entries(
 
1377
        xfs_mount_t             *mp,
 
1378
        xfs_dir_leafblock_t     *leaf,
 
1379
        xfs_ino_t               ino,
 
1380
        int                     *buf_dirty)
 
1381
{
 
1382
        xfs_dir_leaf_entry_t    *entry;
 
1383
        xfs_dir_leaf_name_t     *namest;
 
1384
        xfs_dir_leaf_hdr_t      *hdr;
 
1385
        xfs_dir_leaf_map_t      *map;
 
1386
        xfs_ino_t               tmp_ino;
 
1387
        int                     bytes;
 
1388
        int                     tmp_bytes;
 
1389
        int                     current_hole = 0;
 
1390
        int                     i;
 
1391
        int                     j;
 
1392
        int                     tmp;
 
1393
        int                     start;
 
1394
        int                     before;
 
1395
        int                     after;
 
1396
        int                     smallest;
 
1397
        int                     tablesize;
 
1398
 
 
1399
        entry = &leaf->entries[0];
 
1400
        hdr = &leaf->hdr;
 
1401
 
 
1402
        /*
 
1403
         * we can convert the entries to one character entries
 
1404
         * as long as we have space.  Once we run out, then
 
1405
         * we have to delete really delete (copy over) an entry.
 
1406
         * however, that frees up some space that we could use ...
 
1407
         *
 
1408
         * so the idea is, we'll use up space from all the holes,
 
1409
         * potentially leaving each hole too small to do any good.
 
1410
         * then if need to, we'll delete entries and use that space
 
1411
         * up from the top-most byte down.  that may leave a 4th hole
 
1412
         * but we can represent that by correctly setting the value
 
1413
         * of firstused.  that leaves any hole between the end of
 
1414
         * the entry list and firstused so it doesn't have to be
 
1415
         * recorded in the hole map.
 
1416
         */
 
1417
 
 
1418
        for (bytes = i = 0; i < INT_GET(hdr->count, ARCH_CONVERT); entry++, i++) {
 
1419
                /*
 
1420
                 * skip over entries that are good or already converted
 
1421
                 */
 
1422
                if (entry->namelen != 0)
 
1423
                        continue;
 
1424
 
 
1425
                *buf_dirty = 1;
 
1426
#if 0
 
1427
                /*
 
1428
                 * try and use up existing holes first until they get
 
1429
                 * too small, then set bytes to the # of bytes between
 
1430
                 * the current heap beginning and the last used byte
 
1431
                 * in the entry table.
 
1432
                 */
 
1433
                if (bytes < sizeof(xfs_dir_leaf_name_t) &&
 
1434
                                current_hole < XFS_DIR_LEAF_MAPSIZE)  {
 
1435
                        /*
 
1436
                         * skip over holes that are too small
 
1437
                         */
 
1438
                        while (current_hole < XFS_DIR_LEAF_MAPSIZE &&
 
1439
                                INT_GET(hdr->freemap[current_hole].size, ARCH_CONVERT) <
 
1440
                                        sizeof(xfs_dir_leaf_name_t))  {
 
1441
                                current_hole++;
 
1442
                        }
 
1443
 
 
1444
                        if (current_hole < XFS_DIR_LEAF_MAPSIZE)
 
1445
                                bytes = INT_GET(hdr->freemap[current_hole].size, ARCH_CONVERT);
 
1446
                        else
 
1447
                                bytes = (int) INT_GET(hdr->firstused, ARCH_CONVERT) -
 
1448
                                 ((__psint_t) &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)] -
 
1449
                                  (__psint_t) leaf);
 
1450
                }
 
1451
#endif
 
1452
                current_hole = 0;
 
1453
 
 
1454
                for (map = &hdr->freemap[0];
 
1455
                                current_hole < XFS_DIR_LEAF_MAPSIZE &&
 
1456
                                        INT_GET(map->size, ARCH_CONVERT) < sizeof(xfs_dir_leaf_name_t);
 
1457
                                map++)  {
 
1458
                        current_hole++;
 
1459
                }
 
1460
 
 
1461
                /*
 
1462
                 * if we can use an existing hole, do it.  otherwise,
 
1463
                 * delete entries until the deletions create a big enough
 
1464
                 * hole to convert another entry.  then use up those bytes
 
1465
                 * bytes until you run low.  then delete entries again ...
 
1466
                 */
 
1467
                if (current_hole < XFS_DIR_LEAF_MAPSIZE)  {
 
1468
                        ASSERT(sizeof(xfs_dir_leaf_name_t) <= bytes);
 
1469
 
 
1470
                        do_warn("marking bad entry in directory inode %llu\n",
 
1471
                                ino);
 
1472
 
 
1473
                        entry->namelen = 1;
 
1474
                        INT_SET(entry->nameidx, ARCH_CONVERT, INT_GET(hdr->freemap[current_hole].base, ARCH_CONVERT) +
 
1475
                                        bytes - sizeof(xfs_dir_leaf_name_t));
 
1476
 
 
1477
                        namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
 
1478
                        tmp_ino = NULLFSINO;
 
1479
                        XFS_DIR_SF_PUT_DIRINO_ARCH(&tmp_ino, &namest->inumber, ARCH_CONVERT);
 
1480
                        namest->name[0] = '/';
 
1481
 
 
1482
                        if (INT_GET(entry->nameidx, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT))
 
1483
                                INT_SET(hdr->firstused, ARCH_CONVERT, INT_GET(entry->nameidx, ARCH_CONVERT));
 
1484
                        INT_MOD(hdr->freemap[current_hole].size, ARCH_CONVERT, -(sizeof(xfs_dir_leaf_name_t)));
 
1485
                        INT_MOD(hdr->namebytes, ARCH_CONVERT, +1);
 
1486
                } else  {
 
1487
                        /*
 
1488
                         * delete the table entry and try and account for the
 
1489
                         * space in the holemap.  don't have to update namebytes
 
1490
                         * or firstused since we're not actually deleting any
 
1491
                         * bytes from the heap.  following code swiped from
 
1492
                         * xfs_dir_leaf_remove() in xfs_dir_leaf.c
 
1493
                         */
 
1494
                        INT_MOD(hdr->count, ARCH_CONVERT, -1);
 
1495
                        do_warn(
 
1496
                        "deleting zero length entry in directory inode %llu\n",
 
1497
                                ino);
 
1498
                        /*
 
1499
                         * overwrite the bad entry unless it's the
 
1500
                         * last entry in the list (highly unlikely).
 
1501
                         * zero out the free'd bytes.
 
1502
                         */
 
1503
                        if (INT_GET(hdr->count, ARCH_CONVERT) - i > 0)  {
 
1504
                                memmove(entry, entry + 1, (INT_GET(hdr->count, ARCH_CONVERT) - i) *
 
1505
                                        sizeof(xfs_dir_leaf_entry_t));
 
1506
                        }
 
1507
                        bzero((void *) ((__psint_t) entry +
 
1508
                                (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i - 1) *
 
1509
                                sizeof(xfs_dir_leaf_entry_t)),
 
1510
                                sizeof(xfs_dir_leaf_entry_t));
 
1511
 
 
1512
                        start = (__psint_t) &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)] -
 
1513
                                (__psint_t) &leaf;
 
1514
                        tablesize = sizeof(xfs_dir_leaf_entry_t) *
 
1515
                                (INT_GET(hdr->count, ARCH_CONVERT) + 1) + sizeof(xfs_dir_leaf_hdr_t);
 
1516
                        map = &hdr->freemap[0];
 
1517
                        tmp = INT_GET(map->size, ARCH_CONVERT);
 
1518
                        before = after = -1;
 
1519
                        smallest = XFS_DIR_LEAF_MAPSIZE - 1;
 
1520
                        for (j = 0; j < XFS_DIR_LEAF_MAPSIZE; map++, j++) {
 
1521
                                ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp));
 
1522
                                ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp));
 
1523
                                if (INT_GET(map->base, ARCH_CONVERT) == tablesize) {
 
1524
                                        INT_MOD(map->base, ARCH_CONVERT, -(sizeof(xfs_dir_leaf_entry_t)));
 
1525
                                        INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t));
 
1526
                                }
 
1527
 
 
1528
                                if ((INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT)) == start) {
 
1529
                                        before = j;
 
1530
                                } else if (INT_GET(map->base, ARCH_CONVERT) == start +
 
1531
                                                sizeof(xfs_dir_leaf_entry_t))  {
 
1532
                                        after = j;
 
1533
                                } else if (INT_GET(map->size, ARCH_CONVERT) < tmp) {
 
1534
                                        tmp = INT_GET(map->size, ARCH_CONVERT);
 
1535
                                        smallest = j;
 
1536
                                }
 
1537
                        }
 
1538
 
 
1539
                        /*
 
1540
                         * Coalesce adjacent freemap regions,
 
1541
                         * or replace the smallest region.
 
1542
                         */
 
1543
                        if ((before >= 0) || (after >= 0)) {
 
1544
                                if ((before >= 0) && (after >= 0))  {
 
1545
                                        map = &hdr->freemap[before];
 
1546
                                        INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t));
 
1547
                                        INT_MOD(map->size, ARCH_CONVERT, INT_GET(hdr->freemap[after].size, ARCH_CONVERT));
 
1548
                                        INT_ZERO(hdr->freemap[after].base, ARCH_CONVERT);
 
1549
                                        INT_ZERO(hdr->freemap[after].size, ARCH_CONVERT);
 
1550
                                } else if (before >= 0) {
 
1551
                                        map = &hdr->freemap[before];
 
1552
                                        INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t));
 
1553
                                } else {
 
1554
                                        map = &hdr->freemap[after];
 
1555
                                        INT_SET(map->base, ARCH_CONVERT, start);
 
1556
                                        INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t));
 
1557
                                }
 
1558
                        } else  {
 
1559
                                /*
 
1560
                                 * Replace smallest region
 
1561
                                 * (if it is smaller than free'd entry)
 
1562
                                 */
 
1563
                                map = &hdr->freemap[smallest];
 
1564
                                if (INT_GET(map->size, ARCH_CONVERT) < sizeof(xfs_dir_leaf_entry_t))  {
 
1565
                                        INT_SET(map->base, ARCH_CONVERT, start);
 
1566
                                        INT_SET(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t));
 
1567
                                }
 
1568
                                /*
 
1569
                                 * mark as needing compaction
 
1570
                                 */
 
1571
                                hdr->holes = 1;
 
1572
                        }
 
1573
#if 0
 
1574
                        /*
 
1575
                         * do we have to delete stuff or is there
 
1576
                         * room for deletions?
 
1577
                         */
 
1578
                        ASSERT(current_hole == XFS_DIR_LEAF_MAPSIZE);
 
1579
 
 
1580
                        /*
 
1581
                         * here, bytes == number of unused bytes from
 
1582
                         * end of list to top (beginning) of heap
 
1583
                         * (firstused).  It's ok to leave extra
 
1584
                         * unused bytes in that region because they
 
1585
                         * wind up before firstused (which we reset
 
1586
                         * appropriately
 
1587
                         */
 
1588
                        if (bytes < sizeof(xfs_dir_leaf_name_t))  {
 
1589
                                /*
 
1590
                                 * have to delete an entry because
 
1591
                                 * we have no room to convert it to
 
1592
                                 * a bad entry
 
1593
                                 */
 
1594
                                do_warn(
 
1595
                                "deleting entry in directory inode %llu\n",
 
1596
                                        ino);
 
1597
                                /*
 
1598
                                 * overwrite the bad entry unless it's the
 
1599
                                 * last entry in the list (highly unlikely).
 
1600
                                 */
 
1601
                                if (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i - 1> 0)  {
 
1602
                                        memmove(entry, entry + 1,
 
1603
                                                (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i - 1) *
 
1604
                                                sizeof(xfs_dir_leaf_entry_t));
 
1605
                                }
 
1606
                                bzero((void *) ((__psint_t) entry +
 
1607
                                        (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i - 1) *
 
1608
                                        sizeof(xfs_dir_leaf_entry_t)),
 
1609
                                        sizeof(xfs_dir_leaf_entry_t));
 
1610
 
 
1611
                                /*
 
1612
                                 * bump up free byte count, drop other
 
1613
                                 * index vars since the table just
 
1614
                                 * shrank by one entry and we don't
 
1615
                                 * want to miss any as we walk the table
 
1616
                                 */
 
1617
                                bytes += sizeof(xfs_dir_leaf_entry_t);
 
1618
                                INT_MOD(leaf->hdr.count, ARCH_CONVERT, -1);
 
1619
                                entry--;
 
1620
                                i--;
 
1621
                        } else  {
 
1622
                                /*
 
1623
                                 * convert entry using the bytes in between
 
1624
                                 * the end of the entry table and the heap
 
1625
                                 */
 
1626
                                entry->namelen = 1;
 
1627
                                INT_MOD(leaf->hdr.firstused, ARCH_CONVERT, -(sizeof(xfs_dir_leaf_name_t)));
 
1628
                                INT_SET(entry->nameidx, ARCH_CONVERT, INT_GET(leaf->hdr.firstused, ARCH_CONVERT));
 
1629
 
 
1630
                                namest = XFS_DIR_LEAF_NAMESTRUCT(leaf,
 
1631
                                                        INT_GET(entry->nameidx, ARCH_CONVERT));
 
1632
                                tmp_ino = NULLFSINO;
 
1633
                                XFS_DIR_SF_PUT_DIRINO_ARCH(&tmp_ino,
 
1634
                                                        &namest->inumber, ARCH_CONVERT);
 
1635
                                namest->name[0] = '/';
 
1636
 
 
1637
                                bytes -= sizeof(xfs_dir_leaf_entry_t);
 
1638
                        }
 
1639
#endif
 
1640
                }
 
1641
        }
 
1642
 
 
1643
        return;
 
1644
}
 
1645
#endif
 
1646
 
 
1647
static char dirbuf[64 * 1024];
 
1648
 
 
1649
/*
 
1650
 * called by both node dir and leaf dir processing routines
 
1651
 * validates all contents *but* the sibling pointers (forw/back)
 
1652
 * and the magic number.
 
1653
 *
 
1654
 * returns 0 if the directory is ok or has been brought to the
 
1655
 * stage that it can be fixed up later (in phase 6),
 
1656
 * 1 if it has to be junked.
 
1657
 *
 
1658
 * Right now we fix a lot of things (TBD == to be deleted).
 
1659
 *
 
1660
 *      incorrect . entries - inode # is corrected
 
1661
 *      entries with mismatched hashvalue/name strings - hashvalue reset
 
1662
 *      entries whose hashvalues are out-of-order - entry marked TBD
 
1663
 *      .. entries with invalid inode numbers - entry marked TBD
 
1664
 *      entries with invalid inode numbers - entry marked TBD
 
1665
 *      multiple . entries - all but the first entry are marked TBD
 
1666
 *      zero-length entries - entry is deleted
 
1667
 *      entries with an out-of-bounds name index ptr - entry is deleted
 
1668
 *
 
1669
 * entries marked TBD have the first character of the name (which
 
1670
 *      lives in the heap) have the first character in the name set
 
1671
 *      to '/' -- an illegal value.
 
1672
 *
 
1673
 * entries deleted right here are deleted by blowing away the entry
 
1674
 *      (but leaving the heap untouched).  any space that was used
 
1675
 *      by the deleted entry will be reclaimed by the block freespace
 
1676
 *      (da_freemap) processing code.
 
1677
 *
 
1678
 * if two entries claim the same space in the heap (say, due to
 
1679
 * bad entry name index pointers), we lose the directory.  We could
 
1680
 * try harder to fix this but it'll do for now.
 
1681
 */
 
1682
/* ARGSUSED */
 
1683
int
 
1684
process_leaf_dir_block(
 
1685
        xfs_mount_t             *mp,
 
1686
        xfs_dir_leafblock_t     *leaf,
 
1687
        xfs_dablk_t             da_bno,
 
1688
        xfs_ino_t               ino, 
 
1689
        xfs_dahash_t            last_hashval,   /* last hashval encountered */
 
1690
        int                     ino_discovery,
 
1691
        blkmap_t                *blkmap,
 
1692
        int                     *dot,
 
1693
        int                     *dotdot,
 
1694
        xfs_ino_t               *parent,
 
1695
        int                     *buf_dirty,     /* is buffer dirty? */
 
1696
        xfs_dahash_t            *next_hashval)  /* greatest hashval in block */
 
1697
{
 
1698
        xfs_ino_t                       lino;
 
1699
        xfs_dir_leaf_entry_t            *entry;
 
1700
        xfs_dir_leaf_entry_t            *s_entry;
 
1701
        xfs_dir_leaf_entry_t            *d_entry;
 
1702
        xfs_dir_leafblock_t             *new_leaf;
 
1703
        char                            *first_byte;
 
1704
        xfs_dir_leaf_name_t             *namest;
 
1705
        ino_tree_node_t                 *irec_p;
 
1706
        int                             num_entries;
 
1707
        xfs_dahash_t                    hashval;
 
1708
        int                             i;
 
1709
        int                             nm_illegal;
 
1710
        int                             bytes;
 
1711
        int                             start;
 
1712
        int                             stop;
 
1713
        int                             res = 0;
 
1714
        int                             ino_off;
 
1715
        int                             first_used;
 
1716
        int                             bytes_used;
 
1717
        int                             reset_holes;
 
1718
        int                             zero_len_entries;
 
1719
        char                            fname[MAXNAMELEN + 1];
 
1720
        da_hole_map_t                   holemap;
 
1721
        da_hole_map_t                   bholemap;
 
1722
#if 0
 
1723
        unsigned char                   *dir_freemap;
 
1724
#endif
 
1725
 
 
1726
#ifdef XR_DIR_TRACE
 
1727
        fprintf(stderr, "\tprocess_leaf_dir_block - ino %llu\n", ino);
 
1728
#endif
 
1729
 
 
1730
        /*
 
1731
         * clear static dir block freespace bitmap
 
1732
         */
 
1733
        init_da_freemap(dir_freemap);
 
1734
 
 
1735
#if 0
 
1736
        /*
 
1737
         * XXX - alternatively, do this for parallel usage.
 
1738
         * set up block freespace map.  head part of dir leaf block
 
1739
         * including all entries are packed so we can use sizeof
 
1740
         * and not worry about alignment.
 
1741
         */
 
1742
 
 
1743
        if ((dir_freemap = alloc_da_freemap(mp)) == NULL)  {
 
1744
                do_error("couldn't allocate directory block freemap\n");
 
1745
                abort();
 
1746
        }
 
1747
#endif
 
1748
 
 
1749
        *buf_dirty = 0;
 
1750
        first_used = mp->m_sb.sb_blocksize;
 
1751
        zero_len_entries = 0;
 
1752
        bytes_used = 0;
 
1753
 
 
1754
        i = stop = sizeof(xfs_dir_leaf_hdr_t);
 
1755
        if (set_da_freemap(mp, dir_freemap, 0, stop))  {
 
1756
                do_warn(
 
1757
"directory block header conflicts with used space in directory inode %llu\n",
 
1758
                                ino);
 
1759
                return(1);
 
1760
        }
 
1761
 
 
1762
        /*
 
1763
         * verify structure:  monotonically increasing hash value for
 
1764
         * all leaf entries, indexes for all entries must be within
 
1765
         * this fs block (trivially true for 64K blocks).  also track
 
1766
         * used space so we can check the freespace map.  check for
 
1767
         * zero-length entries.  for now, if anything's wrong, we
 
1768
         * junk the directory and we'll pick up no-longer referenced
 
1769
         * inodes on a later pass.
 
1770
         */
 
1771
        for (i = 0, entry = &leaf->entries[0];
 
1772
                        i < INT_GET(leaf->hdr.count, ARCH_CONVERT);
 
1773
                        i++, entry++)  {
 
1774
                /*
 
1775
                 * check that the name index isn't out of bounds
 
1776
                 * if it is, delete the entry since we can't
 
1777
                 * grab the inode #.
 
1778
                 */
 
1779
                if (INT_GET(entry->nameidx, ARCH_CONVERT) >= mp->m_sb.sb_blocksize)  {
 
1780
                        if (!no_modify)  {
 
1781
                                *buf_dirty = 1;
 
1782
 
 
1783
                                if (INT_GET(leaf->hdr.count, ARCH_CONVERT) > 1)  {
 
1784
                                        do_warn(
 
1785
"nameidx %d for entry #%d, bno %d, ino %llu > fs blocksize, deleting entry\n",
 
1786
                                                INT_GET(entry->nameidx, ARCH_CONVERT), i, da_bno, ino);
 
1787
                                        ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) > i);
 
1788
 
 
1789
                                        bytes = (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i) *
 
1790
                                                sizeof(xfs_dir_leaf_entry_t);
 
1791
 
 
1792
                                        /*
 
1793
                                         * compress table unless we're
 
1794
                                         * only dealing with 1 entry
 
1795
                                         * (the last one) in which case
 
1796
                                         * just zero it.
 
1797
                                         */
 
1798
                                        if (bytes >
 
1799
                                            sizeof(xfs_dir_leaf_entry_t))  {
 
1800
                                                memmove(entry, entry + 1,
 
1801
                                                        bytes);
 
1802
                                                bzero((void *)
 
1803
                                                ((__psint_t) entry + bytes),
 
1804
                                                sizeof(xfs_dir_leaf_entry_t));
 
1805
                                        } else  {
 
1806
                                                bzero(entry,
 
1807
                                                sizeof(xfs_dir_leaf_entry_t));
 
1808
                                        }
 
1809
 
 
1810
                                        /*
 
1811
                                         * sync vars to match smaller table.
 
1812
                                         * don't have to worry about freespace
 
1813
                                         * map since we haven't set it for
 
1814
                                         * this entry yet.
 
1815
                                         */
 
1816
                                        INT_MOD(leaf->hdr.count, ARCH_CONVERT, -1);
 
1817
                                        i--;
 
1818
                                        entry--;
 
1819
                                } else  {
 
1820
                                        do_warn(
 
1821
"nameidx %d, entry #%d, bno %d, ino %llu > fs blocksize, marking entry bad\n",
 
1822
                                                INT_GET(entry->nameidx, ARCH_CONVERT), i, da_bno, ino);
 
1823
                                        INT_SET(entry->nameidx, ARCH_CONVERT, mp->m_sb.sb_blocksize -
 
1824
                                                sizeof(xfs_dir_leaf_name_t));
 
1825
                                        namest = XFS_DIR_LEAF_NAMESTRUCT(leaf,
 
1826
                                                        INT_GET(entry->nameidx, ARCH_CONVERT));
 
1827
                                        lino = NULLFSINO;
 
1828
                                        XFS_DIR_SF_PUT_DIRINO_ARCH(&lino,
 
1829
                                                        &namest->inumber, ARCH_CONVERT);
 
1830
                                        namest->name[0] = '/';
 
1831
                                }
 
1832
                        } else  {
 
1833
                                do_warn(
 
1834
"nameidx %d, entry #%d, bno %d, ino %llu > fs blocksize, would delete entry\n",
 
1835
                                        INT_GET(entry->nameidx, ARCH_CONVERT), i, da_bno, ino);
 
1836
                        }
 
1837
                        continue;
 
1838
                }
 
1839
                /*
 
1840
                 * inode processing -- make sure the inode
 
1841
                 * is in our tree or we add it to the uncertain
 
1842
                 * list if the inode # is valid.  if namelen is 0,
 
1843
                 * we can still try for the inode as long as nameidx
 
1844
                 * is ok.
 
1845
                 */
 
1846
                namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
 
1847
                XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &lino, ARCH_CONVERT);
 
1848
 
 
1849
                /*
 
1850
                 * we may have to blow out an entry because of bad
 
1851
                 * inode numbers.  do NOT touch the name until after
 
1852
                 * we've computed the hashvalue and done a namecheck()
 
1853
                 * on the name.
 
1854
                 */
 
1855
                if (!ino_discovery && lino == NULLFSINO)  {
 
1856
                        /*
 
1857
                         * don't do a damned thing.  We already
 
1858
                         * found this (or did it ourselves) during
 
1859
                         * phase 3.
 
1860
                         */
 
1861
                } else if (verify_inum(mp, lino))  {
 
1862
                        /*
 
1863
                         * bad inode number.  clear the inode
 
1864
                         * number and the entry will get removed
 
1865
                         * later.  We don't trash the directory
 
1866
                         * since it's still structurally intact.
 
1867
                         */
 
1868
                        do_warn(
 
1869
"invalid ino number %llu in dir ino %llu, entry #%d, bno %d\n",
 
1870
                                lino, ino, i, da_bno);
 
1871
                        if (!no_modify)  {
 
1872
                                do_warn(
 
1873
                                "\tclearing ino number in entry %d...\n", i);
 
1874
 
 
1875
                                lino = NULLFSINO;
 
1876
                                XFS_DIR_SF_PUT_DIRINO_ARCH(&lino, &namest->inumber, ARCH_CONVERT);
 
1877
                                *buf_dirty = 1;
 
1878
                        } else  {
 
1879
                                do_warn(
 
1880
                                "\twould clear ino number in entry %d...\n", i);
 
1881
                        }
 
1882
                } else if (lino == mp->m_sb.sb_rbmino)  {
 
1883
                        do_warn(
 
1884
"entry #%d, bno %d in directory %llu references realtime bitmap inode %llu\n",
 
1885
                                i, da_bno, ino, lino);
 
1886
                        if (!no_modify)  {
 
1887
                                do_warn(
 
1888
                                "\tclearing ino number in entry %d...\n", i);
 
1889
 
 
1890
                                lino = NULLFSINO;
 
1891
                                XFS_DIR_SF_PUT_DIRINO_ARCH(&lino, &namest->inumber, ARCH_CONVERT);
 
1892
                                *buf_dirty = 1;
 
1893
                        } else  {
 
1894
                                do_warn(
 
1895
                                "\twould clear ino number in entry %d...\n", i);
 
1896
                        }
 
1897
                } else if (lino == mp->m_sb.sb_rsumino)  {
 
1898
                        do_warn(
 
1899
"entry #%d, bno %d in directory %llu references realtime summary inode %llu\n",
 
1900
                                i, da_bno, ino, lino);
 
1901
                        if (!no_modify)  {
 
1902
                                do_warn(
 
1903
                                "\tclearing ino number in entry %d...\n", i);
 
1904
 
 
1905
                                lino = NULLFSINO;
 
1906
                                XFS_DIR_SF_PUT_DIRINO_ARCH(&lino, &namest->inumber, ARCH_CONVERT);
 
1907
                                *buf_dirty = 1;
 
1908
                        } else  {
 
1909
                                do_warn(
 
1910
                                "\twould clear ino number in entry %d...\n", i);
 
1911
                        }
 
1912
                } else if (lino == mp->m_sb.sb_uquotino)  {
 
1913
                        do_warn(
 
1914
"entry #%d, bno %d in directory %llu references user quota inode %llu\n",
 
1915
                                i, da_bno, ino, lino);
 
1916
                        if (!no_modify)  {
 
1917
                                do_warn(
 
1918
                                "\tclearing ino number in entry %d...\n", i);
 
1919
 
 
1920
                                lino = NULLFSINO;
 
1921
                                XFS_DIR_SF_PUT_DIRINO_ARCH(&lino, &namest->inumber, ARCH_CONVERT);
 
1922
                                *buf_dirty = 1;
 
1923
                        } else  {
 
1924
                                do_warn(
 
1925
                                "\twould clear ino number in entry %d...\n", i);
 
1926
                        }
 
1927
                } else if (lino == mp->m_sb.sb_gquotino)  {
 
1928
                        do_warn(
 
1929
"entry #%d, bno %d in directory %llu references group quota inode %llu\n",
 
1930
                                i, da_bno, ino, lino);
 
1931
                        if (!no_modify)  {
 
1932
                                do_warn(
 
1933
                                "\tclearing ino number in entry %d...\n", i);
 
1934
 
 
1935
                                lino = NULLFSINO;
 
1936
                                XFS_DIR_SF_PUT_DIRINO_ARCH(&lino, &namest->inumber, ARCH_CONVERT);
 
1937
                                *buf_dirty = 1;
 
1938
                        } else  {
 
1939
                                do_warn(
 
1940
                                "\twould clear ino number in entry %d...\n", i);
 
1941
                        }
 
1942
                } else if (lino == old_orphanage_ino)  {
 
1943
                        /*
 
1944
                         * do nothing, silently ignore it, entry has
 
1945
                         * already been marked TBD since old_orphanage_ino
 
1946
                         * is set non-zero.
 
1947
                         */
 
1948
                } else if ((irec_p = find_inode_rec(
 
1949
                                XFS_INO_TO_AGNO(mp, lino),
 
1950
                                XFS_INO_TO_AGINO(mp, lino))) != NULL)  {
 
1951
                        /*
 
1952
                         * inode recs should have only confirmed
 
1953
                         * inodes in them
 
1954
                         */
 
1955
                        ino_off = XFS_INO_TO_AGINO(mp, lino) -
 
1956
                                        irec_p->ino_startnum;
 
1957
                        ASSERT(is_inode_confirmed(irec_p, ino_off));
 
1958
                        /*
 
1959
                         * if inode is marked free and we're in inode
 
1960
                         * discovery mode, leave the entry alone for now.
 
1961
                         * if the inode turns out to be used, we'll figure
 
1962
                         * that out when we scan it.  If the inode really
 
1963
                         * is free, we'll hit this code again in phase 4
 
1964
                         * after we've finished inode discovery and blow
 
1965
                         * out the entry then.
 
1966
                         */
 
1967
                        if (!ino_discovery && is_inode_free(irec_p, ino_off))  {
 
1968
                                if (!no_modify)  {
 
1969
                                        do_warn(
 
1970
"entry references free inode %llu in directory %llu, will clear entry\n",
 
1971
                                                lino, ino);
 
1972
                                        lino = NULLFSINO;
 
1973
                                        XFS_DIR_SF_PUT_DIRINO_ARCH(&lino,
 
1974
                                                        &namest->inumber, ARCH_CONVERT);
 
1975
                                        *buf_dirty = 1;
 
1976
                                } else  {
 
1977
                                        do_warn(
 
1978
"entry references free inode %llu in directory %llu, would clear entry\n",
 
1979
                                                lino, ino);
 
1980
                                }
 
1981
                        }
 
1982
                } else if (ino_discovery)  {
 
1983
                        add_inode_uncertain(mp, lino, 0);
 
1984
                } else  {
 
1985
                        do_warn(
 
1986
        "bad ino number %llu in dir ino %llu, entry #%d, bno %d\n",
 
1987
                                lino, ino, i, da_bno);
 
1988
                        if (!no_modify)  {
 
1989
                                do_warn("clearing inode number...\n");
 
1990
                                lino = NULLFSINO;
 
1991
                                XFS_DIR_SF_PUT_DIRINO_ARCH(&lino, &namest->inumber, ARCH_CONVERT);
 
1992
                                *buf_dirty = 1;
 
1993
                        } else  {
 
1994
                                do_warn("would clear inode number...\n");
 
1995
                        }
 
1996
                }
 
1997
                /*
 
1998
                 * if we have a zero-length entry, trash it.
 
1999
                 * we may lose the inode (chunk) if we don't
 
2000
                 * finish the repair successfully and the inode
 
2001
                 * isn't mentioned anywhere else (like in the inode
 
2002
                 * tree) but the alternative is to risk losing the
 
2003
                 * entire directory by trying to use the next byte
 
2004
                 * to turn the entry into a 1-char entry.  That's
 
2005
                 * probably a safe bet but if it didn't work, we'd
 
2006
                 * lose the entire directory the way we currently do
 
2007
                 * things.  (Maybe we should change that later :-).
 
2008
                 */
 
2009
                if (entry->namelen == 0)  {
 
2010
                        *buf_dirty = 1;
 
2011
 
 
2012
                        if (INT_GET(leaf->hdr.count, ARCH_CONVERT) > 1)  {
 
2013
                                do_warn(
 
2014
        "entry #%d, dir inode %llu, has zero-len name, deleting entry\n",
 
2015
                                        i, ino);
 
2016
                                ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) > i);
 
2017
 
 
2018
                                bytes = (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i) *
 
2019
                                        sizeof(xfs_dir_leaf_entry_t);
 
2020
 
 
2021
                                /*
 
2022
                                 * compress table unless we're
 
2023
                                 * only dealing with 1 entry
 
2024
                                 * (the last one) in which case
 
2025
                                 * just zero it.
 
2026
                                 */
 
2027
                                if (bytes > sizeof(xfs_dir_leaf_entry_t))  {
 
2028
                                        memmove(entry, entry + 1,
 
2029
                                                bytes);
 
2030
                                        bzero((void *)
 
2031
                                                ((__psint_t) entry + bytes),
 
2032
                                                sizeof(xfs_dir_leaf_entry_t));
 
2033
                                } else  {
 
2034
                                        bzero(entry,
 
2035
                                                sizeof(xfs_dir_leaf_entry_t));
 
2036
                                }
 
2037
 
 
2038
                                /*
 
2039
                                 * sync vars to match smaller table.
 
2040
                                 * don't have to worry about freespace
 
2041
                                 * map since we haven't set it for
 
2042
                                 * this entry yet.
 
2043
                                 */
 
2044
                                INT_MOD(leaf->hdr.count, ARCH_CONVERT, -1);
 
2045
                                i--;
 
2046
                                entry--;
 
2047
                        } else  {
 
2048
                                /*
 
2049
                                 * if it's the only entry, preserve the
 
2050
                                 * inode number for now
 
2051
                                 */
 
2052
                                do_warn(
 
2053
        "entry #%d, dir inode %llu, has zero-len name, marking entry bad\n",
 
2054
                                        i, ino);
 
2055
                                INT_SET(entry->nameidx, ARCH_CONVERT, mp->m_sb.sb_blocksize -
 
2056
                                                sizeof(xfs_dir_leaf_name_t));
 
2057
                                namest = XFS_DIR_LEAF_NAMESTRUCT(leaf,
 
2058
                                                INT_GET(entry->nameidx, ARCH_CONVERT));
 
2059
                                XFS_DIR_SF_PUT_DIRINO_ARCH(&lino, &namest->inumber, ARCH_CONVERT);
 
2060
                                namest->name[0] = '/';
 
2061
                        }
 
2062
                } else if (INT_GET(entry->nameidx, ARCH_CONVERT) + entry->namelen > XFS_LBSIZE(mp))  {
 
2063
                        do_warn(
 
2064
"bad size, entry #%d in dir inode %llu, block %u -- entry overflows block\n",
 
2065
                        i, ino, da_bno);
 
2066
 
 
2067
                        return(1);
 
2068
                }
 
2069
 
 
2070
                start = (__psint_t)&leaf->entries[i] - (__psint_t)leaf;;
 
2071
                stop = start + sizeof(xfs_dir_leaf_entry_t);
 
2072
 
 
2073
                if (set_da_freemap(mp, dir_freemap, start, stop))  {
 
2074
                        do_warn(
 
2075
"dir entry slot %d in block %u conflicts with used space in dir inode %llu\n",
 
2076
                                i, da_bno, ino);
 
2077
                        return(1);
 
2078
                }
 
2079
 
 
2080
                /*
 
2081
                 * check if the name is legal.  if so, then
 
2082
                 * check that the name and hashvalues match.
 
2083
                 *
 
2084
                 * if the name is illegal, we don't check the
 
2085
                 * hashvalue computed from it.  we just make
 
2086
                 * sure that the hashvalue in the entry is
 
2087
                 * monotonically increasing wrt to the previous
 
2088
                 * entry.
 
2089
                 *
 
2090
                 * Note that we do NOT have to check the length
 
2091
                 * because the length is stored in a one-byte
 
2092
                 * unsigned int which max's out at MAXNAMELEN
 
2093
                 * making it impossible for the stored length
 
2094
                 * value to be out of range.
 
2095
                 */
 
2096
                bcopy(namest->name, fname, entry->namelen);
 
2097
                fname[entry->namelen] = '\0';
 
2098
                hashval = libxfs_da_hashname(fname, entry->namelen);
 
2099
 
 
2100
                /*
 
2101
                 * only complain about illegal names in phase 3 (when
 
2102
                 * inode discovery is turned on).  Otherwise, we'd complain
 
2103
                 * a lot during phase 4.  If the name is illegal, leave
 
2104
                 * the hash value in that entry alone.
 
2105
                 */
 
2106
                nm_illegal = namecheck(fname, entry->namelen);
 
2107
 
 
2108
                if (ino_discovery && nm_illegal)  {
 
2109
                        /*
 
2110
                         * junk the entry, illegal name
 
2111
                         */
 
2112
                        if (!no_modify)  {
 
2113
                                do_warn(
 
2114
        "illegal name \"%s\" in directory inode %llu, entry will be cleared\n",
 
2115
                                        fname, ino);
 
2116
                                namest->name[0] = '/';
 
2117
                                *buf_dirty = 1;
 
2118
                        } else  {
 
2119
                                do_warn(
 
2120
        "illegal name \"%s\" in directory inode %llu, entry would be cleared\n",
 
2121
                                        fname, ino);
 
2122
                        }
 
2123
                } else if (!nm_illegal && INT_GET(entry->hashval, ARCH_CONVERT) != hashval)  {
 
2124
                        /*
 
2125
                         * try resetting the hashvalue to the correct
 
2126
                         * value for the string, if the string has been
 
2127
                         * corrupted, too, that will get picked up next
 
2128
                         */
 
2129
                        do_warn("\tmismatched hash value for entry \"%s\"\n",
 
2130
                                fname);
 
2131
                        if (!no_modify)  {
 
2132
                                do_warn(
 
2133
                        "\t\tin directory inode %llu.  resetting hash value.\n",
 
2134
                                        ino);
 
2135
                                INT_SET(entry->hashval, ARCH_CONVERT, hashval);
 
2136
                                *buf_dirty = 1;
 
2137
                        } else  {
 
2138
                                do_warn(
 
2139
                "\t\tin directory inode %llu.  would reset hash value.\n",
 
2140
                                        ino);
 
2141
                        }
 
2142
                }
 
2143
                
 
2144
                /*
 
2145
                 * now we can mark entries with NULLFSINO's bad
 
2146
                 */
 
2147
                if (!no_modify && lino == NULLFSINO)  {
 
2148
                        namest->name[0] = '/';
 
2149
                        *buf_dirty = 1;
 
2150
                }
 
2151
 
 
2152
                /*
 
2153
                 * regardless of whether the entry has or hasn't been
 
2154
                 * marked for deletion, the hash value ordering must
 
2155
                 * be maintained.
 
2156
                 */
 
2157
                if (INT_GET(entry->hashval, ARCH_CONVERT) < last_hashval)  {
 
2158
                        /*
 
2159
                         * blow out the entry -- set hashval to sane value
 
2160
                         * and set the first character in the string to
 
2161
                         * the illegal value '/'.  Reset the hash value
 
2162
                         * to the last hashvalue so that verify_da_path
 
2163
                         * will fix up the interior pointers correctly.
 
2164
                         * the entry will be deleted later (by routines
 
2165
                         * that need only the entry #).  We keep the
 
2166
                         * inode number in the entry so we can attach
 
2167
                         * the inode to the orphanage later.
 
2168
                         */
 
2169
                        do_warn("\tbad hash ordering for entry \"%s\"\n",
 
2170
                                fname);
 
2171
                        if (!no_modify)  {
 
2172
                                do_warn(
 
2173
                "\t\tin directory inode %llu.  will clear entry\n",
 
2174
                                        ino);
 
2175
                                INT_SET(entry->hashval, ARCH_CONVERT, last_hashval);
 
2176
                                namest->name[0] = '/';
 
2177
                                *buf_dirty = 1;
 
2178
                        } else  {
 
2179
                                do_warn(
 
2180
                "\t\tin directory inode %llu.  would clear entry\n",
 
2181
                                        ino);
 
2182
                        }
 
2183
                }
 
2184
 
 
2185
                *next_hashval = last_hashval = INT_GET(entry->hashval, ARCH_CONVERT);
 
2186
 
 
2187
                /*
 
2188
                 * if heap data conflicts with something,
 
2189
                 * blow it out and skip the rest of the loop
 
2190
                 */
 
2191
                if (set_da_freemap(mp, dir_freemap, INT_GET(entry->nameidx, ARCH_CONVERT),
 
2192
                                INT_GET(entry->nameidx, ARCH_CONVERT) + sizeof(xfs_dir_leaf_name_t) +
 
2193
                                entry->namelen - 1))  {
 
2194
                        do_warn(
 
2195
"name \"%s\" (block %u, slot %d) conflicts with used space in dir inode %llu\n",
 
2196
                                fname, da_bno, i, ino);
 
2197
                        if (!no_modify)  {
 
2198
                                entry->namelen = 0;
 
2199
                                *buf_dirty = 1;
 
2200
 
 
2201
                                do_warn(
 
2202
                "will clear entry \"%s\" (#%d) in directory inode %llu\n",
 
2203
                                        fname, i, ino);
 
2204
                        } else  {
 
2205
                                do_warn(
 
2206
                "would clear entry \"%s\" (#%d)in directory inode %llu\n",
 
2207
                                        fname, i, ino);
 
2208
                        }
 
2209
                        continue;
 
2210
                }
 
2211
 
 
2212
                /*
 
2213
                 * keep track of heap stats (first byte used, total bytes used)
 
2214
                 */
 
2215
                if (INT_GET(entry->nameidx, ARCH_CONVERT) < first_used)
 
2216
                        first_used = INT_GET(entry->nameidx, ARCH_CONVERT);
 
2217
                bytes_used += entry->namelen;
 
2218
 
 
2219
                /*
 
2220
                 * special . or .. entry processing
 
2221
                 */
 
2222
                if (entry->namelen == 2 && namest->name[0] == '.' &&
 
2223
                                                namest->name[1] == '.') {
 
2224
                        /*
 
2225
                         * the '..' case
 
2226
                         */
 
2227
                        if (!*dotdot) {
 
2228
                                (*dotdot)++;
 
2229
                                *parent = lino;
 
2230
#ifdef XR_DIR_TRACE
 
2231
        fprintf(stderr, "process_leaf_dir_block found .. entry (parent) = %llu\n", lino);
 
2232
#endif
 
2233
                                /*
 
2234
                                 * what if .. == .?  legal only in
 
2235
                                 * the root inode.  blow out entry
 
2236
                                 * and set parent to NULLFSINO otherwise.
 
2237
                                 */
 
2238
                                if (ino == lino &&
 
2239
                                                ino != mp->m_sb.sb_rootino)  {
 
2240
                                        *parent = NULLFSINO;
 
2241
                                        do_warn(
 
2242
        "bad .. entry in dir ino %llu, points to self",
 
2243
                                                ino);
 
2244
                                        if (!no_modify)  {
 
2245
                                                do_warn("will clear entry\n");
 
2246
 
 
2247
                                                namest->name[0] = '/';
 
2248
                                                *buf_dirty = 1;
 
2249
                                        } else  {
 
2250
                                                do_warn("would clear entry\n");
 
2251
                                        }
 
2252
                                } else if (ino != lino &&
 
2253
                                                ino == mp->m_sb.sb_rootino)  {
 
2254
                                        /*
 
2255
                                         * we have to make sure that . == ..
 
2256
                                         * in the root inode
 
2257
                                         */
 
2258
                                        if (!no_modify)  {
 
2259
                                                do_warn(
 
2260
                "correcting .. entry in root inode %llu, was %llu\n",
 
2261
                                                        ino, *parent);
 
2262
                                                XFS_DIR_SF_PUT_DIRINO_ARCH(
 
2263
                                                        &ino,
 
2264
                                                &namest->inumber, ARCH_CONVERT);
 
2265
                                                *buf_dirty = 1;
 
2266
                                        } else  {
 
2267
                                                do_warn(
 
2268
        "bad .. entry (%llu) in root inode %llu should be %llu\n",
 
2269
                                                        *parent,
 
2270
                                                        ino, ino);
 
2271
                                        }
 
2272
                                }
 
2273
                        } else  {
 
2274
                                /*
 
2275
                                 * can't fix the directory unless we know
 
2276
                                 * which .. entry is the right one.  Both
 
2277
                                 * have valid inode numbers, match the hash
 
2278
                                 * value and the hash values are ordered
 
2279
                                 * properly or we wouldn't be here.  So
 
2280
                                 * since both seem equally valid, trash
 
2281
                                 * this one.
 
2282
                                 */
 
2283
                                if (!no_modify)  {
 
2284
                                        do_warn(
 
2285
"multiple .. entries in directory inode %llu, will clear second entry\n",
 
2286
                                                ino);
 
2287
                                        namest->name[0] = '/';
 
2288
                                        *buf_dirty = 1;
 
2289
                                } else  {
 
2290
                                        do_warn(
 
2291
"multiple .. entries in directory inode %llu, would clear second entry\n",
 
2292
                                                ino);
 
2293
                                }
 
2294
                        }
 
2295
                } else if (entry->namelen == 1 && namest->name[0] == '.')  {
 
2296
                        /*
 
2297
                         * the '.' case
 
2298
                         */
 
2299
                        if (!*dot)  {
 
2300
                                (*dot)++;
 
2301
                                if (lino != ino)  {
 
2302
                                        if (!no_modify)  {
 
2303
                                                do_warn(
 
2304
        ". in directory inode %llu has wrong value (%llu), fixing entry...\n",
 
2305
                                                        ino, lino);
 
2306
                                                XFS_DIR_SF_PUT_DIRINO_ARCH(&ino,
 
2307
                                                        &namest->inumber, ARCH_CONVERT);
 
2308
                                                *buf_dirty = 1;
 
2309
                                        } else  {
 
2310
                                                do_warn(
 
2311
                        ". in directory inode %llu has wrong value (%llu)\n",
 
2312
                                                        ino, lino);
 
2313
                                        }
 
2314
                                }
 
2315
                        } else  {
 
2316
                                do_warn(
 
2317
                                "multiple . entries in directory inode %llu\n",
 
2318
                                        ino);
 
2319
                                /*
 
2320
                                 * mark entry as to be junked.
 
2321
                                 */
 
2322
                                if (!no_modify)  {
 
2323
                                        do_warn(
 
2324
                        "will clear one . entry in directory inode %llu\n",
 
2325
                                                ino);
 
2326
                                        namest->name[0] = '/';
 
2327
                                        *buf_dirty = 1;
 
2328
                                } else  {
 
2329
                                        do_warn(
 
2330
                        "would clear one . entry in directory inode %llu\n",
 
2331
                                                ino);
 
2332
                                }
 
2333
                        }
 
2334
                } else  {
 
2335
                        /*
 
2336
                         * all the rest -- make sure only . references self
 
2337
                         */
 
2338
                        if (lino == ino)  {
 
2339
                                do_warn(
 
2340
                        "entry \"%s\" in directory inode %llu points to self, ",
 
2341
                                        fname, ino);
 
2342
                                if (!no_modify)  {
 
2343
                                        do_warn("will clear entry\n");
 
2344
                                        namest->name[0] = '/';
 
2345
                                        *buf_dirty = 1;
 
2346
                                } else  {
 
2347
                                        do_warn("would clear entry\n");
 
2348
                                }
 
2349
                        }
 
2350
                }
 
2351
        }
 
2352
 
 
2353
        /*
 
2354
         * compare top of heap values and reset as required.  if the
 
2355
         * holes flag is set, don't reset first_used unless it's
 
2356
         * pointing to used bytes.  we're being conservative here
 
2357
         * since the block will get compacted anyhow by the kernel.
 
2358
         */
 
2359
        if ((leaf->hdr.holes == 0 && first_used != INT_GET(leaf->hdr.firstused, ARCH_CONVERT)) ||
 
2360
                        INT_GET(leaf->hdr.firstused, ARCH_CONVERT) > first_used)  {
 
2361
                if (!no_modify)  {
 
2362
                        if (verbose)
 
2363
                                do_warn(
 
2364
"- resetting first used heap value from %d to %d in block %u of dir ino %llu\n",
 
2365
                                        (int) INT_GET(leaf->hdr.firstused, ARCH_CONVERT), first_used,
 
2366
                                        da_bno, ino);
 
2367
                        INT_SET(leaf->hdr.firstused, ARCH_CONVERT, first_used);
 
2368
                        *buf_dirty = 1;
 
2369
                } else  {
 
2370
                        if (verbose)
 
2371
                                do_warn(
 
2372
"- would reset first used value from %d to %d in block %u of dir ino %llu\n",
 
2373
                                        (int) INT_GET(leaf->hdr.firstused, ARCH_CONVERT), first_used,
 
2374
                                        da_bno, ino);
 
2375
                }
 
2376
        }
 
2377
 
 
2378
        if (bytes_used != INT_GET(leaf->hdr.namebytes, ARCH_CONVERT))  {
 
2379
                if (!no_modify)  {
 
2380
                        if (verbose)
 
2381
                                do_warn(
 
2382
"- resetting namebytes cnt from %d to %d in block %u of dir inode %llu\n",
 
2383
                                        (int) INT_GET(leaf->hdr.namebytes, ARCH_CONVERT), bytes_used,
 
2384
                                        da_bno, ino);
 
2385
                        INT_SET(leaf->hdr.namebytes, ARCH_CONVERT, bytes_used);
 
2386
                        *buf_dirty = 1;
 
2387
                } else  {
 
2388
                        if (verbose)
 
2389
                                do_warn(
 
2390
"- would reset namebytes cnt from %d to %d in block %u of dir inode %llu\n",
 
2391
                                        (int) INT_GET(leaf->hdr.namebytes, ARCH_CONVERT), bytes_used,
 
2392
                                        da_bno, ino);
 
2393
                }
 
2394
        }
 
2395
 
 
2396
        /*
 
2397
         * If the hole flag is not set, then we know that there can
 
2398
         * be no lost holes.  If the hole flag is set, then it's ok
 
2399
         * if the on-disk holemap doesn't describe everything as long
 
2400
         * as what it does describe doesn't conflict with reality.
 
2401
         */
 
2402
 
 
2403
        reset_holes = 0;
 
2404
 
 
2405
        bholemap.lost_holes = leaf->hdr.holes;
 
2406
        for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; i++)  {
 
2407
                bholemap.hentries[i].base = INT_GET(leaf->hdr.freemap[i].base, ARCH_CONVERT);
 
2408
                bholemap.hentries[i].size = INT_GET(leaf->hdr.freemap[i].size, ARCH_CONVERT);
 
2409
        }
 
2410
 
 
2411
        /*
 
2412
         * Ok, now set up our own freespace list
 
2413
         * (XFS_DIR_LEAF_MAPSIZE (3) * biggest regions)
 
2414
         * and see if they match what's in the block
 
2415
         */
 
2416
        bzero(&holemap, sizeof(da_hole_map_t));
 
2417
        process_da_freemap(mp, dir_freemap, &holemap);
 
2418
 
 
2419
        if (zero_len_entries)  {
 
2420
                reset_holes = 1;
 
2421
        } else if (leaf->hdr.holes == 0)  {
 
2422
                if (holemap.lost_holes > 0)  {
 
2423
                        if (verbose)
 
2424
                                do_warn(
 
2425
        "- found unexpected lost holes in block %u, dir inode %llu\n",
 
2426
                                        da_bno, ino);
 
2427
 
 
2428
                        reset_holes = 1;
 
2429
                } else if (compare_da_freemaps(mp, &holemap, &bholemap,
 
2430
                                XFS_DIR_LEAF_MAPSIZE, ino, da_bno))  {
 
2431
                        if (verbose)
 
2432
                                do_warn(
 
2433
                        "- hole info non-optimal in block %u, dir inode %llu\n",
 
2434
                                        da_bno, ino);
 
2435
                        reset_holes = 1;
 
2436
                }
 
2437
        } else if (verify_da_freemap(mp, dir_freemap, &holemap, ino, da_bno))  {
 
2438
                if (verbose)
 
2439
                        do_warn(
 
2440
                        "- hole info incorrect in block %u, dir inode %llu\n",
 
2441
                                da_bno, ino);
 
2442
                reset_holes = 1;
 
2443
        }
 
2444
 
 
2445
        if (reset_holes)  {
 
2446
                /*
 
2447
                 * have to reset block hole info
 
2448
                 */
 
2449
                if (verbose)  {
 
2450
                        do_warn(
 
2451
        "- existing hole info for block %d, dir inode %llu (base, size) - \n",
 
2452
                                da_bno, ino);
 
2453
                        do_warn("- \t");
 
2454
                        for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; i++)  {
 
2455
                                do_warn(
 
2456
                                "- (%d, %d) ", bholemap.hentries[i].base,
 
2457
                                        bholemap.hentries[i].size);  
 
2458
                        }
 
2459
                        do_warn("- holes flag = %d\n", bholemap.lost_holes);
 
2460
                }
 
2461
 
 
2462
                if (!no_modify)  {
 
2463
                        if (verbose)
 
2464
                                do_warn(
 
2465
                "- compacting block %u in dir inode %llu\n",
 
2466
                                        da_bno, ino);
 
2467
 
 
2468
                        new_leaf = (xfs_dir_leafblock_t *) &dirbuf[0];
 
2469
 
 
2470
                        /*
 
2471
                         * copy leaf block header
 
2472
                         */
 
2473
                        bcopy(&leaf->hdr, &new_leaf->hdr,
 
2474
                                sizeof(xfs_dir_leaf_hdr_t));
 
2475
 
 
2476
                        /*
 
2477
                         * reset count in case we have some zero length entries
 
2478
                         * that are being junked
 
2479
                         */
 
2480
                        num_entries = 0;
 
2481
                        first_used = XFS_LBSIZE(mp);
 
2482
                        first_byte = (char *) new_leaf
 
2483
                                        + (__psint_t) XFS_LBSIZE(mp);
 
2484
 
 
2485
                        /*
 
2486
                         * copy entry table and pack names starting from the end
 
2487
                         * of the block
 
2488
                         */
 
2489
                        for (i = 0, s_entry = &leaf->entries[0],
 
2490
                                        d_entry = &new_leaf->entries[0];
 
2491
                                        i < INT_GET(leaf->hdr.count, ARCH_CONVERT);
 
2492
                                        i++, s_entry++)  {
 
2493
                                /*
 
2494
                                 * skip zero-length entries
 
2495
                                 */
 
2496
                                if (s_entry->namelen == 0)
 
2497
                                        continue;
 
2498
 
 
2499
                                bytes = sizeof(xfs_dir_leaf_name_t)
 
2500
                                        + s_entry->namelen - 1;
 
2501
 
 
2502
                                if ((__psint_t) first_byte - bytes <
 
2503
                                                sizeof(xfs_dir_leaf_entry_t)
 
2504
                                                + (__psint_t) d_entry)  {
 
2505
                                        do_warn(
 
2506
        "not enough space in block %u of dir inode %llu for all entries\n",
 
2507
                                                da_bno, ino);
 
2508
                                        break;
 
2509
                                }
 
2510
 
 
2511
                                first_used -= bytes;
 
2512
                                first_byte -= bytes;
 
2513
 
 
2514
                                INT_SET(d_entry->nameidx, ARCH_CONVERT, first_used);
 
2515
                                INT_SET(d_entry->hashval, ARCH_CONVERT, INT_GET(s_entry->hashval, ARCH_CONVERT));
 
2516
                                d_entry->namelen = s_entry->namelen;
 
2517
                                d_entry->pad2 = 0;
 
2518
 
 
2519
                                bcopy((char *) leaf + INT_GET(s_entry->nameidx, ARCH_CONVERT),
 
2520
                                        first_byte, bytes);
 
2521
 
 
2522
                                num_entries++;
 
2523
                                d_entry++;
 
2524
                        }
 
2525
 
 
2526
                        ASSERT((char *) first_byte >= (char *) d_entry);
 
2527
                        ASSERT(first_used <= XFS_LBSIZE(mp));
 
2528
 
 
2529
                        /*
 
2530
                         * zero space between end of table and top of heap
 
2531
                         */
 
2532
                        bzero(d_entry, (__psint_t) first_byte
 
2533
                                        - (__psint_t) d_entry);
 
2534
 
 
2535
                        /*
 
2536
                         * reset header info
 
2537
                         */
 
2538
                        if (num_entries != INT_GET(new_leaf->hdr.count, ARCH_CONVERT))
 
2539
                                INT_SET(new_leaf->hdr.count, ARCH_CONVERT, num_entries);
 
2540
 
 
2541
                        INT_SET(new_leaf->hdr.firstused, ARCH_CONVERT, first_used);
 
2542
                        new_leaf->hdr.holes = 0;
 
2543
                        new_leaf->hdr.pad1 = 0;
 
2544
 
 
2545
                        INT_SET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT, (__psint_t) d_entry
 
2546
                                                        - (__psint_t) new_leaf);
 
2547
                        INT_SET(new_leaf->hdr.freemap[0].size, ARCH_CONVERT, (__psint_t) first_byte
 
2548
                                                        - (__psint_t) d_entry);
 
2549
 
 
2550
                        ASSERT(INT_GET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT) < first_used);
 
2551
                        ASSERT(INT_GET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT) ==
 
2552
                                        (__psint_t) (&new_leaf->entries[0])
 
2553
                                        - (__psint_t) new_leaf
 
2554
                                        + i * sizeof(xfs_dir_leaf_entry_t));
 
2555
                        ASSERT(INT_GET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT) < XFS_LBSIZE(mp));
 
2556
                        ASSERT(INT_GET(new_leaf->hdr.freemap[0].size, ARCH_CONVERT) < XFS_LBSIZE(mp));
 
2557
                        ASSERT(INT_GET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT) +
 
2558
                                INT_GET(new_leaf->hdr.freemap[0].size, ARCH_CONVERT) == first_used);
 
2559
 
 
2560
                        INT_ZERO(new_leaf->hdr.freemap[1].base, ARCH_CONVERT);
 
2561
                        INT_ZERO(new_leaf->hdr.freemap[1].size, ARCH_CONVERT);
 
2562
                        INT_ZERO(new_leaf->hdr.freemap[2].base, ARCH_CONVERT);
 
2563
                        INT_ZERO(new_leaf->hdr.freemap[2].size, ARCH_CONVERT);
 
2564
 
 
2565
                        /*
 
2566
                         * final step, copy block back
 
2567
                         */
 
2568
                        bcopy(new_leaf, leaf, mp->m_sb.sb_blocksize);
 
2569
 
 
2570
                        *buf_dirty = 1;
 
2571
                } else  {
 
2572
                        if (verbose)
 
2573
                                do_warn(
 
2574
                        "- would compact block %u in dir inode %llu\n",
 
2575
                                        da_bno, ino);
 
2576
                }
 
2577
        }
 
2578
#if 0
 
2579
        if (!no_modify)  {
 
2580
                /*
 
2581
                 * now take care of deleting or marking the entries with
 
2582
                 * zero-length namelen's
 
2583
                 */
 
2584
                junk_zerolen_dir_leaf_entries(mp, leaf, ino, buf_dirty);
 
2585
        }
 
2586
#endif
 
2587
#ifdef XR_DIR_TRACE
 
2588
        fprintf(stderr, "process_leaf_dir_block returns %d\n", res);
 
2589
#endif
 
2590
        return((res > 0) ? 1 : 0);
 
2591
}
 
2592
 
 
2593
/*
 
2594
 * returns 0 if the directory is ok, 1 if it has to be junked.
 
2595
 */
 
2596
int
 
2597
process_leaf_dir_level(xfs_mount_t      *mp,
 
2598
                        da_bt_cursor_t  *da_cursor,
 
2599
                        int             ino_discovery,
 
2600
                        int             *repair,
 
2601
                        int             *dot,
 
2602
                        int             *dotdot,
 
2603
                        xfs_ino_t       *parent)
 
2604
{
 
2605
        xfs_dir_leafblock_t     *leaf;
 
2606
        xfs_buf_t               *bp;
 
2607
        xfs_ino_t               ino;
 
2608
        xfs_dfsbno_t            dev_bno;
 
2609
        xfs_dablk_t             da_bno;
 
2610
        xfs_dablk_t             prev_bno;
 
2611
        int                     res = 0;
 
2612
        int                     buf_dirty = 0;
 
2613
        xfs_daddr_t             bd_addr;
 
2614
        xfs_dahash_t            current_hashval = 0;
 
2615
        xfs_dahash_t            greatest_hashval;
 
2616
 
 
2617
#ifdef XR_DIR_TRACE
 
2618
        fprintf(stderr, "process_leaf_dir_level - ino %llu\n", da_cursor->ino);
 
2619
#endif
 
2620
        *repair = 0;
 
2621
        da_bno = da_cursor->level[0].bno;
 
2622
        ino = da_cursor->ino;
 
2623
        prev_bno = 0;
 
2624
 
 
2625
        do {
 
2626
                dev_bno = blkmap_get(da_cursor->blkmap, da_bno);
 
2627
                /*
 
2628
                 * directory code uses 0 as the NULL block pointer
 
2629
                 * since 0 is the root block and no directory block
 
2630
                 * pointer can point to the root block of the btree
 
2631
                 */
 
2632
                ASSERT(da_bno != 0);
 
2633
 
 
2634
                if (dev_bno == NULLDFSBNO) {
 
2635
                        do_warn("can't map block %u for directory inode %llu\n",
 
2636
                                da_bno, ino);
 
2637
                        goto error_out;
 
2638
                }
 
2639
 
 
2640
                bd_addr = (xfs_daddr_t)XFS_FSB_TO_DADDR(mp, dev_bno);
 
2641
 
 
2642
                bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dev_bno),
 
2643
                                        XFS_FSB_TO_BB(mp, 1), 0);
 
2644
                if (!bp) {
 
2645
                        do_warn("can't read file block %u (fsbno %llu, daddr %lld) "
 
2646
                                "for directory inode %llu\n",
 
2647
                                da_bno, dev_bno, (__int64_t) bd_addr, ino);
 
2648
                        goto error_out;
 
2649
                }
 
2650
 
 
2651
                leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp);
 
2652
 
 
2653
                /*
 
2654
                 * check magic number for leaf directory btree block
 
2655
                 */
 
2656
                if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) {
 
2657
                        do_warn("bad directory leaf magic # %#x for dir ino %llu\n",
 
2658
                                INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), ino);
 
2659
                        libxfs_putbuf(bp);
 
2660
                        goto error_out;
 
2661
                }
 
2662
                /*
 
2663
                 * keep track of greatest block # -- that gets
 
2664
                 * us the length of the directory
 
2665
                 */
 
2666
                if (da_bno > da_cursor->greatest_bno)
 
2667
                        da_cursor->greatest_bno = da_bno;
 
2668
 
 
2669
                buf_dirty = 0;
 
2670
                /*
 
2671
                 * for each block, process the block, verify it's path,
 
2672
                 * then get next block.  update cursor values along the way
 
2673
                 */
 
2674
                if (process_leaf_dir_block(mp, leaf, da_bno, ino,
 
2675
                                current_hashval, ino_discovery,
 
2676
                                da_cursor->blkmap, dot, dotdot, parent,
 
2677
                                &buf_dirty, &greatest_hashval))  {
 
2678
                        libxfs_putbuf(bp);
 
2679
                        goto error_out;
 
2680
                }
 
2681
 
 
2682
                /*
 
2683
                 * index can be set to hdr.count so match the
 
2684
                 * indexes of the interior blocks -- which at the
 
2685
                 * end of the block will point to 1 after the final
 
2686
                 * real entry in the block
 
2687
                 */
 
2688
                da_cursor->level[0].hashval = greatest_hashval;
 
2689
                da_cursor->level[0].bp = bp;
 
2690
                da_cursor->level[0].bno = da_bno;
 
2691
                da_cursor->level[0].index = INT_GET(leaf->hdr.count, ARCH_CONVERT);
 
2692
                da_cursor->level[0].dirty = buf_dirty;
 
2693
 
 
2694
                if (INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != prev_bno)  {
 
2695
                        do_warn("bad sibling back pointer for directory block %u "
 
2696
                                "in directory inode %llu\n", da_bno, ino);
 
2697
                        libxfs_putbuf(bp);
 
2698
                        goto error_out;
 
2699
                }
 
2700
 
 
2701
                prev_bno = da_bno;
 
2702
                da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT);
 
2703
 
 
2704
                if (da_bno != 0)
 
2705
                        if (verify_da_path(mp, da_cursor, 0))  {
 
2706
                                libxfs_putbuf(bp);
 
2707
                                goto error_out;
 
2708
                        }
 
2709
 
 
2710
                current_hashval = greatest_hashval;
 
2711
 
 
2712
                ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify));
 
2713
 
 
2714
                if (buf_dirty && !no_modify)  {
 
2715
                        *repair = 1;
 
2716
                        libxfs_writebuf(bp, 0);
 
2717
                }
 
2718
                else
 
2719
                        libxfs_putbuf(bp);
 
2720
        } while (da_bno != 0 && res == 0);
 
2721
 
 
2722
        if (verify_final_da_path(mp, da_cursor, 0))  {
 
2723
                /*
 
2724
                 * verify the final path up (right-hand-side) if still ok
 
2725
                 */
 
2726
                do_warn("bad hash path in directory %llu\n", da_cursor->ino);
 
2727
                goto error_out;
 
2728
        }
 
2729
 
 
2730
#ifdef XR_DIR_TRACE
 
2731
        fprintf(stderr, "process_leaf_dir_level returns %d (%s)\n",
 
2732
                res, ((res) ? "bad" : "ok"));
 
2733
#endif
 
2734
        /*
 
2735
         * redundant but just for testing
 
2736
         */
 
2737
        release_da_cursor(mp, da_cursor, 0);
 
2738
 
 
2739
        return(res);
 
2740
 
 
2741
error_out:
 
2742
        /*
 
2743
         * release all buffers holding interior btree blocks
 
2744
         */
 
2745
        err_release_da_cursor(mp, da_cursor, 0);
 
2746
 
 
2747
        return(1);
 
2748
}
 
2749
 
 
2750
/*
 
2751
 * a node directory is a true btree directory -- where the directory
 
2752
 * has gotten big enough that it is represented as a non-trivial (e.g.
 
2753
 * has more than just a root block) btree.
 
2754
 *
 
2755
 * Note that if we run into any problems, we trash the
 
2756
 * directory.  Even if it's the root directory,
 
2757
 * we'll be able to traverse all the disconnected
 
2758
 * subtrees later (phase 6).
 
2759
 *
 
2760
 * one day, if we actually fix things, we'll set repair to 1 to
 
2761
 * indicate that we have or that we should.
 
2762
 *
 
2763
 * dirname can be set to NULL if the name is unknown (or to
 
2764
 * the string representation of the inode)
 
2765
 *
 
2766
 * returns 0 if things are ok, 1 if bad (directory needs to be junked)
 
2767
 */
 
2768
/* ARGSUSED */
 
2769
int
 
2770
process_node_dir(
 
2771
        xfs_mount_t     *mp,
 
2772
        xfs_ino_t       ino,
 
2773
        xfs_dinode_t    *dip,
 
2774
        int             ino_discovery,
 
2775
        blkmap_t        *blkmap,
 
2776
        int             *dot,
 
2777
        int             *dotdot,
 
2778
        xfs_ino_t       *parent,        /* out - parent ino #  or NULLFSINO */
 
2779
        char            *dirname,
 
2780
        int             *repair)
 
2781
{
 
2782
        xfs_dablk_t                     bno;
 
2783
        int                             error = 0;
 
2784
        da_bt_cursor_t                  da_cursor;
 
2785
 
 
2786
#ifdef XR_DIR_TRACE
 
2787
        fprintf(stderr, "process_node_dir - ino %llu\n", ino);
 
2788
#endif
 
2789
        *repair = *dot = *dotdot = 0;
 
2790
        *parent = NULLFSINO;
 
2791
 
 
2792
        /*
 
2793
         * try again -- traverse down left-side of tree until we hit
 
2794
         * the left-most leaf block setting up the btree cursor along
 
2795
         * the way.  Then walk the leaf blocks left-to-right, calling
 
2796
         * a parent-verification routine each time we traverse a block.
 
2797
         */
 
2798
        bzero(&da_cursor, sizeof(da_bt_cursor_t));
 
2799
 
 
2800
        da_cursor.active = 0;
 
2801
        da_cursor.type = 0;
 
2802
        da_cursor.ino = ino;
 
2803
        da_cursor.dip = dip;
 
2804
        da_cursor.greatest_bno = 0;
 
2805
        da_cursor.blkmap = blkmap;
 
2806
 
 
2807
        /*
 
2808
         * now process interior node
 
2809
         */
 
2810
 
 
2811
        error = traverse_int_dablock(mp, &da_cursor, &bno, XFS_DATA_FORK);
 
2812
 
 
2813
        if (error == 0)
 
2814
                return(1);
 
2815
 
 
2816
        /*
 
2817
         * now pass cursor and bno into leaf-block processing routine
 
2818
         * the leaf dir level routine checks the interior paths
 
2819
         * up to the root including the final right-most path.
 
2820
         */
 
2821
 
 
2822
        error = process_leaf_dir_level(mp, &da_cursor, ino_discovery,
 
2823
                                        repair, dot, dotdot, parent);
 
2824
 
 
2825
        if (error)
 
2826
                return(1);
 
2827
 
 
2828
        /*
 
2829
         * sanity check inode size
 
2830
         */
 
2831
        if (INT_GET(dip->di_core.di_size, ARCH_CONVERT) <
 
2832
                        (da_cursor.greatest_bno + 1) * mp->m_sb.sb_blocksize)  {
 
2833
                if ((xfs_fsize_t) (da_cursor.greatest_bno
 
2834
                                * mp->m_sb.sb_blocksize) > UINT_MAX)  { 
 
2835
                        do_warn(
 
2836
"out of range internal directory block numbers (inode %llu)\n",
 
2837
                                ino);
 
2838
                        return(1);
 
2839
                }
 
2840
 
 
2841
                do_warn(
 
2842
"setting directory inode (%llu) size to %llu bytes, was %lld bytes\n",
 
2843
                        ino,
 
2844
                        (xfs_dfiloff_t) (da_cursor.greatest_bno + 1)
 
2845
                                * mp->m_sb.sb_blocksize,
 
2846
                        INT_GET(dip->di_core.di_size, ARCH_CONVERT));
 
2847
 
 
2848
                INT_SET(dip->di_core.di_size, ARCH_CONVERT, (xfs_fsize_t)
 
2849
                        (da_cursor.greatest_bno + 1) * mp->m_sb.sb_blocksize);
 
2850
        }
 
2851
        return(0);
 
2852
}
 
2853
 
 
2854
/*
 
2855
 * a leaf directory is one where the directory is too big for
 
2856
 * the inode data fork but is small enough to fit into one
 
2857
 * directory btree block (filesystem block) outside the inode
 
2858
 *
 
2859
 * returns NULLFSINO if the directory is cannot be salvaged
 
2860
 * and the .. ino if things are ok (even if the directory had
 
2861
 * to be altered to make it ok).
 
2862
 *
 
2863
 * dirname can be set to NULL if the name is unknown (or to
 
2864
 * the string representation of the inode)
 
2865
 *
 
2866
 * returns 0 if things are ok, 1 if bad (directory needs to be junked)
 
2867
 */
 
2868
/* ARGSUSED */
 
2869
int
 
2870
process_leaf_dir(
 
2871
        xfs_mount_t     *mp,
 
2872
        xfs_ino_t       ino,
 
2873
        xfs_dinode_t    *dip,
 
2874
        int             ino_discovery,
 
2875
        int             *dino_dirty,
 
2876
        blkmap_t        *blkmap,
 
2877
        int             *dot,           /* out - 1 if there is a dot, else 0 */
 
2878
        int             *dotdot,        /* out - 1 if there's a dotdot, else 0 */
 
2879
        xfs_ino_t       *parent,        /* out - parent ino #  or NULLFSINO */
 
2880
        char            *dirname,       /* in - directory pathname */
 
2881
        int             *repair)        /* out - 1 if something was fixed */
 
2882
{
 
2883
        xfs_dir_leafblock_t     *leaf;
 
2884
        xfs_dahash_t    next_hashval;
 
2885
        xfs_dfsbno_t    bno;
 
2886
        xfs_buf_t       *bp;
 
2887
        int             buf_dirty = 0;
 
2888
 
 
2889
#ifdef XR_DIR_TRACE
 
2890
        fprintf(stderr, "process_leaf_dir - ino %llu\n", ino);
 
2891
#endif
 
2892
        *repair = *dot = *dotdot = 0;
 
2893
        *parent = NULLFSINO;
 
2894
 
 
2895
        bno = blkmap_get(blkmap, 0);
 
2896
        if (bno == NULLDFSBNO) {
 
2897
                do_warn("block 0 for directory inode %llu is missing\n", ino);
 
2898
                return(1);
 
2899
        }
 
2900
        bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
 
2901
                        XFS_FSB_TO_BB(mp, 1), 0);
 
2902
        if (!bp) {
 
2903
                do_warn("can't read block 0 for directory inode %llu\n", ino);
 
2904
                return(1);
 
2905
        }
 
2906
        /*
 
2907
         * verify leaf block
 
2908
         */
 
2909
        leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp);
 
2910
 
 
2911
        /*
 
2912
         * check magic number for leaf directory btree block
 
2913
         */
 
2914
        if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) {
 
2915
                do_warn("bad directory leaf magic # %#x for dir ino %llu\n",
 
2916
                        INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), ino);
 
2917
                libxfs_putbuf(bp);
 
2918
                return(1);
 
2919
        }
 
2920
 
 
2921
        if (process_leaf_dir_block(mp, leaf, 0, ino, 0, ino_discovery, blkmap,
 
2922
                        dot, dotdot, parent, &buf_dirty, &next_hashval)) {
 
2923
                /*
 
2924
                 * the block is bad.  lose the directory.
 
2925
                 * XXX - later, we should try and just lose
 
2926
                 * the block without losing the entire directory
 
2927
                 */
 
2928
                ASSERT(*dotdot == 0 || (*dotdot == 1 && *parent != NULLFSINO));
 
2929
                libxfs_putbuf(bp);
 
2930
                return(1);
 
2931
        }
 
2932
 
 
2933
        /*
 
2934
         * check sibling pointers in leaf block (above doesn't do it)
 
2935
         */
 
2936
        if (INT_GET(leaf->hdr.info.forw, ARCH_CONVERT) != 0 ||
 
2937
                                INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != 0)  {
 
2938
                if (!no_modify)  {
 
2939
                        do_warn("clearing forw/back pointers for directory inode "
 
2940
                                "%llu\n", ino);
 
2941
                        buf_dirty = 1;
 
2942
                        INT_ZERO(leaf->hdr.info.forw, ARCH_CONVERT);
 
2943
                        INT_ZERO(leaf->hdr.info.back, ARCH_CONVERT);
 
2944
                } else  {
 
2945
                        do_warn("would clear forw/back pointers for directory inode "
 
2946
                                "%llu\n", ino);
 
2947
                }
 
2948
        }
 
2949
 
 
2950
        ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify));
 
2951
 
 
2952
        if (buf_dirty && !no_modify)
 
2953
                libxfs_writebuf(bp, 0);
 
2954
        else
 
2955
                libxfs_putbuf(bp);
 
2956
 
 
2957
        return(0);
 
2958
}
 
2959
 
 
2960
/*
 
2961
 * returns 1 if things are bad (directory needs to be junked)
 
2962
 * and 0 if things are ok.  If ino_discovery is 1, add unknown
 
2963
 * inodes to uncertain inode list.
 
2964
 */
 
2965
int
 
2966
process_dir(
 
2967
        xfs_mount_t     *mp,
 
2968
        xfs_ino_t       ino,
 
2969
        xfs_dinode_t    *dip,
 
2970
        int             ino_discovery,
 
2971
        int             *dino_dirty,
 
2972
        char            *dirname,
 
2973
        xfs_ino_t       *parent,
 
2974
        blkmap_t        *blkmap)
 
2975
{
 
2976
        int             dot;
 
2977
        int             dotdot;
 
2978
        int             repair = 0;
 
2979
        int             res = 0;
 
2980
 
 
2981
        *parent = NULLFSINO;
 
2982
        dot = dotdot = 0;
 
2983
 
 
2984
        /*
 
2985
         * branch off depending on the type of inode.  This routine
 
2986
         * is only called ONCE so all the subordinate routines will
 
2987
         * fix '.' and junk '..' if they're bogus.
 
2988
         */
 
2989
        if (INT_GET(dip->di_core.di_size, ARCH_CONVERT) <= XFS_DFORK_DSIZE_ARCH(dip, mp, ARCH_CONVERT))  {
 
2990
                dot = 1;
 
2991
                dotdot = 1;
 
2992
                if (process_shortform_dir(mp, ino, dip, ino_discovery,
 
2993
                                dino_dirty, parent, dirname, &repair))  {
 
2994
                        res = 1;
 
2995
                }
 
2996
        } else if (INT_GET(dip->di_core.di_size, ARCH_CONVERT) <= XFS_LBSIZE(mp))  {
 
2997
                if (process_leaf_dir(mp, ino, dip, ino_discovery,
 
2998
                                dino_dirty, blkmap, &dot, &dotdot,
 
2999
                                parent, dirname, &repair))  {
 
3000
                        res = 1;
 
3001
                }
 
3002
        } else  {
 
3003
                if (process_node_dir(mp, ino, dip, ino_discovery,
 
3004
                                blkmap, &dot, &dotdot,
 
3005
                                parent, dirname, &repair))  {
 
3006
                        res = 1;
 
3007
                }
 
3008
        }
 
3009
        /*
 
3010
         * bad . entries in all directories will be fixed up in phase 6
 
3011
         */
 
3012
        if (dot == 0) {
 
3013
                do_warn("no . entry for directory %llu\n", ino);
 
3014
        }
 
3015
 
 
3016
        /*
 
3017
         * shortform dirs always have a .. entry.  .. for all longform
 
3018
         * directories will get fixed in phase 6. .. for other shortform
 
3019
         * dirs also get fixed there.  .. for a shortform root was
 
3020
         * fixed in place since we know what it should be
 
3021
         */
 
3022
        if (dotdot == 0 && ino != mp->m_sb.sb_rootino) {
 
3023
                do_warn("no .. entry for directory %llu\n", ino);
 
3024
        } else if (dotdot == 0 && ino == mp->m_sb.sb_rootino) {
 
3025
                do_warn("no .. entry for root directory %llu\n", ino);
 
3026
                need_root_dotdot = 1;
 
3027
        }
 
3028
        
 
3029
#ifdef XR_DIR_TRACE
 
3030
        fprintf(stderr, "(process_dir), parent of %llu is %llu\n", ino, parent);
 
3031
#endif
 
3032
        return(res);
 
3033
}