Merge remote-tracking branch 'staging/staging-next'
[deliverable/linux.git] / drivers / staging / lustre / lustre / llite / xattr.c
index 98303cf8581555e0c553dc025c5cbafea5bd7220..7b8d4699a71a8d7fe183b41953abf257f0927552 100644 (file)
@@ -99,46 +99,57 @@ int xattr_type_filter(struct ll_sb_info *sbi, int xattr_type)
        return 0;
 }
 
-static
-int ll_setxattr_common(struct inode *inode, const char *name,
-                      const void *value, size_t size,
-                      int flags, __u64 valid)
+static int
+ll_xattr_set_common(const struct xattr_handler *handler,
+                   struct dentry *dentry, struct inode *inode,
+                   const char *name, const void *value, size_t size,
+                   int flags)
 {
+       char fullname[strlen(handler->prefix) + strlen(name) + 1];
        struct ll_sb_info *sbi = ll_i2sbi(inode);
        struct ptlrpc_request *req = NULL;
-       int xattr_type, rc;
        const char *pv = value;
+       __u64 valid;
+       int rc;
+
+       if (flags == XATTR_REPLACE) {
+               ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_REMOVEXATTR, 1);
+               valid = OBD_MD_FLXATTRRM;
+       } else {
+               ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_SETXATTR, 1);
+               valid = OBD_MD_FLXATTR;
+       }
 
-       xattr_type = get_xattr_type(name);
-       rc = xattr_type_filter(sbi, xattr_type);
+       rc = xattr_type_filter(sbi, handler->flags);
        if (rc)
                return rc;
 
-       if ((xattr_type == XATTR_ACL_ACCESS_T ||
-            xattr_type == XATTR_ACL_DEFAULT_T) &&
+       if ((handler->flags == XATTR_ACL_ACCESS_T ||
+            handler->flags == XATTR_ACL_DEFAULT_T) &&
            !inode_owner_or_capable(inode))
                return -EPERM;
 
        /* b10667: ignore lustre special xattr for now */
-       if ((xattr_type == XATTR_TRUSTED_T && strcmp(name, "trusted.lov") == 0) ||
-           (xattr_type == XATTR_LUSTRE_T && strcmp(name, "lustre.lov") == 0))
+       if ((handler->flags == XATTR_TRUSTED_T && !strcmp(name, "lov")) ||
+           (handler->flags == XATTR_LUSTRE_T && !strcmp(name, "lov")))
                return 0;
 
        /* b15587: ignore security.capability xattr for now */
-       if ((xattr_type == XATTR_SECURITY_T &&
-            strcmp(name, "security.capability") == 0))
+       if ((handler->flags == XATTR_SECURITY_T &&
+            !strcmp(name, "capability")))
                return 0;
 
        /* LU-549:  Disable security.selinux when selinux is disabled */
-       if (xattr_type == XATTR_SECURITY_T && !selinux_is_enabled() &&
-           strcmp(name, "security.selinux") == 0)
+       if (handler->flags == XATTR_SECURITY_T && !selinux_is_enabled() &&
+           strcmp(name, "selinux") == 0)
                return -EOPNOTSUPP;
 
+       sprintf(fullname, "%s%s\n", handler->prefix, name);
        rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode),
