Commit 5c6a9f7d authored by Andreas Gruenbacher's avatar Andreas Gruenbacher Committed by Trond Myklebust

[PATCH] NFS: Cache the NFSv3 acls.

 Attach acls to inodes in the icache to avoid unnecessary GETACL RPC
 round-trips.  As long as the client doesn't retrieve any acls itself, only the
 default acls of exiting directories and the default and access acls of new
 directories will end up in the cache, which preserves some memory compared to
 always caching the access and default acl of all files.
Signed-off-by: default avatarAndreas Gruenbacher <agruen@suse.de>
Acked-by: default avatarOlaf Kirch <okir@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 055ffbea
...@@ -113,6 +113,69 @@ int nfs3_removexattr(struct dentry *dentry, const char *name) ...@@ -113,6 +113,69 @@ int nfs3_removexattr(struct dentry *dentry, const char *name)
return nfs3_proc_setacl(inode, type, NULL); return nfs3_proc_setacl(inode, type, NULL);
} }
static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi)
{
if (nfsi->acl_access != ERR_PTR(-EAGAIN)) {
posix_acl_release(nfsi->acl_access);
nfsi->acl_access = ERR_PTR(-EAGAIN);
}
if (nfsi->acl_default != ERR_PTR(-EAGAIN)) {
posix_acl_release(nfsi->acl_default);
nfsi->acl_default = ERR_PTR(-EAGAIN);
}
}
void nfs3_forget_cached_acls(struct inode *inode)
{
dprintk("NFS: nfs3_forget_cached_acls(%s/%ld)\n", inode->i_sb->s_id,
inode->i_ino);
spin_lock(&inode->i_lock);
__nfs3_forget_cached_acls(NFS_I(inode));
spin_unlock(&inode->i_lock);
}
static struct posix_acl *nfs3_get_cached_acl(struct inode *inode, int type)
{
struct nfs_inode *nfsi = NFS_I(inode);
struct posix_acl *acl = ERR_PTR(-EAGAIN);
spin_lock(&inode->i_lock);
switch(type) {
case ACL_TYPE_ACCESS:
acl = nfsi->acl_access;
break;
case ACL_TYPE_DEFAULT:
acl = nfsi->acl_default;
break;
default:
return ERR_PTR(-EINVAL);
}
if (acl == ERR_PTR(-EAGAIN))
acl = ERR_PTR(-EAGAIN);
else
acl = posix_acl_dup(acl);
spin_unlock(&inode->i_lock);
dprintk("NFS: nfs3_get_cached_acl(%s/%ld, %d) = %p\n", inode->i_sb->s_id,
inode->i_ino, type, acl);
return acl;
}
static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl,
struct posix_acl *dfacl)
{
struct nfs_inode *nfsi = NFS_I(inode);
dprintk("nfs3_cache_acls(%s/%ld, %p, %p)\n", inode->i_sb->s_id,
inode->i_ino, acl, dfacl);
spin_lock(&inode->i_lock);
__nfs3_forget_cached_acls(NFS_I(inode));
nfsi->acl_access = posix_acl_dup(acl);
nfsi->acl_default = posix_acl_dup(dfacl);
spin_unlock(&inode->i_lock);
}
struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
{ {
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
...@@ -126,26 +189,32 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) ...@@ -126,26 +189,32 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
struct nfs3_getaclres res = { struct nfs3_getaclres res = {
.fattr = &fattr, .fattr = &fattr,
}; };
struct posix_acl *acl = NULL; struct posix_acl *acl;
int status, count; int status, count;
if (!nfs_server_capable(inode, NFS_CAP_ACLS)) if (!nfs_server_capable(inode, NFS_CAP_ACLS))
return ERR_PTR(-EOPNOTSUPP); return ERR_PTR(-EOPNOTSUPP);
switch (type) { status = nfs_revalidate_inode(server, inode);
case ACL_TYPE_ACCESS: if (status < 0)
args.mask = NFS_ACLCNT|NFS_ACL; return ERR_PTR(status);
break; acl = nfs3_get_cached_acl(inode, type);
if (acl != ERR_PTR(-EAGAIN))
case ACL_TYPE_DEFAULT: return acl;
if (!S_ISDIR(inode->i_mode)) acl = NULL;
/*
* Only get the access acl when explicitly requested: We don't
* need it for access decisions, and only some applications use
* it. Applications which request the access acl first are not
* penalized from this optimization.
*/
if (type == ACL_TYPE_ACCESS)
args.mask |= NFS_ACLCNT|NFS_ACL;
if (S_ISDIR(inode->i_mode))
args.mask |= NFS_DFACLCNT|NFS_DFACL;
if (args.mask == 0)
return NULL; return NULL;
args.mask = NFS_DFACLCNT|NFS_DFACL;
break;
default:
return ERR_PTR(-EINVAL);
}
dprintk("NFS call getacl\n"); dprintk("NFS call getacl\n");
status = rpc_call(server->client_acl, ACLPROC3_GETACL, status = rpc_call(server->client_acl, ACLPROC3_GETACL,
...@@ -180,6 +249,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type) ...@@ -180,6 +249,7 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
res.acl_access = NULL; res.acl_access = NULL;
} }
} }
nfs3_cache_acls(inode, res.acl_access, res.acl_default);
switch(type) { switch(type) {
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
......
...@@ -882,4 +882,5 @@ struct nfs_rpc_ops nfs_v3_clientops = { ...@@ -882,4 +882,5 @@ struct nfs_rpc_ops nfs_v3_clientops = {
.file_open = nfs_open, .file_open = nfs_open,
.file_release = nfs_release, .file_release = nfs_release,
.lock = nfs3_proc_lock, .lock = nfs3_proc_lock,
.clear_acl_cache = nfs3_forget_cached_acls,
}; };
...@@ -91,6 +91,8 @@ struct nfs_open_context { ...@@ -91,6 +91,8 @@ struct nfs_open_context {
*/ */
struct nfs_delegation; struct nfs_delegation;
struct posix_acl;
/* /*
* nfs fs inode data in memory * nfs fs inode data in memory
*/ */
...@@ -144,6 +146,10 @@ struct nfs_inode { ...@@ -144,6 +146,10 @@ struct nfs_inode {
atomic_t data_updates; atomic_t data_updates;
struct nfs_access_entry cache_access; struct nfs_access_entry cache_access;
#ifdef CONFIG_NFS_V3_ACL
struct posix_acl *acl_access;
struct posix_acl *acl_default;
#endif
/* /*
* This is the cookie verifier used for NFSv3 readdir * This is the cookie verifier used for NFSv3 readdir
...@@ -480,6 +486,7 @@ extern int nfs3_proc_setacl(struct inode *inode, int type, ...@@ -480,6 +486,7 @@ extern int nfs3_proc_setacl(struct inode *inode, int type,
struct posix_acl *acl); struct posix_acl *acl);
extern int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode, extern int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode,
mode_t mode); mode_t mode);
extern void nfs3_forget_cached_acls(struct inode *inode);
#else #else
static inline int nfs3_proc_set_default_acl(struct inode *dir, static inline int nfs3_proc_set_default_acl(struct inode *dir,
struct inode *inode, struct inode *inode,
...@@ -487,6 +494,10 @@ static inline int nfs3_proc_set_default_acl(struct inode *dir, ...@@ -487,6 +494,10 @@ static inline int nfs3_proc_set_default_acl(struct inode *dir,
{ {
return 0; return 0;
} }
static inline void nfs3_forget_cached_acls(struct inode *inode)
{
}
#endif /* CONFIG_NFS_V3_ACL */ #endif /* CONFIG_NFS_V3_ACL */
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment