Whamcloud - gitweb
LU-3527 nodemap: idmap management functions
[fs/lustre-release.git] / lustre / nodemap / nodemap_handler.c
index d261d65..ae814d4 100644 (file)
@@ -40,7 +40,7 @@ struct proc_dir_entry *proc_lustre_nodemap_root;
 static atomic_t nodemap_highest_id;
 
 /* Simple flag to determine if nodemaps are active */
-bool nodemap_idmap_active;
+bool nodemap_active;
 
 /**
  * pointer to default nodemap kept to keep from
@@ -62,7 +62,17 @@ static cfs_hash_t *nodemap_hash;
  */
 static void nodemap_destroy(struct lu_nodemap *nodemap)
 {
-       lprocfs_remove(&(nodemap->nm_proc_entry));
+       struct lu_nid_range *range;
+       struct lu_nid_range *temp;
+
+       list_for_each_entry_safe(range, temp, &nodemap->nm_ranges,
+                                rn_list) {
+               range_delete(range);
+       }
+
+       idmap_delete_tree(nodemap);
+
+       lprocfs_remove(&nodemap->nm_proc_entry);
        OBD_FREE_PTR(nodemap);
 }
 
@@ -98,6 +108,7 @@ static void *nodemap_hs_key(cfs_hlist_node_t *hnode)
        struct lu_nodemap *nodemap;
 
        nodemap = cfs_hlist_entry(hnode, struct lu_nodemap, nm_hash);
+
        return nodemap->nm_name;
 }
 
@@ -107,6 +118,7 @@ static int nodemap_hs_keycmp(const void *key,
        struct lu_nodemap *nodemap;
 
        nodemap = nodemap_hs_key(compared_hnode);
+
        return !strcmp(key, nodemap->nm_name);
 }
 
