Whamcloud - gitweb
LU-8802 obd: remove MAX_OBD_DEVICES 40/51040/17
authorTimothy Day <timday@amazon.com>
Tue, 9 May 2023 05:07:36 +0000 (05:07 +0000)
committerOleg Drokin <green@whamcloud.com>
Wed, 25 Oct 2023 18:05:21 +0000 (18:05 +0000)
Remove this arbitrary limit by reimplementing the array as an
Xarray. Xarray can grow and shink dynamically, hence saving
memory and allow for many more OBD devices. There is still
technically a limit OBD_MAX_INDEX, which is xa_limit_31b.max
or around 2 billion. This is far more than is practically
useful.

This patch also adds various iterators for OBD devices, which
are used to simplify code in various places.

Removing class_obd_list() since it is unused. Rename
class_dev_by_str() to class_str2obd() to keep the pattern.
Several class_* functions have been refactored to improve
locking. The larger issue of OBD device locking will be
addressed separately.

Update the OBD device lifecycle test to try loading
more devices (about 24,000 for now).

Currently, adding an additional OBD device is an O(n^2)
operation due to the class_name2dev calls in
class_register_device(). This will be addressed in a future
patch adding a hash table for OBD device name lookups.

Further, OBD life cycle management could likely be simplified
by using Xarray marks. Right now, it is handled by a bit
field in the obd_device struct. Since the scope of the changes
needed to simplify this seem large, this will also be addressed
separately.

Test-Parameters: testlist=sanity env=ONLY=55,ONLY_REPEAT=10
Signed-off-by: Timothy Day <timday@amazon.com>
Change-Id: Icb2cd94a5529e79f5d3ebd0de5e0f225cf212075
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/51040
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: James Simmons <jsimmons@infradead.org>
Reviewed-by: Neil Brown <neilb@suse.de>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
13 files changed:
lustre/include/obd.h
lustre/include/obd_class.h
lustre/ldlm/ldlm_lib.c
lustre/llite/llite_lib.c
lustre/lov/lov_dev.c
lustre/mgs/mgs_llog.c
lustre/obdclass/class_obd.c
lustre/obdclass/genops.c
lustre/obdclass/kernelcomm.c
lustre/obdclass/obd_config.c
lustre/obdclass/obd_mount.c
lustre/obdclass/obd_sysfs.c
lustre/tests/sanity.sh

index d1759c6..e5c9e7f 100644 (file)
@@ -49,8 +49,6 @@
 #include <lustre_intent.h>
 #include <lvfs.h>
 
-#define MAX_OBD_DEVICES 8192
-
 struct osc_async_rc {
         int     ar_rc;
         int     ar_force_sync;
index cef3782..8f76738 100644 (file)
                                         * device.
                                         */
 
-extern rwlock_t obd_dev_lock;
+#define OBD_MAX_INDEX xa_limit_31b.max
+
+#define obd_device_find(devno)                                         \
+       xa_find(&obd_devs, &devno, OBD_MAX_INDEX, XA_PRESENT)
+
+#define obd_device_find_after(devno)                                   \
+       xa_find_after(&obd_devs, &devno, OBD_MAX_INDEX, XA_PRESENT)
+
+#define obd_device_for_each(devno, obd)                        \
+       xa_for_each(&obd_devs, devno, obd)
+
+#define obd_device_for_each_start(devno, obd, start)   \
+       xa_for_each_start(&obd_devs, devno, obd, start)
+
+#define obd_device_for_each_cond(devno, obd, cond)      \
+       obd_device_for_each(devno, obd)                  \
+       if (cond)
+
+#define obd_device_for_each_uuid(devno, obd, uuid)      \
+       obd_device_for_each_cond(devno, obd,             \
+                                obd_uuid_equals(uuid, &obd->obd_uuid))
+
+#define obd_device_lock() xa_lock(&obd_devs)
+#define obd_device_unlock() xa_unlock(&obd_devs)
 
 /* OBD Operations Declarations */
 extern struct obd_device *class_exp2obd(struct obd_export *);
@@ -60,6 +83,7 @@ int jobid_set_current(char *jobid);
 struct lu_device_type;
 
 /* genops.c */
+extern struct xarray obd_devs;
 struct obd_export *class_conn2export(struct lustre_handle *);
 #ifdef HAVE_SERVER_SUPPORT
 struct obd_type *class_add_symlinks(const char *name, bool enable_proc);
@@ -75,19 +99,16 @@ int class_register_device(struct obd_device *obd);
 void class_unregister_device(struct obd_device *obd);
 void class_free_dev(struct obd_device *obd);
 
-struct obd_device *class_dev_by_str(const char *str);
+struct obd_device *class_str2obd(const char *str);
 int class_name2dev(const char *name);
 struct obd_device *class_name2obd(const char *name);
 int class_uuid2dev(struct obd_uuid *uuid);
 struct obd_device *class_uuid2obd(struct obd_uuid *uuid);
-void class_obd_list(void);
 struct obd_device *class_find_client_obd(struct obd_uuid *tgt_uuid,
                                         const char *type_name,
                                         struct obd_uuid *grp_uuid);
-struct obd_device *class_devices_in_group(struct obd_uuid *grp_uuid,
-                                         int *next);
 struct obd_device *class_num2obd(int num);
-int get_devices_count(void);
+int class_obd_devs_count(void);
 
 int class_notify_sptlrpc_conf(const char *fsname, int namelen);
 
@@ -458,11 +479,6 @@ static inline int exp_check_ops(struct obd_export *exp)
        RETURN(0);
 }
 
