aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/nfs/dir.c133
-rw-r--r--fs/nfs/inode.c13
-rw-r--r--include/linux/nfs_fs.h5
3 files changed, 124 insertions, 27 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)
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index d349fb2245da..b94ab060bb1e 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -76,19 +76,14 @@ int nfs_write_inode(struct inode *inode, int sync)
76 76
77void nfs_clear_inode(struct inode *inode) 77void nfs_clear_inode(struct inode *inode)
78{ 78{
79 struct nfs_inode *nfsi = NFS_I(inode);
80 struct rpc_cred *cred;
81
82 /* 79 /*
83 * The following should never happen... 80 * The following should never happen...
84 */ 81 */
85 BUG_ON(nfs_have_writebacks(inode)); 82 BUG_ON(nfs_have_writebacks(inode));
86 BUG_ON (!list_empty(&nfsi->open_files)); 83 BUG_ON(!list_empty(&NFS_I(inode)->open_files));
84 BUG_ON(atomic_read(&NFS_I(inode)->data_updates) != 0);
87 nfs_zap_acl_cache(inode); 85 nfs_zap_acl_cache(inode);
88 cred = nfsi->cache_access.cred; 86 nfs_access_zap_cache(inode);
89 if (cred)
90 put_rpccred(cred);
91 BUG_ON(atomic_read(&nfsi->data_updates) != 0);
92} 87}
93 88
94/** 89/**
@@ -290,7 +285,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
290 nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); 285 nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
291 nfsi->attrtimeo_timestamp = jiffies; 286 nfsi->attrtimeo_timestamp = jiffies;
292 memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); 287 memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
293 nfsi->cache_access.cred = NULL; 288 nfsi->access_cache = RB_ROOT;
294 289
295 unlock_new_inode(inode); 290 unlock_new_inode(inode);
296 } else 291 } else
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 6c2066caeaab..cc013ed2e52e 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -42,6 +42,7 @@
42#include <linux/in.h> 42#include <linux/in.h>
43#include <linux/mm.h> 43#include <linux/mm.h>
44#include <linux/pagemap.h> 44#include <linux/pagemap.h>
45#include <linux/rbtree.h>
45#include <linux/rwsem.h> 46#include <linux/rwsem.h>
46#include <linux/wait.h> 47#include <linux/wait.h>
47 48
@@ -69,6 +70,7 @@
69 * NFSv3/v4 Access mode cache entry 70 * NFSv3/v4 Access mode cache entry
70 */ 71 */
71struct nfs_access_entry { 72struct nfs_access_entry {
73 struct rb_node rb_node;
72 unsigned long jiffies; 74 unsigned long jiffies;
73 struct rpc_cred * cred; 75 struct rpc_cred * cred;
74 int mask; 76 int mask;
@@ -145,7 +147,7 @@ struct nfs_inode {
145 */ 147 */
146 atomic_t data_updates; 148 atomic_t data_updates;
147 149
148 struct nfs_access_entry cache_access; 150 struct rb_root access_cache;
149#ifdef CONFIG_NFS_V3_ACL 151#ifdef CONFIG_NFS_V3_ACL
150 struct posix_acl *acl_access; 152 struct posix_acl *acl_access;
151 struct posix_acl *acl_default; 153 struct posix_acl *acl_default;
@@ -297,6 +299,7 @@ extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
297extern int nfs_permission(struct inode *, int, struct nameidata *); 299extern int nfs_permission(struct inode *, int, struct nameidata *);
298extern int nfs_access_get_cached(struct inode *, struct rpc_cred *, struct nfs_access_entry *); 300extern int nfs_access_get_cached(struct inode *, struct rpc_cred *, struct nfs_access_entry *);
299extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *); 301extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
302extern void nfs_access_zap_cache(struct inode *inode);
300extern int nfs_open(struct inode *, struct file *); 303extern int nfs_open(struct inode *, struct file *);
301extern int nfs_release(struct inode *, struct file *); 304extern int nfs_release(struct inode *, struct file *);
302extern int nfs_attribute_timeout(struct inode *inode); 305extern int nfs_attribute_timeout(struct inode *inode);