@@ -204,6 +216,10 @@ static int nodemap_init_hash(void)
  */
 static bool nodemap_name_is_valid(const char *name)
 {
+       if (strlen(name) > LUSTRE_NODEMAP_NAME_LENGTH ||
+           strlen(name) == 0)
+               return false;
+
        for (; *name != '\0'; name++) {
                if (!isalnum(*name) && *name != '_')
                        return false;
@@ -217,7 +233,7 @@ static bool nodemap_name_is_valid(const char *name)
  * Look nodemap up in the nodemap hash
  *
  * \param      name            name of nodemap
- * \paramA     nodemap         found nodemap or NULL
+ * \param      nodemap         found nodemap or NULL
  * \retval     lu_nodemap      named nodemap
  * \retval     NULL            nodemap doesn't exist
  */
@@ -225,14 +241,316 @@ static int nodemap_lookup(const char *name, struct lu_nodemap **nodemap)
 {
        int rc = 0;
 
+       *nodemap = NULL;
+
        if (!nodemap_name_is_valid(name))
                GOTO(out, rc = -EINVAL);
 
        *nodemap = cfs_hash_lookup(nodemap_hash, name);
+       if (*nodemap == NULL)
+               rc = -ENOENT;
+
+out:
+       return rc;
+}
+
+/**
+ * classify the nid into the proper nodemap
+ *
+ * \param      nid                     nid to classify
+ * \retval     nodemap                 nodemap containing the nid
+ * \retval     default_nodemap         default nodemap
+ */
+struct lu_nodemap *nodemap_classify_nid(lnet_nid_t nid)
+{
+       struct lu_nid_range     *range;
+
+       range = range_search(nid);
+       if (range != NULL)
+               return range->rn_nodemap;
+
+       return default_nodemap;
+}
+EXPORT_SYMBOL(nodemap_classify_nid);
+
+/**
+ * simple check for default nodemap
+ */
+static bool is_default_nodemap(const struct lu_nodemap *nodemap)
+{
+       return nodemap->nm_id == 0;
+}
+
+/**
+ * parse a nodemap range string into two nids
+ *
+ * \param      range_str               string to parse
+ * \param      range[2]                array of two nids
+ * \reyval     0 on success
+ */
+int nodemap_parse_range(const char *range_str, lnet_nid_t range[2])
+{
+       char    buf[LNET_NIDSTR_SIZE * 2 + 2];
+       char    *ptr = NULL;
+       char    *start_nidstr;
+       char    *end_nidstr;
+       int     rc = 0;
+
+       snprintf(buf, sizeof(buf), "%s", range_str);
+       ptr = buf;
+       start_nidstr = strsep(&ptr, ":");
+       end_nidstr = strsep(&ptr, ":");
+
+       if (start_nidstr == NULL || end_nidstr == NULL)
+               GOTO(out, rc = -EINVAL);
+
+       range[0] = libcfs_str2nid(start_nidstr);
+       range[1] = libcfs_str2nid(end_nidstr);
+
+out:
+       return rc;
+
+}
+EXPORT_SYMBOL(nodemap_parse_range);
+
+/**
+ * parse a string containing an id map of form "client_id:filesystem_id"
+ * into an array of __u32 * for use in mapping functions
+ *
+ * \param      idmap_str               map string
+ * \param      idmap                   array[2] of __u32
+ *
+ * \retval     0 on success
+ */
+int nodemap_parse_idmap(const char *idmap_str, __u32 idmap[2])
+{
+       char    *end;
+
+       if (idmap_str == NULL)
+               return -EINVAL;
+
+       idmap[0] = simple_strtoul(idmap_str, &end, 10);
+       if (end == idmap_str || *end != ':')
+               return -EINVAL;
+
+       idmap_str = end + 1;
+       idmap[1] = simple_strtoul(idmap_str, &end, 10);
+       if (end == idmap_str)
+               return -EINVAL;
+
+       return 0;
+}
+EXPORT_SYMBOL(nodemap_parse_idmap);
+
+/**
+ * add an idmap to the proper nodemap trees
+ *
+ * \param      name            name of nodemap
+ * \param      id_type         NODEMAP_UID or NODEMAP_GID
+ * \param      map             array[2] __u32 containing the mapA values
+ *                             map[0] is client id
+ *                             map[1] is the filesystem id
+ *
+ * \retval     0 on success
+ */
+int nodemap_add_idmap(const char *name, enum nodemap_id_type id_type,
+                     const __u32 map[2])
+{
+       struct lu_nodemap       *nodemap = NULL;
+       struct lu_idmap         *idmap;
+       int                     rc = 0;
+
+       rc = nodemap_lookup(name, &nodemap);
+       if (nodemap == NULL || is_default_nodemap(nodemap))
+               GOTO(out, rc = -EINVAL);
+
+       idmap = idmap_create(map[0], map[1]);
+       if (idmap == NULL)
+               GOTO(out_putref, rc = -ENOMEM);
+
+       idmap_insert(id_type, idmap, nodemap);
+
+out_putref:
+       nodemap_putref(nodemap);
+out:
+       return rc;
+}
+EXPORT_SYMBOL(nodemap_add_idmap);
+
+/**
+ * delete idmap from proper nodemap tree
+ *
+ * \param      name            name of nodemap
+ * \param      id_type         NODEMAP_UID or NODEMAP_GID
+ * \param      map             array[2] __u32 containing the mapA values
+ *                             map[0] is client id
+ *                             map[1] is the filesystem id
+ *
+ * \retval     0 on success
+ */
+int nodemap_del_idmap(const char *name, enum nodemap_id_type id_type,
+                     const __u32 map[2])
+{
+       struct lu_nodemap       *nodemap = NULL;
+       struct lu_idmap         *idmap = NULL;
+       int                     rc = 0;
+
+       rc = nodemap_lookup(name, &nodemap);
+       if (nodemap == NULL || is_default_nodemap(nodemap))
+               GOTO(out, rc = -EINVAL);
+
+       idmap = idmap_search(nodemap, NODEMAP_CLIENT_TO_FS, id_type,
+                            map[0]);
+       if (idmap == NULL)
+               GOTO(out_putref, rc = -EINVAL);
+
+       idmap_delete(id_type, idmap, nodemap);
+
+out_putref:
+       nodemap_putref(nodemap);
+out:
+       return rc;
+}
+EXPORT_SYMBOL(nodemap_del_idmap);
+
+/**
+ * mapping function for nodemap idmaps
+ *
+ * \param      nodemap         lu_nodemap structure defining nodemap
+ * \param      node_type       NODEMAP_UID or NODEMAP_GID
+ * \param      tree_type       NODEMAP_CLIENT_TO_FS or
+ *                             NODEMAP_FS_TO_CLIENT
+ * \param      id              id to map
+ *
+ * \retval     mapped id according to the rules below.
+ *
+ * if the nodemap_active is false, just return the passed id without mapping
+ *
+ * if the id to be looked up in 0, check that root access is allowed and if it
+ * is, return 0. Otherwise, return the squash uid or gid.
+ *
+ * if the nodemap is configured to trusted the ids from the client system, just
+ * return the passwd id without mapping.
+ *
+ * if by this point, we haven't returned and the nodemap in question is the
+ * default nodemap, return the dquash uid or gid.
+ *
+ * after these checks, search the proper tree for the mapping, and if found
+ * return the mapped value, otherwise return the squash uid or gid.
+ */
+__u32 nodemap_map_id(struct lu_nodemap *nodemap,
+                    enum nodemap_id_type id_type,
+                    enum nodemap_tree_type tree_type, __u32 id)
+{
+       struct lu_idmap         *idmap = NULL;
+
+       if (!nodemap_active)
+               goto out;
+
+       if (id == 0) {
+               if (nodemap->nmf_allow_root_access)
+                       goto out;
+               else
+                       goto squash;
+       }
+
+       if (nodemap->nmf_trust_client_ids)
+               goto out;
+
+       if (is_default_nodemap(nodemap))
+               goto squash;
+
+       idmap = idmap_search(nodemap, tree_type, id_type, id);
+       if (idmap == NULL)
+               goto squash;
+
+       if (tree_type == NODEMAP_FS_TO_CLIENT)
+               return idmap->id_client;
 
+       return idmap->id_fs;
+
+squash:
+       if (id_type == NODEMAP_UID)
+               return nodemap->nm_squash_uid;
+       else
+               return nodemap->nm_squash_gid;
+out:
+       return id;
+}
+EXPORT_SYMBOL(nodemap_map_id);
+
+/*
+ * add nid range to nodemap
+ * \param      name            nodemap name
+ * \param      range_st        string containing nid range
+ * \retval     0 on success
+ *
+ * add an range to the global range tree and attached the
+ * range to the named nodemap.
+ */
+int nodemap_add_range(const char *name, const lnet_nid_t nid[2])
+{
+       struct lu_nodemap       *nodemap = NULL;
+       struct lu_nid_range     *range;
+       int rc;
+
+       rc = nodemap_lookup(name, &nodemap);
+       if (nodemap == NULL || is_default_nodemap(nodemap))
+               GOTO(out, rc = -EINVAL);
+
+       range = range_create(nid[0], nid[1], nodemap);
+       if (range == NULL)
+               GOTO(out_putref, rc = -ENOMEM);
+
+       rc = range_insert(range);
+       if (rc != 0) {
+               CERROR("cannot insert nodemap range into '%s': rc = %d\n",
+                     nodemap->nm_name, rc);
+               list_del(&range->rn_list);
+               range_destroy(range);
+               GOTO(out_putref, rc = -ENOMEM);
+       }
+
+       list_add(&range->rn_list, &nodemap->nm_ranges);
+
+out_putref:
+       nodemap_putref(nodemap);
+out:
+       return rc;
+}
+EXPORT_SYMBOL(nodemap_add_range);
+
+/**
+ * delete a range
+ * \param      name            nodemap name
+ * \param      range_str       string containing range
+ * \retval     0 on success
+ *
+ * Delete range from global range tree, and remove it
+ * from the list in the associated nodemap.
+ */
+int nodemap_del_range(const char *name, const lnet_nid_t nid[2])
+{
+       struct lu_nodemap       *nodemap;
+       struct lu_nid_range     *range;
+       int                     rc = 0;
+
+       rc = nodemap_lookup(name, &nodemap);
+       if (nodemap == NULL || is_default_nodemap(nodemap))
+               GOTO(out, rc = -EINVAL);
+
+       range = range_find(nid[0], nid[1]);
+       if (range == NULL)
+               GOTO(out_putref, rc = -EINVAL);
+
+       range_delete(range);
+
+out_putref:
+       nodemap_putref(nodemap);
 out:
        return rc;
 }
+EXPORT_SYMBOL(nodemap_del_range);
 
 /**
  * Nodemap constructor
@@ -256,14 +574,13 @@ static int nodemap_create(const char *name, bool is_default)
        int     rc = 0;
 
        rc = nodemap_lookup(name, &nodemap);
-       if (rc < 0)
+       if (rc == -EINVAL)
                goto out;
 
-       if (nodemap != NULL) {
+       if (rc != -ENOENT) {
                nodemap_putref(nodemap);
                GOTO(out, rc = -EEXIST);
        }
-
        OBD_ALLOC_PTR(nodemap);
 
        if (nodemap == NULL) {
@@ -276,10 +593,10 @@ static int nodemap_create(const char *name, bool is_default)
        snprintf(nodemap->nm_name, sizeof(nodemap->nm_name), "%s", name);
 
        INIT_LIST_HEAD(&(nodemap->nm_ranges));
-       nodemap->nm_local_to_remote_uidmap = RB_ROOT;
-       nodemap->nm_remote_to_local_uidmap = RB_ROOT;
-       nodemap->nm_local_to_remote_gidmap = RB_ROOT;
-       nodemap->nm_remote_to_local_gidmap = RB_ROOT;
+       nodemap->nm_fs_to_client_uidmap = RB_ROOT;
+       nodemap->nm_client_to_fs_uidmap = RB_ROOT;
+       nodemap->nm_fs_to_client_gidmap = RB_ROOT;
+       nodemap->nm_client_to_fs_gidmap = RB_ROOT;
 
        if (is_default) {
                nodemap->nm_id = LUSTRE_NODEMAP_DEFAULT_ID;
@@ -322,6 +639,111 @@ out:
 }
 
 /**
+ * update flag to turn on or off nodemap functions
+ * \param      name            nodemap name
+ * \param      admin_string    string containing updated value
+ * \retval     0 on success
+ *
+ * Update admin flag to turn on or off nodemap functions.
+ */
+int nodemap_set_allow_root(const char *name, bool allow_root)
+{
+       struct lu_nodemap       *nodemap = NULL;
+       int                     rc = 0;
+
+       rc = nodemap_lookup(name, &nodemap);
+       if (nodemap == NULL)
+               GOTO(out, rc = -ENOENT);
+
+       nodemap->nmf_allow_root_access = allow_root;
+       nodemap_putref(nodemap);
+out:
+       return rc;
+}
+EXPORT_SYMBOL(nodemap_set_allow_root);
+
+/**
+ * updated trust_client_ids flag for nodemap
+ *
+ * \param      name            nodemap name
+ * \param      trust_string    new value for trust flag
+ * \retval     0 on success
+ *
+ * Update the trust_client_ids flag for a nodemap.
+ */
+int nodemap_set_trust_client_ids(const char *name, bool trust_client_ids)
+{
+       struct lu_nodemap       *nodemap = NULL;
+       int                     rc = 0;
+
+       rc = nodemap_lookup(name, &nodemap);
+       if (nodemap == NULL)
+               GOTO(out, rc = -ENOENT);
+
+       nodemap->nmf_trust_client_ids = trust_client_ids;
+       nodemap_putref(nodemap);
+out:
+       return rc;
+}
+EXPORT_SYMBOL(nodemap_set_trust_client_ids);
+
+/**
+ * update the squash_uid for a nodemap
+ *
+ * \param      name            nodemap name
+ * \param      uid_string      string containing new squash_uid value
+ * \retval     0 on success
+ *
+ * Update the squash_uid for a nodemap. The squash_uid is the uid
+ * that the all client uids are mapped to if nodemap is active,
+ * the trust_client_ids flag is not set, and the uid is not in
+ * the idmap tree.
+ */
+int nodemap_set_squash_uid(const char *name, uid_t uid)
+{
+       struct lu_nodemap       *nodemap = NULL;
+       int                     rc = 0;
+
+       rc = nodemap_lookup(name, &nodemap);
+       if (nodemap == NULL)
+               GOTO(out, rc = -ENOENT);
+
+       nodemap->nm_squash_uid = uid;
+       nodemap_putref(nodemap);
+out:
+       return rc;
+}
+EXPORT_SYMBOL(nodemap_set_squash_uid);
+
+/**
+ * update the squash_gid for a nodemap
+ *
+ * \param      name            nodemap name
+ * \param      gid_string      string containing new squash_gid value
+ * \retval     0 on success
+ *
+ * Update the squash_gid for a nodemap. The squash_uid is the gid
+ * that the all client gids are mapped to if nodemap is active,
+ * the trust_client_ids flag is not set, and the gid is not in
+ * the idmap tree.
+ */
+int nodemap_set_squash_gid(const char *name, gid_t gid)
+{
+       struct lu_nodemap       *nodemap = NULL;
+       int                     rc = 0;
+
+       rc = nodemap_lookup(name, &nodemap);
+       if (nodemap == NULL)
+               GOTO(out, rc = -ENOENT);
+
+       nodemap->nm_squash_gid = gid;
+       nodemap_putref(nodemap);
+out:
+       return rc;
+}
+EXPORT_SYMBOL(nodemap_set_squash_gid);
+
+/**
  * Add a nodemap
  *
  * \param      name            name of nodemap
@@ -363,6 +785,17 @@ out:
 EXPORT_SYMBOL(nodemap_del);
 
 /**
+ * activate nodemap functions
+ *
+ * \param      value           1 for on, 0 for off
+ */
+void nodemap_activate(const bool value)
+{
+       nodemap_active = value;
+}
+EXPORT_SYMBOL(nodemap_activate);
+
+/**
  * Cleanup nodemap module on exit
  */
 static void nodemap_mod_exit(void)