aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/dir.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-07-25 11:28:18 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-09-22 23:24:28 -0400
commit1c3c07e9f6cc50dab2aeb8051325e317d4f6c70e (patch)
tree96bbc2a304e9a0e831daf589d1662c6129303796 /fs/nfs/dir.c
parent3eeab61aa3ddd3c0bedb7449ada1599de22fdb5a (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.c133
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
1641int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res) 1641static void nfs_access_free_entry(struct nfs_access_entry *entry)
1642{
1643 put_rpccred(entry->cred);
1644 kfree(entry);
1645}
1646
1647static 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
1654void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) 1672void 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) { 1679static 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
1697int 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;
1715out:
1716 spin_unlock(&inode->i_lock);
1717 return err;
1718out_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;
1723out_zap:
1724 /* This will release the spinlock */
1725 __nfs_access_zap_cache(inode);
1726 return -ENOENT;
1727}
1728
1729static 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;
1752found:
1753 rb_replace_node(parent, &set->rb_node, root_node);
1754 spin_unlock(&inode->i_lock);
1755 nfs_access_free_entry(entry);
1756}
1757
1758void 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
1672static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) 1771static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)