diff options
Diffstat (limited to 'fs/dcache.c')
-rw-r--r-- | fs/dcache.c | 178 |
1 files changed, 128 insertions, 50 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 2bac4ba1d1d3..d68631f18df1 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -43,7 +43,7 @@ static __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock); | |||
43 | 43 | ||
44 | EXPORT_SYMBOL(dcache_lock); | 44 | EXPORT_SYMBOL(dcache_lock); |
45 | 45 | ||
46 | static kmem_cache_t *dentry_cache __read_mostly; | 46 | static struct kmem_cache *dentry_cache __read_mostly; |
47 | 47 | ||
48 | #define DNAME_INLINE_LEN (sizeof(struct dentry)-offsetof(struct dentry,d_iname)) | 48 | #define DNAME_INLINE_LEN (sizeof(struct dentry)-offsetof(struct dentry,d_iname)) |
49 | 49 | ||
@@ -68,15 +68,19 @@ struct dentry_stat_t dentry_stat = { | |||
68 | .age_limit = 45, | 68 | .age_limit = 45, |
69 | }; | 69 | }; |
70 | 70 | ||
71 | static void d_callback(struct rcu_head *head) | 71 | static void __d_free(struct dentry *dentry) |
72 | { | 72 | { |
73 | struct dentry * dentry = container_of(head, struct dentry, d_u.d_rcu); | ||
74 | |||
75 | if (dname_external(dentry)) | 73 | if (dname_external(dentry)) |
76 | kfree(dentry->d_name.name); | 74 | kfree(dentry->d_name.name); |
77 | kmem_cache_free(dentry_cache, dentry); | 75 | kmem_cache_free(dentry_cache, dentry); |
78 | } | 76 | } |
79 | 77 | ||
78 | static void d_callback(struct rcu_head *head) | ||
79 | { | ||
80 | struct dentry * dentry = container_of(head, struct dentry, d_u.d_rcu); | ||
81 | __d_free(dentry); | ||
82 | } | ||
83 | |||
80 | /* | 84 | /* |
81 | * no dcache_lock, please. The caller must decrement dentry_stat.nr_dentry | 85 | * no dcache_lock, please. The caller must decrement dentry_stat.nr_dentry |
82 | * inside dcache_lock. | 86 | * inside dcache_lock. |
@@ -85,7 +89,11 @@ static void d_free(struct dentry *dentry) | |||
85 | { | 89 | { |
86 | if (dentry->d_op && dentry->d_op->d_release) | 90 | if (dentry->d_op && dentry->d_op->d_release) |
87 | dentry->d_op->d_release(dentry); | 91 | dentry->d_op->d_release(dentry); |
88 | call_rcu(&dentry->d_u.d_rcu, d_callback); | 92 | /* if dentry was never inserted into hash, immediate free is OK */ |
93 | if (dentry->d_hash.pprev == NULL) | ||
94 | __d_free(dentry); | ||
95 | else | ||
96 | call_rcu(&dentry->d_u.d_rcu, d_callback); | ||
89 | } | 97 | } |
90 | 98 | ||
91 | /* | 99 | /* |
@@ -478,11 +486,12 @@ static void prune_dcache(int count, struct super_block *sb) | |||
478 | up_read(s_umount); | 486 | up_read(s_umount); |
479 | } | 487 | } |
480 | spin_unlock(&dentry->d_lock); | 488 | spin_unlock(&dentry->d_lock); |
481 | /* Cannot remove the first dentry, and it isn't appropriate | 489 | /* |
482 | * to move it to the head of the list, so give up, and try | 490 | * Insert dentry at the head of the list as inserting at the |
483 | * later | 491 | * tail leads to a cycle. |
484 | */ | 492 | */ |
485 | break; | 493 | list_add(&dentry->d_lru, &dentry_unused); |
494 | dentry_stat.nr_unused++; | ||
486 | } | 495 | } |
487 | spin_unlock(&dcache_lock); | 496 | spin_unlock(&dcache_lock); |
488 | } | 497 | } |
@@ -556,6 +565,7 @@ repeat: | |||
556 | static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | 565 | static void shrink_dcache_for_umount_subtree(struct dentry *dentry) |
557 | { | 566 | { |
558 | struct dentry *parent; | 567 | struct dentry *parent; |
568 | unsigned detached = 0; | ||
559 | 569 | ||
560 | BUG_ON(!IS_ROOT(dentry)); | 570 | BUG_ON(!IS_ROOT(dentry)); |
561 | 571 | ||
@@ -620,7 +630,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
620 | atomic_dec(&parent->d_count); | 630 | atomic_dec(&parent->d_count); |
621 | 631 | ||
622 | list_del(&dentry->d_u.d_child); | 632 | list_del(&dentry->d_u.d_child); |
623 | dentry_stat.nr_dentry--; /* For d_free, below */ | 633 | detached++; |
624 | 634 | ||
625 | inode = dentry->d_inode; | 635 | inode = dentry->d_inode; |
626 | if (inode) { | 636 | if (inode) { |
@@ -638,7 +648,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
638 | * otherwise we ascend to the parent and move to the | 648 | * otherwise we ascend to the parent and move to the |
639 | * next sibling if there is one */ | 649 | * next sibling if there is one */ |
640 | if (!parent) | 650 | if (!parent) |
641 | return; | 651 | goto out; |
642 | 652 | ||
643 | dentry = parent; | 653 | dentry = parent; |
644 | 654 | ||
@@ -647,6 +657,11 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
647 | dentry = list_entry(dentry->d_subdirs.next, | 657 | dentry = list_entry(dentry->d_subdirs.next, |
648 | struct dentry, d_u.d_child); | 658 | struct dentry, d_u.d_child); |
649 | } | 659 | } |
660 | out: | ||
661 | /* several dentries were freed, need to correct nr_dentry */ | ||
662 | spin_lock(&dcache_lock); | ||
663 | dentry_stat.nr_dentry -= detached; | ||
664 | spin_unlock(&dcache_lock); | ||
650 | } | 665 | } |
651 | 666 | ||
652 | /* | 667 | /* |
@@ -1469,23 +1484,21 @@ static void switch_names(struct dentry *dentry, struct dentry *target) | |||
1469 | * deleted it. | 1484 | * deleted it. |
1470 | */ | 1485 | */ |
1471 | 1486 | ||
1472 | /** | 1487 | /* |
1473 | * d_move - move a dentry | 1488 | * d_move_locked - move a dentry |
1474 | * @dentry: entry to move | 1489 | * @dentry: entry to move |
1475 | * @target: new dentry | 1490 | * @target: new dentry |
1476 | * | 1491 | * |
1477 | * Update the dcache to reflect the move of a file name. Negative | 1492 | * Update the dcache to reflect the move of a file name. Negative |
1478 | * dcache entries should not be moved in this way. | 1493 | * dcache entries should not be moved in this way. |
1479 | */ | 1494 | */ |
1480 | 1495 | static void d_move_locked(struct dentry * dentry, struct dentry * target) | |
1481 | void d_move(struct dentry * dentry, struct dentry * target) | ||
1482 | { | 1496 | { |
1483 | struct hlist_head *list; | 1497 | struct hlist_head *list; |
1484 | 1498 | ||
1485 | if (!dentry->d_inode) | 1499 | if (!dentry->d_inode) |
1486 | printk(KERN_WARNING "VFS: moving negative dcache entry\n"); | 1500 | printk(KERN_WARNING "VFS: moving negative dcache entry\n"); |
1487 | 1501 | ||
1488 | spin_lock(&dcache_lock); | ||
1489 | write_seqlock(&rename_lock); | 1502 | write_seqlock(&rename_lock); |
1490 | /* | 1503 | /* |
1491 | * XXXX: do we really need to take target->d_lock? | 1504 | * XXXX: do we really need to take target->d_lock? |
@@ -1536,7 +1549,81 @@ already_unhashed: | |||
1536 | fsnotify_d_move(dentry); | 1549 | fsnotify_d_move(dentry); |
1537 | spin_unlock(&dentry->d_lock); | 1550 | spin_unlock(&dentry->d_lock); |
1538 | write_sequnlock(&rename_lock); | 1551 | write_sequnlock(&rename_lock); |
1552 | } | ||
1553 | |||
1554 | /** | ||
1555 | * d_move - move a dentry | ||
1556 | * @dentry: entry to move | ||
1557 | * @target: new dentry | ||
1558 | * | ||
1559 | * Update the dcache to reflect the move of a file name. Negative | ||
1560 | * dcache entries should not be moved in this way. | ||
1561 | */ | ||
1562 | |||
1563 | void d_move(struct dentry * dentry, struct dentry * target) | ||
1564 | { | ||
1565 | spin_lock(&dcache_lock); | ||
1566 | d_move_locked(dentry, target); | ||
1567 | spin_unlock(&dcache_lock); | ||
1568 | } | ||
1569 | |||
1570 | /* | ||
1571 | * Helper that returns 1 if p1 is a parent of p2, else 0 | ||
1572 | */ | ||
1573 | static int d_isparent(struct dentry *p1, struct dentry *p2) | ||
1574 | { | ||
1575 | struct dentry *p; | ||
1576 | |||
1577 | for (p = p2; p->d_parent != p; p = p->d_parent) { | ||
1578 | if (p->d_parent == p1) | ||
1579 | return 1; | ||
1580 | } | ||
1581 | return 0; | ||
1582 | } | ||
1583 | |||
1584 | /* | ||
1585 | * This helper attempts to cope with remotely renamed directories | ||
1586 | * | ||
1587 | * It assumes that the caller is already holding | ||
1588 | * dentry->d_parent->d_inode->i_mutex and the dcache_lock | ||
1589 | * | ||
1590 | * Note: If ever the locking in lock_rename() changes, then please | ||
1591 | * remember to update this too... | ||
1592 | * | ||
1593 | * On return, dcache_lock will have been unlocked. | ||
1594 | */ | ||
1595 | static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias) | ||
1596 | { | ||
1597 | struct mutex *m1 = NULL, *m2 = NULL; | ||
1598 | struct dentry *ret; | ||
1599 | |||
1600 | /* If alias and dentry share a parent, then no extra locks required */ | ||
1601 | if (alias->d_parent == dentry->d_parent) | ||
1602 | goto out_unalias; | ||
1603 | |||
1604 | /* Check for loops */ | ||
1605 | ret = ERR_PTR(-ELOOP); | ||
1606 | if (d_isparent(alias, dentry)) | ||
1607 | goto out_err; | ||
1608 | |||
1609 | /* See lock_rename() */ | ||
1610 | ret = ERR_PTR(-EBUSY); | ||
1611 | if (!mutex_trylock(&dentry->d_sb->s_vfs_rename_mutex)) | ||
1612 | goto out_err; | ||
1613 | m1 = &dentry->d_sb->s_vfs_rename_mutex; | ||
1614 | if (!mutex_trylock(&alias->d_parent->d_inode->i_mutex)) | ||
1615 | goto out_err; | ||
1616 | m2 = &alias->d_parent->d_inode->i_mutex; | ||
1617 | out_unalias: | ||
1618 | d_move_locked(alias, dentry); | ||
1619 | ret = alias; | ||
1620 | out_err: | ||
1539 | spin_unlock(&dcache_lock); | 1621 | spin_unlock(&dcache_lock); |
1622 | if (m2) | ||
1623 | mutex_unlock(m2); | ||
1624 | if (m1) | ||
1625 | mutex_unlock(m1); | ||
1626 | return ret; | ||
1540 | } | 1627 | } |
1541 | 1628 | ||
1542 | /* | 1629 | /* |
@@ -1581,7 +1668,7 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) | |||
1581 | */ | 1668 | */ |
1582 | struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | 1669 | struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) |
1583 | { | 1670 | { |
1584 | struct dentry *alias, *actual; | 1671 | struct dentry *actual; |
1585 | 1672 | ||
1586 | BUG_ON(!d_unhashed(dentry)); | 1673 | BUG_ON(!d_unhashed(dentry)); |
1587 | 1674 | ||
@@ -1593,26 +1680,27 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | |||
1593 | goto found_lock; | 1680 | goto found_lock; |
1594 | } | 1681 | } |
1595 | 1682 | ||
1596 | /* See if a disconnected directory already exists as an anonymous root | 1683 | if (S_ISDIR(inode->i_mode)) { |
1597 | * that we should splice into the tree instead */ | 1684 | struct dentry *alias; |
1598 | if (S_ISDIR(inode->i_mode) && (alias = __d_find_alias(inode, 1))) { | 1685 | |
1599 | spin_lock(&alias->d_lock); | 1686 | /* Does an aliased dentry already exist? */ |
1600 | 1687 | alias = __d_find_alias(inode, 0); | |
1601 | /* Is this a mountpoint that we could splice into our tree? */ | 1688 | if (alias) { |
1602 | if (IS_ROOT(alias)) | 1689 | actual = alias; |
1603 | goto connect_mountpoint; | 1690 | /* Is this an anonymous mountpoint that we could splice |
1604 | 1691 | * into our tree? */ | |
1605 | if (alias->d_name.len == dentry->d_name.len && | 1692 | if (IS_ROOT(alias)) { |
1606 | alias->d_parent == dentry->d_parent && | 1693 | spin_lock(&alias->d_lock); |
1607 | memcmp(alias->d_name.name, | 1694 | __d_materialise_dentry(dentry, alias); |
1608 | dentry->d_name.name, | 1695 | __d_drop(alias); |
1609 | dentry->d_name.len) == 0) | 1696 | goto found; |
1610 | goto replace_with_alias; | 1697 | } |
1611 | 1698 | /* Nope, but we must(!) avoid directory aliasing */ | |
1612 | spin_unlock(&alias->d_lock); | 1699 | actual = __d_unalias(dentry, alias); |
1613 | 1700 | if (IS_ERR(actual)) | |
1614 | /* Doh! Seem to be aliasing directories for some reason... */ | 1701 | dput(alias); |
1615 | dput(alias); | 1702 | goto out_nolock; |
1703 | } | ||
1616 | } | 1704 | } |
1617 | 1705 | ||
1618 | /* Add a unique reference */ | 1706 | /* Add a unique reference */ |
@@ -1628,7 +1716,7 @@ found: | |||
1628 | _d_rehash(actual); | 1716 | _d_rehash(actual); |
1629 | spin_unlock(&actual->d_lock); | 1717 | spin_unlock(&actual->d_lock); |
1630 | spin_unlock(&dcache_lock); | 1718 | spin_unlock(&dcache_lock); |
1631 | 1719 | out_nolock: | |
1632 | if (actual == dentry) { | 1720 | if (actual == dentry) { |
1633 | security_d_instantiate(dentry, inode); | 1721 | security_d_instantiate(dentry, inode); |
1634 | return NULL; | 1722 | return NULL; |
@@ -1637,16 +1725,6 @@ found: | |||
1637 | iput(inode); | 1725 | iput(inode); |
1638 | return actual; | 1726 | return actual; |
1639 | 1727 | ||
1640 | /* Convert the anonymous/root alias into an ordinary dentry */ | ||
1641 | connect_mountpoint: | ||
1642 | __d_materialise_dentry(dentry, alias); | ||
1643 | |||
1644 | /* Replace the candidate dentry with the alias in the tree */ | ||
1645 | replace_with_alias: | ||
1646 | __d_drop(alias); | ||
1647 | actual = alias; | ||
1648 | goto found; | ||
1649 | |||
1650 | shouldnt_be_hashed: | 1728 | shouldnt_be_hashed: |
1651 | spin_unlock(&dcache_lock); | 1729 | spin_unlock(&dcache_lock); |
1652 | BUG(); | 1730 | BUG(); |
@@ -2002,10 +2080,10 @@ static void __init dcache_init(unsigned long mempages) | |||
2002 | } | 2080 | } |
2003 | 2081 | ||
2004 | /* SLAB cache for __getname() consumers */ | 2082 | /* SLAB cache for __getname() consumers */ |
2005 | kmem_cache_t *names_cachep __read_mostly; | 2083 | struct kmem_cache *names_cachep __read_mostly; |
2006 | 2084 | ||
2007 | /* SLAB cache for file structures */ | 2085 | /* SLAB cache for file structures */ |
2008 | kmem_cache_t *filp_cachep __read_mostly; | 2086 | struct kmem_cache *filp_cachep __read_mostly; |
2009 | 2087 | ||
2010 | EXPORT_SYMBOL(d_genocide); | 2088 | EXPORT_SYMBOL(d_genocide); |
2011 | 2089 | ||