Whamcloud - gitweb
LU-2275: obdclass: Proper error cleaup for class_newdev
[fs/lustre-release.git] / lustre / obdclass / genops.c
index 9839fcd..316c9f9 100644 (file)
@@ -65,6 +65,7 @@ static void print_export_data(struct obd_export *exp,
                               const char *status, int locks);
 
 int (*ptlrpc_put_connection_superhack)(struct ptlrpc_connection *c);
+EXPORT_SYMBOL(ptlrpc_put_connection_superhack);
 
 /*
  * support functions: we could use inter-module communication, but this
@@ -111,6 +112,7 @@ struct obd_type *class_search_type(const char *name)
         cfs_spin_unlock(&obd_types_lock);
         return NULL;
 }
+EXPORT_SYMBOL(class_search_type);
 
 struct obd_type *class_get_type(const char *name)
 {
@@ -119,6 +121,10 @@ struct obd_type *class_get_type(const char *name)
 #ifdef HAVE_MODULE_LOADING_SUPPORT
         if (!type) {
                 const char *modname = name;
+
+               if (strcmp(modname, "obdfilter") == 0)
+                       modname = "ofd";
+
                 if (!cfs_request_module("%s", modname)) {
                         CDEBUG(D_INFO, "Loaded module '%s'\n", modname);
                         type = class_search_type(name);
@@ -240,9 +246,11 @@ int class_unregister_type(const char *name)
                 RETURN(-EBUSY);
         }
 
-        if (type->typ_procroot) {
-                lprocfs_remove(&type->typ_procroot);
-        }
+       /* we do not use type->typ_procroot as for compatibility purposes
+        * other modules can share names (i.e. lod can use lov entry). so
+        * we can't reference pointer as it can get invalided when another
+        * module removes the entry */
+       lprocfs_try_remove_proc_entry(type->typ_name, proc_lustre_root);
 
         if (type->typ_lu)
                 lu_device_type_fini(type->typ_lu);
@@ -292,10 +300,9 @@ struct obd_device *class_newdev(const char *type_name, const char *name)
         }
 
         newdev = obd_device_alloc();
-        if (newdev == NULL) {
-                class_put_type(type);
-                RETURN(ERR_PTR(-ENOMEM));
-        }
+       if (newdev == NULL)
+               GOTO(out_type, result = ERR_PTR(-ENOMEM));
+
         LASSERT(newdev->obd_magic == OBD_DEVICE_MAGIC);
 
         cfs_write_lock(&obd_dev_lock);
@@ -335,17 +342,21 @@ struct obd_device *class_newdev(const char *type_name, const char *name)
         if (result == NULL && i >= class_devno_max()) {
                 CERROR("all %u OBD devices used, increase MAX_OBD_DEVICES\n",
                        class_devno_max());
-                RETURN(ERR_PTR(-EOVERFLOW));
+               GOTO(out, result = ERR_PTR(-EOVERFLOW));
         }
 
-        if (IS_ERR(result)) {
-                obd_device_free(newdev);
-                class_put_type(type);
-        } else {
-                CDEBUG(D_IOCTL, "Adding new device %s (%p)\n",
-                       result->obd_name, result);
-        }
-        RETURN(result);
+       if (IS_ERR(result))
+               GOTO(out, result);
+
+       CDEBUG(D_IOCTL, "Adding new device %s (%p)\n",
+              result->obd_name, result);
+
+       RETURN(result);
+out:
+       obd_device_free(newdev);
+out_type:
+       class_put_type(type);
+       return result;
 }
 
 void class_release_dev(struct obd_device *obd)
@@ -730,58 +741,21 @@ struct obd_import *class_conn2cliimp(struct lustre_handle *conn)
 EXPORT_SYMBOL(class_conn2cliimp);
 
 /* Export management functions */
