+
+cfs_spinlock_t obd_minor_lock;
+/**
+ * Maximum number of OBD devices on a single node (includes devices
+ * from all filesystems mounted on a client). This limit is itself arbitrary,
+ * though the lov_user_md_{v1,v3} structures (used for specifying the
+ * striping layout from llapi_setstripe() and on directory default EAs)
+ * have a 16-bit limit on the starting OST index.
+ **/
+const int obd_minor_map_size = 65536;
+cfs_bitmap_t *obd_minor_map;
+
+int obd_minor_alloc(void)
+{
+ int ret;
+
+ cfs_spin_lock(&obd_minor_lock);
+ ret = cfs_find_first_zero_bit(obd_minor_map->data, obd_minor_map_size);
+ if (ret != obd_minor_map_size)
+ cfs_bitmap_set(obd_minor_map, ret);
+ else
+ ret = -1;
+ cfs_spin_unlock(&obd_minor_lock);
+
+ return ret;
+}
+void obd_minor_release(long minor)
+{
+ cfs_spin_lock(&obd_minor_lock);
+ cfs_bitmap_clear(obd_minor_map, minor);
+ cfs_spin_unlock(&obd_minor_lock);
+}
+
+int obd_minor_valid(long minor)
+{
+ int ret;
+
+ cfs_spin_lock(&obd_minor_lock);
+ ret = cfs_bitmap_check(obd_minor_map, minor);
+ cfs_spin_unlock(&obd_minor_lock);
+
+ return ret;
+}
+
+static CFS_LIST_HEAD(obd_dev_list);
+static const int obd_hash_init_bits = 10;
+static const int obd_hash_max_bits = 30;
+static const int obd_hash_bkt_bits = 10;
+
+static cfs_hash_t *obd_name_hash = NULL;
+static unsigned obd_name_hops_hash(cfs_hash_t *lh, const void *key,
+ unsigned mask)
+{
+ return cfs_hash_djb2_hash(key, strlen(key), mask);
+}
+
+static void *obd_name_hops_obj(cfs_hlist_node_t *hn)
+{
+ struct obd_device *obd = cfs_hlist_entry(hn, struct obd_device,
+ obd_name_node);
+ LASSERTF(obd->obd_magic == OBD_DEVICE_MAGIC,
+ "%p obd_magic %08x != %08x\n",
+ obd, obd->obd_magic, OBD_DEVICE_MAGIC);
+
+ return (void *)obd;
+}
+
+static void *obd_name_hops_key(cfs_hlist_node_t *hn)
+{
+ struct obd_device *obd = obd_name_hops_obj(hn);
+
+ return &obd->obd_name;
+}
+
+static int obd_name_hops_compare(const void *key, cfs_hlist_node_t *hn)
+{
+ void *nk = obd_name_hops_key(hn);
+
+ return strcmp(key, nk) == 0;
+}
+
+static void obd_name_hops_noop(cfs_hash_t *hs, cfs_hlist_node_t *hn)
+{
+ obd_name_hops_obj(hn);
+}
+
+static cfs_hash_ops_t obd_name_hops = {
+ .hs_hash = obd_name_hops_hash,
+ .hs_keycmp = obd_name_hops_compare,
+ .hs_key = obd_name_hops_key,
+ .hs_object = obd_name_hops_obj,
+ .hs_get = obd_name_hops_noop,
+ .hs_put_locked = obd_name_hops_noop,
+};
+
+static cfs_hash_t *obd_uuid_hash = NULL;
+static unsigned obd_uuid_hops_hash(cfs_hash_t *lh, const void *key,
+ unsigned mask)
+{
+ return cfs_hash_djb2_hash(key, strlen(key), mask);
+}
+
+static void *obd_uuid_hops_obj(cfs_hlist_node_t *hn)
+{
+ struct obd_device *obd = cfs_hlist_entry(hn, struct obd_device,
+ obd_uuid_node);
+ LASSERTF(obd->obd_magic == OBD_DEVICE_MAGIC,
+ "%p obd_magic %08x != %08x\n",
+ obd, obd->obd_magic, OBD_DEVICE_MAGIC);
+
+ return (void *)obd;
+}
+
+static void *obd_uuid_hops_key(cfs_hlist_node_t *hn)
+{
+ struct obd_device *obd = obd_uuid_hops_obj(hn);
+
+ return &obd->obd_uuid;
+}
+
+static int obd_uuid_hops_compare(const void *key, cfs_hlist_node_t *hn)
+{
+ void *nk = obd_uuid_hops_key(hn);
+
+ return obd_uuid_equals(key, nk);
+}
+
+static void obd_uuid_hops_noop(cfs_hash_t *hs, cfs_hlist_node_t *hn)
+{
+ obd_uuid_hops_obj(hn);
+}
+
+static cfs_hash_ops_t obd_uuid_hops = {
+ .hs_hash = obd_uuid_hops_hash,
+ .hs_keycmp = obd_uuid_hops_compare,
+ .hs_key = obd_uuid_hops_key,
+ .hs_object = obd_uuid_hops_obj,
+ .hs_get = obd_uuid_hops_noop,
+ .hs_put_locked = obd_uuid_hops_noop,
+};
+
+static cfs_hash_t *obd_minor_hash = NULL;
+static unsigned obd_minor_hops_hash(cfs_hash_t *lh, const void *key,
+ unsigned mask)
+{
+ return cfs_hash_u32_hash(*((__u32 *)key), mask);
+}
+
+static void *obd_minor_hops_obj(cfs_hlist_node_t *hn)
+{
+ struct obd_device *obd = cfs_hlist_entry(hn, struct obd_device,
+ obd_minor_node);
+ LASSERTF(obd->obd_magic == OBD_DEVICE_MAGIC,
+ "%p obd_magic %08x != %08x\n",
+ obd, obd->obd_magic, OBD_DEVICE_MAGIC);
+
+ return (void *)obd;
+}
+
+static void *obd_minor_hops_key(cfs_hlist_node_t *hn)
+{
+ struct obd_device *obd = obd_minor_hops_obj(hn);
+
+ return &obd->obd_minor;
+}
+
+static int obd_minor_hops_compare(const void *key, cfs_hlist_node_t *hn)
+{
+ __u32 *nk = obd_minor_hops_key(hn);
+
+ return *((__u32 *)key) == *nk;
+}
+
+static void obd_minor_hops_noop(cfs_hash_t *hs, cfs_hlist_node_t *hn)
+{
+ obd_minor_hops_obj(hn);
+}
+
+static cfs_hash_ops_t obd_minor_hops = {
+ .hs_hash = obd_minor_hops_hash,
+ .hs_keycmp = obd_minor_hops_compare,
+ .hs_key = obd_minor_hops_key,
+ .hs_object = obd_minor_hops_obj,
+ .hs_get = obd_minor_hops_noop,
+ .hs_put_locked = obd_minor_hops_noop,
+};
+
+int obd_hashes_init(void)
+{
+ obd_name_hash = cfs_hash_create("obd_name",
+ obd_hash_init_bits, obd_hash_max_bits,
+ obd_hash_bkt_bits, 0,
+ CFS_HASH_MIN_THETA, CFS_HASH_MAX_THETA,
+ &obd_name_hops,
+ CFS_HASH_DEFAULT | CFS_HASH_NO_ITEMREF);
+ if (obd_name_hash == NULL)
+ return -ENOMEM;
+
+ obd_uuid_hash = cfs_hash_create("obd_uuid",
+ obd_hash_init_bits, obd_hash_max_bits,
+ obd_hash_bkt_bits, 0,
+ CFS_HASH_MIN_THETA, CFS_HASH_MAX_THETA,
+ &obd_uuid_hops,
+ CFS_HASH_DEFAULT | CFS_HASH_NO_ITEMREF);
+ if (obd_name_hash == NULL)
+ return -ENOMEM;
+
+ obd_minor_hash = cfs_hash_create("obd_minor",
+ obd_hash_init_bits, obd_hash_max_bits,
+ obd_hash_bkt_bits, 0,
+ CFS_HASH_MIN_THETA, CFS_HASH_MAX_THETA,
+ &obd_minor_hops,
+ CFS_HASH_DEFAULT | CFS_HASH_NO_ITEMREF);
+ if (obd_name_hash == NULL)
+ return -ENOMEM;
+
+ obd_minor_map = CFS_ALLOCATE_BITMAP(obd_minor_map_size);
+ if (obd_minor_map == NULL)
+ return -ENOMEM;
+
+ cfs_spin_lock_init(&obd_minor_lock);
+
+ return 0;
+}
+
+void obd_hashes_fini(void)
+{
+ if (obd_minor_map)
+ CFS_FREE_BITMAP(obd_minor_map);
+ cfs_hash_putref(obd_name_hash);
+ cfs_hash_putref(obd_uuid_hash);
+ cfs_hash_putref(obd_minor_hash);
+}
+