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(); |