-                        valid, name, pv, size, 0, flags,
+                        valid, fullname, pv, size, 0, flags,
                         ll_i2suppgid(inode), &req);
        if (rc) {
-               if (rc == -EOPNOTSUPP && xattr_type == XATTR_USER_T) {
+               if (rc == -EOPNOTSUPP && handler->flags == XATTR_USER_T) {
                        LCONSOLE_INFO("Disabling user_xattr feature because it is not supported on the server\n");
                        sbi->ll_flags &= ~LL_SBI_USER_XATTR;
                }
@@ -149,8 +160,10 @@ int ll_setxattr_common(struct inode *inode, const char *name,
        return 0;
 }
 
-int ll_setxattr(struct dentry *dentry, struct inode *inode,
-               const char *name, const void *value, size_t size, int flags)
+static int ll_xattr_set(const struct xattr_handler *handler,
+                       struct dentry *dentry, struct inode *inode,
+                       const char *name, const void *value, size_t size,
+                       int flags)
 {
        LASSERT(inode);
        LASSERT(name);
@@ -158,20 +171,24 @@ int ll_setxattr(struct dentry *dentry, struct inode *inode,
        CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), xattr %s\n",
               PFID(ll_inode2fid(inode)), inode, name);
 
-       ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_SETXATTR, 1);
-
-       if ((strncmp(name, XATTR_TRUSTED_PREFIX,
-                    sizeof(XATTR_TRUSTED_PREFIX) - 1) == 0 &&
-            strcmp(name + sizeof(XATTR_TRUSTED_PREFIX) - 1, "lov") == 0) ||
-           (strncmp(name, XATTR_LUSTRE_PREFIX,
-                    sizeof(XATTR_LUSTRE_PREFIX) - 1) == 0 &&
-            strcmp(name + sizeof(XATTR_LUSTRE_PREFIX) - 1, "lov") == 0)) {
+       if (!strcmp(name, "lov")) {
                struct lov_user_md *lump = (struct lov_user_md *)value;
+               int op_type = flags == XATTR_REPLACE ? LPROC_LL_REMOVEXATTR :
+                                                      LPROC_LL_SETXATTR;
                int rc = 0;
 
+               ll_stats_ops_tally(ll_i2sbi(inode), op_type, 1);
+
                if (size != 0 && size < sizeof(struct lov_user_md))
                        return -EINVAL;
 
+               /*
+                * It is possible to set an xattr to a "" value of zero size.
+                * For this case we are going to treat it as a removal.
+                */
+               if (!size && lump)
+                       lump = NULL;
+
                /* Attributes that are saved via getxattr will always have
                 * the stripe_offset as 0.  Instead, the MDS should be
                 * allowed to pick the starting OST index.   b=17846
@@ -194,92 +211,27 @@ int ll_setxattr(struct dentry *dentry, struct inode *inode,
 
                return rc;
 
-       } else if (strcmp(name, XATTR_NAME_LMA) == 0 ||
-                  strcmp(name, XATTR_NAME_LINK) == 0)
+       } else if (!strcmp(name, "lma") || !strcmp(name, "link")) {
+               ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_SETXATTR, 1);
                return 0;
+       }
 
-       return ll_setxattr_common(inode, name, value, size, flags,
-                                 OBD_MD_FLXATTR);
-}
-
-int ll_removexattr(struct dentry *dentry, const char *name)
-{
-       struct inode *inode = d_inode(dentry);
-
-       LASSERT(inode);
-       LASSERT(name);
-
-       CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), xattr %s\n",
-              PFID(ll_inode2fid(inode)), inode, name);
-
-       ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_REMOVEXATTR, 1);
-       return ll_setxattr_common(inode, name, NULL, 0, 0,
-                                 OBD_MD_FLXATTRRM);
+       return ll_xattr_set_common(handler, dentry, inode, name, value, size,
+                                  flags);
 }
 
-static
-int ll_getxattr_common(struct inode *inode, const char *name,
-                      void *buffer, size_t size, __u64 valid)
+static int
+ll_xattr_list(struct inode *inode, const char *name, int type, void *buffer,
+             size_t size, __u64 valid)
 {
+       struct ll_inode_info *lli = ll_i2info(inode);
        struct ll_sb_info *sbi = ll_i2sbi(inode);
        struct ptlrpc_request *req = NULL;
        struct mdt_body *body;
-       int xattr_type, rc;
        void *xdata;
-       struct ll_inode_info *lli = ll_i2info(inode);
+       int rc;
 
-       CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n",
-              PFID(ll_inode2fid(inode)), inode);
-
-       /* listxattr have slightly different behavior from of ext3:
-        * without 'user_xattr' ext3 will list all xattr names but
-        * filtered out "^user..*"; we list them all for simplicity.
-        */
-       if (!name) {
-               xattr_type = XATTR_OTHER_T;
-               goto do_getxattr;
-       }
-
-       xattr_type = get_xattr_type(name);
-       rc = xattr_type_filter(sbi, xattr_type);
-       if (rc)
-               return rc;
-
-       /* b15587: ignore security.capability xattr for now */
-       if ((xattr_type == XATTR_SECURITY_T &&
-            strcmp(name, "security.capability") == 0))
-               return -ENODATA;
-
-       /* LU-549:  Disable security.selinux when selinux is disabled */
-       if (xattr_type == XATTR_SECURITY_T && !selinux_is_enabled() &&
-           strcmp(name, "security.selinux") == 0)
-               return -EOPNOTSUPP;
-
-#ifdef CONFIG_FS_POSIX_ACL
-       /* posix acl is under protection of LOOKUP lock. when calling to this,
-        * we just have path resolution to the target inode, so we have great
-        * chance that cached ACL is uptodate.
-        */
-       if (xattr_type == XATTR_ACL_ACCESS_T) {
-               struct posix_acl *acl;
-
-               spin_lock(&lli->lli_lock);
-               acl = posix_acl_dup(lli->lli_posix_acl);
-               spin_unlock(&lli->lli_lock);
-
-               if (!acl)
-                       return -ENODATA;
-
-               rc = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
-               posix_acl_release(acl);
-               return rc;
-       }
-       if (xattr_type == XATTR_ACL_DEFAULT_T && !S_ISDIR(inode->i_mode))
-               return -ENODATA;
-#endif
-
-do_getxattr:
-       if (sbi->ll_xattr_cache_enabled && xattr_type != XATTR_ACL_ACCESS_T) {
+       if (sbi->ll_xattr_cache_enabled && type != XATTR_ACL_ACCESS_T) {
                rc = ll_xattr_cache_get(inode, name, buffer, size, valid);
                if (rc == -EAGAIN)
                        goto getxattr_nocache;
@@ -311,36 +263,36 @@ getxattr_nocache:
 
                /* only detect the xattr size */
                if (size == 0) {
-                       rc = body->eadatasize;
+                       rc = body->mbo_eadatasize;
                        goto out;
                }
 
-               if (size < body->eadatasize) {
+               if (size < body->mbo_eadatasize) {
                        CERROR("server bug: replied size %u > %u\n",
-                              body->eadatasize, (int)size);
+                              body->mbo_eadatasize, (int)size);
                        rc = -ERANGE;
                        goto out;
                }
 
-               if (body->eadatasize == 0) {
+               if (body->mbo_eadatasize == 0) {
                        rc = -ENODATA;
                        goto out;
                }
 
                /* do not need swab xattr data */
                xdata = req_capsule_server_sized_get(&req->rq_pill, &RMF_EADATA,
-                                                    body->eadatasize);
+                                                    body->mbo_eadatasize);
                if (!xdata) {
                        rc = -EFAULT;
                        goto out;
                }
 
-               memcpy(buffer, xdata, body->eadatasize);
-               rc = body->eadatasize;
+               memcpy(buffer, xdata, body->mbo_eadatasize);
+               rc = body->mbo_eadatasize;
        }
 
 out_xattr:
-       if (rc == -EOPNOTSUPP && xattr_type == XATTR_USER_T) {
+       if (rc == -EOPNOTSUPP && type == XATTR_USER_T) {
                LCONSOLE_INFO(
                        "%s: disabling user_xattr feature because it is not supported on the server: rc = %d\n",
                        ll_get_fsname(inode->i_sb, NULL, 0), rc);
@@ -351,8 +303,65 @@ out:
        return rc;
 }
 
-ssize_t ll_getxattr(struct dentry *dentry, struct inode *inode,
-                   const char *name, void *buffer, size_t size)
+static int ll_xattr_get_common(const struct xattr_handler *handler,
+                              struct dentry *dentry, struct inode *inode,
+                              const char *name, void *buffer, size_t size)
+{
+       char fullname[strlen(handler->prefix) + strlen(name) + 1];
+       struct ll_sb_info *sbi = ll_i2sbi(inode);
+#ifdef CONFIG_FS_POSIX_ACL
+       struct ll_inode_info *lli = ll_i2info(inode);
+#endif
+       int rc;
+
+       CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n",
+              PFID(ll_inode2fid(inode)), inode);
+
+       ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_GETXATTR, 1);
+
+       rc = xattr_type_filter(sbi, handler->flags);
+       if (rc)
+               return rc;
+
+       /* b15587: ignore security.capability xattr for now */
+       if ((handler->flags == XATTR_SECURITY_T && !strcmp(name, "capability")))
+               return -ENODATA;
+
+       /* LU-549:  Disable security.selinux when selinux is disabled */
+       if (handler->flags == XATTR_SECURITY_T && !selinux_is_enabled() &&
+           !strcmp(name, "selinux"))
+               return -EOPNOTSUPP;
+
+#ifdef CONFIG_FS_POSIX_ACL
+       /* posix acl is under protection of LOOKUP lock. when calling to this,
+        * we just have path resolution to the target inode, so we have great
+        * chance that cached ACL is uptodate.
+        */
+       if (handler->flags == XATTR_ACL_ACCESS_T) {
+               struct posix_acl *acl;
+
+               spin_lock(&lli->lli_lock);
+               acl = posix_acl_dup(lli->lli_posix_acl);
+               spin_unlock(&lli->lli_lock);
+
+               if (!acl)
+                       return -ENODATA;
+
+               rc = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
+               posix_acl_release(acl);
+               return rc;
+       }
+       if (handler->flags == XATTR_ACL_DEFAULT_T && !S_ISDIR(inode->i_mode))
+               return -ENODATA;
+#endif
+       sprintf(fullname, "%s%s\n", handler->prefix, name);
+       return ll_xattr_list(inode, fullname, handler->flags, buffer, size,
+                            OBD_MD_FLXATTR);
+}
+
+static int ll_xattr_get(const struct xattr_handler *handler,
+                       struct dentry *dentry, struct inode *inode,
+                       const char *name, void *buffer, size_t size)
 {
        LASSERT(inode);
        LASSERT(name);
@@ -360,36 +369,23 @@ ssize_t ll_getxattr(struct dentry *dentry, struct inode *inode,
        CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), xattr %s\n",
               PFID(ll_inode2fid(inode)), inode, name);
 
-       ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_GETXATTR, 1);
-
-       if ((strncmp(name, XATTR_TRUSTED_PREFIX,
-                    sizeof(XATTR_TRUSTED_PREFIX) - 1) == 0 &&
-            strcmp(name + sizeof(XATTR_TRUSTED_PREFIX) - 1, "lov") == 0) ||
-           (strncmp(name, XATTR_LUSTRE_PREFIX,
-                    sizeof(XATTR_LUSTRE_PREFIX) - 1) == 0 &&
-            strcmp(name + sizeof(XATTR_LUSTRE_PREFIX) - 1, "lov") == 0)) {
+       if (!strcmp(name, "lov")) {
                struct lov_stripe_md *lsm;
                struct lov_user_md *lump;
                struct lov_mds_md *lmm = NULL;
                struct ptlrpc_request *request = NULL;
                int rc = 0, lmmsize = 0;
 
+               ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_GETXATTR, 1);
+
                if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
                        return -ENODATA;
 
-               if (size == 0 && S_ISDIR(inode->i_mode)) {
-                       /* XXX directory EA is fix for now, optimize to save
-                        * RPC transfer
-                        */
-                       rc = sizeof(struct lov_user_md);
-                       goto out;
-               }
-
                lsm = ccc_inode_lsm_get(inode);
                if (!lsm) {
                        if (S_ISDIR(inode->i_mode)) {
-                               rc = ll_dir_getstripe(inode, &lmm,
-                                                     &lmmsize, &request);
+                               rc = ll_dir_getstripe(inode, (void **)&lmm,
+                                                     &lmmsize, &request, 0);
                        } else {
                                rc = -ENODATA;
                        }
@@ -439,7 +435,7 @@ out:
                return rc;
        }
 
-       return ll_getxattr_common(inode, name, buffer, size, OBD_MD_FLXATTR);
+       return ll_xattr_get_common(handler, dentry, inode, name, buffer, size);
 }
 
 ssize_t ll_listxattr(struct dentry *dentry, char *buffer, size_t size)
@@ -457,7 +453,8 @@ ssize_t ll_listxattr(struct dentry *dentry, char *buffer, size_t size)
 
        ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_LISTXATTR, 1);
 
-       rc = ll_getxattr_common(inode, NULL, buffer, size, OBD_MD_FLXATTRLS);
+       rc = ll_xattr_list(inode, NULL, XATTR_OTHER_T, buffer, size,
+                          OBD_MD_FLXATTRLS);
        if (rc < 0)
                goto out;
 
@@ -488,7 +485,8 @@ ssize_t ll_listxattr(struct dentry *dentry, char *buffer, size_t size)
                if (!ll_i2info(inode)->lli_has_smd)
                        rc2 = -1;
        } else if (S_ISDIR(inode->i_mode)) {
-               rc2 = ll_dir_getstripe(inode, &lmm, &lmmsize, &request);
+               rc2 = ll_dir_getstripe(inode, (void **)&lmm, &lmmsize,
+                                      &request, 0);
        }
 
        if (rc2 < 0) {
@@ -518,3 +516,57 @@ out:
 
        return rc;
 }
