/** nodemap this export is a member of */
struct lu_nodemap *ted_nodemap;
- struct hlist_node ted_nodemap_member;
+ struct list_head ted_nodemap_member;
/* Every reply data fields below are
* protected by ted_lcd_lock */
struct lu_nodemap {
/* human readable ID */
- char nm_name[LUSTRE_NODEMAP_NAME_LENGTH + 1];
+ char nm_name[LUSTRE_NODEMAP_NAME_LENGTH + 1];
/* flags to govern nodemap behavior */
- bool nmf_trust_client_ids:1,
- nmf_allow_root_access:1,
- nmf_block_lookups:1,
- nmf_hmac_required:1,
- nmf_encryption_required:1;
+ bool nmf_trust_client_ids:1,
+ nmf_allow_root_access:1,
+ nmf_block_lookups:1,
+ nmf_hmac_required:1,
+ nmf_encryption_required:1;
/* unique ID set by MGS */
- int nm_id;
+ unsigned int nm_id;
/* nodemap ref counter */
- atomic_t nm_refcount;
+ atomic_t nm_refcount;
/* UID to squash unmapped UIDs */
- uid_t nm_squash_uid;
+ uid_t nm_squash_uid;
/* GID to squash unmapped GIDs */
- gid_t nm_squash_gid;
+ gid_t nm_squash_gid;
/* NID range list */
- struct list_head nm_ranges;
+ struct list_head nm_ranges;
/* lock for idmap red/black trees */
- rwlock_t nm_idmap_lock;
+ rwlock_t nm_idmap_lock;
/* UID map keyed by local UID */
- struct rb_root nm_fs_to_client_uidmap;
+ struct rb_root nm_fs_to_client_uidmap;
/* UID map keyed by remote UID */
- struct rb_root nm_client_to_fs_uidmap;
+ struct rb_root nm_client_to_fs_uidmap;
/* GID map keyed by local UID */
- struct rb_root nm_fs_to_client_gidmap;
+ struct rb_root nm_fs_to_client_gidmap;
/* GID map keyed by remote UID */
- struct rb_root nm_client_to_fs_gidmap;
+ struct rb_root nm_client_to_fs_gidmap;
/* proc directory entry */
struct proc_dir_entry *nm_proc_entry;
/* attached client members of this nodemap */
- struct cfs_hash *nm_member_hash;
+ struct mutex nm_member_list_lock;
+ struct list_head nm_member_list;
/* access by nodemap name */
- struct hlist_node nm_hash;
+ struct hlist_node nm_hash;
/* used when unloading nodemaps */
- struct list_head nm_list;
+ struct list_head nm_list;
};
void nodemap_activate(const bool value);
int nodemap_add(const char *nodemap_name);
int nodemap_del(const char *nodemap_name);
-struct lu_nodemap *nodemap_classify_nid(lnet_nid_t nid);
int nodemap_add_member(lnet_nid_t nid, struct obd_export *exp);
void nodemap_del_member(struct obd_export *exp);
int nodemap_parse_range(const char *range_string, lnet_nid_t range[2]);
enum nodemap_tree_type tree_type, __u32 id);
ssize_t nodemap_map_acl(struct lu_nodemap *nodemap, void *buf, size_t size,
enum nodemap_tree_type tree_type);
+void nodemap_test_nid(lnet_nid_t nid, char *name_buf, size_t name_len);
+__u32 nodemap_test_id(lnet_nid_t nid, enum nodemap_id_type idtype,
+ __u32 client_id);
#endif /* _LUSTRE_NODEMAP_H */
struct obd_ioctl_data *data)
{
struct lustre_cfg *lcfg = NULL;
- struct lu_nodemap *nodemap;
lnet_nid_t nid;
const char *nodemap_name = NULL;
const char *nidstr = NULL;
const char *idtype_str = NULL;
char *param = NULL;
char fs_idstr[16];
+ char name_buf[LUSTRE_NODEMAP_NAME_LENGTH + 1];
int rc = 0;
- __u32 client_id;
+ unsigned long client_id;
__u32 fs_id;
__u32 cmd;
int idtype;
GOTO(out_lcfg, rc = -EINVAL);
nidstr = lustre_cfg_string(lcfg, 1);
nid = libcfs_str2nid(nidstr);
- nodemap = nodemap_classify_nid(nid);
- memset(data->ioc_pbuf1, 0, data->ioc_plen1);
- if (copy_to_user(data->ioc_pbuf1, nodemap->nm_name,
- strlen(nodemap->nm_name)) != 0)
+ nodemap_test_nid(nid, name_buf, sizeof(name_buf));
+ rc = copy_to_user(data->ioc_pbuf1, name_buf,
+ MIN(data->ioc_plen1, sizeof(name_buf)));
+ if (rc != 0)
GOTO(out_lcfg, rc = -EFAULT);
break;
case LCFG_NODEMAP_TEST_ID:
client_idstr = lustre_cfg_string(lcfg, 3);
nid = libcfs_str2nid(nidstr);
- nodemap = nodemap_classify_nid(nid);
- client_id = simple_strtoul(client_idstr, NULL, 10);
-
if (strcmp(idtype_str, "uid") == 0)
idtype = NODEMAP_UID;
else
idtype = NODEMAP_GID;
- fs_id = nodemap_map_id(nodemap, idtype, NODEMAP_CLIENT_TO_FS,
- client_id);
+ rc = kstrtoul(client_idstr, 10, &client_id);
+ if (rc != 0)
+ GOTO(out_lcfg, rc = -EINVAL);
+
+ fs_id = nodemap_test_id(nid, idtype, client_id);
if (data->ioc_plen1 < sizeof(fs_idstr))
GOTO(out_lcfg, rc = -EINVAL);
idmap_delete_tree(nodemap);
write_unlock(&nodemap->nm_idmap_lock);
nm_member_reclassify_nodemap(nodemap);
- if (!cfs_hash_is_empty(nodemap->nm_member_hash))
+ if (!list_empty(&nodemap->nm_member_list))
CWARN("nodemap_destroy failed to reclassify all members\n");
- nm_member_delete_hash(nodemap);
+ nm_member_delete_list(nodemap);
OBD_FREE_PTR(nodemap);
}
}
/**
- * classify the nid into the proper nodemap
+ * Classify the nid into the proper nodemap. Caller must hold
+ * nm_range_tree_lock, and call nodemap_putref when done with nodemap.
*
* \param nid nid to classify
* \retval nodemap nodemap containing the nid
struct lu_nodemap *nodemap_classify_nid(lnet_nid_t nid)
{
struct lu_nid_range *range;
+ struct lu_nodemap *nodemap;
range = range_search(nid);
if (range != NULL)
- return range->rn_nodemap;
+ nodemap = range->rn_nodemap;
+ else
+ nodemap = default_nodemap;
+ nodemap_getref(nodemap);
- return default_nodemap;
+ return nodemap;
}
-EXPORT_SYMBOL(nodemap_classify_nid);
/**
* simple check for default nodemap
nodemap = nodemap_classify_nid(nid);
rc = nm_member_add(nodemap, exp);
read_unlock(&nm_range_tree_lock);
+ nodemap_putref(nodemap);
return rc;
}
EXPORT_SYMBOL(nodemap_add_member);
GOTO(out, rc = -EEXIST);
}
-
- rc = nm_member_init_hash(nodemap);
- if (rc != 0) {
- OBD_FREE_PTR(nodemap);
- goto out;
- }
-
INIT_LIST_HEAD(&nodemap->nm_ranges);
INIT_LIST_HEAD(&nodemap->nm_list);
+ INIT_LIST_HEAD(&nodemap->nm_member_list);
+ mutex_init(&nodemap->nm_member_list_lock);
rwlock_init(&nodemap->nm_idmap_lock);
nodemap->nm_fs_to_client_uidmap = RB_ROOT;
nodemap->nm_client_to_fs_uidmap = RB_ROOT;
cfs_hash_for_each_safe(nodemap_hash, nm_member_revoke_all_cb, NULL);
}
+/**
+ * Returns the nodemap classification for a given nid into an ioctl buffer.
+ * Useful for testing the nodemap configuration to make sure it is working as
+ * expected.
+ *
+ * \param nid nid to classify
+ * \param[out] name_buf buffer to write the nodemap name to
+ * \param name_len length of buffer
+ */
+void nodemap_test_nid(lnet_nid_t nid, char *name_buf, size_t name_len)
+{
+ struct lu_nodemap *nodemap;
+
+ read_lock(&nm_range_tree_lock);
+ nodemap = nodemap_classify_nid(nid);
+ read_unlock(&nm_range_tree_lock);
+
+ strncpy(name_buf, nodemap->nm_name, name_len);
+ if (name_len > 0)
+ name_buf[name_len - 1] = '\0';
+
+ nodemap_putref(nodemap);
+}
+EXPORT_SYMBOL(nodemap_test_nid);
+
+/**
+ * Returns the id mapping for a given nid/id pair. Useful for testing the
+ * nodemap configuration to make sure it is working as expected.
+ *
+ * \param nid nid to classify
+ * \param idtype uid or gid
+ * \param client_id id to map to fs
+ *
+ * \retval the mapped fs_id of the given client_id
+ */
+__u32 nodemap_test_id(lnet_nid_t nid, enum nodemap_id_type idtype,
+ __u32 client_id)
+{
+ struct lu_nodemap *nodemap;
+ __u32 fs_id;
+
+ read_lock(&nm_range_tree_lock);
+ nodemap = nodemap_classify_nid(nid);
+ read_unlock(&nm_range_tree_lock);
+
+ fs_id = nodemap_map_id(nodemap, idtype, NODEMAP_CLIENT_TO_FS,
+ client_id);
+ nodemap_putref(nodemap);
+
+ return fs_id;
+}
+EXPORT_SYMBOL(nodemap_test_id);
enum nodemap_id_type id_type,
__u32 id);
int nodemap_cleanup_nodemaps(void);
-int nm_member_init_hash(struct lu_nodemap *nodemap);
int nm_member_add(struct lu_nodemap *nodemap, struct obd_export *exp);
void nm_member_del(struct lu_nodemap *nodemap, struct obd_export *exp);
-void nm_member_delete_hash(struct lu_nodemap *nodemap);
+void nm_member_delete_list(struct lu_nodemap *nodemap);
+struct lu_nodemap *nodemap_classify_nid(lnet_nid_t nid);
void nm_member_reclassify_nodemap(struct lu_nodemap *nodemap);
void nm_member_revoke_locks(struct lu_nodemap *nodemap);
void nm_member_revoke_all(void);
struct rb_node *nm_rb_next_postorder(const struct rb_node *node);
struct rb_node *nm_rb_first_postorder(const struct rb_root *root);
+void nodemap_putref(struct lu_nodemap *nodemap);
#define nm_rbtree_postorder_for_each_entry_safe(pos, n, \
root, field) \
}
/**
- * Hash callback, reads and prints the exports attached to this nodemap.
+ * Reads and prints the exports attached to the given nodemap.
*
- * \param hs nodemap member hash
- * \param bd unused
- * \param hnode current member in hash
- * \param data seq_file to print to
- * \retval 0 success
- */
-static int nodemap_exports_show_cb(struct cfs_hash *hs, struct cfs_hash_bd *bd,
- struct hlist_node *hnode, void *data)
-{
- struct seq_file *m = data;
- struct obd_export *exp;
- char nidstr[LNET_NIDSTR_SIZE] = "<unknown>";
-
- exp = hlist_entry(hnode, struct obd_export,
- exp_target_data.ted_nodemap_member);
- if (exp->exp_connection != NULL)
- libcfs_nid2str_r(exp->exp_connection->c_peer.nid,
- nidstr, sizeof(nidstr));
-
- seq_printf(m, " { nid: %s, uuid: %s },",
- nidstr, exp->exp_client_uuid.uuid);
-
- return 0;
-}
-
-/**
- * Reads and prints the exports attached to the given nodemap via hash
- * foreach callback.
- *
- * \param m seq file in proc fs
+ * \param m seq file in proc fs, stores nodemap
* \param data unused
* \retval 0 success
*/
static int nodemap_exports_show(struct seq_file *m, void *data)
{
- struct lu_nodemap *nodemap = m->private;
+ struct lu_nodemap *nodemap = m->private;
+ struct obd_export *exp;
+ char nidstr[LNET_NIDSTR_SIZE] = "<unknown>";
seq_printf(m, "[\n");
- cfs_hash_for_each(nodemap->nm_member_hash, nodemap_exports_show_cb, m);
+ mutex_lock(&nodemap->nm_member_list_lock);
+ list_for_each_entry(exp, &nodemap->nm_member_list,
+ exp_target_data.ted_nodemap_member) {
+ if (exp->exp_connection != NULL)
+ libcfs_nid2str_r(exp->exp_connection->c_peer.nid,
+ nidstr, sizeof(nidstr));
+
+ seq_printf(m, " { nid: %s, uuid: %s },",
+ nidstr, exp->exp_client_uuid.uuid);
+ }
+ mutex_unlock(&nodemap->nm_member_list_lock);
seq_printf(m, "\n");
seq_printf(m, "]\n");
#define HASH_NODEMAP_MEMBER_MAX_BITS 7
/**
- * member hash functions
+ * Delete a member from a member list
*
- * The purpose of this hash is to maintain the list of
- * exports that are connected and associated with a
- * particular nodemap
- */
-static void nm_member_getref(struct obd_export *exp)
-{
-}
-
-void nm_member_putref(struct obd_export *exp)
-{
-}
-
-static __u32 nm_member_hashfn(struct cfs_hash *hash_body,
- const void *key, unsigned mask)
-{
- return hash_long((unsigned long)key, hash_body->hs_bkt_bits) & mask;
-}
-
-static void *nm_member_hs_key(struct hlist_node *hnode)
-{
- struct obd_export *exp;
-
- exp = hlist_entry(hnode, struct obd_export,
- exp_target_data.ted_nodemap_member);
-
- return exp;
-}
-
-static int nm_member_hs_keycmp(const void *key, struct hlist_node *hnode)
-{
- struct obd_export *exp;
-
- exp = hlist_entry(hnode, struct obd_export,
- exp_target_data.ted_nodemap_member);
-
- return key == exp;
-}
-
-static void *nm_member_hs_hashobject(struct hlist_node *hnode)
-{
- return hlist_entry(hnode, struct obd_export,
- exp_target_data.ted_nodemap_member);
-}
-
-static void nm_member_hs_get(struct cfs_hash *hs, struct hlist_node *hnode)
-{
- struct obd_export *exp;
-
- exp = hlist_entry(hnode, struct obd_export,
- exp_target_data.ted_nodemap_member);
- nm_member_getref(exp);
-}
-
-static void nm_member_hs_put_locked(struct cfs_hash *hs,
- struct hlist_node *hnode)
-{
- struct obd_export *exp;
-
- exp = hlist_entry(hnode, struct obd_export,
- exp_target_data.ted_nodemap_member);
- nm_member_putref(exp);
-}
-
-/**
- * Delete a member from a member hash
- *
- * \param nodemap nodemap containing hash
- * \paraa nid nid of member to delete
+ * \param nodemap nodemap containing list
+ * \param exp export member to delete
*/
void nm_member_del(struct lu_nodemap *nodemap, struct obd_export *exp)
{
- struct obd_export *exp1;
+ mutex_lock(&nodemap->nm_member_list_lock);
+ list_del_init(&exp->exp_target_data.ted_nodemap_member);
+ mutex_unlock(&nodemap->nm_member_list_lock);
- exp1 = cfs_hash_del_key(nodemap->nm_member_hash, exp);
- if (exp1 != NULL)
- class_export_put(exp1);
-
- LASSERT(hlist_unhashed(&exp->exp_target_data.ted_nodemap_member));
exp->exp_target_data.ted_nodemap = NULL;
-}
-
-static struct cfs_hash_ops nm_member_hash_operations = {
- .hs_hash = nm_member_hashfn,
- .hs_key = nm_member_hs_key,
- .hs_keycmp = nm_member_hs_keycmp,
- .hs_object = nm_member_hs_hashobject,
- .hs_get = nm_member_hs_get,
- .hs_put_locked = nm_member_hs_put_locked,
-};
-
-/**
- * Init a member hash of a nodemap
- *
- * \param nodemap nodemap containing the member hash
- */
-int nm_member_init_hash(struct lu_nodemap *nodemap)
-{
- char nodemap_hashname[LUSTRE_NODEMAP_NAME_LENGTH + 3];
-
-
- snprintf(nodemap_hashname, sizeof(nodemap_hashname),
- "nm-%s", nodemap->nm_name);
- nodemap->nm_member_hash = cfs_hash_create(nodemap_hashname,
- HASH_NODEMAP_MEMBER_CUR_BITS,
- HASH_NODEMAP_MEMBER_MAX_BITS,
- HASH_NODEMAP_MEMBER_BKT_BITS, 0,
- CFS_HASH_MIN_THETA,
- CFS_HASH_MAX_THETA,
- &nm_member_hash_operations,
- CFS_HASH_DEFAULT);
- if (nodemap->nm_member_hash == NULL)
- return -ENOMEM;
-
- return 0;
-}
-
-/**
- * Callback from deleting a hash member
- */
-static int nm_member_delete_hash_cb(struct cfs_hash *hs, struct cfs_hash_bd *bd,
- struct hlist_node *hnode, void *data)
-{
- struct obd_export *exp;
-
- exp = hlist_entry(hnode, struct obd_export,
- exp_target_data.ted_nodemap_member);
-
- exp->exp_target_data.ted_nodemap = NULL;
- cfs_hash_bd_del_locked(hs, bd, hnode);
class_export_put(exp);
-
- return 0;
}
/**
- * Delete a member hash from a nodemap
+ * Delete a member list from a nodemap
*
- * \param nodemap nodemap to remove the hash from
+ * \param nodemap nodemap to remove the list from
*/
-void nm_member_delete_hash(struct lu_nodemap *nodemap)
+void nm_member_delete_list(struct lu_nodemap *nodemap)
{
- cfs_hash_for_each_safe(nodemap->nm_member_hash,
- nm_member_delete_hash_cb,
- nodemap);
- cfs_hash_putref(nodemap->nm_member_hash);
+ struct obd_export *exp;
+ struct obd_export *tmp;
+
+ mutex_lock(&nodemap->nm_member_list_lock);
+ list_for_each_entry_safe(exp, tmp, &nodemap->nm_member_list,
+ exp_target_data.ted_nodemap_member) {
+ exp->exp_target_data.ted_nodemap = NULL;
+ list_del_init(&exp->exp_target_data.ted_nodemap_member);
+ class_export_put(exp);
+ }
+ mutex_unlock(&nodemap->nm_member_list_lock);
}
/**
* Add a member export to a nodemap
*
- * \param nodemap nodemap to search
- * \param exp obd_export to search
- * \retval -EEXIST export is already hashed to a different nodemap
+ * \param nodemap nodemap to add to
+ * \param exp obd_export to add
+ * \retval -EEXIST export is already part of a different nodemap
* \retval -EINVAL export is NULL
*/
int nm_member_add(struct lu_nodemap *nodemap, struct obd_export *exp)
{
- int rc = 0;
-
if (exp == NULL) {
CWARN("attempted to add null export to nodemap %s\n",
nodemap->nm_name);
return -EINVAL;
}
- if (hlist_unhashed(&exp->exp_target_data.ted_nodemap_member) == 0) {
+ if (exp->exp_target_data.ted_nodemap != NULL &&
+ !list_empty(&exp->exp_target_data.ted_nodemap_member)) {
/* export is already member of nodemap */
if (exp->exp_target_data.ted_nodemap == nodemap)
return 0;
return -EEXIST;
}
+ class_export_get(exp);
exp->exp_target_data.ted_nodemap = nodemap;
+ mutex_lock(&nodemap->nm_member_list_lock);
+ list_add(&exp->exp_target_data.ted_nodemap_member,
+ &nodemap->nm_member_list);
+ mutex_unlock(&nodemap->nm_member_list_lock);
- rc = cfs_hash_add_unique(nodemap->nm_member_hash, exp,
- &exp->exp_target_data.ted_nodemap_member);
-
- if (rc == 0)
- class_export_get(exp);
- /* else -EALREADY - exp already in nodemap hash */
-
- return rc;
+ return 0;
}
/**
ldlm_revoke_export_locks(exp);
}
-static int nm_member_reclassify_cb(struct cfs_hash *hs, struct cfs_hash_bd *bd,
- struct hlist_node *hnode, void *data)
-{
- struct obd_export *exp;
- struct lu_nodemap *nodemap;
-
- exp = hlist_entry(hnode, struct obd_export,
- exp_target_data.ted_nodemap_member);
- if (exp == NULL)
- goto out;
-
- /* Must use bd_del_locked inside a cfs_hash callback, and exp->nodemap
- * should never be NULL. For those reasons, can't use member_del.
- */
- read_lock(&nm_range_tree_lock);
- nodemap = nodemap_classify_nid(exp->exp_connection->c_peer.nid);
- if (exp->exp_target_data.ted_nodemap != nodemap) {
- cfs_hash_bd_del_locked(hs, bd, hnode);
- exp->exp_target_data.ted_nodemap = nodemap;
- cfs_hash_add_unique(nodemap->nm_member_hash, exp,
- &exp->exp_target_data.ted_nodemap_member);
- }
- read_unlock(&nm_range_tree_lock);
-
- nm_member_exp_revoke(exp);
-out:
- return 0;
-}
-
/* Mutex used to serialize calls to reclassify_nodemap_lock */
DEFINE_MUTEX(reclassify_nodemap_lock);
*/
void nm_member_reclassify_nodemap(struct lu_nodemap *nodemap)
{
+ struct obd_export *exp;
+ struct obd_export *tmp;
+ struct lu_nodemap *new_nodemap;
+
/* reclassify only one nodemap at a time to avoid deadlock */
mutex_lock(&reclassify_nodemap_lock);
- cfs_hash_for_each_safe(nodemap->nm_member_hash,
- nm_member_reclassify_cb,
- NULL);
+ mutex_lock(&nodemap->nm_member_list_lock);
+ list_for_each_entry_safe(exp, tmp, &nodemap->nm_member_list,
+ exp_target_data.ted_nodemap_member) {
+ lnet_nid_t nid = exp->exp_connection->c_peer.nid;
+
+ /* nodemap_classify_nid requires range tree lock */
+ read_lock(&nm_range_tree_lock);
+ new_nodemap = nodemap_classify_nid(nid);
+ read_unlock(&nm_range_tree_lock);
+ if (new_nodemap != nodemap) {
+ /* don't use member_del because ted_nodemap
+ * should never be null
+ */
+ list_del_init(&exp->exp_target_data.ted_nodemap_member);
+ exp->exp_target_data.ted_nodemap = new_nodemap;
+
+ /* could deadlock if new_nodemap also reclassifying */
+ mutex_lock(&new_nodemap->nm_member_list_lock);
+ list_add(&exp->exp_target_data.ted_nodemap_member,
+ &new_nodemap->nm_member_list);
+ mutex_unlock(&new_nodemap->nm_member_list_lock);
+ nm_member_exp_revoke(exp);
+ }
+ nodemap_putref(new_nodemap);
+ }
+ mutex_unlock(&nodemap->nm_member_list_lock);
mutex_unlock(&reclassify_nodemap_lock);
}
-static int
-nm_member_revoke_locks_cb(struct cfs_hash *hs, struct cfs_hash_bd *bd,
- struct hlist_node *hnode, void *data)
-{
- struct obd_export *exp;
- exp = hlist_entry(hnode, struct obd_export,
- exp_target_data.ted_nodemap_member);
- if (exp == NULL)
- return 0;
-
- nm_member_exp_revoke(exp);
- return 0;
-}
-
/**
* Revoke the locks for member exports. Changing the idmap is
* akin to deleting the security context. If the locks are not
*/
void nm_member_revoke_locks(struct lu_nodemap *nodemap)
{
- cfs_hash_for_each(nodemap->nm_member_hash, nm_member_revoke_locks_cb,
- NULL);
+ struct obd_export *exp;
+ struct obd_export *tmp;
+
+ mutex_lock(&nodemap->nm_member_list_lock);
+ list_for_each_entry_safe(exp, tmp, &nodemap->nm_member_list,
+ exp_target_data.ted_nodemap_member)
+ nm_member_exp_revoke(exp);
+ mutex_unlock(&nodemap->nm_member_list_lock);
}