Whamcloud - gitweb
LU-11085 nodemap: switch interval tree to in-kernel impl.
[fs/lustre-release.git] / lustre / ptlrpc / nodemap_handler.c
index 41d8984..5fc80bf 100644 (file)
@@ -257,14 +257,14 @@ struct lu_nodemap *nodemap_lookup(const char *name)
  */
 struct lu_nodemap *nodemap_classify_nid(lnet_nid_t nid)
 {
-       struct lu_nid_range     *range;
-       struct lu_nodemap       *nodemap;
+       struct lu_nid_range *range;
+       struct lu_nodemap *nodemap;
        int rc;
 
        ENTRY;
 
        /* don't use 0@lo, use the first non-lo local NID instead */
-       if (LNET_NETTYP(LNET_NIDNET(nid)) == LOLND) {
+       if (nid == LNET_NID_LO_0) {
                struct lnet_process_id id;
                int i = 0;
 
@@ -272,7 +272,7 @@ struct lu_nodemap *nodemap_classify_nid(lnet_nid_t nid)
                        rc = LNetGetId(i++, &id);
                        if (rc < 0)
                                RETURN(ERR_PTR(-EINVAL));
-               } while (LNET_NETTYP(LNET_NIDNET(id.nid)) == LOLND);
+               } while (id.nid == LNET_NID_LO_0);
 
                nid = id.nid;
                CDEBUG(D_INFO, "found nid %s\n", libcfs_nid2str(nid));
@@ -924,8 +924,20 @@ static int nodemap_set_fileset_helper(struct nodemap_config *config,
 {
        int rc = 0;
 
-       /* we allow fileset = "" which means clear fileset info */
-       if (fileset == NULL || (fileset[0] != 0 && fileset[0] != '/'))
+       /* Allow 'fileset=clear' in addition to 'fileset=""' to clear fileset
+        * because either command 'lctl set_param -P *.*.fileset=""' or
+        * 'lctl nodemap_set_fileset --fileset ""' can only work correctly
+        * on MGS, while on other servers, both commands will invoke upcall
+        * "/usr/sbin/lctl set_param nodemap.default.fileset=" by function
+        * process_param2_config(), which will cause "no value" error and
+        * won't clear fileset.
+        * 'fileset=""' is still kept for compatibility reason.
+        */
+       if (fileset == NULL)
+               rc = -EINVAL;
+       else if (fileset[0] == '\0' || strcmp(fileset, "clear") == 0)
+               nodemap->nm_fileset[0] = '\0';
+       else if (fileset[0] != '/')
                rc = -EINVAL;
        else if (strlcpy(nodemap->nm_fileset, fileset,
                         sizeof(nodemap->nm_fileset)) >=
@@ -947,8 +959,7 @@ int nodemap_set_fileset(const char *name, const char *fileset)
                GOTO(out, rc = PTR_ERR(nodemap));
        }
 
-       rc = nodemap_set_fileset_helper(active_config, nodemap,
-                                               fileset);
+       rc = nodemap_set_fileset_helper(active_config, nodemap, fileset);
        mutex_unlock(&active_config_lock);
 
        nodemap_putref(nodemap);
@@ -973,6 +984,111 @@ char *nodemap_get_fileset(const struct lu_nodemap *nodemap)
 }
 EXPORT_SYMBOL(nodemap_get_fileset);
 
+static int nodemap_validate_sepol(const char *sepol)
+{
+       char buf[LUSTRE_NODEMAP_SEPOL_LENGTH + 1];
+       char *p = (char *)sepol;
+       char *q = buf;
+       char polname[NAME_MAX + 1] = "";
+       char hash[SELINUX_POLICY_HASH_LEN + 1] = "";
+       unsigned char mode;
+       unsigned short ver;
+
+       BUILD_BUG_ON(sizeof(buf) != sizeof(((struct lu_nodemap *)0)->nm_sepol));
+
+       if (sepol == NULL)
+               return -EINVAL;
+
+       /* we allow sepol = "" which means clear SELinux policy info */
+       if (sepol[0] == '\0')
+               return 0;
+
+       /* make a copy of sepol, by replacing ':' with space
+        * so that we can use sscanf over the string
+        */
+       while (p-sepol < sizeof(buf)) {
+               if (*p == ':')
+                       *q = ' ';
+               else
+                       *q = *p;
+               if (*p == '\0')
+                       break;
+               p++;
+               q++;
+       }
+       if (p-sepol == sizeof(buf))
+               return -ENAMETOOLONG;
+
+       if (sscanf(buf, "%1hhu %s %hu %s", &mode, polname, &ver, hash) != 4)
+               return -EINVAL;
+
+       if (mode != 0 && mode != 1)
+               return -EINVAL;
+
+       return 0;
+}
+
+/**
+ * set SELinux policy on nodemap
+ * \param      name            nodemap to set SELinux policy info on
+ * \param      sepol           string containing SELinux policy info
+ * \retval     0 on success
+ *
+ * set SELinux policy info on the named nodemap
+ */
+int nodemap_set_sepol(const char *name, const char *sepol)
+{
+       struct lu_nodemap       *nodemap = NULL;
+       int                      rc;
+
+       rc = nodemap_validate_sepol(sepol);
+       if (rc < 0)
+               GOTO(out, rc);
+
+       mutex_lock(&active_config_lock);
+       nodemap = nodemap_lookup(name);
+       if (IS_ERR(nodemap)) {
+               mutex_unlock(&active_config_lock);
+               GOTO(out, rc = PTR_ERR(nodemap));
+       }
+
+       if (is_default_nodemap(nodemap)) {
+               /* We do not want nodes in the default nodemap to have
+                * SELinux restrictions. Sec admin should create dedicated
+                * nodemap entries for this.
+                */
+               GOTO(out_putref, rc = -EINVAL);
+       }
+
+       /* truncation cannot happen, as string length was checked in
+        * nodemap_validate_sepol()
+        */
+       strlcpy(nodemap->nm_sepol, sepol, sizeof(nodemap->nm_sepol));
+
+out_putref:
+       mutex_unlock(&active_config_lock);
+       nodemap_putref(nodemap);
+out:
+       return rc;
+}
+EXPORT_SYMBOL(nodemap_set_sepol);
+
+/**
+ * get SELinux policy info defined on nodemap
+ * \param      nodemap         nodemap to get SELinux policy info from
+ * \retval     SELinux policy info, or NULL if not defined or not activated
+ *
+ * get the SELinux policy info defined on the nodemap
+ */
+const char *nodemap_get_sepol(const struct lu_nodemap *nodemap)
+{
+       if (is_default_nodemap(nodemap))
+               return NULL;
+       else
+               return (char *)nodemap->nm_sepol;
+}
+EXPORT_SYMBOL(nodemap_get_sepol);
+
 /**
  * Nodemap constructor
  *
@@ -999,6 +1115,7 @@ struct lu_nodemap *nodemap_create(const char *name,
        struct lu_nodemap       *default_nodemap;
        struct cfs_hash         *hash = config->nmc_nodemap_hash;
        int                      rc = 0;
+       ENTRY;
 
        default_nodemap = config->nmc_default_nodemap;
 
@@ -1012,9 +1129,8 @@ struct lu_nodemap *nodemap_create(const char *name,
 
        OBD_ALLOC_PTR(nodemap);
        if (nodemap == NULL) {
-               CERROR("cannot allocate memory (%zu bytes)"
-                      "for nodemap '%s'\n", sizeof(*nodemap),
-                      name);
+               CERROR("cannot allocate memory (%zu bytes) for nodemap '%s'\n",
+                      sizeof(*nodemap), name);
                GOTO(out, rc = -ENOMEM);
        }
 
@@ -1056,10 +1172,12 @@ struct lu_nodemap *nodemap_create(const char *name,
                nodemap->nmf_map_uid_only = 0;
                nodemap->nmf_map_gid_only = 0;
                nodemap->nmf_enable_audit = 1;
+               nodemap->nmf_forbid_encryption = 0;
 
                nodemap->nm_squash_uid = NODEMAP_NOBODY_UID;
                nodemap->nm_squash_gid = NODEMAP_NOBODY_GID;
                nodemap->nm_fileset[0] = '\0';
+               nodemap->nm_sepol[0] = '\0';
                if (!is_default)
                        CWARN("adding nodemap '%s' to config without"
                              " default nodemap\n", nodemap->nm_name);
@@ -1076,17 +1194,20 @@ struct lu_nodemap *nodemap_create(const char *name,
                                default_nodemap->nmf_map_gid_only;
                nodemap->nmf_enable_audit =
                        default_nodemap->nmf_enable_audit;
+               nodemap->nmf_forbid_encryption =
+                       default_nodemap->nmf_forbid_encryption;
 
                nodemap->nm_squash_uid = default_nodemap->nm_squash_uid;
                nodemap->nm_squash_gid = default_nodemap->nm_squash_gid;
                nodemap->nm_fileset[0] = '\0';
+               nodemap->nm_sepol[0] = '\0';
        }
 
-       return nodemap;
+       RETURN(nodemap);
 
 out:
        CERROR("cannot add nodemap: '%s': rc = %d\n", name, rc);
-       return ERR_PTR(rc);
+       RETURN(ERR_PTR(rc));
 }
 
 /**
@@ -1316,6 +1437,34 @@ out:
 }
 EXPORT_SYMBOL(nodemap_set_audit_mode);
 
+/**
+ * Set the nmf_forbid_encryption flag to true or false.
+ * \param      name                    nodemap name
+ * \param      forbid_encryption       if true, forbid encryption
+ * \retval     0 on success
+ *
+ */
+int nodemap_set_forbid_encryption(const char *name, bool forbid_encryption)
+{
+       struct lu_nodemap       *nodemap = NULL;
+       int                     rc = 0;
+
+       mutex_lock(&active_config_lock);
+       nodemap = nodemap_lookup(name);
+       mutex_unlock(&active_config_lock);
+       if (IS_ERR(nodemap))
+               GOTO(out, rc = PTR_ERR(nodemap));
+
+       nodemap->nmf_forbid_encryption = forbid_encryption;
+       rc = nodemap_idx_nodemap_update(nodemap);
+
+       nm_member_revoke_locks(nodemap);
+       nodemap_putref(nodemap);
+out:
+       return rc;
+}
+EXPORT_SYMBOL(nodemap_set_forbid_encryption);
+
 
 /**
  * Add a nodemap
@@ -1473,6 +1622,8 @@ struct nodemap_config *nodemap_config_alloc(void)
 
        init_rwsem(&config->nmc_range_tree_lock);
 
+       config->nmc_range_tree.nmrt_range_interval_root = INTERVAL_TREE_ROOT;
+
        return config;
 }
 EXPORT_SYMBOL(nodemap_config_alloc);