summaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/block/drbd/drbd_main.c')
-rw-r--r--drivers/block/drbd/drbd_main.c96
1 files changed, 71 insertions, 25 deletions
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 4da017d22f4b..f13d836e76a6 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -118,7 +118,7 @@ module_param_string(usermode_helper, usermode_helper, sizeof(usermode_helper), 0
* as member "struct gendisk *vdisk;"
*/
struct idr drbd_devices;
-struct list_head drbd_connections; /* list of struct drbd_connection */
+struct list_head drbd_resources;
struct kmem_cache *drbd_request_cache;
struct kmem_cache *drbd_ee_cache; /* peer requests */
@@ -330,7 +330,8 @@ static int drbd_thread_setup(void *arg)
int retval;
snprintf(current->comm, sizeof(current->comm), "drbd_%c_%s",
- thi->name[0], thi->connection->name);
+ thi->name[0],
+ thi->connection->resource->name);
restart:
retval = thi->function(thi);
@@ -411,7 +412,7 @@ int drbd_thread_start(struct drbd_thread *thi)
flush_signals(current); /* otherw. may get -ERESTARTNOINTR */
nt = kthread_create(drbd_thread_setup, (void *) thi,
- "drbd_%c_%s", thi->name[0], thi->connection->name);
+ "drbd_%c_%s", thi->name[0], thi->connection->resource->name);
if (IS_ERR(nt)) {
conn_err(connection, "Couldn't start thread\n");
@@ -2276,12 +2277,31 @@ void drbd_restart_request(struct drbd_request *req)
queue_work(retry.wq, &retry.worker);
}
+void drbd_destroy_resource(struct kref *kref)
+{
+ struct drbd_resource *resource =
+ container_of(kref, struct drbd_resource, kref);
+
+ kfree(resource->name);
+ kfree(resource);
+}
+
+void drbd_free_resource(struct drbd_resource *resource)
+{
+ struct drbd_connection *connection, *tmp;
+
+ for_each_connection_safe(connection, tmp, resource) {
+ list_del(&connection->connections);
+ kref_put(&connection->kref, drbd_destroy_connection);
+ }
+ kref_put(&resource->kref, drbd_destroy_resource);
+}
static void drbd_cleanup(void)
{
unsigned int i;
struct drbd_device *device;
- struct drbd_connection *connection, *tmp;
+ struct drbd_resource *resource, *tmp;
unregister_reboot_notifier(&drbd_notifier);
@@ -2311,10 +2331,9 @@ static void drbd_cleanup(void)
}
/* not _rcu since, no other updater anymore. Genl already unregistered */
- list_for_each_entry_safe(connection, tmp, &drbd_connections, connections) {
- list_del(&connection->connections); /* not _rcu no proc, not other threads */
- /* synchronize_rcu(); */
- kref_put(&connection->kref, drbd_destroy_connection);
+ for_each_resource_safe(resource, tmp, &drbd_resources) {
+ list_del(&resource->resources);
+ drbd_free_resource(resource);
}
drbd_destroy_mempools();
@@ -2391,13 +2410,15 @@ static void drbd_init_workqueue(struct drbd_work_queue* wq)
struct drbd_connection *conn_get_by_name(const char *name)
{
struct drbd_connection *connection;
+ struct drbd_resource *resource;
if (!name || !name[0])
return NULL;
rcu_read_lock();
- list_for_each_entry_rcu(connection, &drbd_connections, connections) {
- if (!strcmp(connection->name, name)) {
+ for_each_resource_rcu(resource, &drbd_resources) {
+ if (!strcmp(resource->name, name)) {
+ connection = first_connection(resource);
kref_get(&connection->kref);
goto found;
}
@@ -2411,16 +2432,19 @@ found:
struct drbd_connection *conn_get_by_addrs(void *my_addr, int my_addr_len,
void *peer_addr, int peer_addr_len)
{
+ struct drbd_resource *resource;
struct drbd_connection *connection;
rcu_read_lock();
- list_for_each_entry_rcu(connection, &drbd_connections, connections) {
- if (connection->my_addr_len == my_addr_len &&
- connection->peer_addr_len == peer_addr_len &&
- !memcmp(&connection->my_addr, my_addr, my_addr_len) &&
- !memcmp(&connection->peer_addr, peer_addr, peer_addr_len)) {
- kref_get(&connection->kref);
- goto found;
+ for_each_resource_rcu(resource, &drbd_resources) {
+ for_each_connection_rcu(connection, resource) {
+ if (connection->my_addr_len == my_addr_len &&
+ connection->peer_addr_len == peer_addr_len &&
+ !memcmp(&connection->my_addr, my_addr, my_addr_len) &&
+ !memcmp(&connection->peer_addr, peer_addr, peer_addr_len)) {
+ kref_get(&connection->kref);
+ goto found;
+ }
}
}
connection = NULL;
@@ -2506,19 +2530,34 @@ fail:
}
+struct drbd_resource *drbd_create_resource(const char *name)
+{
+ struct drbd_resource *resource;
+
+ resource = kmalloc(sizeof(struct drbd_resource), GFP_KERNEL);
+ if (!resource)
+ return NULL;
+ resource->name = kstrdup(name, GFP_KERNEL);
+ if (!resource->name) {
+ kfree(resource);
+ return NULL;
+ }
+ kref_init(&resource->kref);
+ INIT_LIST_HEAD(&resource->connections);
+ list_add_tail_rcu(&resource->resources, &drbd_resources);
+ return resource;
+}
+
/* caller must be under genl_lock() */
struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts)
{
+ struct drbd_resource *resource;
struct drbd_connection *connection;
connection = kzalloc(sizeof(struct drbd_connection), GFP_KERNEL);
if (!connection)
return NULL;
- connection->name = kstrdup(name, GFP_KERNEL);
- if (!connection->name)
- goto fail;
-
if (drbd_alloc_socket(&connection->data))
goto fail;
if (drbd_alloc_socket(&connection->meta))
@@ -2545,6 +2584,10 @@ struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts)
connection->send.current_epoch_nr = 0;
connection->send.current_epoch_writes = 0;
+ resource = drbd_create_resource(name);
+ if (!resource)
+ goto fail;
+
connection->cstate = C_STANDALONE;
mutex_init(&connection->cstate_mutex);
spin_lock_init(&connection->req_lock);
@@ -2561,7 +2604,10 @@ struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts)
drbd_thread_init(connection, &connection->asender, drbd_asender, "asender");
kref_init(&connection->kref);
- list_add_tail_rcu(&connection->connections, &drbd_connections);
+
+ kref_get(&resource->kref);
+ connection->resource = resource;
+ list_add_tail_rcu(&connection->connections, &resource->connections);
return connection;
@@ -2570,7 +2616,6 @@ fail:
free_cpumask_var(connection->cpu_mask);
drbd_free_socket(&connection->meta);
drbd_free_socket(&connection->data);
- kfree(connection->name);
kfree(connection);
return NULL;
@@ -2579,6 +2624,7 @@ fail:
void drbd_destroy_connection(struct kref *kref)
{
struct drbd_connection *connection = container_of(kref, struct drbd_connection, kref);
+ struct drbd_resource *resource = connection->resource;
if (atomic_read(&connection->current_epoch->epoch_size) != 0)
conn_err(connection, "epoch_size:%d\n", atomic_read(&connection->current_epoch->epoch_size));
@@ -2589,10 +2635,10 @@ void drbd_destroy_connection(struct kref *kref)
free_cpumask_var(connection->cpu_mask);
drbd_free_socket(&connection->meta);
drbd_free_socket(&connection->data);
- kfree(connection->name);
kfree(connection->int_dig_in);
kfree(connection->int_dig_vv);
kfree(connection);
+ kref_put(&resource->kref, drbd_destroy_resource);
}
static int init_submitter(struct drbd_device *device)
@@ -2775,7 +2821,7 @@ int __init drbd_init(void)
idr_init(&drbd_devices);
rwlock_init(&global_state_lock);
- INIT_LIST_HEAD(&drbd_connections);
+ INIT_LIST_HEAD(&drbd_resources);
err = drbd_genl_register();
if (err) {