summaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_main.c
diff options
context:
space:
mode:
authorAndreas Gruenbacher2011-06-08 22:17:38 +0200
committerPhilipp Reisner2014-02-17 16:44:53 +0100
commit77c556f663b7ac066268c94c18670ce93dec60c0 (patch)
treec05d7b93806b46528e4007ca2bf83ecfb2ec0671 /drivers/block/drbd/drbd_main.c
parentdrbd: Improve some function and variable naming (diff)
downloadkernel-qcow2-linux-77c556f663b7ac066268c94c18670ce93dec60c0.tar.gz
kernel-qcow2-linux-77c556f663b7ac066268c94c18670ce93dec60c0.tar.xz
kernel-qcow2-linux-77c556f663b7ac066268c94c18670ce93dec60c0.zip
drbd: Add struct drbd_resource
In a first step, each resource has exactly one connection, and both objects are allocated at the same time. The final result will be one resource and zero or more connections. Only allow to delete a resource if all its connections are C_STANDALONE. Stop the worker threads of all connections early enough. Signed-off-by: Andreas Gruenbacher <agruen@linbit.com> Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
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) {