From: Trond Myklebust Date: Mon, 13 Aug 2007 08:02:31 -0400 Subject: NFS: Add an NFS version specific permission() method. Signed-off-by: Trond Myklebust --- fs/nfs/dir.c | 45 +++++++++++++++++++++++++++------------------ fs/nfs/nfs3proc.c | 7 +++++++ fs/nfs/nfs4proc.c | 7 +++++++ fs/nfs/proc.c | 16 +++++++++++++++- include/linux/nfs_fs.h | 1 + include/linux/nfs_xdr.h | 1 + 6 files changed, 58 insertions(+), 19 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index a968acb..6364c06 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1906,14 +1906,32 @@ static int nfs_do_uncached_access(struct inode *inode, struct rpc_cred *cred, in return nfs_access_to_permission(&cache, mask); } -static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) +/** + * nfs_generic_permission - check permissions if the server supports ACCESS + * @inode: inode to check + * @cred: rpc credentials of caller + * @mask: permissions mask + * @force_reval: flag to force a revalidation of the cache + */ +int nfs_generic_permission(struct inode *inode, struct rpc_cred *cred, + int mask, int force_reval) { - int status; + int err, ret; - status = nfs_do_cached_access(inode, cred, mask); - if (status == 0 || status == -EACCES) - return status; - return nfs_do_uncached_access(inode, cred, mask); + ret = nfs_do_cached_access(inode, cred, mask); + if (ret == 0 || ret == -EACCES) { + if (!force_reval) + goto out; + err = __nfs_revalidate_inode(NFS_SERVER(inode), inode); + if (err < 0) + return err; + if (!(NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACCESS)) + goto out; + } + + ret = nfs_do_uncached_access(inode, cred, mask); +out: + return ret; } static int nfs_open_permission_mask(int openflags) @@ -1931,7 +1949,8 @@ static int nfs_open_permission_mask(int openflags) int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags) { - return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags)); + return NFS_PROTO(inode)->permission(inode, cred, + nfs_open_permission_mask(openflags), 0); } int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) @@ -1968,13 +1987,9 @@ int nfs_permission(struct inode *inode, int mask, struct nameidata *nd) force_lookup: lock_kernel(); - - if (!NFS_PROTO(inode)->access) - goto out_notsup; - cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); if (!IS_ERR(cred)) { - res = nfs_do_access(inode, cred, mask); + res = NFS_PROTO(inode)->permission(inode, cred, mask, 0); put_rpccred(cred); } else res = PTR_ERR(cred); @@ -1983,12 +1998,6 @@ out: dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d\n", inode->i_sb->s_id, inode->i_ino, mask, res); return res; -out_notsup: - res = nfs_revalidate_inode(NFS_SERVER(inode), inode); - if (res == 0) - res = generic_permission(inode, mask, NULL); - unlock_kernel(); - goto out; } /* diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 02ae784..0a0bf06 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -177,6 +177,12 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name, return status; } +static int nfs3_proc_permission(struct inode *inode, struct rpc_cred *cred, + int mask, int force_reval) +{ + return nfs_generic_permission(inode, cred, mask, force_reval); +} + static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry, struct nfs_fattr *fattr) { struct nfs3_accessargs arg = { @@ -777,6 +783,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = { .getattr = nfs3_proc_getattr, .setattr = nfs3_proc_setattr, .lookup = nfs3_proc_lookup, + .permission = nfs3_proc_permission, .access = nfs3_proc_access, .readlink = nfs3_proc_readlink, .create = nfs3_proc_create, diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7a8d505..bf47637 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1751,6 +1751,12 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh return err; } +static int nfs4_proc_permission(struct inode *inode, struct rpc_cred *cred, + int mask, int force_reval) +{ + return nfs_generic_permission(inode, cred, mask, force_reval); +} + static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry, struct nfs_fattr *fattr) { struct nfs_server *server = NFS_SERVER(inode); @@ -3710,6 +3716,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = { .setattr = nfs4_proc_setattr, .lookupfh = nfs4_proc_lookupfh, .lookup = nfs4_proc_lookup, + .permission = nfs4_proc_permission, .access = nfs4_proc_access, .readlink = nfs4_proc_readlink, .create = nfs4_proc_create, diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index c9f46a2..a57b324 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -164,6 +164,20 @@ nfs_proc_lookup(struct inode *dir, struct qstr *name, return status; } +static int nfs_proc_permission(struct inode *inode, struct rpc_cred *cred, + int mask, int force_reval) +{ + int ret; + + if (force_reval) + ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode); + else + ret = nfs_revalidate_inode(NFS_SERVER(inode), inode); + if (ret < 0) + return ret; + return generic_permission(inode, mask, NULL); +} + static int nfs_proc_readlink(struct inode *inode, struct page *page, unsigned int pgbase, unsigned int pglen) { @@ -606,7 +620,7 @@ const struct nfs_rpc_ops nfs_v2_clientops = { .getattr = nfs_proc_getattr, .setattr = nfs_proc_setattr, .lookup = nfs_proc_lookup, - .access = NULL, /* access */ + .permission = nfs_proc_permission, .readlink = nfs_proc_readlink, .create = nfs_proc_create, .remove = nfs_proc_remove, diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 7095aaa..c15c68a 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -370,6 +370,7 @@ extern void nfs_force_lookup_revalidate(struct inode *dir); extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr); extern int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags); extern void nfs_access_zap_cache(struct inode *inode); +extern int nfs_generic_permission(struct inode *inode, struct rpc_cred *cred, int mask, int force_reval); /* * linux/fs/nfs/symlink.c diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 0bb40f7..1602549 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -789,6 +789,7 @@ struct nfs_rpc_ops { struct iattr *); int (*lookup) (struct inode *, struct qstr *, struct nfs_fh *, struct nfs_fattr *); + int (*permission) (struct inode *, struct rpc_cred *, int, int); int (*access) (struct inode *, struct nfs_access_entry *, struct nfs_fattr *); int (*readlink)(struct inode *, struct page *, unsigned int,