-static inline int class_devno_max(void)
-{
-       return MAX_OBD_DEVICES;
-}
-
 static inline int obd_get_info(const struct lu_env *env, struct obd_export *exp,
                               __u32 keylen, void *key,
                               __u32 *vallen, void *val)
index 07d9332..ca44c1d 100644 (file)
@@ -1102,7 +1102,7 @@ int target_handle_connect(struct ptlrpc_request *req)
                GOTO(out, rc = -EINVAL);
        }
 
-       target = class_dev_by_str(str);
+       target = class_str2obd(str);
        if (!target) {
                deuuidify(str, NULL, &target_start, &target_len);
                LCONSOLE_ERROR_MSG(0x137,
index f0b8dec..db455fe 100644 (file)
@@ -1504,9 +1504,10 @@ void ll_put_super(struct super_block *sb)
        struct obd_device *obd;
        struct lustre_sb_info *lsi = s2lsi(sb);
        struct ll_sb_info *sbi = ll_s2sbi(sb);
+       unsigned long dev_no = 0;
        char *profilenm = get_profile_name(sb);
        unsigned long cfg_instance = ll_get_cfg_instance(sb);
-       int next, force = 1;
+       int force = 1;
 
        ENTRY;
 
@@ -1533,11 +1534,10 @@ void ll_put_super(struct super_block *sb)
         * lustre_common_put_super, since l_d cleans up osc's as well.
         */
        if (force) {
-               next = 0;
-               while ((obd = class_devices_in_group(&sbi->ll_sb_uuid,
-                                                    &next)) != NULL) {
+               obd_device_lock();
+               obd_device_for_each_uuid(dev_no, obd, &sbi->ll_sb_uuid)
                        obd->obd_force = force;
-               }
+               obd_device_unlock();
        }
 
        if (sbi->ll_client_common_fill_super_succeeded) {
@@ -1549,8 +1549,12 @@ void ll_put_super(struct super_block *sb)
        if (CFS_FAIL_CHECK(OBD_FAIL_OBD_CLEANUP))
                goto skip_cleanup;
 
-       next = 0;
-       while ((obd = class_devices_in_group(&sbi->ll_sb_uuid, &next)))
+       /*
+        * Cleanup, detach OBD devices, and remove them from Xarray.
+        * We don't grab the xa_lock() since class_manual_cleanup()
+        * uses the lock internally.
+        */
+       obd_device_for_each_uuid(dev_no, obd, &sbi->ll_sb_uuid)
                class_manual_cleanup(obd);
 
 skip_cleanup:
index e83ee15..ec53d02 100644 (file)
@@ -381,8 +381,8 @@ static int lov_add_mdc_target(const struct lu_env *env, struct lu_device *d,
 {
        struct lov_device *ld = lu2lov_dev(d);
        struct obd_device *lov_obd = d->ld_obd;
-       struct obd_device *lmv_obd;
-       int next;
+       struct obd_device *lmv_obd = NULL;
+       unsigned long dev_no = 0;
        int rc = 0;
 
        ENTRY;
@@ -404,23 +404,26 @@ static int lov_add_mdc_target(const struct lu_env *env, struct lu_device *d,
         * to be sure LMV is set up and can be found
         */
        if (!ld->ld_lmv) {
-               next = 0;
-               while ((lmv_obd = class_devices_in_group(&lov_obd->obd_uuid,
-                                                        &next)) != NULL) {
+               obd_device_lock();
+               obd_device_for_each_uuid(dev_no, lmv_obd,
+                                        &lov_obd->obd_uuid) {
                        if ((strncmp(lmv_obd->obd_type->typ_name,
                                     LUSTRE_LMV_NAME,
-                                    strlen(LUSTRE_LMV_NAME)) == 0))
+                                    strlen(LUSTRE_LMV_NAME)) == 0)) {
+                               spin_lock(&lmv_obd->obd_dev_lock);
+                               class_incref(lmv_obd, "lov", ld);
+                               spin_unlock(&lmv_obd->obd_dev_lock);
                                break;
+                       }
                }
+               obd_device_unlock();
+
                if (!lmv_obd) {
                        CERROR("%s: cannot find LMV OBD by UUID (%s)\n",
                               lov_obd->obd_name,
                               obd_uuid2str(&lmv_obd->obd_uuid));
                        RETURN(-ENODEV);
                }
-               spin_lock(&lmv_obd->obd_dev_lock);
-               class_incref(lmv_obd, "lov", ld);
-               spin_unlock(&lmv_obd->obd_dev_lock);
                ld->ld_lmv = lmv_obd;
        }
 
index 0781c6c..c95e5d4 100644 (file)
@@ -1539,8 +1539,7 @@ static int mgs_parse_devname(char *devname, char *fsname, u32 *index)
 /* This is only called during replace_nids */
 static int only_mgs_is_running(struct obd_device *mgs_obd)
 {
-       /* TDB: Is global variable with devices count exists? */
-       int num_devices = get_devices_count();
+       int num_devices = class_obd_devs_count();
        int num_exports = 0;
        struct obd_export *exp;
 
index f7270f8..8d2ebc2 100644 (file)
@@ -490,11 +490,8 @@ int class_handle_ioctl(unsigned int cmd, void __user *uarg)
                if (strnlen(data->ioc_inlbuf4, MAX_OBD_NAME) >= MAX_OBD_NAME)
                        GOTO(out, rc = -EINVAL);
                obd = class_name2obd(data->ioc_inlbuf4);
-       } else if (data->ioc_dev < class_devno_max()) {
-               obd = class_num2obd(data->ioc_dev);
        } else {
-               rc = OBD_IOC_ERROR("obdclass", cmd, "no device", -EINVAL);
-               GOTO(out, rc);
+               obd = class_num2obd(data->ioc_dev);
        }
 
        if (obd == NULL) {
index 879080b..2c094fb 100644 (file)
 #include <lustre_disk.h>
 #include <lustre_kernelcomm.h>
 
-DEFINE_RWLOCK(obd_dev_lock);
-static struct obd_device *obd_devs[MAX_OBD_DEVICES];
+DEFINE_XARRAY_ALLOC(obd_devs);
+EXPORT_SYMBOL(obd_devs);
+
+static atomic_t obd_devs_count = ATOMIC_INIT(0);
 
 static struct kmem_cache *obd_device_cachep;
 static struct kobj_type class_ktype;
@@ -61,10 +63,6 @@ static LIST_HEAD(obd_stale_exports);
 static DEFINE_SPINLOCK(obd_stale_export_lock);
 static atomic_t obd_stale_export_num = ATOMIC_INIT(0);
 
-/*
- * support functions: we could use inter-module communication, but this
- * is more portable to other OS's
- */
 static struct obd_device *obd_device_alloc(void)
 {
        struct obd_device *obd;
@@ -78,16 +76,17 @@ static struct obd_device *obd_device_alloc(void)
 
 static void obd_device_free(struct obd_device *obd)
 {
-        LASSERT(obd != NULL);
-        LASSERTF(obd->obd_magic == OBD_DEVICE_MAGIC, "obd %p obd_magic %08x != %08x\n",
-                 obd, obd->obd_magic, OBD_DEVICE_MAGIC);
-        if (obd->obd_namespace != NULL) {
-                CERROR("obd %p: namespace %p was not properly cleaned up (obd_force=%d)!\n",
-                       obd, obd->obd_namespace, obd->obd_force);
-                LBUG();
-        }
-        lu_ref_fini(&obd->obd_reference);
-        OBD_SLAB_FREE_PTR(obd, obd_device_cachep);
+       LASSERT(obd != NULL);
+       LASSERTF(obd->obd_magic == OBD_DEVICE_MAGIC,
+                "obd %p obd_magic %08x != %08x\n",
+                obd, obd->obd_magic, OBD_DEVICE_MAGIC);
+       if (obd->obd_namespace != NULL) {
+               CERROR("obd %p: namespace %p was not properly cleaned up (obd_force=%d)!\n",
+                      obd, obd->obd_namespace, obd->obd_force);
+               LBUG();
+       }
+       lu_ref_fini(&obd->obd_reference);
+       OBD_SLAB_FREE_PTR(obd, obd_device_cachep);
 }
 
 struct obd_type *class_search_type(const char *name)
@@ -433,9 +432,9 @@ void class_free_dev(struct obd_device *obd)
 
        LASSERTF(obd->obd_magic == OBD_DEVICE_MAGIC, "%p obd_magic %08x "
                 "!= %08x\n", obd, obd->obd_magic, OBD_DEVICE_MAGIC);
-       LASSERTF(obd->obd_minor == -1 || obd_devs[obd->obd_minor] == obd,
+       LASSERTF(obd->obd_minor == -1 || class_num2obd(obd->obd_minor) == obd,
                 "obd %p != obd_devs[%d] %p\n",
-                obd, obd->obd_minor, obd_devs[obd->obd_minor]);
+                obd, obd->obd_minor, class_num2obd(obd->obd_minor));
        LASSERTF(kref_read(&obd->obd_refcount) == 0,
                 "obd_refcount should be 0, not %d\n",
                 kref_read(&obd->obd_refcount));
@@ -464,7 +463,7 @@ void class_free_dev(struct obd_device *obd)
 /**
  * Unregister obd device.
  *
- * Free slot in obd_dev[] used by \a obd.
+ * Remove an obd from obd_dev
  *
  * \param[in] new_obd obd_device to be unregistered
  *
@@ -472,280 +471,221 @@ void class_free_dev(struct obd_device *obd)
  */
 void class_unregister_device(struct obd_device *obd)
 {
-       write_lock(&obd_dev_lock);
        if (obd->obd_minor >= 0) {
-               LASSERT(obd_devs[obd->obd_minor] == obd);
-               obd_devs[obd->obd_minor] = NULL;
+               xa_erase(&obd_devs, obd->obd_minor);
+               class_decref(obd, "obd_device_list", obd);
                obd->obd_minor = -1;
+               atomic_dec(&obd_devs_count);
        }
-       write_unlock(&obd_dev_lock);
 }
 
 /**
  * Register obd device.
  *
- * Find free slot in obd_devs[], fills it with \a new_obd.
+ * Add new_obd to obd_devs
  *
  * \param[in] new_obd obd_device to be registered
  *
  * \retval 0          success
  * \retval -EEXIST    device with this name is registered
- * \retval -EOVERFLOW obd_devs[] is full
  */
 int class_register_device(struct obd_device *new_obd)
 {
-       int ret = 0;
-       int i;
-       int new_obd_minor = 0;
-       bool minor_assign = false;
-       bool retried = false;
-
-again:
-       write_lock(&obd_dev_lock);
-       for (i = 0; i < class_devno_max(); i++) {
-               struct obd_device *obd = class_num2obd(i);
-
-               if (obd != NULL &&
-                   (strcmp(new_obd->obd_name, obd->obd_name) == 0)) {
-
-                       if (!retried) {
-                               write_unlock(&obd_dev_lock);
-
-                               /* the obd_device could be waited to be
-                                * destroyed by the "obd_zombie_impexp_thread".
-                                */
-                               obd_zombie_barrier();
-                               retried = true;
-                               goto again;
-                       }
+       int rc = 0;
+       int dev_no = 0;
 
-                       CERROR("%s: already exists, won't add\n",
-                              obd->obd_name);
-                       /* in case we found a free slot before duplicate */
-                       minor_assign = false;
-                       ret = -EEXIST;
-                       break;
-               }
-               if (!minor_assign && obd == NULL) {
-                       new_obd_minor = i;
-                       minor_assign = true;
-               }
+       if (new_obd == NULL) {
+               rc = -1;
+               goto out;
        }
 
-       if (minor_assign) {
-               new_obd->obd_minor = new_obd_minor;
-               LASSERTF(obd_devs[new_obd_minor] == NULL, "obd_devs[%d] "
-                        "%p\n", new_obd_minor, obd_devs[new_obd_minor]);
-               obd_devs[new_obd_minor] = new_obd;
-       } else {
-               if (ret == 0) {
-                       ret = -EOVERFLOW;
-                       CERROR("%s: all %u/%u devices used, increase "
-                              "MAX_OBD_DEVICES: rc = %d\n", new_obd->obd_name,
-                              i, class_devno_max(), ret);
-               }
-       }
-       write_unlock(&obd_dev_lock);
-
-       RETURN(ret);
-}
-
-static int class_name2dev_nolock(const char *name)
-{
-        int i;
+       /*
+        * The obd_device could be waiting to be
+        * destroyed by "obd_zombie_impexp_thread"
+        */
+       if (class_name2dev(new_obd->obd_name) != -1)
+               obd_zombie_barrier();
 
-        if (!name)
-                return -1;
+       if (class_name2dev(new_obd->obd_name) == -1) {
+               class_incref(new_obd, "obd_device_list", new_obd);
+               rc = xa_alloc(&obd_devs, &dev_no, new_obd,
+                             xa_limit_31b, GFP_ATOMIC);
 
-        for (i = 0; i < class_devno_max(); i++) {
-                struct obd_device *obd = class_num2obd(i);
+               if (rc != 0)
+                       goto out;
 
-               if (obd && strcmp(name, obd->obd_name) == 0) {
-                        /* Make sure we finished attaching before we give
-                           out any references */
-                        LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
-                        if (obd->obd_attached) {
-                                return i;
-                        }
-                        break;
-                }
-        }
+               new_obd->obd_minor = dev_no;
+               atomic_inc(&obd_devs_count);
+       } else {
+               rc = -EEXIST;
+       }
 
-        return -1;
+out:
+       RETURN(rc);
 }
 
 int class_name2dev(const char *name)
 {
-       int i;
+       struct obd_device *obd = NULL;
+       unsigned long dev_no = 0;
+       int ret;
 
        if (!name)
                return -1;
 
-       read_lock(&obd_dev_lock);
-       i = class_name2dev_nolock(name);
-       read_unlock(&obd_dev_lock);
+       obd_device_lock();
+       obd_device_for_each(dev_no, obd) {
+               if (strcmp(name, obd->obd_name) == 0) {
+                       /*
+                        * Make sure we finished attaching before we give
+                        * out any references
+                        */
+                       LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
+                       if (obd->obd_attached) {
+                               ret = obd->obd_minor;
+                               obd_device_unlock();
+                               return ret;
+                       }
+                       break;
+               }
+       }
+       obd_device_unlock();
 
-       return i;
+       return -1;
 }
 EXPORT_SYMBOL(class_name2dev);
 
 struct obd_device *class_name2obd(const char *name)
 {
-        int dev = class_name2dev(name);
-
-        if (dev < 0 || dev > class_devno_max())
-                return NULL;
-        return class_num2obd(dev);
-}
-EXPORT_SYMBOL(class_name2obd);
+       struct obd_device *obd = NULL;
+       unsigned long dev_no = 0;
 
-static int class_uuid2dev_nolock(struct obd_uuid *uuid)
-{
-        int i;
-
-        for (i = 0; i < class_devno_max(); i++) {
-                struct obd_device *obd = class_num2obd(i);
+       if (!name)
+               return NULL;
 
-                if (obd && obd_uuid_equals(uuid, &obd->obd_uuid)) {
-                        LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
-                        return i;
-                }
-        }
+       obd_device_lock();
+       obd_device_for_each(dev_no, obd) {
+               if (strcmp(name, obd->obd_name) == 0) {
+                       /*
+                        * Make sure we finished attaching before we give
+                        * out any references
+                        */
+                       LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
+                       if (obd->obd_attached)
+                               break;
+               }
+       }
+       obd_device_unlock();
 
-        return -1;
+       /*
+        * TODO: We give out a reference without class_incref(). This isn't
+        * ideal, but this behavior is identical in previous implementations
+        * of this function.
+        */
+       return obd;
 }
+EXPORT_SYMBOL(class_name2obd);
 
 int class_uuid2dev(struct obd_uuid *uuid)
 {
-       int i;
+       struct obd_device *obd = NULL;
+       unsigned long dev_no = 0;
+       int ret;
 
-       read_lock(&obd_dev_lock);
-       i = class_uuid2dev_nolock(uuid);
-       read_unlock(&obd_dev_lock);
+       obd_device_lock();
+       obd_device_for_each(dev_no, obd) {
+               if (obd_uuid_equals(uuid, &obd->obd_uuid)) {
+                       LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
+                       ret = obd->obd_minor;
+                       obd_device_unlock();
+                       return ret;
+               }
+       }
+       obd_device_unlock();
 
-       return i;
+       return -1;
 }
 EXPORT_SYMBOL(class_uuid2dev);
 
 struct obd_device *class_uuid2obd(struct obd_uuid *uuid)
 {
-        int dev = class_uuid2dev(uuid);
-        if (dev < 0)
-                return NULL;
-        return class_num2obd(dev);
+       struct obd_device *obd = NULL;
+       unsigned long dev_no = 0;
+
+       obd_device_lock();
+       obd_device_for_each(dev_no, obd) {
+               if (obd_uuid_equals(uuid, &obd->obd_uuid)) {
+                       LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
+                       break;
+               }
+       }
+       obd_device_unlock();
+
+       /*
+        * TODO: We give out a reference without class_incref(). This isn't
+        * ideal, but this behavior is identical in previous implementations
+        * of this function.
+        */
+       return obd;
 }
 EXPORT_SYMBOL(class_uuid2obd);
 
-/**
- * Get obd device from ::obd_devs[]
- *
- * \param num [in] array index
- *
- * \retval NULL if ::obd_devs[\a num] does not contains an obd device
- *         otherwise return the obd device there.
- */
-struct obd_device *class_num2obd(int num)
+struct obd_device *class_num2obd(int dev_no)
 {
-        struct obd_device *obd = NULL;
-
-        if (num < class_devno_max()) {
-                obd = obd_devs[num];
-                if (obd == NULL)
-                        return NULL;
-
-                LASSERTF(obd->obd_magic == OBD_DEVICE_MAGIC,
-                         "%p obd_magic %08x != %08x\n",
-                         obd, obd->obd_magic, OBD_DEVICE_MAGIC);
-                LASSERTF(obd->obd_minor == num,
-                         "%p obd_minor %0d != %0d\n",
-                         obd, obd->obd_minor, num);
-        }
-
-        return obd;
+       return xa_load(&obd_devs, dev_no);
 }
 EXPORT_SYMBOL(class_num2obd);
 
 /**
- * Find obd in obd_dev[] by name or uuid.
+ * Find obd by name or uuid.
  *
  * Increment obd's refcount if found.
  *
  * \param[in] str obd name or uuid
  *
  * \retval NULL    if not found
- * \retval target  pointer to found obd_device
+ * \retval obd     pointer to found obd_device
  */
-struct obd_device *class_dev_by_str(const char *str)
+struct obd_device *class_str2obd(const char *str)
 {
-       struct obd_device *target = NULL;
-       struct obd_uuid tgtuuid;
-       int rc;
+       struct obd_device *obd = NULL;
+       struct obd_uuid uuid;
+       unsigned long dev_no = 0;
 
-       obd_str2uuid(&tgtuuid, str);
+       obd_str2uuid(&uuid, str);
 
-       read_lock(&obd_dev_lock);
-       rc = class_uuid2dev_nolock(&tgtuuid);
-       if (rc < 0)
-               rc = class_name2dev_nolock(str);
-
-       if (rc >= 0)
-               target = class_num2obd(rc);
-
-       if (target != NULL)
-               class_incref(target, "find", current);
-       read_unlock(&obd_dev_lock);
+       obd_device_lock();
+       obd_device_for_each(dev_no, obd) {
+               if (obd_uuid_equals(&uuid, &obd->obd_uuid) ||
+                   (strcmp(str, obd->obd_name) == 0)) {
+                       /*
+                        * Make sure we finished attaching before we give
+                        * out any references
+                        */
+                       LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
+                       if (obd->obd_attached) {
+                               class_incref(obd, "find", current);
+                               break;
+                       }
+                       RETURN(NULL);
+               }
+       }
+       obd_device_unlock();
 
-       RETURN(target);
+       RETURN(obd);
 }
-EXPORT_SYMBOL(class_dev_by_str);
+EXPORT_SYMBOL(class_str2obd);
 
 /**
  * Get obd devices count. Device in any
  *    state are counted
  * \retval obd device count
  */
-int get_devices_count(void)
+int class_obd_devs_count(void)
 {
-       int index, max_index = class_devno_max(), dev_count = 0;
-
-       read_lock(&obd_dev_lock);
-       for (index = 0; index <= max_index; index++) {
-               struct obd_device *obd = class_num2obd(index);
-               if (obd != NULL)
-                       dev_count++;
-       }
-       read_unlock(&obd_dev_lock);
-
-       return dev_count;
-}
-EXPORT_SYMBOL(get_devices_count);
-
-void class_obd_list(void)
-{
-        char *status;
-        int i;
-
-       read_lock(&obd_dev_lock);
-        for (i = 0; i < class_devno_max(); i++) {
-                struct obd_device *obd = class_num2obd(i);
-
-                if (obd == NULL)
-                        continue;
-                if (obd->obd_stopping)
-                        status = "ST";
-                else if (obd->obd_set_up)
-                        status = "UP";
-                else if (obd->obd_attached)
-                        status = "AT";
-                else
-                        status = "--";
-                LCONSOLE(D_CONFIG, "%3d %s %s %s %s %d\n",
-                         i, status, obd->obd_type->typ_name,
-                         obd->obd_name, obd->obd_uuid.uuid,
-                        kref_read(&obd->obd_refcount));
-        }
-       read_unlock(&obd_dev_lock);
+       return atomic_read(&obd_devs_count);
 }
+EXPORT_SYMBOL(class_obd_devs_count);
 
 /* Search for a client OBD connected to tgt_uuid.  If grp_uuid is
  * specified, then only the client with that uuid is returned,
@@ -755,83 +695,44 @@ struct obd_device *class_find_client_obd(struct obd_uuid *tgt_uuid,
                                         const char *type_name,
                                         struct obd_uuid *grp_uuid)
 {
-        int i;
-
-       read_lock(&obd_dev_lock);
-        for (i = 0; i < class_devno_max(); i++) {
-                struct obd_device *obd = class_num2obd(i);
+       struct obd_device *obd = NULL;
+       unsigned long dev_no = 0;
 
-                if (obd == NULL)
-                        continue;
+       obd_device_lock();
+       obd_device_for_each(dev_no, obd) {
                if ((strncmp(obd->obd_type->typ_name, type_name,
                             strlen(type_name)) == 0)) {
-                        if (obd_uuid_equals(tgt_uuid,
-                                            &obd->u.cli.cl_target_uuid) &&
-                            ((grp_uuid)? obd_uuid_equals(grp_uuid,
-                                                         &obd->obd_uuid) : 1)) {
-                               read_unlock(&obd_dev_lock);
-                                return obd;
-                        }
-                }
-        }
-       read_unlock(&obd_dev_lock);
+                       if (obd_uuid_equals(tgt_uuid,
+                                           &obd->u.cli.cl_target_uuid) &&
+                           ((grp_uuid) ? obd_uuid_equals(grp_uuid,
+                                                        &obd->obd_uuid) : 1)) {
+                               obd_device_unlock();
+                               return obd;
+                       }
+               }
+       }
+       obd_device_unlock();
 
-        return NULL;
+       return NULL;
 }
 EXPORT_SYMBOL(class_find_client_obd);
 
-/* Iterate the obd_device list looking devices have grp_uuid. Start
- * searching at *next, and if a device is found, the next index to look
- * at is saved in *next. If next is NULL, then the first matching device
- * will always be returned.
- */
-struct obd_device *class_devices_in_group(struct obd_uuid *grp_uuid, int *next)
-{
-        int i;
-
-        if (next == NULL)
-                i = 0;
-        else if (*next >= 0 && *next < class_devno_max())
-                i = *next;
-        else
-                return NULL;
-
-       read_lock(&obd_dev_lock);
-        for (; i < class_devno_max(); i++) {
-                struct obd_device *obd = class_num2obd(i);
-
-                if (obd == NULL)
-                        continue;
-                if (obd_uuid_equals(grp_uuid, &obd->obd_uuid)) {
-                        if (next != NULL)
-                                *next = i+1;
-                       read_unlock(&obd_dev_lock);
-                        return obd;
-                }
-        }
-       read_unlock(&obd_dev_lock);
-
-        return NULL;
-}
-EXPORT_SYMBOL(class_devices_in_group);
-
 /**
  * to notify sptlrpc log for \a fsname has changed, let every relevant OBD
  * adjust sptlrpc settings accordingly.
  */
 int class_notify_sptlrpc_conf(const char *fsname, int namelen)
 {
-        struct obd_device  *obd;
-        const char         *type;
-        int                 i, rc = 0, rc2;
+       struct obd_device *obd = NULL;
+       unsigned long dev_no = 0;
+       const char *type;
+       int rc = 0, rc2;
 
-        LASSERT(namelen > 0);
+       LASSERT(namelen > 0);
 
-       read_lock(&obd_dev_lock);
-       for (i = 0; i < class_devno_max(); i++) {
-               obd = class_num2obd(i);
-
-               if (obd == NULL || obd->obd_set_up == 0 || obd->obd_stopping)
+       obd_device_lock();
+       obd_device_for_each(dev_no, obd) {
+               if (obd->obd_set_up == 0 || obd->obd_stopping)
                        continue;
 
                /* only notify mdc, osc, osp, lwp, mdt, ost
@@ -845,20 +746,21 @@ int class_notify_sptlrpc_conf(const char *fsname, int namelen)
                    strcmp(type, LUSTRE_OST_NAME) != 0)
                        continue;
 
-                if (strncmp(obd->obd_name, fsname, namelen))
-                        continue;
+               if (strncmp(obd->obd_name, fsname, namelen))
+                       continue;
 
-                class_incref(obd, __FUNCTION__, obd);
-               read_unlock(&obd_dev_lock);
-                rc2 = obd_set_info_async(NULL, obd->obd_self_export,
-                                         sizeof(KEY_SPTLRPC_CONF),
-                                         KEY_SPTLRPC_CONF, 0, NULL, NULL);
-                rc = rc ? rc : rc2;
-                class_decref(obd, __FUNCTION__, obd);
-               read_lock(&obd_dev_lock);
-        }
-       read_unlock(&obd_dev_lock);
-        return rc;
+               class_incref(obd, __func__, obd);
+               obd_device_unlock();
+               rc2 = obd_set_info_async(NULL, obd->obd_self_export,
+                                        sizeof(KEY_SPTLRPC_CONF),
+                                        KEY_SPTLRPC_CONF, 0, NULL, NULL);
+               rc = rc ? rc : rc2;
+               obd_device_lock();
+               class_decref(obd, __func__, obd);
+       }
+       obd_device_unlock();
+
+       return rc;
 }
 EXPORT_SYMBOL(class_notify_sptlrpc_conf);
 
index fd86b93..c08c85c 100644 (file)
@@ -170,12 +170,14 @@ static int lustre_device_list_dump(struct sk_buff *msg,
 {
        struct genl_dev_list *glist = device_dump_ctx(cb);
        struct obd_device *filter = glist->gdl_target;
+       struct obd_device *obd = NULL;
 #ifdef HAVE_NL_PARSE_WITH_EXT_ACK
        struct netlink_ext_ack *extack = NULL;
 #endif
        int portid = NETLINK_CB(cb->skb).portid;
        int seq = cb->nlh->nlmsg_seq;
-       int idx, rc = 0;
+       unsigned long idx = 0;
+       int rc = 0;
 
 #ifdef HAVE_NL_DUMP_WITH_EXT_ACK
        extack = cb->extack;
@@ -195,15 +197,11 @@ static int lustre_device_list_dump(struct sk_buff *msg,
                }
        }
 
-       for (idx = glist->gdl_start; idx < class_devno_max(); idx++) {
-               struct obd_device *obd;
+       obd_device_lock();
+       obd_device_for_each_start(idx, obd, glist->gdl_start) {
                const char *status;
                void *hdr;
 
-               obd = class_num2obd(idx);
-               if (!obd)
-                       continue;
-
                if (filter && filter != obd)
                        continue;
 
@@ -255,9 +253,11 @@ static int lustre_device_list_dump(struct sk_buff *msg,
 
                genlmsg_end(msg, hdr);
        }
+       obd_device_unlock();
 
-       glist->gdl_start = idx;
+       glist->gdl_start = idx + 1;
        rc = lnet_nl_send_error(cb->skb, portid, seq, rc);
+
        return rc < 0 ? rc : msg->len;
 }
 
index 2498c7a..eec745f 100644 (file)
@@ -85,7 +85,6 @@ static const struct rhashtable_params uuid_hash_params = {
        .key_offset     = offsetof(struct obd_export, exp_client_uuid),
        .head_offset    = offsetof(struct obd_export, exp_uuid_hash),
        .obj_cmpfn      = uuid_keycmp,
-       .max_size       = MAX_OBD_DEVICES,
        .automatic_shrinking = true,
 };
 
@@ -804,10 +803,10 @@ int class_detach(struct obd_device *obd, struct lustre_cfg *lcfg)
                RETURN(-ENODEV);
        }
        obd->obd_attached = 0;
-       spin_unlock(&obd->obd_dev_lock);
 
        /* cleanup in progress. we don't like to find this device after now */
        class_unregister_device(obd);
+       spin_unlock(&obd->obd_dev_lock);
 
        CDEBUG(D_IOCTL, "detach on obd %s (uuid %s)\n",
               obd->obd_name, obd->obd_uuid.uuid);
index 9487b68..af6eebb 100644 (file)
@@ -109,7 +109,6 @@ out:
                                   "%s: Confguration from log %s failed from MGS %d. Communication error between node & MGS, a bad configuration, or other errors. See syslog for more info\n",
                                   mgc->obd_name, logname, rc);
 
-       /* class_obd_list(); */
        RETURN(rc);
 }
 EXPORT_SYMBOL(lustre_process_log);
index 05c9f60..d689480 100644 (file)
@@ -235,41 +235,31 @@ static ssize_t pinger_show(struct kobject *kobj, struct attribute *attr,
 static ssize_t
 health_check_show(struct kobject *kobj, struct attribute *attr, char *buf)
 {
+       struct obd_device *obd = NULL;
+       unsigned long dev_no = 0;
        bool healthy = true;
        size_t len = 0;
-       int i;
 
        if (libcfs_catastrophe)
                return sprintf(buf, "LBUG\n");
 
-       read_lock(&obd_dev_lock);
-       for (i = 0; i < class_devno_max(); i++) {
-               struct obd_device *obd;
-
-               obd = class_num2obd(i);
-               if (obd == NULL || !obd->obd_attached || !obd->obd_set_up)
-                       continue;
-
+       obd_device_lock();
+       obd_device_for_each_cond(dev_no, obd, obd->obd_attached &&
+                                obd->obd_set_up && !obd->obd_stopping &&
+                                !obd->obd_read_only) {
                LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
-               if (obd->obd_stopping)
-                       continue;
-
-               if (obd->obd_read_only)
-                       continue;
 
                class_incref(obd, __func__, current);
-               read_unlock(&obd_dev_lock);
-
+               obd_device_unlock();
                if (obd_health_check(NULL, obd))
                        healthy = false;
-
+               obd_device_lock();
                class_decref(obd, __func__, current);
-               read_lock(&obd_dev_lock);
 
                if (!healthy)
                        break;
        }
-       read_unlock(&obd_dev_lock);
+       obd_device_unlock();
 
        if (healthy)
                len = sprintf(buf, "healthy\n");
@@ -459,35 +449,71 @@ static struct attribute *lustre_attrs[] = {
 
 static void *obd_device_list_seq_start(struct seq_file *p, loff_t *pos)
 {
-       if (*pos >= class_devno_max())
+       struct obd_device *obd;
+       unsigned long devno;
+
+       devno = *pos;
+       obd_device_lock();
+       obd = obd_device_find(devno);
+
+       if (!obd) {
+               obd_device_unlock();
                return NULL;
+       }
 
-       return pos;
+       *pos = devno;
+       class_incref(obd, "obd_device_list_seq", obd);
+       obd_device_unlock();
+
+       return obd;
 }
 
 static void obd_device_list_seq_stop(struct seq_file *p, void *v)
 {
+       struct obd_device *obd = v;
+
+       if (!obd)
+               return;
+
+       obd_device_lock();
+       class_decref(obd, "obd_device_list_seq", obd);
+       obd_device_unlock();
 }
 
 static void *obd_device_list_seq_next(struct seq_file *p, void *v, loff_t *pos)
 {
-       ++*pos;
-       if (*pos >= class_devno_max())
+       struct obd_device *obd = v;
+       unsigned long devno;
+
+       obd_device_lock();
+       class_decref(obd, "obd_device_list_seq", obd);
+       devno = *pos;
+       obd = obd_device_find_after(devno);
+
+       if (!obd) {
+               (*pos)++;
+               obd_device_unlock();
                return NULL;
+       }
 
-       return pos;
+       *pos = devno;
+       class_incref(obd, "obd_device_list_seq", obd);
+       obd_device_unlock();
+
+       return obd;
 }
 
 static int obd_device_list_seq_show(struct seq_file *p, void *v)
 {
-       loff_t index = *(loff_t *)v;
-       struct obd_device *obd = class_num2obd((int)index);
+       struct obd_device *obd = v;
+       int dev_no = obd->obd_minor;
        char *status;
 
-       if (obd == NULL)
+       if (!obd)
                return 0;
 
        LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
+
        if (obd->obd_stopping)
                status = "ST";
        else if (obd->obd_inactive)
@@ -500,9 +526,10 @@ static int obd_device_list_seq_show(struct seq_file *p, void *v)
                status = "--";
 
        seq_printf(p, "%3d %s %s %s %s %d\n",
-                  (int)index, status, obd->obd_type->typ_name,
+                  dev_no, status, obd->obd_type->typ_name,
                   obd->obd_name, obd->obd_uuid.uuid,
                   kref_read(&obd->obd_refcount));
+
        return 0;
 }
 
@@ -594,31 +621,24 @@ static const struct file_operations checksum_speed_fops = {
 static int
 health_check_seq_show(struct seq_file *m, void *unused)
 {
-       int i;
-
-       read_lock(&obd_dev_lock);
-       for (i = 0; i < class_devno_max(); i++) {
-               struct obd_device *obd;
-
-               obd = class_num2obd(i);
-               if (obd == NULL || !obd->obd_attached || !obd->obd_set_up)
-                       continue;
+       struct obd_device *obd = NULL;
+       unsigned long dev_no = 0;
 
+       obd_device_lock();
+       obd_device_for_each_cond(dev_no, obd, obd->obd_attached &&
+                                obd->obd_set_up && !obd->obd_stopping) {
                LASSERT(obd->obd_magic == OBD_DEVICE_MAGIC);
-               if (obd->obd_stopping)
-                       continue;
 
                class_incref(obd, __func__, current);
-               read_unlock(&obd_dev_lock);
-
+               obd_device_unlock();
                if (obd_health_check(NULL, obd)) {
                        seq_printf(m, "device %s reported unhealthy\n",
                                   obd->obd_name);
                }
+               obd_device_lock();
                class_decref(obd, __func__, current);
-               read_lock(&obd_dev_lock);
        }
-       read_unlock(&obd_dev_lock);
+       obd_device_unlock();
 
        return 0;
 }
index 3f96ca7..d057091 100755 (executable)
@@ -6391,7 +6391,11 @@ run_test 55a "OBD device life cycle unit tests"
 test_55b() {
        local dev_path="/sys/kernel/debug/lustre/devices"
        local dev_count="$(wc -l $dev_path | awk '{print $1}')"
-       local num_dev_to_create="$((8192 - $dev_count))"
+
+       # Set up a large number of devices, using the number
+       # that can be set up in about a minute (based on prior
+       # testing). We don't want to run this test forever.
+       local num_dev_to_create="$(( 24000 - $dev_count))"
 
        load_module obdclass/obd_test || error "load_module failed"