+
+static const struct xattr_handler ll_user_xattr_handler = {
+       .prefix = XATTR_USER_PREFIX,
+       .flags = XATTR_USER_T,
+       .get = ll_xattr_get_common,
+       .set = ll_xattr_set_common,
+};
+
+static const struct xattr_handler ll_trusted_xattr_handler = {
+       .prefix = XATTR_TRUSTED_PREFIX,
+       .flags = XATTR_TRUSTED_T,
+       .get = ll_xattr_get,
+       .set = ll_xattr_set,
+};
+
+static const struct xattr_handler ll_security_xattr_handler = {
+       .prefix = XATTR_SECURITY_PREFIX,
+       .flags = XATTR_SECURITY_T,
+       .get = ll_xattr_get_common,
+       .set = ll_xattr_set_common,
+};
+
+static const struct xattr_handler ll_acl_access_xattr_handler = {
+       .prefix = XATTR_NAME_POSIX_ACL_ACCESS,
+       .flags = XATTR_ACL_ACCESS_T,
+       .get = ll_xattr_get_common,
+       .set = ll_xattr_set_common,
+};
+
+static const struct xattr_handler ll_acl_default_xattr_handler = {
+       .prefix = XATTR_NAME_POSIX_ACL_DEFAULT,
+       .flags = XATTR_ACL_DEFAULT_T,
+       .get = ll_xattr_get_common,
+       .set = ll_xattr_set_common,
+};
+
+static const struct xattr_handler ll_lustre_xattr_handler = {
+       .prefix = XATTR_LUSTRE_PREFIX,
+       .flags = XATTR_LUSTRE_T,
+       .get = ll_xattr_get,
+       .set = ll_xattr_set,
+};
+
+const struct xattr_handler *ll_xattr_handlers[] = {
+       &ll_user_xattr_handler,
+       &ll_trusted_xattr_handler,
+       &ll_security_xattr_handler,
+#ifdef CONFIG_FS_POSIX_ACL
+       &ll_acl_access_xattr_handler,
+       &ll_acl_default_xattr_handler,
+#endif
+       &ll_lustre_xattr_handler,
+       NULL,
+};
This page took 0.03017 seconds and 5 git commands to generate.