Skip to content

Commit

Permalink
NFS: Add an ACCESS cache memory shrinker
Browse files Browse the repository at this point in the history
A pinned inode may in theory end up filling memory with cached ACCESS
calls. This patch ensures that the VM may shrink away the cache in these
particular cases.
The shrinker works by iterating through the list of inodes on the global
nfs_access_lru_list, and removing the least recently used access
cache entry until it is done (or until the entire cache is empty).

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
Trond Myklebust authored and Trond Myklebust committed Sep 23, 2006
1 parent cfcea3e commit 979df72
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 0 deletions.
44 changes: 44 additions & 0 deletions fs/nfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1651,6 +1651,50 @@ static void nfs_access_free_entry(struct nfs_access_entry *entry)
smp_mb__after_atomic_dec();
}

int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask)
{
LIST_HEAD(head);
struct nfs_inode *nfsi;
struct nfs_access_entry *cache;

spin_lock(&nfs_access_lru_lock);
restart:
list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) {
struct inode *inode;

if (nr_to_scan-- == 0)
break;
inode = igrab(&nfsi->vfs_inode);
if (inode == NULL)
continue;
spin_lock(&inode->i_lock);
if (list_empty(&nfsi->access_cache_entry_lru))
goto remove_lru_entry;
cache = list_entry(nfsi->access_cache_entry_lru.next,
struct nfs_access_entry, lru);
list_move(&cache->lru, &head);
rb_erase(&cache->rb_node, &nfsi->access_cache);
if (!list_empty(&nfsi->access_cache_entry_lru))
list_move_tail(&nfsi->access_cache_inode_lru,
&nfs_access_lru_list);
else {
remove_lru_entry:
list_del_init(&nfsi->access_cache_inode_lru);
clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags);
}
spin_unlock(&inode->i_lock);
iput(inode);
goto restart;
}
spin_unlock(&nfs_access_lru_lock);
while (!list_empty(&head)) {
cache = list_entry(head.next, struct nfs_access_entry, lru);
list_del(&cache->lru);
nfs_access_free_entry(cache);
}
return (atomic_long_read(&nfs_access_nr_entries) / 100) * sysctl_vfs_cache_pressure;
}

static void __nfs_access_zap_cache(struct inode *inode)
{
struct nfs_inode *nfsi = NFS_I(inode);
Expand Down
3 changes: 3 additions & 0 deletions fs/nfs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ extern int nfs4_proc_fs_locations(struct inode *dir, struct dentry *dentry,
struct page *page);
#endif

/* dir.c */
extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask);

/* inode.c */
extern struct inode *nfs_alloc_inode(struct super_block *sb);
extern void nfs_destroy_inode(struct inode *);
Expand Down
5 changes: 5 additions & 0 deletions fs/nfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
&nfs_idmap_cache_timeout, 0644);
#endif

static struct shrinker *acl_shrinker;

/*
* Register the NFS filesystems
*/
Expand All @@ -240,6 +242,7 @@ int __init register_nfs_fs(void)
if (ret < 0)
goto error_2;
#endif
acl_shrinker = set_shrinker(DEFAULT_SEEKS, nfs_access_cache_shrinker);
return 0;

#ifdef CONFIG_NFS_V4
Expand All @@ -257,6 +260,8 @@ int __init register_nfs_fs(void)
*/
void __exit unregister_nfs_fs(void)
{
if (acl_shrinker != NULL)
remove_shrinker(acl_shrinker);
#ifdef CONFIG_NFS_V4
unregister_filesystem(&nfs4_fs_type);
nfs_unregister_sysctl();
Expand Down

0 comments on commit 979df72

Please sign in to comment.