summaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_main.c
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@linbit.com>2011-07-22 14:29:02 +0200
committerPhilipp Reisner <philipp.reisner@linbit.com>2014-02-17 16:46:49 +0100
commit625a6ba2bd9d2720e64048188c6771b9da867884 (patch)
tree3eca33a9452580d097e20087795709fcabd5fc53 /drivers/block/drbd/drbd_main.c
parentdrbd: Define the size of res_opts->cpu_mask in a single place (diff)
downloadlinux-625a6ba2bd9d2720e64048188c6771b9da867884.tar.xz
linux-625a6ba2bd9d2720e64048188c6771b9da867884.zip
drbd: Move cpu_mask from connection to resource
Also fix drbd_calc_cpu_mask() to spread resources equally over all online cpus independent of device minor numbers. 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.c74
1 files changed, 45 insertions, 29 deletions
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 59a58e896cf5..b0b2eb172491 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -511,28 +511,38 @@ int conn_lowest_minor(struct drbd_connection *connection)
#ifdef CONFIG_SMP
/**
* drbd_calc_cpu_mask() - Generate CPU masks, spread over all CPUs
- * @device: DRBD device.
*
- * Forces all threads of a device onto the same CPU. This is beneficial for
+ * Forces all threads of a resource onto the same CPU. This is beneficial for
* DRBD's performance. May be overwritten by user's configuration.
*/
-void drbd_calc_cpu_mask(struct drbd_connection *connection)
+static void drbd_calc_cpu_mask(cpumask_var_t *cpu_mask)
{
- int ord, cpu;
+ unsigned int *resources_per_cpu, min_index = ~0;
- /* user override. */
- if (cpumask_weight(connection->cpu_mask))
- return;
+ resources_per_cpu = kzalloc(nr_cpu_ids * sizeof(*resources_per_cpu), GFP_KERNEL);
+ if (resources_per_cpu) {
+ struct drbd_resource *resource;
+ unsigned int cpu, min = ~0;
- ord = conn_lowest_minor(connection) % cpumask_weight(cpu_online_mask);
- for_each_online_cpu(cpu) {
- if (ord-- == 0) {
- cpumask_set_cpu(cpu, connection->cpu_mask);
- return;
+ rcu_read_lock();
+ for_each_resource_rcu(resource, &drbd_resources) {
+ for_each_cpu(cpu, resource->cpu_mask)
+ resources_per_cpu[cpu]++;
}
+ rcu_read_unlock();
+ for_each_online_cpu(cpu) {
+ if (resources_per_cpu[cpu] < min) {
+ min = resources_per_cpu[cpu];
+ min_index = cpu;
+ }
+ }
+ kfree(resources_per_cpu);
+ }
+ if (min_index == ~0) {
+ cpumask_setall(*cpu_mask);
+ return;
}
- /* should not be reached */
- cpumask_setall(connection->cpu_mask);
+ cpumask_set_cpu(min_index, *cpu_mask);
}
/**
@@ -550,8 +560,10 @@ void drbd_thread_current_set_cpu(struct drbd_thread *thi)
if (!thi->reset_cpu_mask)
return;
thi->reset_cpu_mask = 0;
- set_cpus_allowed_ptr(p, thi->connection->cpu_mask);
+ set_cpus_allowed_ptr(p, thi->connection->resource->cpu_mask);
}
+#else
+#define drbd_calc_cpu_mask(A) ({})
#endif
/**
@@ -2287,6 +2299,7 @@ void drbd_destroy_resource(struct kref *kref)
container_of(kref, struct drbd_resource, kref);
idr_destroy(&resource->devices);
+ free_cpumask_var(resource->cpu_mask);
kfree(resource->name);
kfree(resource);
}
@@ -2512,10 +2525,11 @@ int set_resource_options(struct drbd_resource *resource, struct res_opts *res_op
}
}
resource->res_opts = *res_opts;
- for_each_connection_rcu(connection, resource) {
- if (!cpumask_equal(connection->cpu_mask, new_cpu_mask)) {
- cpumask_copy(connection->cpu_mask, new_cpu_mask);
- drbd_calc_cpu_mask(connection);
+ if (cpumask_empty(new_cpu_mask))
+ drbd_calc_cpu_mask(&new_cpu_mask);
+ if (!cpumask_equal(resource->cpu_mask, new_cpu_mask)) {
+ cpumask_copy(resource->cpu_mask, new_cpu_mask);
+ for_each_connection_rcu(connection, resource) {
connection->receiver.reset_cpu_mask = 1;
connection->asender.reset_cpu_mask = 1;
connection->worker.reset_cpu_mask = 1;
@@ -2535,12 +2549,12 @@ struct drbd_resource *drbd_create_resource(const char *name)
resource = kzalloc(sizeof(struct drbd_resource), GFP_KERNEL);
if (!resource)
- return NULL;
+ goto fail;
resource->name = kstrdup(name, GFP_KERNEL);
- if (!resource->name) {
- kfree(resource);
- return NULL;
- }
+ if (!resource->name)
+ goto fail_free_resource;
+ if (!zalloc_cpumask_var(&resource->cpu_mask, GFP_KERNEL))
+ goto fail_free_name;
kref_init(&resource->kref);
idr_init(&resource->devices);
INIT_LIST_HEAD(&resource->connections);
@@ -2548,6 +2562,13 @@ struct drbd_resource *drbd_create_resource(const char *name)
mutex_init(&resource->conf_update);
spin_lock_init(&resource->req_lock);
return resource;
+
+fail_free_name:
+ kfree(resource->name);
+fail_free_resource:
+ kfree(resource);
+fail:
+ return NULL;
}
/* caller must be under genl_lock() */
@@ -2565,9 +2586,6 @@ struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts)
if (drbd_alloc_socket(&connection->meta))
goto fail;
- if (!zalloc_cpumask_var(&connection->cpu_mask, GFP_KERNEL))
- goto fail;
-
connection->current_epoch = kzalloc(sizeof(struct drbd_epoch), GFP_KERNEL);
if (!connection->current_epoch)
goto fail;
@@ -2616,7 +2634,6 @@ fail_resource:
drbd_free_resource(resource);
fail:
kfree(connection->current_epoch);
- free_cpumask_var(connection->cpu_mask);
drbd_free_socket(&connection->meta);
drbd_free_socket(&connection->data);
kfree(connection);
@@ -2634,7 +2651,6 @@ void drbd_destroy_connection(struct kref *kref)
idr_destroy(&connection->peer_devices);
- free_cpumask_var(connection->cpu_mask);
drbd_free_socket(&connection->meta);
drbd_free_socket(&connection->data);
kfree(connection->int_dig_in);