diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-07-25 11:28:18 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-09-22 23:24:28 -0400 |
commit | 1c3c07e9f6cc50dab2aeb8051325e317d4f6c70e (patch) | |
tree | 96bbc2a304e9a0e831daf589d1662c6129303796 /fs/nfs/dir.c | |
parent | 3eeab61aa3ddd3c0bedb7449ada1599de22fdb5a (diff) |
NFS: Add a new ACCESS rpc call cache to the linux nfs client
The current access cache only allows one entry at a time to be cached for each
inode. Add a per-inode red-black tree in order to allow more than one to
be cached at a time.
Should significantly cut down the time spent in path traversal for shared
directories such as ${PATH}, /usr/share, etc.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/dir.c')
-rw-r--r-- | fs/nfs/dir.c | 133 |
1 files changed, 116 insertions, 17 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index e7ffb4deb3e5..094afded2b11 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -1638,35 +1638,134 @@ out: | |||
1638 | return error; | 1638 | return error; |
1639 | } | 1639 | } |
1640 | 1640 | ||
1641 | int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res) | 1641 | static void nfs_access_free_entry(struct nfs_access_entry *entry) |
1642 | { | ||
1643 | put_rpccred(entry->cred); | ||
1644 | kfree(entry); | ||
1645 | } | ||
1646 | |||
1647 | static void __nfs_access_zap_cache(struct inode *inode) | ||
1642 | { | 1648 | { |
1643 | struct nfs_inode *nfsi = NFS_I(inode); | 1649 | struct nfs_inode *nfsi = NFS_I(inode); |
1644 | struct nfs_access_entry *cache = &nfsi->cache_access; | 1650 | struct rb_root *root_node = &nfsi->access_cache; |
1651 | struct rb_node *n, *dispose = NULL; | ||
1652 | struct nfs_access_entry *entry; | ||
1653 | |||
1654 | /* Unhook entries from the cache */ | ||
1655 | while ((n = rb_first(root_node)) != NULL) { | ||
1656 | entry = rb_entry(n, struct nfs_access_entry, rb_node); | ||
1657 | rb_erase(n, root_node); | ||
1658 | n->rb_left = dispose; | ||
1659 | dispose = n; | ||
1660 | } | ||
1661 | nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS; | ||
1662 | spin_unlock(&inode->i_lock); | ||
1645 | 1663 | ||
1646 | if (cache->cred != cred | 1664 | /* Now kill them all! */ |
1647 | || time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode)) | 1665 | while (dispose != NULL) { |
1648 | || (nfsi->cache_validity & NFS_INO_INVALID_ACCESS)) | 1666 | n = dispose; |
1649 | return -ENOENT; | 1667 | dispose = n->rb_left; |
1650 | memcpy(res, cache, sizeof(*res)); | 1668 | nfs_access_free_entry(rb_entry(n, struct nfs_access_entry, rb_node)); |
1651 | return 0; | 1669 | } |
1652 | } | 1670 | } |
1653 | 1671 | ||
1654 | void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) | 1672 | void nfs_access_zap_cache(struct inode *inode) |
1655 | { | 1673 | { |
1656 | struct nfs_inode *nfsi = NFS_I(inode); | 1674 | spin_lock(&inode->i_lock); |
1657 | struct nfs_access_entry *cache = &nfsi->cache_access; | 1675 | /* This will release the spinlock */ |
1676 | __nfs_access_zap_cache(inode); | ||
1677 | } | ||
1658 | 1678 | ||
1659 | if (cache->cred != set->cred) { | 1679 | static struct nfs_access_entry *nfs_access_search_rbtree(struct inode *inode, struct rpc_cred *cred) |
1660 | if (cache->cred) | 1680 | { |
1661 | put_rpccred(cache->cred); | 1681 | struct rb_node *n = NFS_I(inode)->access_cache.rb_node; |
1662 | cache->cred = get_rpccred(set->cred); | 1682 | struct nfs_access_entry *entry; |
1683 | |||
1684 | while (n != NULL) { | ||
1685 | entry = rb_entry(n, struct nfs_access_entry, rb_node); | ||
1686 | |||
1687 | if (cred < entry->cred) | ||
1688 | n = n->rb_left; | ||
1689 | else if (cred > entry->cred) | ||
1690 | n = n->rb_right; | ||
1691 | else | ||
1692 | return entry; | ||
1663 | } | 1693 | } |
1664 | /* FIXME: replace current access_cache BKL reliance with inode->i_lock */ | 1694 | return NULL; |
1695 | } | ||
1696 | |||
1697 | int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res) | ||
1698 | { | ||
1699 | struct nfs_inode *nfsi = NFS_I(inode); | ||
1700 | struct nfs_access_entry *cache; | ||
1701 | int err = -ENOENT; | ||
1702 | |||
1665 | spin_lock(&inode->i_lock); | 1703 | spin_lock(&inode->i_lock); |
1666 | nfsi->cache_validity &= ~NFS_INO_INVALID_ACCESS; | 1704 | if (nfsi->cache_validity & NFS_INO_INVALID_ACCESS) |
1705 | goto out_zap; | ||
1706 | cache = nfs_access_search_rbtree(inode, cred); | ||
1707 | if (cache == NULL) | ||
1708 | goto out; | ||
1709 | if (time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))) | ||
1710 | goto out_stale; | ||
1711 | res->jiffies = cache->jiffies; | ||
1712 | res->cred = cache->cred; | ||
1713 | res->mask = cache->mask; | ||
1714 | err = 0; | ||
1715 | out: | ||
1716 | spin_unlock(&inode->i_lock); | ||
1717 | return err; | ||
1718 | out_stale: | ||
1719 | rb_erase(&cache->rb_node, &nfsi->access_cache); | ||
1720 | spin_unlock(&inode->i_lock); | ||
1721 | nfs_access_free_entry(cache); | ||
1722 | return -ENOENT; | ||
1723 | out_zap: | ||
1724 | /* This will release the spinlock */ | ||
1725 | __nfs_access_zap_cache(inode); | ||
1726 | return -ENOENT; | ||
1727 | } | ||
1728 | |||
1729 | static void nfs_access_add_rbtree(struct inode *inode, struct nfs_access_entry *set) | ||
1730 | { | ||
1731 | struct rb_root *root_node = &NFS_I(inode)->access_cache; | ||
1732 | struct rb_node **p = &root_node->rb_node; | ||
1733 | struct rb_node *parent = NULL; | ||
1734 | struct nfs_access_entry *entry; | ||
1735 | |||
1736 | spin_lock(&inode->i_lock); | ||
1737 | while (*p != NULL) { | ||
1738 | parent = *p; | ||
1739 | entry = rb_entry(parent, struct nfs_access_entry, rb_node); | ||
1740 | |||
1741 | if (set->cred < entry->cred) | ||
1742 | p = &parent->rb_left; | ||
1743 | else if (set->cred > entry->cred) | ||
1744 | p = &parent->rb_right; | ||
1745 | else | ||
1746 | goto found; | ||
1747 | } | ||
1748 | rb_link_node(&set->rb_node, parent, p); | ||
1749 | rb_insert_color(&set->rb_node, root_node); | ||
1667 | spin_unlock(&inode->i_lock); | 1750 | spin_unlock(&inode->i_lock); |
1751 | return; | ||
1752 | found: | ||
1753 | rb_replace_node(parent, &set->rb_node, root_node); | ||
1754 | spin_unlock(&inode->i_lock); | ||
1755 | nfs_access_free_entry(entry); | ||
1756 | } | ||
1757 | |||
1758 | void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) | ||
1759 | { | ||
1760 | struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL); | ||
1761 | if (cache == NULL) | ||
1762 | return; | ||
1763 | RB_CLEAR_NODE(&cache->rb_node); | ||
1668 | cache->jiffies = set->jiffies; | 1764 | cache->jiffies = set->jiffies; |
1765 | cache->cred = get_rpccred(set->cred); | ||
1669 | cache->mask = set->mask; | 1766 | cache->mask = set->mask; |
1767 | |||
1768 | nfs_access_add_rbtree(inode, cache); | ||
1670 | } | 1769 | } |
1671 | 1770 | ||
1672 | static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) | 1771 | static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) |