-
-/* if export is involved in recovery then clean up related things */
-void class_export_recovery_cleanup(struct obd_export *exp)
-{
-        struct obd_device *obd = exp->exp_obd;
-
-        cfs_spin_lock(&obd->obd_recovery_task_lock);
-        if (exp->exp_delayed)
-                obd->obd_delayed_clients--;
-        if (obd->obd_recovering && exp->exp_in_recovery) {
-                cfs_spin_lock(&exp->exp_lock);
-                exp->exp_in_recovery = 0;
-                cfs_spin_unlock(&exp->exp_lock);
-                LASSERT_ATOMIC_POS(&obd->obd_connected_clients);
-                cfs_atomic_dec(&obd->obd_connected_clients);
-        }
-        cfs_spin_unlock(&obd->obd_recovery_task_lock);
-        /** Cleanup req replay fields */
-        if (exp->exp_req_replay_needed) {
-                cfs_spin_lock(&exp->exp_lock);
-                exp->exp_req_replay_needed = 0;
-                cfs_spin_unlock(&exp->exp_lock);
-                LASSERT(cfs_atomic_read(&obd->obd_req_replay_clients));
-                cfs_atomic_dec(&obd->obd_req_replay_clients);
-        }
-        /** Cleanup lock replay data */
-        if (exp->exp_lock_replay_needed) {
-                cfs_spin_lock(&exp->exp_lock);
-                exp->exp_lock_replay_needed = 0;
-                cfs_spin_unlock(&exp->exp_lock);
-                LASSERT(cfs_atomic_read(&obd->obd_lock_replay_clients));
-                cfs_atomic_dec(&obd->obd_lock_replay_clients);
-        }
-}
-
 static void class_export_destroy(struct obd_export *exp)
 {
         struct obd_device *obd = exp->exp_obd;
         ENTRY;
 
         LASSERT_ATOMIC_ZERO(&exp->exp_refcount);
-        LASSERT(obd != NULL);
+       LASSERT(obd != NULL);
 
         CDEBUG(D_IOCTL, "destroying export %p/%s for %s\n", exp,
                exp->exp_client_uuid.uuid, obd->obd_name);
 
-
         /* "Local" exports (lctl, LOV->{mdc,osc}) have no connection. */
         if (exp->exp_connection)
                 ptlrpc_put_connection_superhack(exp->exp_connection);
 
-        LASSERT(cfs_list_empty(&exp->exp_flock_wait_list));
         LASSERT(cfs_list_empty(&exp->exp_outstanding_replies));
         LASSERT(cfs_list_empty(&exp->exp_uncommitted_replies));
         LASSERT(cfs_list_empty(&exp->exp_req_replay_queue));
@@ -798,6 +772,11 @@ static void export_handle_addref(void *export)
         class_export_get(export);
 }
 
+static struct portals_handle_ops export_handle_ops = {
+       .hop_addref = export_handle_addref,
+       .hop_free   = NULL,
+};
+
 struct obd_export *class_export_get(struct obd_export *exp)
 {
         cfs_atomic_inc(&exp->exp_refcount);
@@ -821,7 +800,6 @@ void class_export_put(struct obd_export *exp)
 
                 /* release nid stat refererence */
                 lprocfs_exp_cleanup(exp);
-                class_export_recovery_cleanup(exp);
 
                 obd_zombie_export_add(exp);
         }
@@ -845,6 +823,7 @@ struct obd_export *class_new_export(struct obd_device *obd,
 
         export->exp_conn_cnt = 0;
         export->exp_lock_hash = NULL;
+       export->exp_flock_hash = NULL;
         cfs_atomic_set(&export->exp_refcount, 2);
         cfs_atomic_set(&export->exp_rpc_count, 0);
         cfs_atomic_set(&export->exp_cb_count, 0);
@@ -855,16 +834,14 @@ struct obd_export *class_new_export(struct obd_device *obd,
 #endif
         cfs_atomic_set(&export->exp_replay_count, 0);
         export->exp_obd = obd;
-        CFS_INIT_LIST_HEAD(&export->exp_flock_wait_list);
-        cfs_rwlock_init(&export->exp_flock_wait_lock);
         CFS_INIT_LIST_HEAD(&export->exp_outstanding_replies);
         cfs_spin_lock_init(&export->exp_uncommitted_replies_lock);
         CFS_INIT_LIST_HEAD(&export->exp_uncommitted_replies);
         CFS_INIT_LIST_HEAD(&export->exp_req_replay_queue);
         CFS_INIT_LIST_HEAD(&export->exp_handle.h_link);
         CFS_INIT_LIST_HEAD(&export->exp_hp_rpcs);
-        class_handle_hash(&export->exp_handle, export_handle_addref);
-        export->exp_last_request_time = cfs_time_current_sec();
+       class_handle_hash(&export->exp_handle, &export_handle_ops);
+       export->exp_last_request_time = cfs_time_current_sec();
         cfs_spin_lock_init(&export->exp_lock);
         cfs_spin_lock_init(&export->exp_rpc_lock);
         CFS_INIT_HLIST_NODE(&export->exp_uuid_hash);
@@ -976,6 +953,11 @@ static void import_handle_addref(void *import)
         class_import_get(import);
 }
 
+static struct portals_handle_ops import_handle_ops = {
+       .hop_addref = import_handle_addref,
+       .hop_free   = NULL,
+};
+
 struct obd_import *class_import_get(struct obd_import *import)
 {
         cfs_atomic_inc(&import->imp_refcount);
@@ -1002,7 +984,9 @@ void class_import_put(struct obd_import *imp)
                 obd_zombie_import_add(imp);
         }
 
-        EXIT;
+       /* catch possible import put race */
+       LASSERT_ATOMIC_GE_LT(&imp->imp_refcount, 0, LI_POISON);
+       EXIT;
 }
 EXPORT_SYMBOL(class_import_put);
 
@@ -1044,7 +1028,7 @@ struct obd_import *class_new_import(struct obd_device *obd)
         cfs_atomic_set(&imp->imp_inval_count, 0);
         CFS_INIT_LIST_HEAD(&imp->imp_conn_list);
         CFS_INIT_LIST_HEAD(&imp->imp_handle.h_link);
-        class_handle_hash(&imp->imp_handle, import_handle_addref);
+       class_handle_hash(&imp->imp_handle, &import_handle_ops);
         init_imp_at(&imp->imp_at);
 
         /* the default magic is V2, will be used in connect RPC, and
@@ -1138,6 +1122,39 @@ int class_connect(struct lustre_handle *conn, struct obd_device *obd,
 }
 EXPORT_SYMBOL(class_connect);
 
+/* if export is involved in recovery then clean up related things */
+void class_export_recovery_cleanup(struct obd_export *exp)
+{
+        struct obd_device *obd = exp->exp_obd;
+
+        cfs_spin_lock(&obd->obd_recovery_task_lock);
+        if (exp->exp_delayed)
+                obd->obd_delayed_clients--;
+        if (obd->obd_recovering && exp->exp_in_recovery) {
+                cfs_spin_lock(&exp->exp_lock);
+                exp->exp_in_recovery = 0;
+                cfs_spin_unlock(&exp->exp_lock);
+                LASSERT_ATOMIC_POS(&obd->obd_connected_clients);
+                cfs_atomic_dec(&obd->obd_connected_clients);
+        }
+        cfs_spin_unlock(&obd->obd_recovery_task_lock);
+        /** Cleanup req replay fields */
+        if (exp->exp_req_replay_needed) {
+                cfs_spin_lock(&exp->exp_lock);
+                exp->exp_req_replay_needed = 0;
+                cfs_spin_unlock(&exp->exp_lock);
+                LASSERT(cfs_atomic_read(&obd->obd_req_replay_clients));
+                cfs_atomic_dec(&obd->obd_req_replay_clients);
+        }
+        /** Cleanup lock replay data */
+        if (exp->exp_lock_replay_needed) {
+                cfs_spin_lock(&exp->exp_lock);
+                exp->exp_lock_replay_needed = 0;
+                cfs_spin_unlock(&exp->exp_lock);
+                LASSERT(cfs_atomic_read(&obd->obd_lock_replay_clients));
+                cfs_atomic_dec(&obd->obd_lock_replay_clients);
+        }
+}
 
 /* This function removes 1-3 references from the export:
  * 1 - for export pointer passed
@@ -1176,6 +1193,7 @@ int class_disconnect(struct obd_export *export)
                              &export->exp_connection->c_peer.nid,
                              &export->exp_nid_hash);
 
+        class_export_recovery_cleanup(export);
         class_unlink_export(export);
 no_disconn:
         class_export_put(export);
@@ -1273,32 +1291,31 @@ void class_disconnect_stale_exports(struct obd_device *obd,
                                     int (*test_export)(struct obd_export *))
 {
         cfs_list_t work_list;
-        cfs_list_t *pos, *n;
-        struct obd_export *exp;
+       struct obd_export *exp, *n;
         int evicted = 0;
         ENTRY;
 
         CFS_INIT_LIST_HEAD(&work_list);
         cfs_spin_lock(&obd->obd_dev_lock);
-        cfs_list_for_each_safe(pos, n, &obd->obd_exports) {
-                int failed;
-
-                exp = cfs_list_entry(pos, struct obd_export, exp_obd_chain);
-
+       cfs_list_for_each_entry_safe(exp, n, &obd->obd_exports,
+                                    exp_obd_chain) {
                 /* don't count self-export as client */
                 if (obd_uuid_equals(&exp->exp_client_uuid,
                                     &exp->exp_obd->obd_uuid))
                         continue;
 
-                if (test_export(exp))
-                        continue;
+               /* don't evict clients which have no slot in last_rcvd
+                * (e.g. lightweight connection) */
+               if (exp->exp_target_data.ted_lr_idx == -1)
+                       continue;
 
-                cfs_spin_lock(&exp->exp_lock);
-                failed = exp->exp_failed;
-                exp->exp_failed = 1;
-                cfs_spin_unlock(&exp->exp_lock);
-                if (failed)
-                        continue;
+               cfs_spin_lock(&exp->exp_lock);
+               if (test_export(exp)) {
+                       cfs_spin_unlock(&exp->exp_lock);
+                       continue;
+               }
+               exp->exp_failed = 1;
+               cfs_spin_unlock(&exp->exp_lock);
 
                 cfs_list_move(&exp->exp_obd_chain, &work_list);
                 evicted++;
@@ -1342,8 +1359,8 @@ void class_fail_export(struct obd_export *exp)
         if (obd_dump_on_timeout)
                 libcfs_debug_dumplog();
 
-        /* need for safe call CDEBUG after obd_disconnect */
-        class_export_get(exp);
+       /* need for safe call CDEBUG after obd_disconnect */
+       class_export_get(exp);
 
         /* Most callers into obd_disconnect are removing their own reference
          * (request, for example) in addition to the one from the hash table.
@@ -1355,7 +1372,7 @@ void class_fail_export(struct obd_export *exp)
         else
                 CDEBUG(D_HA, "disconnected export %p/%s\n",
                        exp, exp->exp_client_uuid.uuid);
-        class_export_put(exp);
+       class_export_put(exp);
 }
 EXPORT_SYMBOL(class_fail_export);