aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/nfs4proc.c69
1 files changed, 65 insertions, 4 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 1b14d17ae9a4..c91c09938a55 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2162,6 +2162,60 @@ nfs4_proc_file_release(struct inode *inode, struct file *filp)
2162 return 0; 2162 return 0;
2163} 2163}
2164 2164
2165static inline int nfs4_server_supports_acls(struct nfs_server *server)
2166{
2167 return (server->caps & NFS_CAP_ACLS)
2168 && (server->acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
2169 && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL);
2170}
2171
2172/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_CACHE_SIZE, and that
2173 * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_CACHE_SIZE) bytes on
2174 * the stack.
2175 */
2176#define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT)
2177
2178static void buf_to_pages(const void *buf, size_t buflen,
2179 struct page **pages, unsigned int *pgbase)
2180{
2181 const void *p = buf;
2182
2183 *pgbase = offset_in_page(buf);
2184 p -= *pgbase;
2185 while (p < buf + buflen) {
2186 *(pages++) = virt_to_page(p);
2187 p += PAGE_CACHE_SIZE;
2188 }
2189}
2190
2191static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
2192{
2193 struct nfs_server *server = NFS_SERVER(inode);
2194 struct page *pages[NFS4ACL_MAXPAGES];
2195 struct nfs_getaclargs args = {
2196 .fh = NFS_FH(inode),
2197 .acl_pages = pages,
2198 .acl_len = buflen,
2199 };
2200 size_t resp_len = buflen;
2201 struct rpc_message msg = {
2202 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL],
2203 .rpc_argp = &args,
2204 .rpc_resp = &resp_len,
2205 };
2206 int ret;
2207
2208 if (!nfs4_server_supports_acls(server))
2209 return -EOPNOTSUPP;
2210 buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase);
2211 ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
2212 if (buflen && resp_len > buflen)
2213 return -ERANGE;
2214 if (ret == 0)
2215 ret = resp_len;
2216 return ret;
2217}
2218
2165static int 2219static int
2166nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) 2220nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server)
2167{ 2221{
@@ -2733,6 +2787,8 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
2733} 2787}
2734 2788
2735 2789
2790#define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
2791
2736int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, 2792int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf,
2737 size_t buflen, int flags) 2793 size_t buflen, int flags)
2738{ 2794{
@@ -2746,18 +2802,23 @@ int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf,
2746ssize_t nfs4_getxattr(struct dentry *dentry, const char *key, void *buf, 2802ssize_t nfs4_getxattr(struct dentry *dentry, const char *key, void *buf,
2747 size_t buflen) 2803 size_t buflen)
2748{ 2804{
2749 return -EOPNOTSUPP; 2805 struct inode *inode = dentry->d_inode;
2806
2807 if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0)
2808 return -EOPNOTSUPP;
2809
2810 return nfs4_proc_get_acl(inode, buf, buflen);
2750} 2811}
2751 2812
2752ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) 2813ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
2753{ 2814{
2754 ssize_t len = 0; 2815 size_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1;
2755 2816
2756 if (buf && buflen < len) 2817 if (buf && buflen < len)
2757 return -ERANGE; 2818 return -ERANGE;
2758 if (buf) 2819 if (buf)
2759 memcpy(buf, "", 0); 2820 memcpy(buf, XATTR_NAME_NFSV4_ACL, len);
2760 return 0; 2821 return len;
2761} 2822}
2762 2823
2763struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { 2824struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = {