Commit 7b8b44eb authored by Trond Myklebust's avatar Trond Myklebust Committed by Anna Schumaker

NFSv4: Specify the type of ACL to cache

When caching a NFSv4 ACL, we want to specify whether we are caching an
NFSv4.0 type acl, the NFSv4.1 dacl or the NFSv4.1 sacl.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent 69494938
...@@ -5772,9 +5772,17 @@ static int nfs4_proc_renew(struct nfs_client *clp, const struct cred *cred) ...@@ -5772,9 +5772,17 @@ static int nfs4_proc_renew(struct nfs_client *clp, const struct cred *cred)
return 0; return 0;
} }
static inline int nfs4_server_supports_acls(struct nfs_server *server) static bool nfs4_server_supports_acls(const struct nfs_server *server,
enum nfs4_acl_type type)
{ {
return server->caps & NFS_CAP_ACLS; switch (type) {
default:
return server->attr_bitmask[0] & FATTR4_WORD0_ACL;
case NFS4ACL_DACL:
return server->attr_bitmask[1] & FATTR4_WORD1_DACL;
case NFS4ACL_SACL:
return server->attr_bitmask[1] & FATTR4_WORD1_SACL;
}
} }
/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that /* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that
...@@ -5813,6 +5821,7 @@ int nfs4_buf_to_pages_noslab(const void *buf, size_t buflen, ...@@ -5813,6 +5821,7 @@ int nfs4_buf_to_pages_noslab(const void *buf, size_t buflen,
} }
struct nfs4_cached_acl { struct nfs4_cached_acl {
enum nfs4_acl_type type;
int cached; int cached;
size_t len; size_t len;
char data[]; char data[];
...@@ -5833,7 +5842,8 @@ static void nfs4_zap_acl_attr(struct inode *inode) ...@@ -5833,7 +5842,8 @@ static void nfs4_zap_acl_attr(struct inode *inode)
nfs4_set_cached_acl(inode, NULL); nfs4_set_cached_acl(inode, NULL);
} }
static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_t buflen) static ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf,
size_t buflen, enum nfs4_acl_type type)
{ {
struct nfs_inode *nfsi = NFS_I(inode); struct nfs_inode *nfsi = NFS_I(inode);
struct nfs4_cached_acl *acl; struct nfs4_cached_acl *acl;
...@@ -5843,6 +5853,8 @@ static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_ ...@@ -5843,6 +5853,8 @@ static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_
acl = nfsi->nfs4_acl; acl = nfsi->nfs4_acl;
if (acl == NULL) if (acl == NULL)
goto out; goto out;
if (acl->type != type)
goto out;
if (buf == NULL) /* user is just asking for length */ if (buf == NULL) /* user is just asking for length */
goto out_len; goto out_len;
if (acl->cached == 0) if (acl->cached == 0)
...@@ -5858,7 +5870,9 @@ static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_ ...@@ -5858,7 +5870,9 @@ static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_
return ret; return ret;
} }
static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len) static void nfs4_write_cached_acl(struct inode *inode, struct page **pages,
size_t pgbase, size_t acl_len,
enum nfs4_acl_type type)
{ {
struct nfs4_cached_acl *acl; struct nfs4_cached_acl *acl;
size_t buflen = sizeof(*acl) + acl_len; size_t buflen = sizeof(*acl) + acl_len;
...@@ -5875,6 +5889,7 @@ static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size ...@@ -5875,6 +5889,7 @@ static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size
goto out; goto out;
acl->cached = 0; acl->cached = 0;
} }
acl->type = type;
acl->len = acl_len; acl->len = acl_len;
out: out:
nfs4_set_cached_acl(inode, acl); nfs4_set_cached_acl(inode, acl);
...@@ -5890,7 +5905,8 @@ static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size ...@@ -5890,7 +5905,8 @@ static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size
* length. The next getxattr call will then produce another round trip to * length. The next getxattr call will then produce another round trip to
* the server, this time with the input buf of the required size. * the server, this time with the input buf of the required size.
*/ */
static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf,
size_t buflen, enum nfs4_acl_type type)
{ {
struct page **pages; struct page **pages;
struct nfs_getaclargs args = { struct nfs_getaclargs args = {
...@@ -5947,7 +5963,8 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu ...@@ -5947,7 +5963,8 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
ret = -ERANGE; ret = -ERANGE;
goto out_free; goto out_free;
} }
nfs4_write_cached_acl(inode, pages, res.acl_data_offset, res.acl_len); nfs4_write_cached_acl(inode, pages, res.acl_data_offset, res.acl_len,
type);
if (buf) { if (buf) {
if (res.acl_len > buflen) { if (res.acl_len > buflen) {
ret = -ERANGE; ret = -ERANGE;
...@@ -5967,14 +5984,15 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu ...@@ -5967,14 +5984,15 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
return ret; return ret;
} }
static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf,
size_t buflen, enum nfs4_acl_type type)
{ {
struct nfs4_exception exception = { struct nfs4_exception exception = {
.interruptible = true, .interruptible = true,
}; };
ssize_t ret; ssize_t ret;
do { do {
ret = __nfs4_get_acl_uncached(inode, buf, buflen); ret = __nfs4_get_acl_uncached(inode, buf, buflen, type);
trace_nfs4_get_acl(inode, ret); trace_nfs4_get_acl(inode, ret);
if (ret >= 0) if (ret >= 0)
break; break;
...@@ -5983,27 +6001,29 @@ static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bufl ...@@ -5983,27 +6001,29 @@ static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bufl
return ret; return ret;
} }
static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen,
enum nfs4_acl_type type)
{ {
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
int ret; int ret;
if (!nfs4_server_supports_acls(server)) if (!nfs4_server_supports_acls(server, type))
return -EOPNOTSUPP; return -EOPNOTSUPP;
ret = nfs_revalidate_inode(inode, NFS_INO_INVALID_CHANGE); ret = nfs_revalidate_inode(inode, NFS_INO_INVALID_CHANGE);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
nfs_zap_acl_cache(inode); nfs_zap_acl_cache(inode);
ret = nfs4_read_cached_acl(inode, buf, buflen); ret = nfs4_read_cached_acl(inode, buf, buflen, type);
if (ret != -ENOENT) if (ret != -ENOENT)
/* -ENOENT is returned if there is no ACL or if there is an ACL /* -ENOENT is returned if there is no ACL or if there is an ACL
* but no cached acl data, just the acl length */ * but no cached acl data, just the acl length */
return ret; return ret;
return nfs4_get_acl_uncached(inode, buf, buflen); return nfs4_get_acl_uncached(inode, buf, buflen, type);
} }
static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen) static int __nfs4_proc_set_acl(struct inode *inode, const void *buf,
size_t buflen, enum nfs4_acl_type type)
{ {
struct nfs_server *server = NFS_SERVER(inode); struct nfs_server *server = NFS_SERVER(inode);
struct page *pages[NFS4ACL_MAXPAGES]; struct page *pages[NFS4ACL_MAXPAGES];
...@@ -6024,7 +6044,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl ...@@ -6024,7 +6044,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
/* You can't remove system.nfs4_acl: */ /* You can't remove system.nfs4_acl: */
if (buflen == 0) if (buflen == 0)
return -EINVAL; return -EINVAL;
if (!nfs4_server_supports_acls(server)) if (!nfs4_server_supports_acls(server, type))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (npages > ARRAY_SIZE(pages)) if (npages > ARRAY_SIZE(pages))
return -ERANGE; return -ERANGE;
...@@ -6055,12 +6075,13 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl ...@@ -6055,12 +6075,13 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
return ret; return ret;
} }
static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen) static int nfs4_proc_set_acl(struct inode *inode, const void *buf,
size_t buflen, enum nfs4_acl_type type)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = { };
int err; int err;
do { do {
err = __nfs4_proc_set_acl(inode, buf, buflen); err = __nfs4_proc_set_acl(inode, buf, buflen, type);
trace_nfs4_set_acl(inode, err); trace_nfs4_set_acl(inode, err);
if (err == -NFS4ERR_BADOWNER || err == -NFS4ERR_BADNAME) { if (err == -NFS4ERR_BADOWNER || err == -NFS4ERR_BADNAME) {
/* /*
...@@ -7659,19 +7680,19 @@ static int nfs4_xattr_set_nfs4_acl(const struct xattr_handler *handler, ...@@ -7659,19 +7680,19 @@ static int nfs4_xattr_set_nfs4_acl(const struct xattr_handler *handler,
const char *key, const void *buf, const char *key, const void *buf,
size_t buflen, int flags) size_t buflen, int flags)
{ {
return nfs4_proc_set_acl(inode, buf, buflen); return nfs4_proc_set_acl(inode, buf, buflen, NFS4ACL_ACL);
} }
static int nfs4_xattr_get_nfs4_acl(const struct xattr_handler *handler, static int nfs4_xattr_get_nfs4_acl(const struct xattr_handler *handler,
struct dentry *unused, struct inode *inode, struct dentry *unused, struct inode *inode,
const char *key, void *buf, size_t buflen) const char *key, void *buf, size_t buflen)
{ {
return nfs4_proc_get_acl(inode, buf, buflen); return nfs4_proc_get_acl(inode, buf, buflen, NFS4ACL_ACL);
} }
static bool nfs4_xattr_list_nfs4_acl(struct dentry *dentry) static bool nfs4_xattr_list_nfs4_acl(struct dentry *dentry)
{ {
return nfs4_server_supports_acls(NFS_SERVER(d_inode(dentry))); return nfs4_server_supports_acls(NFS_SB(dentry->d_sb), NFS4ACL_ACL);
} }
#ifdef CONFIG_NFS_V4_SECURITY_LABEL #ifdef CONFIG_NFS_V4_SECURITY_LABEL
......
...@@ -451,6 +451,8 @@ enum lock_type4 { ...@@ -451,6 +451,8 @@ enum lock_type4 {
#define FATTR4_WORD1_TIME_MODIFY (1UL << 21) #define FATTR4_WORD1_TIME_MODIFY (1UL << 21)
#define FATTR4_WORD1_TIME_MODIFY_SET (1UL << 22) #define FATTR4_WORD1_TIME_MODIFY_SET (1UL << 22)
#define FATTR4_WORD1_MOUNTED_ON_FILEID (1UL << 23) #define FATTR4_WORD1_MOUNTED_ON_FILEID (1UL << 23)
#define FATTR4_WORD1_DACL (1UL << 26)
#define FATTR4_WORD1_SACL (1UL << 27)
#define FATTR4_WORD1_FS_LAYOUT_TYPES (1UL << 30) #define FATTR4_WORD1_FS_LAYOUT_TYPES (1UL << 30)
#define FATTR4_WORD2_LAYOUT_TYPES (1UL << 0) #define FATTR4_WORD2_LAYOUT_TYPES (1UL << 0)
#define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1) #define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1)
......
...@@ -800,6 +800,13 @@ struct nfs_setattrargs { ...@@ -800,6 +800,13 @@ struct nfs_setattrargs {
const struct nfs4_label *label; const struct nfs4_label *label;
}; };
enum nfs4_acl_type {
NFS4ACL_NONE = 0,
NFS4ACL_ACL,
NFS4ACL_DACL,
NFS4ACL_SACL,
};
struct nfs_setaclargs { struct nfs_setaclargs {
struct nfs4_sequence_args seq_args; struct nfs4_sequence_args seq_args;
struct nfs_fh * fh; struct nfs_fh * fh;
......
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