diff options
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/nfs4proc.c | 69 |
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 | ||
2165 | static 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 | |||
2178 | static 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 | |||
2191 | static 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 | |||
2165 | static int | 2219 | static int |
2166 | nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server) | 2220 | nfs4_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 | |||
2736 | int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf, | 2792 | int 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, | |||
2746 | ssize_t nfs4_getxattr(struct dentry *dentry, const char *key, void *buf, | 2802 | ssize_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 | ||
2752 | ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen) | 2813 | ssize_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 | ||
2763 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 2824 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { |