1263
1260
* entry count, verify level
1266
if (XFS_DA_NODE_MAGIC !=
1267
INT_GET(newnode->hdr.info.magic, ARCH_CONVERT)) {
1263
if (XFS_DA_NODE_MAGIC != be16_to_cpu(newnode->hdr.info.magic)) {
1268
1264
do_warn(_("bad magic number %x in block %u (%llu) "
1269
1265
"for directory inode %llu\n"),
1270
INT_GET(newnode->hdr.info.magic, ARCH_CONVERT),
1266
be16_to_cpu(newnode->hdr.info.magic),
1271
1267
dabno, fsbno, cursor->ino);
1274
if (INT_GET(newnode->hdr.info.back, ARCH_CONVERT) !=
1275
cursor->level[this_level].bno) {
1270
if (be32_to_cpu(newnode->hdr.info.back) !=
1271
cursor->level[this_level].bno) {
1276
1272
do_warn(_("bad back pointer in block %u (%llu) "
1277
1273
"for directory inode %llu\n"),
1278
1274
dabno, fsbno, cursor->ino);
1281
if (INT_GET(newnode->hdr.count, ARCH_CONVERT) >
1282
mp->m_dir_node_ents) {
1277
if (be16_to_cpu(newnode->hdr.count) > mp->m_dir_node_ents) {
1283
1278
do_warn(_("entry count %d too large in block %u (%llu) "
1284
1279
"for directory inode %llu\n"),
1285
INT_GET(newnode->hdr.count, ARCH_CONVERT),
1280
be16_to_cpu(newnode->hdr.count),
1286
1281
dabno, fsbno, cursor->ino);
1289
if (INT_GET(newnode->hdr.level, ARCH_CONVERT) != this_level) {
1284
if (be16_to_cpu(newnode->hdr.level) != this_level) {
1290
1285
do_warn(_("bad level %d in block %u (%llu) "
1291
1286
"for directory inode %llu\n"),
1292
INT_GET(newnode->hdr.level, ARCH_CONVERT),
1287
be16_to_cpu(newnode->hdr.level),
1293
1288
dabno, fsbno, cursor->ino);
1375
* handles junking directory leaf block entries that have zero lengths
1376
* buf_dirty is an in/out, set to 1 if the leaf was modified.
1377
* we do NOT initialize it to zero if nothing happened because it
1378
* may be already set by the caller. Assumes that the block
1379
* has been compacted before calling this routine.
1382
junk_zerolen_dir_leaf_entries(
1384
xfs_dir_leafblock_t *leaf,
1388
xfs_dir_leaf_entry_t *entry;
1389
xfs_dir_leaf_name_t *namest;
1390
xfs_dir_leaf_hdr_t *hdr;
1391
xfs_dir_leaf_map_t *map;
1395
int current_hole = 0;
1405
entry = &leaf->entries[0];
1409
* we can convert the entries to one character entries
1410
* as long as we have space. Once we run out, then
1411
* we have to delete really delete (copy over) an entry.
1412
* however, that frees up some space that we could use ...
1414
* so the idea is, we'll use up space from all the holes,
1415
* potentially leaving each hole too small to do any good.
1416
* then if need to, we'll delete entries and use that space
1417
* up from the top-most byte down. that may leave a 4th hole
1418
* but we can represent that by correctly setting the value
1419
* of firstused. that leaves any hole between the end of
1420
* the entry list and firstused so it doesn't have to be
1421
* recorded in the hole map.
1424
for (bytes = i = 0; i < INT_GET(hdr->count, ARCH_CONVERT); entry++, i++) {
1426
* skip over entries that are good or already converted
1428
if (entry->namelen != 0)
1434
* try and use up existing holes first until they get
1435
* too small, then set bytes to the # of bytes between
1436
* the current heap beginning and the last used byte
1437
* in the entry table.
1439
if (bytes < sizeof(xfs_dir_leaf_name_t) &&
1440
current_hole < XFS_DIR_LEAF_MAPSIZE) {
1442
* skip over holes that are too small
1444
while (current_hole < XFS_DIR_LEAF_MAPSIZE &&
1445
INT_GET(hdr->freemap[current_hole].size, ARCH_CONVERT) <
1446
sizeof(xfs_dir_leaf_name_t)) {
1450
if (current_hole < XFS_DIR_LEAF_MAPSIZE)
1451
bytes = INT_GET(hdr->freemap[current_hole].size, ARCH_CONVERT);
1453
bytes = (int) INT_GET(hdr->firstused, ARCH_CONVERT) -
1454
((__psint_t) &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)] -
1460
for (map = &hdr->freemap[0];
1461
current_hole < XFS_DIR_LEAF_MAPSIZE &&
1462
INT_GET(map->size, ARCH_CONVERT) < sizeof(xfs_dir_leaf_name_t);
1468
* if we can use an existing hole, do it. otherwise,
1469
* delete entries until the deletions create a big enough
1470
* hole to convert another entry. then use up those bytes
1471
* bytes until you run low. then delete entries again ...
1473
if (current_hole < XFS_DIR_LEAF_MAPSIZE) {
1474
ASSERT(sizeof(xfs_dir_leaf_name_t) <= bytes);
1476
do_warn(_("marking bad entry in directory inode %llu\n"),
1480
INT_SET(entry->nameidx, ARCH_CONVERT, INT_GET(hdr->freemap[current_hole].base, ARCH_CONVERT) +
1481
bytes - sizeof(xfs_dir_leaf_name_t));
1483
namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
1484
tmp_ino = NULLFSINO;
1485
XFS_DIR_SF_PUT_DIRINO(&tmp_ino, &namest->inumber);
1486
namest->name[0] = '/';
1488
if (INT_GET(entry->nameidx, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT))
1489
INT_SET(hdr->firstused, ARCH_CONVERT, INT_GET(entry->nameidx, ARCH_CONVERT));
1490
INT_MOD(hdr->freemap[current_hole].size, ARCH_CONVERT, -(sizeof(xfs_dir_leaf_name_t)));
1491
INT_MOD(hdr->namebytes, ARCH_CONVERT, +1);
1494
* delete the table entry and try and account for the
1495
* space in the holemap. don't have to update namebytes
1496
* or firstused since we're not actually deleting any
1497
* bytes from the heap. following code swiped from
1498
* xfs_dir_leaf_remove() in xfs_dir_leaf.c
1500
INT_MOD(hdr->count, ARCH_CONVERT, -1);
1502
_("deleting zero length entry in directory inode %llu\n"),
1505
* overwrite the bad entry unless it's the
1506
* last entry in the list (highly unlikely).
1507
* zero out the free'd bytes.
1509
if (INT_GET(hdr->count, ARCH_CONVERT) - i > 0) {
1510
memmove(entry, entry + 1, (INT_GET(hdr->count, ARCH_CONVERT) - i) *
1511
sizeof(xfs_dir_leaf_entry_t));
1513
memset((void *) ((__psint_t) entry +
1514
(INT_GET(leaf->hdr.count, ARCH_CONVERT) - i - 1) *
1515
sizeof(xfs_dir_leaf_entry_t)), 0,
1516
sizeof(xfs_dir_leaf_entry_t));
1518
start = (__psint_t) &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)] -
1520
tablesize = sizeof(xfs_dir_leaf_entry_t) *
1521
(INT_GET(hdr->count, ARCH_CONVERT) + 1) + sizeof(xfs_dir_leaf_hdr_t);
1522
map = &hdr->freemap[0];
1523
tmp = INT_GET(map->size, ARCH_CONVERT);
1524
before = after = -1;
1525
smallest = XFS_DIR_LEAF_MAPSIZE - 1;
1526
for (j = 0; j < XFS_DIR_LEAF_MAPSIZE; map++, j++) {
1527
ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp));
1528
ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp));
1529
if (INT_GET(map->base, ARCH_CONVERT) == tablesize) {
1530
INT_MOD(map->base, ARCH_CONVERT, -(sizeof(xfs_dir_leaf_entry_t)));
1531
INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t));
1534
if ((INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT)) == start) {
1536
} else if (INT_GET(map->base, ARCH_CONVERT) == start +
1537
sizeof(xfs_dir_leaf_entry_t)) {
1539
} else if (INT_GET(map->size, ARCH_CONVERT) < tmp) {
1540
tmp = INT_GET(map->size, ARCH_CONVERT);
1546
* Coalesce adjacent freemap regions,
1547
* or replace the smallest region.
1549
if ((before >= 0) || (after >= 0)) {
1550
if ((before >= 0) && (after >= 0)) {
1551
map = &hdr->freemap[before];
1552
INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t));
1553
INT_MOD(map->size, ARCH_CONVERT, INT_GET(hdr->freemap[after].size, ARCH_CONVERT));
1554
hdr->freemap[after].base = 0;
1555
hdr->freemap[after].size = 0;
1556
} else if (before >= 0) {
1557
map = &hdr->freemap[before];
1558
INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t));
1560
map = &hdr->freemap[after];
1561
INT_SET(map->base, ARCH_CONVERT, start);
1562
INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t));
1566
* Replace smallest region
1567
* (if it is smaller than free'd entry)
1569
map = &hdr->freemap[smallest];
1570
if (INT_GET(map->size, ARCH_CONVERT) < sizeof(xfs_dir_leaf_entry_t)) {
1571
INT_SET(map->base, ARCH_CONVERT, start);
1572
INT_SET(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t));
1575
* mark as needing compaction
1581
* do we have to delete stuff or is there
1582
* room for deletions?
1584
ASSERT(current_hole == XFS_DIR_LEAF_MAPSIZE);
1587
* here, bytes == number of unused bytes from
1588
* end of list to top (beginning) of heap
1589
* (firstused). It's ok to leave extra
1590
* unused bytes in that region because they
1591
* wind up before firstused (which we reset
1594
if (bytes < sizeof(xfs_dir_leaf_name_t)) {
1596
* have to delete an entry because
1597
* we have no room to convert it to
1601
_("deleting entry in directory inode %llu\n"),
1604
* overwrite the bad entry unless it's the
1605
* last entry in the list (highly unlikely).
1607
if (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i - 1> 0) {
1608
memmove(entry, entry + 1,
1609
(INT_GET(leaf->hdr.count, ARCH_CONVERT) - i - 1) *
1610
sizeof(xfs_dir_leaf_entry_t));
1612
memset((void *) ((__psint_t) entry +
1613
(INT_GET(leaf->hdr.count, ARCH_CONVERT) - i - 1) *
1614
sizeof(xfs_dir_leaf_entry_t)), 0,
1615
sizeof(xfs_dir_leaf_entry_t));
1618
* bump up free byte count, drop other
1619
* index vars since the table just
1620
* shrank by one entry and we don't
1621
* want to miss any as we walk the table
1623
bytes += sizeof(xfs_dir_leaf_entry_t);
1624
INT_MOD(leaf->hdr.count, ARCH_CONVERT, -1);
1629
* convert entry using the bytes in between
1630
* the end of the entry table and the heap
1633
INT_MOD(leaf->hdr.firstused, ARCH_CONVERT, -(sizeof(xfs_dir_leaf_name_t)));
1634
INT_SET(entry->nameidx, ARCH_CONVERT, INT_GET(leaf->hdr.firstused, ARCH_CONVERT));
1636
namest = XFS_DIR_LEAF_NAMESTRUCT(leaf,
1637
INT_GET(entry->nameidx, ARCH_CONVERT));
1638
tmp_ino = NULLFSINO;
1639
XFS_DIR_SF_PUT_DIRINO(&tmp_ino,
1641
namest->name[0] = '/';
1643
bytes -= sizeof(xfs_dir_leaf_entry_t);
1653
1368
size_t ts_dirbuf_size = 64*1024;
2366
2072
* pointing to used bytes. we're being conservative here
2367
2073
* since the block will get compacted anyhow by the kernel.
2369
if ((leaf->hdr.holes == 0 &&
2370
first_used != INT_GET(leaf->hdr.firstused, ARCH_CONVERT)) ||
2371
INT_GET(leaf->hdr.firstused, ARCH_CONVERT) > first_used) {
2075
if ((leaf->hdr.holes == 0 &&
2076
first_used != be16_to_cpu(leaf->hdr.firstused)) ||
2077
be16_to_cpu(leaf->hdr.firstused) > first_used) {
2372
2078
if (!no_modify) {
2375
2081
_("- resetting first used heap value from %d to %d in block %u of dir ino %llu\n"),
2376
(int) INT_GET(leaf->hdr.firstused,
2082
be16_to_cpu(leaf->hdr.firstused),
2378
2083
first_used, da_bno, ino);
2379
INT_SET(leaf->hdr.firstused, ARCH_CONVERT, first_used);
2084
leaf->hdr.firstused = cpu_to_be16(first_used);
2380
2085
*buf_dirty = 1;
2384
2089
_("- would reset first used value from %d to %d in block %u of dir ino %llu\n"),
2385
(int) INT_GET(leaf->hdr.firstused,
2090
be16_to_cpu(leaf->hdr.firstused),
2387
2091
first_used, da_bno, ino);
2391
if (bytes_used != INT_GET(leaf->hdr.namebytes, ARCH_CONVERT)) {
2095
if (bytes_used != be16_to_cpu(leaf->hdr.namebytes)) {
2392
2096
if (!no_modify) {
2395
2099
_("- resetting namebytes cnt from %d to %d in block %u of dir inode %llu\n"),
2396
(int) INT_GET(leaf->hdr.namebytes,
2100
be16_to_cpu(leaf->hdr.namebytes),
2398
2101
bytes_used, da_bno, ino);
2399
INT_SET(leaf->hdr.namebytes, ARCH_CONVERT, bytes_used);
2102
leaf->hdr.namebytes = cpu_to_be16(bytes_used);
2400
2103
*buf_dirty = 1;
2404
2107
_("- would reset namebytes cnt from %d to %d in block %u of dir inode %llu\n"),
2405
(int) INT_GET(leaf->hdr.namebytes,
2108
be16_to_cpu(leaf->hdr.namebytes),
2407
2109
bytes_used, da_bno, ino);
2551
2253
* reset header info
2553
if (num_entries != INT_GET(new_leaf->hdr.count, ARCH_CONVERT))
2554
INT_SET(new_leaf->hdr.count, ARCH_CONVERT, num_entries);
2255
if (num_entries != be16_to_cpu(new_leaf->hdr.count))
2256
new_leaf->hdr.count = cpu_to_be16(num_entries);
2556
INT_SET(new_leaf->hdr.firstused, ARCH_CONVERT, first_used);
2258
new_leaf->hdr.firstused = cpu_to_be16(first_used);
2557
2259
new_leaf->hdr.holes = 0;
2558
2260
new_leaf->hdr.pad1 = 0;
2560
INT_SET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT, (__psint_t) d_entry
2561
- (__psint_t) new_leaf);
2562
INT_SET(new_leaf->hdr.freemap[0].size, ARCH_CONVERT, (__psint_t) first_byte
2563
- (__psint_t) d_entry);
2262
new_leaf->hdr.freemap[0].base = cpu_to_be16(
2263
(__psint_t) d_entry - (__psint_t) new_leaf);
2264
new_leaf->hdr.freemap[0].size = cpu_to_be16(
2265
(__psint_t) first_byte - (__psint_t) d_entry);
2565
ASSERT(INT_GET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT) < first_used);
2566
ASSERT(INT_GET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT) ==
2267
ASSERT(be16_to_cpu(new_leaf->hdr.freemap[0].base) < first_used);
2268
ASSERT(be16_to_cpu(new_leaf->hdr.freemap[0].base) ==
2567
2269
(__psint_t) (&new_leaf->entries[0])
2568
2270
- (__psint_t) new_leaf
2569
2271
+ i * sizeof(xfs_dir_leaf_entry_t));
2570
ASSERT(INT_GET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT) < XFS_LBSIZE(mp));
2571
ASSERT(INT_GET(new_leaf->hdr.freemap[0].size, ARCH_CONVERT) < XFS_LBSIZE(mp));
2572
ASSERT(INT_GET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT) +
2573
INT_GET(new_leaf->hdr.freemap[0].size, ARCH_CONVERT) == first_used);
2272
ASSERT(be16_to_cpu(new_leaf->hdr.freemap[0].base) < XFS_LBSIZE(mp));
2273
ASSERT(be16_to_cpu(new_leaf->hdr.freemap[0].size) < XFS_LBSIZE(mp));
2274
ASSERT(be16_to_cpu(new_leaf->hdr.freemap[0].base) +
2275
be16_to_cpu(new_leaf->hdr.freemap[0].size) == first_used);
2575
2277
new_leaf->hdr.freemap[1].base = 0;
2576
2278
new_leaf->hdr.freemap[1].size = 0;
3009
2709
* is only called ONCE so all the subordinate routines will
3010
2710
* fix '.' and junk '..' if they're bogus.
3012
if (INT_GET(dip->di_core.di_size, ARCH_CONVERT) <=
3013
XFS_DFORK_DSIZE(dip, mp)) {
2712
if (be64_to_cpu(dip->di_core.di_size) <= XFS_DFORK_DSIZE(dip, mp)) {
3016
2715
if (process_shortform_dir(mp, ino, dip, ino_discovery,
3017
dino_dirty, parent, dirname, &repair)) {
2716
dino_dirty, parent, dirname, &repair))
3020
} else if (INT_GET(dip->di_core.di_size, ARCH_CONVERT) <=
2718
} else if (be64_to_cpu(dip->di_core.di_size) <= XFS_LBSIZE(mp)) {
3022
2719
if (process_leaf_dir(mp, ino, dip, ino_discovery,
3023
2720
dino_dirty, blkmap, &dot, &dotdot,
3024
parent, dirname, &repair)) {
2721
parent, dirname, &repair))
3028
2724
if (process_node_dir(mp, ino, dip, ino_discovery,
3029
2725
blkmap, &dot, &dotdot,
3030
parent, dirname, &repair)) {
2726
parent, dirname, &repair))
3035
2730
* bad . entries in all directories will be fixed up in phase 6
3038
2733
do_warn(_("no . entry for directory %llu\n"), ino);
3042
2736
* shortform dirs always have a .. entry. .. for all longform