NFSv4.2: hook in the user extended attribute handlers
authorFrank van der Linden <fllinden@amazon.com>
Tue, 23 Jun 2020 22:39:03 +0000 (22:39 +0000)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Mon, 13 Jul 2020 21:52:45 +0000 (17:52 -0400)
Now that all the lower level code is there to make the RPC calls, hook
it in to the xattr handlers and the listxattr entry point, to make them
available.

Signed-off-by: Frank van der Linden <fllinden@amazon.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/nfs4proc.c

index 0fbd292..92a0795 100644 (file)
@@ -66,6 +66,7 @@
 #include "nfs4idmap.h"
 #include "nfs4session.h"
 #include "fscache.h"
+#include "nfs42.h"
 
 #include "nfs4trace.h"
 
@@ -7440,6 +7441,103 @@ nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
 
 #endif
 
+#ifdef CONFIG_NFS_V4_2
+static int nfs4_xattr_set_nfs4_user(const struct xattr_handler *handler,
+                                   struct dentry *unused, struct inode *inode,
+                                   const char *key, const void *buf,
+                                   size_t buflen, int flags)
+{
+       struct nfs_access_entry cache;
+
+       if (!nfs_server_capable(inode, NFS_CAP_XATTR))
+               return -EOPNOTSUPP;
+
+       /*
+        * There is no mapping from the MAY_* flags to the NFS_ACCESS_XA*
+        * flags right now. Handling of xattr operations use the normal
+        * file read/write permissions.
+        *
+        * Just in case the server has other ideas (which RFC 8276 allows),
+        * do a cached access check for the XA* flags to possibly avoid
+        * doing an RPC and getting EACCES back.
+        */
+       if (!nfs_access_get_cached(inode, current_cred(), &cache, true)) {
+               if (!(cache.mask & NFS_ACCESS_XAWRITE))
+                       return -EACCES;
+       }
+
+       if (buf == NULL)
+               return nfs42_proc_removexattr(inode, key);
+       else
+               return nfs42_proc_setxattr(inode, key, buf, buflen, flags);
+}
+
+static int nfs4_xattr_get_nfs4_user(const struct xattr_handler *handler,
+                                   struct dentry *unused, struct inode *inode,
+                                   const char *key, void *buf, size_t buflen)
+{
+       struct nfs_access_entry cache;
+
+       if (!nfs_server_capable(inode, NFS_CAP_XATTR))
+               return -EOPNOTSUPP;
+
+       if (!nfs_access_get_cached(inode, current_cred(), &cache, true)) {
+               if (!(cache.mask & NFS_ACCESS_XAREAD))
+                       return -EACCES;
+       }
+
+       return nfs42_proc_getxattr(inode, key, buf, buflen);
+}
+
+static ssize_t
+nfs4_listxattr_nfs4_user(struct inode *inode, char *list, size_t list_len)
+{
+       u64 cookie;
+       bool eof;
+       int ret, size;
+       char *buf;
+       size_t buflen;
+       struct nfs_access_entry cache;
+
+       if (!nfs_server_capable(inode, NFS_CAP_XATTR))
+               return 0;
+
+       if (!nfs_access_get_cached(inode, current_cred(), &cache, true)) {
+               if (!(cache.mask & NFS_ACCESS_XALIST))
+                       return 0;
+       }
+
+       cookie = 0;
+       eof = false;
+       buflen = list_len ? list_len : XATTR_LIST_MAX;
+       buf = list_len ? list : NULL;
+       size = 0;
+
+       while (!eof) {
+               ret = nfs42_proc_listxattrs(inode, buf, buflen,
+                   &cookie, &eof);
+               if (ret < 0)
+                       return ret;
+
+               if (list_len) {
+                       buf += ret;
+                       buflen -= ret;
+               }
+               size += ret;
+       }
+
+       return size;
+}
+
+#else
+
+static ssize_t
+nfs4_listxattr_nfs4_user(struct inode *inode, char *list, size_t list_len)
+{
+       return 0;
+}
+#endif /* CONFIG_NFS_V4_2 */
+
 /*
  * nfs_fhget will use either the mounted_on_fileid or the fileid
  */
@@ -10045,7 +10143,7 @@ const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
 
 static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
 {
-       ssize_t error, error2;
+       ssize_t error, error2, error3;
 
        error = generic_listxattr(dentry, list, size);
        if (error < 0)
@@ -10058,7 +10156,17 @@ static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
        error2 = nfs4_listxattr_nfs4_label(d_inode(dentry), list, size);
        if (error2 < 0)
                return error2;
-       return error + error2;
+
+       if (list) {
+               list += error2;
+               size -= error2;
+       }
+
+       error3 = nfs4_listxattr_nfs4_user(d_inode(dentry), list, size);
+       if (error3 < 0)
+               return error3;
+
+       return error + error2 + error3;
 }
 
 static const struct inode_operations nfs4_dir_inode_operations = {
@@ -10146,11 +10254,22 @@ static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
        .set    = nfs4_xattr_set_nfs4_acl,
 };
 
+#ifdef CONFIG_NFS_V4_2
+static const struct xattr_handler nfs4_xattr_nfs4_user_handler = {
+       .prefix = XATTR_USER_PREFIX,
+       .get    = nfs4_xattr_get_nfs4_user,
+       .set    = nfs4_xattr_set_nfs4_user,
+};
+#endif
+
 const struct xattr_handler *nfs4_xattr_handlers[] = {
        &nfs4_xattr_nfs4_acl_handler,
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
        &nfs4_xattr_nfs4_label_handler,
 #endif
+#ifdef CONFIG_NFS_V4_2
+       &nfs4_xattr_nfs4_user_handler,
+#endif
        NULL
 };