diff options
Diffstat (limited to 'fs/dcache.c')
| -rw-r--r-- | fs/dcache.c | 282 |
1 files changed, 241 insertions, 41 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 2355bddad8de..fd4a428998ef 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -478,11 +478,12 @@ static void prune_dcache(int count, struct super_block *sb) | |||
| 478 | up_read(s_umount); | 478 | up_read(s_umount); |
| 479 | } | 479 | } |
| 480 | spin_unlock(&dentry->d_lock); | 480 | spin_unlock(&dentry->d_lock); |
| 481 | /* Cannot remove the first dentry, and it isn't appropriate | 481 | /* |
| 482 | * to move it to the head of the list, so give up, and try | 482 | * Insert dentry at the head of the list as inserting at the |
| 483 | * later | 483 | * tail leads to a cycle. |
| 484 | */ | 484 | */ |
| 485 | break; | 485 | list_add(&dentry->d_lru, &dentry_unused); |
| 486 | dentry_stat.nr_unused++; | ||
| 486 | } | 487 | } |
| 487 | spin_unlock(&dcache_lock); | 488 | spin_unlock(&dcache_lock); |
| 488 | } | 489 | } |
| @@ -549,6 +550,142 @@ repeat: | |||
| 549 | } | 550 | } |
| 550 | 551 | ||
| 551 | /* | 552 | /* |
| 553 | * destroy a single subtree of dentries for unmount | ||
| 554 | * - see the comments on shrink_dcache_for_umount() for a description of the | ||
| 555 | * locking | ||
| 556 | */ | ||
| 557 | static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | ||
| 558 | { | ||
| 559 | struct dentry *parent; | ||
| 560 | unsigned detached = 0; | ||
| 561 | |||
| 562 | BUG_ON(!IS_ROOT(dentry)); | ||
| 563 | |||
| 564 | /* detach this root from the system */ | ||
| 565 | spin_lock(&dcache_lock); | ||
| 566 | if (!list_empty(&dentry->d_lru)) { | ||
| 567 | dentry_stat.nr_unused--; | ||
| 568 | list_del_init(&dentry->d_lru); | ||
| 569 | } | ||
| 570 | __d_drop(dentry); | ||
| 571 | spin_unlock(&dcache_lock); | ||
| 572 | |||
| 573 | for (;;) { | ||
| 574 | /* descend to the first leaf in the current subtree */ | ||
| 575 | while (!list_empty(&dentry->d_subdirs)) { | ||
| 576 | struct dentry *loop; | ||
| 577 | |||
| 578 | /* this is a branch with children - detach all of them | ||
| 579 | * from the system in one go */ | ||
| 580 | spin_lock(&dcache_lock); | ||
| 581 | list_for_each_entry(loop, &dentry->d_subdirs, | ||
| 582 | d_u.d_child) { | ||
| 583 | if (!list_empty(&loop->d_lru)) { | ||
| 584 | dentry_stat.nr_unused--; | ||
| 585 | list_del_init(&loop->d_lru); | ||
| 586 | } | ||
| 587 | |||
| 588 | __d_drop(loop); | ||
| 589 | cond_resched_lock(&dcache_lock); | ||
| 590 | } | ||
| 591 | spin_unlock(&dcache_lock); | ||
| 592 | |||
| 593 | /* move to the first child */ | ||
| 594 | dentry = list_entry(dentry->d_subdirs.next, | ||
| 595 | struct dentry, d_u.d_child); | ||
| 596 | } | ||
| 597 | |||
| 598 | /* consume the dentries from this leaf up through its parents | ||
| 599 | * until we find one with children or run out altogether */ | ||
| 600 | do { | ||
| 601 | struct inode *inode; | ||
| 602 | |||
| 603 | if (atomic_read(&dentry->d_count) != 0) { | ||
| 604 | printk(KERN_ERR | ||
| 605 | "BUG: Dentry %p{i=%lx,n=%s}" | ||
| 606 | " still in use (%d)" | ||
| 607 | " [unmount of %s %s]\n", | ||
| 608 | dentry, | ||
| 609 | dentry->d_inode ? | ||
| 610 | dentry->d_inode->i_ino : 0UL, | ||
| 611 | dentry->d_name.name, | ||
| 612 | atomic_read(&dentry->d_count), | ||
| 613 | dentry->d_sb->s_type->name, | ||
| 614 | dentry->d_sb->s_id); | ||
| 615 | BUG(); | ||
| 616 | } | ||
| 617 | |||
| 618 | parent = dentry->d_parent; | ||
| 619 | if (parent == dentry) | ||
| 620 | parent = NULL; | ||
| 621 | else | ||
| 622 | atomic_dec(&parent->d_count); | ||
| 623 | |||
| 624 | list_del(&dentry->d_u.d_child); | ||
| 625 | detached++; | ||
| 626 | |||
| 627 | inode = dentry->d_inode; | ||
| 628 | if (inode) { | ||
| 629 | dentry->d_inode = NULL; | ||
| 630 | list_del_init(&dentry->d_alias); | ||
| 631 | if (dentry->d_op && dentry->d_op->d_iput) | ||
| 632 | dentry->d_op->d_iput(dentry, inode); | ||
| 633 | else | ||
| 634 | iput(inode); | ||
| 635 | } | ||
| 636 | |||
| 637 | d_free(dentry); | ||
| 638 | |||
| 639 | /* finished when we fall off the top of the tree, | ||
| 640 | * otherwise we ascend to the parent and move to the | ||
| 641 | * next sibling if there is one */ | ||
| 642 | if (!parent) | ||
| 643 | goto out; | ||
| 644 | |||
| 645 | dentry = parent; | ||
| 646 | |||
| 647 | } while (list_empty(&dentry->d_subdirs)); | ||
| 648 | |||
| 649 | dentry = list_entry(dentry->d_subdirs.next, | ||
| 650 | struct dentry, d_u.d_child); | ||
| 651 | } | ||
| 652 | out: | ||
| 653 | /* several dentries were freed, need to correct nr_dentry */ | ||
| 654 | spin_lock(&dcache_lock); | ||
| 655 | dentry_stat.nr_dentry -= detached; | ||
| 656 | spin_unlock(&dcache_lock); | ||
| 657 | } | ||
| 658 | |||
| 659 | /* | ||
| 660 | * destroy the dentries attached to a superblock on unmounting | ||
| 661 | * - we don't need to use dentry->d_lock, and only need dcache_lock when | ||
| 662 | * removing the dentry from the system lists and hashes because: | ||
| 663 | * - the superblock is detached from all mountings and open files, so the | ||
| 664 | * dentry trees will not be rearranged by the VFS | ||
| 665 | * - s_umount is write-locked, so the memory pressure shrinker will ignore | ||
| 666 | * any dentries belonging to this superblock that it comes across | ||
| 667 | * - the filesystem itself is no longer permitted to rearrange the dentries | ||
| 668 | * in this superblock | ||
| 669 | */ | ||
| 670 | void shrink_dcache_for_umount(struct super_block *sb) | ||
| 671 | { | ||
| 672 | struct dentry *dentry; | ||
| 673 | |||
| 674 | if (down_read_trylock(&sb->s_umount)) | ||
| 675 | BUG(); | ||
| 676 | |||
| 677 | dentry = sb->s_root; | ||
| 678 | sb->s_root = NULL; | ||
| 679 | atomic_dec(&dentry->d_count); | ||
| 680 | shrink_dcache_for_umount_subtree(dentry); | ||
| 681 | |||
| 682 | while (!hlist_empty(&sb->s_anon)) { | ||
| 683 | dentry = hlist_entry(sb->s_anon.first, struct dentry, d_hash); | ||
| 684 | shrink_dcache_for_umount_subtree(dentry); | ||
| 685 | } | ||
| 686 | } | ||
| 687 | |||
| 688 | /* | ||
| 552 | * Search for at least 1 mount point in the dentry's subdirs. | 689 | * Search for at least 1 mount point in the dentry's subdirs. |
| 553 | * We descend to the next level whenever the d_subdirs | 690 | * We descend to the next level whenever the d_subdirs |
| 554 | * list is non-empty and continue searching. | 691 | * list is non-empty and continue searching. |
| @@ -1339,23 +1476,21 @@ static void switch_names(struct dentry *dentry, struct dentry *target) | |||
| 1339 | * deleted it. | 1476 | * deleted it. |
| 1340 | */ | 1477 | */ |
| 1341 | 1478 | ||
| 1342 | /** | 1479 | /* |
| 1343 | * d_move - move a dentry | 1480 | * d_move_locked - move a dentry |
| 1344 | * @dentry: entry to move | 1481 | * @dentry: entry to move |
| 1345 | * @target: new dentry | 1482 | * @target: new dentry |
| 1346 | * | 1483 | * |
| 1347 | * Update the dcache to reflect the move of a file name. Negative | 1484 | * Update the dcache to reflect the move of a file name. Negative |
| 1348 | * dcache entries should not be moved in this way. | 1485 | * dcache entries should not be moved in this way. |
| 1349 | */ | 1486 | */ |
| 1350 | 1487 | static void d_move_locked(struct dentry * dentry, struct dentry * target) | |
| 1351 | void d_move(struct dentry * dentry, struct dentry * target) | ||
| 1352 | { | 1488 | { |
| 1353 | struct hlist_head *list; | 1489 | struct hlist_head *list; |
| 1354 | 1490 | ||
| 1355 | if (!dentry->d_inode) | 1491 | if (!dentry->d_inode) |
| 1356 | printk(KERN_WARNING "VFS: moving negative dcache entry\n"); | 1492 | printk(KERN_WARNING "VFS: moving negative dcache entry\n"); |
| 1357 | 1493 | ||
| 1358 | spin_lock(&dcache_lock); | ||
| 1359 | write_seqlock(&rename_lock); | 1494 | write_seqlock(&rename_lock); |
| 1360 | /* | 1495 | /* |
| 1361 | * XXXX: do we really need to take target->d_lock? | 1496 | * XXXX: do we really need to take target->d_lock? |
| @@ -1406,7 +1541,81 @@ already_unhashed: | |||
| 1406 | fsnotify_d_move(dentry); | 1541 | fsnotify_d_move(dentry); |
| 1407 | spin_unlock(&dentry->d_lock); | 1542 | spin_unlock(&dentry->d_lock); |
| 1408 | write_sequnlock(&rename_lock); | 1543 | write_sequnlock(&rename_lock); |
| 1544 | } | ||
| 1545 | |||
| 1546 | /** | ||
| 1547 | * d_move - move a dentry | ||
| 1548 | * @dentry: entry to move | ||
| 1549 | * @target: new dentry | ||
| 1550 | * | ||
| 1551 | * Update the dcache to reflect the move of a file name. Negative | ||
| 1552 | * dcache entries should not be moved in this way. | ||
| 1553 | */ | ||
| 1554 | |||
| 1555 | void d_move(struct dentry * dentry, struct dentry * target) | ||
| 1556 | { | ||
| 1557 | spin_lock(&dcache_lock); | ||
| 1558 | d_move_locked(dentry, target); | ||
| 1559 | spin_unlock(&dcache_lock); | ||
| 1560 | } | ||
| 1561 | |||
| 1562 | /* | ||
| 1563 | * Helper that returns 1 if p1 is a parent of p2, else 0 | ||
| 1564 | */ | ||
| 1565 | static int d_isparent(struct dentry *p1, struct dentry *p2) | ||
| 1566 | { | ||
| 1567 | struct dentry *p; | ||
| 1568 | |||
| 1569 | for (p = p2; p->d_parent != p; p = p->d_parent) { | ||
| 1570 | if (p->d_parent == p1) | ||
| 1571 | return 1; | ||
| 1572 | } | ||
| 1573 | return 0; | ||
| 1574 | } | ||
| 1575 | |||
| 1576 | /* | ||
| 1577 | * This helper attempts to cope with remotely renamed directories | ||
| 1578 | * | ||
| 1579 | * It assumes that the caller is already holding | ||
| 1580 | * dentry->d_parent->d_inode->i_mutex and the dcache_lock | ||
| 1581 | * | ||
| 1582 | * Note: If ever the locking in lock_rename() changes, then please | ||
| 1583 | * remember to update this too... | ||
| 1584 | * | ||
| 1585 | * On return, dcache_lock will have been unlocked. | ||
| 1586 | */ | ||
| 1587 | static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias) | ||
| 1588 | { | ||
| 1589 | struct mutex *m1 = NULL, *m2 = NULL; | ||
| 1590 | struct dentry *ret; | ||
| 1591 | |||
| 1592 | /* If alias and dentry share a parent, then no extra locks required */ | ||
| 1593 | if (alias->d_parent == dentry->d_parent) | ||
| 1594 | goto out_unalias; | ||
| 1595 | |||
| 1596 | /* Check for loops */ | ||
| 1597 | ret = ERR_PTR(-ELOOP); | ||
| 1598 | if (d_isparent(alias, dentry)) | ||
| 1599 | goto out_err; | ||
| 1600 | |||
| 1601 | /* See lock_rename() */ | ||
| 1602 | ret = ERR_PTR(-EBUSY); | ||
| 1603 | if (!mutex_trylock(&dentry->d_sb->s_vfs_rename_mutex)) | ||
| 1604 | goto out_err; | ||
| 1605 | m1 = &dentry->d_sb->s_vfs_rename_mutex; | ||
| 1606 | if (!mutex_trylock(&alias->d_parent->d_inode->i_mutex)) | ||
| 1607 | goto out_err; | ||
| 1608 | m2 = &alias->d_parent->d_inode->i_mutex; | ||
| 1609 | out_unalias: | ||
| 1610 | d_move_locked(alias, dentry); | ||
| 1611 | ret = alias; | ||
| 1612 | out_err: | ||
| 1409 | spin_unlock(&dcache_lock); | 1613 | spin_unlock(&dcache_lock); |
| 1614 | if (m2) | ||
| 1615 | mutex_unlock(m2); | ||
| 1616 | if (m1) | ||
| 1617 | mutex_unlock(m1); | ||
| 1618 | return ret; | ||
| 1410 | } | 1619 | } |
| 1411 | 1620 | ||
| 1412 | /* | 1621 | /* |
| @@ -1451,7 +1660,7 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) | |||
| 1451 | */ | 1660 | */ |
| 1452 | struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | 1661 | struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) |
| 1453 | { | 1662 | { |
| 1454 | struct dentry *alias, *actual; | 1663 | struct dentry *actual; |
| 1455 | 1664 | ||
| 1456 | BUG_ON(!d_unhashed(dentry)); | 1665 | BUG_ON(!d_unhashed(dentry)); |
| 1457 | 1666 | ||
| @@ -1463,26 +1672,27 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | |||
| 1463 | goto found_lock; | 1672 | goto found_lock; |
| 1464 | } | 1673 | } |
| 1465 | 1674 | ||
| 1466 | /* See if a disconnected directory already exists as an anonymous root | 1675 | if (S_ISDIR(inode->i_mode)) { |
| 1467 | * that we should splice into the tree instead */ | 1676 | struct dentry *alias; |
| 1468 | if (S_ISDIR(inode->i_mode) && (alias = __d_find_alias(inode, 1))) { | 1677 | |
| 1469 | spin_lock(&alias->d_lock); | 1678 | /* Does an aliased dentry already exist? */ |
| 1470 | 1679 | alias = __d_find_alias(inode, 0); | |
| 1471 | /* Is this a mountpoint that we could splice into our tree? */ | 1680 | if (alias) { |
| 1472 | if (IS_ROOT(alias)) | 1681 | actual = alias; |
| 1473 | goto connect_mountpoint; | 1682 | /* Is this an anonymous mountpoint that we could splice |
| 1474 | 1683 | * into our tree? */ | |
| 1475 | if (alias->d_name.len == dentry->d_name.len && | 1684 | if (IS_ROOT(alias)) { |
| 1476 | alias->d_parent == dentry->d_parent && | 1685 | spin_lock(&alias->d_lock); |
| 1477 | memcmp(alias->d_name.name, | 1686 | __d_materialise_dentry(dentry, alias); |
| 1478 | dentry->d_name.name, | 1687 | __d_drop(alias); |
| 1479 | dentry->d_name.len) == 0) | 1688 | goto found; |
| 1480 | goto replace_with_alias; | 1689 | } |
| 1481 | 1690 | /* Nope, but we must(!) avoid directory aliasing */ | |
| 1482 | spin_unlock(&alias->d_lock); | 1691 | actual = __d_unalias(dentry, alias); |
| 1483 | 1692 | if (IS_ERR(actual)) | |
| 1484 | /* Doh! Seem to be aliasing directories for some reason... */ | 1693 | dput(alias); |
| 1485 | dput(alias); | 1694 | goto out_nolock; |
| 1695 | } | ||
| 1486 | } | 1696 | } |
| 1487 | 1697 | ||
| 1488 | /* Add a unique reference */ | 1698 | /* Add a unique reference */ |
| @@ -1498,7 +1708,7 @@ found: | |||
| 1498 | _d_rehash(actual); | 1708 | _d_rehash(actual); |
| 1499 | spin_unlock(&actual->d_lock); | 1709 | spin_unlock(&actual->d_lock); |
| 1500 | spin_unlock(&dcache_lock); | 1710 | spin_unlock(&dcache_lock); |
| 1501 | 1711 | out_nolock: | |
| 1502 | if (actual == dentry) { | 1712 | if (actual == dentry) { |
| 1503 | security_d_instantiate(dentry, inode); | 1713 | security_d_instantiate(dentry, inode); |
| 1504 | return NULL; | 1714 | return NULL; |
| @@ -1507,16 +1717,6 @@ found: | |||
| 1507 | iput(inode); | 1717 | iput(inode); |
| 1508 | return actual; | 1718 | return actual; |
| 1509 | 1719 | ||
| 1510 | /* Convert the anonymous/root alias into an ordinary dentry */ | ||
| 1511 | connect_mountpoint: | ||
| 1512 | __d_materialise_dentry(dentry, alias); | ||
| 1513 | |||
| 1514 | /* Replace the candidate dentry with the alias in the tree */ | ||
| 1515 | replace_with_alias: | ||
| 1516 | __d_drop(alias); | ||
| 1517 | actual = alias; | ||
| 1518 | goto found; | ||
| 1519 | |||
| 1520 | shouldnt_be_hashed: | 1720 | shouldnt_be_hashed: |
| 1521 | spin_unlock(&dcache_lock); | 1721 | spin_unlock(&dcache_lock); |
| 1522 | BUG(); | 1722 | BUG(); |
