+DEFINE_IDR(mdc_changelog_minor_idr);
+static DEFINE_SPINLOCK(chlg_minor_lock);
+
+static int chlg_minor_alloc(int *pminor)
+{
+ void *minor_allocated = (void *)-1;
+ int minor;
+
+ idr_preload(GFP_KERNEL);
+ spin_lock(&chlg_minor_lock);
+ minor = idr_alloc(&mdc_changelog_minor_idr, minor_allocated, 0,
+ MDC_CHANGELOG_DEV_COUNT, GFP_NOWAIT);
+ spin_unlock(&chlg_minor_lock);
+ idr_preload_end();
+
+ if (minor < 0)
+ return minor;
+
+ *pminor = minor;
+ return 0;
+}
+
+static void chlg_minor_free(int minor)
+{
+ spin_lock(&chlg_minor_lock);
+ idr_remove(&mdc_changelog_minor_idr, minor);
+ spin_unlock(&chlg_minor_lock);
+}
+
+static void chlg_device_release(struct device *dev)
+{
+ struct chlg_registered_dev *entry = dev_get_drvdata(dev);
+
+ chlg_minor_free(MINOR(entry->ced_cdev.dev));
+ OBD_FREE_PTR(entry);
+}
+
+/**
+ * Deregister a changelog character device whose refcount has reached zero.
+ */
+static void chlg_dev_clear(struct kref *kref)
+{
+ struct chlg_registered_dev *entry;
+
+ ENTRY;
+ entry = container_of(kref, struct chlg_registered_dev,
+ ced_refs);
+
+ list_del(&entry->ced_link);
+ cdev_device_del(&entry->ced_cdev, &entry->ced_device);
+ put_device(&entry->ced_device);
+ EXIT;
+}
+
+static inline struct obd_device* chlg_obd_get(struct chlg_registered_dev *dev)
+{
+ struct obd_device *obd;
+
+ mutex_lock(&chlg_registered_dev_lock);
+ if (list_empty(&dev->ced_obds))
+ return NULL;
+
+ obd = list_first_entry(&dev->ced_obds, struct obd_device,
+ u.cli.cl_chg_dev_linkage);
+ class_incref(obd, "changelog", dev);
+ mutex_unlock(&chlg_registered_dev_lock);
+ return obd;
+}
+
+static inline void chlg_obd_put(struct chlg_registered_dev *dev,
+ struct obd_device *obd)
+{
+ class_decref(obd, "changelog", dev);
+}
+