-void class_disconnect_all(struct obd_device *obddev)
-{
- int again = 1;
-
- while (again) {
- spin_lock(&obddev->obd_dev_lock);
- if (!list_empty(&obddev->obd_exports)) {
- struct obd_export *export;
- struct lustre_handle conn;
- int rc;
-
- export = list_entry(obddev->obd_exports.next,
- struct obd_export,
- exp_obd_chain);
- conn.addr = (__u64)(unsigned long)export;
- conn.cookie = export->exp_cookie;
- spin_unlock(&obddev->obd_dev_lock);
- CERROR("force disconnecting %s:%s export %p\n",
- export->exp_obd->obd_type->typ_name,
- export->exp_connection->c_remote_uuid, export);
- rc = obd_disconnect(&conn);
- if (rc < 0) {
- /* AED: not so sure about this... We can't
- * loop here forever, yet we shouldn't leak
- * exports on a struct we will soon destroy.
- */
- CERROR("destroy export %p with err: rc = %d\n",
- export, rc);
- class_destroy_export(export);
- }
+void class_disconnect_exports(struct obd_device *obd, int flags)
+{
+ int rc;
+ struct list_head *tmp, *n, work_list;
+ struct lustre_handle fake_conn;
+ struct obd_export *fake_exp, *exp;
+ ENTRY;
+
+ /* Move all of the exports from obd_exports to a work list, en masse. */
+ spin_lock(&obd->obd_dev_lock);
+ list_add(&work_list, &obd->obd_exports);
+ list_del_init(&obd->obd_exports);
+ spin_unlock(&obd->obd_dev_lock);
+
+ CDEBUG(D_HA, "OBD device %d (%p) has exports, "
+ "disconnecting them\n", obd->obd_minor, obd);
+ list_for_each_safe(tmp, n, &work_list) {
+ exp = list_entry(tmp, struct obd_export, exp_obd_chain);
+ class_export_get(exp);
+
+ if (obd_uuid_equals(&exp->exp_client_uuid,
+ &exp->exp_obd->obd_uuid)) {
+ CDEBUG(D_HA,
+ "exp %p export uuid == obd uuid, don't discon\n",
+ exp);
+ /* Need to delete this now so we don't end up pointing
+ * to work_list later when this export is cleaned up. */
+ list_del_init(&exp->exp_obd_chain);
+ class_export_put(exp);
+ continue;
+ }
+
+ fake_conn.cookie = exp->exp_handle.h_cookie;
+ fake_exp = class_conn2export(&fake_conn);
+ if (!fake_exp) {
+ class_export_put(exp);
+ continue;
+ }
+ rc = obd_disconnect(fake_exp, flags);
+ class_export_put(exp);
+ if (rc) {
+ CDEBUG(D_HA, "disconnecting export %p failed: %d\n",
+ exp, rc);