+ /* destroy an uuid-export hash body */
+ lustre_hash_exit(&obd->obd_uuid_hash_body);
+
+ /* destroy a nid-export hash body */
+ lustre_hash_exit(&obd->obd_nid_hash_body);
+
+ /* Precleanup stage 1, we must make sure all exports (other than the
+ self-export) get destroyed. */
+ err = obd_precleanup(obd, OBD_CLEANUP_EXPORTS);
+ if (err)
+ CERROR("Precleanup %s returned %d\n",
+ obd->obd_name, err);
+
+ class_decref(obd);
+ obd->obd_set_up = 0;
+
+ RETURN(0);
+}
+
+struct obd_device *class_incref(struct obd_device *obd)
+{
+ atomic_inc(&obd->obd_refcount);
+ CDEBUG(D_INFO, "incref %s (%p) now %d\n", obd->obd_name, obd,
+ atomic_read(&obd->obd_refcount));
+
+ return obd;
+}
+
+void class_decref(struct obd_device *obd)
+{
+ int err;
+ int refs;
+
+ spin_lock(&obd->obd_dev_lock);
+ atomic_dec(&obd->obd_refcount);
+ refs = atomic_read(&obd->obd_refcount);
+ spin_unlock(&obd->obd_dev_lock);
+
+ CDEBUG(D_INFO, "Decref %s (%p) now %d\n", obd->obd_name, obd, refs);
+
+ if ((refs == 1) && obd->obd_stopping) {
+ /* All exports (other than the self-export) have been
+ destroyed; there should be no more in-progress ops
+ by this point.*/
+ /* if we're not stopping, we didn't finish setup */
+ /* Precleanup stage 2, do other type-specific
+ cleanup requiring the self-export. */
+ err = obd_precleanup(obd, OBD_CLEANUP_SELF_EXP);
+ if (err)
+ CERROR("Precleanup %s returned %d\n",
+ obd->obd_name, err);
+ obd->obd_self_export->exp_flags |=
+ (obd->obd_fail ? OBD_OPT_FAILOVER : 0) |
+ (obd->obd_force ? OBD_OPT_FORCE : 0);
+ /* note that we'll recurse into class_decref again */
+ class_unlink_export(obd->obd_self_export);
+ return;
+ }
+
+ if (refs == 0) {
+ CDEBUG(D_CONFIG, "finishing cleanup of obd %s (%s)\n",
+ obd->obd_name, obd->obd_uuid.uuid);
+ LASSERT(!obd->obd_attached);
+ if (obd->obd_stopping) {
+ /* If we're not stopping, we were never set up */
+ err = obd_cleanup(obd);
+ if (err)
+ CERROR("Cleanup %s returned %d\n",
+ obd->obd_name, err);