aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@linbit.com>2011-06-08 16:17:38 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2014-02-17 10:44:53 -0500
commit77c556f663b7ac066268c94c18670ce93dec60c0 (patch)
treec05d7b93806b46528e4007ca2bf83ecfb2ec0671
parent05a10ec7900dbdba008a24bf56b3490c4b568d2c (diff)
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>
-rw-r--r--drivers/block/drbd/drbd_int.h45
-rw-r--r--drivers/block/drbd/drbd_main.c96
-rw-r--r--drivers/block/drbd/drbd_nl.c116
3 files changed, 179 insertions, 78 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index b324314768fd..b51ecdbdd30c 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -105,7 +105,7 @@ struct drbd_connection;
105#define DEV (disk_to_dev(device->vdisk)) 105#define DEV (disk_to_dev(device->vdisk))
106 106
107#define conn_printk(LEVEL, TCONN, FMT, ARGS...) \ 107#define conn_printk(LEVEL, TCONN, FMT, ARGS...) \
108 printk(LEVEL "d-con %s: " FMT, TCONN->name , ## ARGS) 108 printk(LEVEL "d-con %s: " FMT, TCONN->resource->name , ## ARGS)
109#define conn_alert(TCONN, FMT, ARGS...) conn_printk(KERN_ALERT, TCONN, FMT, ## ARGS) 109#define conn_alert(TCONN, FMT, ARGS...) conn_printk(KERN_ALERT, TCONN, FMT, ## ARGS)
110#define conn_crit(TCONN, FMT, ARGS...) conn_printk(KERN_CRIT, TCONN, FMT, ## ARGS) 110#define conn_crit(TCONN, FMT, ARGS...) conn_printk(KERN_CRIT, TCONN, FMT, ## ARGS)
111#define conn_err(TCONN, FMT, ARGS...) conn_printk(KERN_ERR, TCONN, FMT, ## ARGS) 111#define conn_err(TCONN, FMT, ARGS...) conn_printk(KERN_ERR, TCONN, FMT, ## ARGS)
@@ -167,7 +167,7 @@ drbd_insert_fault(struct drbd_device *device, unsigned int type) {
167 167
168extern struct ratelimit_state drbd_ratelimit_state; 168extern struct ratelimit_state drbd_ratelimit_state;
169extern struct idr drbd_devices; /* RCU, updates: genl_lock() */ 169extern struct idr drbd_devices; /* RCU, updates: genl_lock() */
170extern struct list_head drbd_connections; /* RCU, updates: genl_lock() */ 170extern struct list_head drbd_resources; /* RCU, updates: genl_lock() */
171 171
172extern const char *cmdname(enum drbd_packet cmd); 172extern const char *cmdname(enum drbd_packet cmd);
173 173
@@ -536,9 +536,16 @@ enum {
536 DISCONNECT_SENT, 536 DISCONNECT_SENT,
537}; 537};
538 538
539struct drbd_connection { /* is a resource from the config file */ 539struct drbd_resource {
540 char *name; /* Resource name */ 540 char *name;
541 struct list_head connections; /* linked on global drbd_connections */ 541 struct kref kref;
542 struct list_head connections;
543 struct list_head resources;
544};
545
546struct drbd_connection {
547 struct list_head connections;
548 struct drbd_resource *resource;
542 struct kref kref; 549 struct kref kref;
543 struct idr volumes; /* <connection, vnr> to device mapping */ 550 struct idr volumes; /* <connection, vnr> to device mapping */
544 enum drbd_conns cstate; /* Only C_STANDALONE to C_WF_REPORT_PARAMS */ 551 enum drbd_conns cstate; /* Only C_STANDALONE to C_WF_REPORT_PARAMS */
@@ -779,6 +786,24 @@ static inline struct drbd_peer_device *first_peer_device(struct drbd_device *dev
779 return list_first_entry(&device->peer_devices, struct drbd_peer_device, peer_devices); 786 return list_first_entry(&device->peer_devices, struct drbd_peer_device, peer_devices);
780} 787}
781 788
789#define for_each_resource(resource, _resources) \
790 list_for_each_entry(resource, _resources, resources)
791
792#define for_each_resource_rcu(resource, _resources) \
793 list_for_each_entry_rcu(resource, _resources, resources)
794
795#define for_each_resource_safe(resource, tmp, _resources) \
796 list_for_each_entry_safe(resource, tmp, _resources, resources)
797
798#define for_each_connection(connection, resource) \
799 list_for_each_entry(connection, &resource->connections, connections)
800
801#define for_each_connection_rcu(connection, resource) \
802 list_for_each_entry_rcu(connection, &resource->connections, connections)
803
804#define for_each_connection_safe(connection, tmp, resource) \
805 list_for_each_entry_safe(connection, tmp, &resource->connections, connections)
806
782#define for_each_peer_device(peer_device, device) \ 807#define for_each_peer_device(peer_device, device) \
783 list_for_each_entry(peer_device, &device->peer_devices, peer_devices) 808 list_for_each_entry(peer_device, &device->peer_devices, peer_devices)
784 809
@@ -1177,12 +1202,16 @@ extern int conn_lowest_minor(struct drbd_connection *connection);
1177enum drbd_ret_code drbd_create_minor(struct drbd_connection *connection, unsigned int minor, int vnr); 1202enum drbd_ret_code drbd_create_minor(struct drbd_connection *connection, unsigned int minor, int vnr);
1178extern void drbd_destroy_device(struct kref *kref); 1203extern void drbd_destroy_device(struct kref *kref);
1179 1204
1205extern struct drbd_resource *drbd_create_resource(const char *name);
1206extern void drbd_free_resource(struct drbd_resource *resource);
1207
1180extern int set_resource_options(struct drbd_connection *connection, struct res_opts *res_opts); 1208extern int set_resource_options(struct drbd_connection *connection, struct res_opts *res_opts);
1181extern struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts); 1209extern struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts);
1182extern void drbd_destroy_connection(struct kref *kref); 1210extern void drbd_destroy_connection(struct kref *kref);
1183struct drbd_connection *conn_get_by_name(const char *name); 1211struct drbd_connection *conn_get_by_name(const char *name);
1184extern struct drbd_connection *conn_get_by_addrs(void *my_addr, int my_addr_len, 1212extern struct drbd_connection *conn_get_by_addrs(void *my_addr, int my_addr_len,
1185 void *peer_addr, int peer_addr_len); 1213 void *peer_addr, int peer_addr_len);
1214extern void drbd_destroy_resource(struct kref *kref);
1186extern void conn_free_crypto(struct drbd_connection *connection); 1215extern void conn_free_crypto(struct drbd_connection *connection);
1187 1216
1188extern int proc_details; 1217extern int proc_details;
@@ -2082,4 +2111,10 @@ static inline void drbd_md_flush(struct drbd_device *device)
2082 } 2111 }
2083} 2112}
2084 2113
2114static inline struct drbd_connection *first_connection(struct drbd_resource *resource)
2115{
2116 return list_first_entry(&resource->connections,
2117 struct drbd_connection, connections);
2118}
2119
2085#endif 2120#endif
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
118 * as member "struct gendisk *vdisk;" 118 * as member "struct gendisk *vdisk;"
119 */ 119 */
120struct idr drbd_devices; 120struct idr drbd_devices;
121struct list_head drbd_connections; /* list of struct drbd_connection */ 121struct list_head drbd_resources;
122 122
123struct kmem_cache *drbd_request_cache; 123struct kmem_cache *drbd_request_cache;
124struct kmem_cache *drbd_ee_cache; /* peer requests */ 124struct kmem_cache *drbd_ee_cache; /* peer requests */
@@ -330,7 +330,8 @@ static int drbd_thread_setup(void *arg)
330 int retval; 330 int retval;
331 331
332 snprintf(current->comm, sizeof(current->comm), "drbd_%c_%s", 332 snprintf(current->comm, sizeof(current->comm), "drbd_%c_%s",
333 thi->name[0], thi->connection->name); 333 thi->name[0],
334 thi->connection->resource->name);
334 335
335restart: 336restart:
336 retval = thi->function(thi); 337 retval = thi->function(thi);
@@ -411,7 +412,7 @@ int drbd_thread_start(struct drbd_thread *thi)
411 flush_signals(current); /* otherw. may get -ERESTARTNOINTR */ 412 flush_signals(current); /* otherw. may get -ERESTARTNOINTR */
412 413
413 nt = kthread_create(drbd_thread_setup, (void *) thi, 414 nt = kthread_create(drbd_thread_setup, (void *) thi,
414 "drbd_%c_%s", thi->name[0], thi->connection->name); 415 "drbd_%c_%s", thi->name[0], thi->connection->resource->name);
415 416
416 if (IS_ERR(nt)) { 417 if (IS_ERR(nt)) {
417 conn_err(connection, "Couldn't start thread\n"); 418 conn_err(connection, "Couldn't start thread\n");
@@ -2276,12 +2277,31 @@ void drbd_restart_request(struct drbd_request *req)
2276 queue_work(retry.wq, &retry.worker); 2277 queue_work(retry.wq, &retry.worker);
2277} 2278}
2278 2279
2280void drbd_destroy_resource(struct kref *kref)
2281{
2282 struct drbd_resource *resource =
2283 container_of(kref, struct drbd_resource, kref);
2284
2285 kfree(resource->name);
2286 kfree(resource);
2287}
2288
2289void drbd_free_resource(struct drbd_resource *resource)
2290{
2291 struct drbd_connection *connection, *tmp;
2292
2293 for_each_connection_safe(connection, tmp, resource) {
2294 list_del(&connection->connections);
2295 kref_put(&connection->kref, drbd_destroy_connection);
2296 }
2297 kref_put(&resource->kref, drbd_destroy_resource);
2298}
2279 2299
2280static void drbd_cleanup(void) 2300static void drbd_cleanup(void)
2281{ 2301{
2282 unsigned int i; 2302 unsigned int i;
2283 struct drbd_device *device; 2303 struct drbd_device *device;
2284 struct drbd_connection *connection, *tmp; 2304 struct drbd_resource *resource, *tmp;
2285 2305
2286 unregister_reboot_notifier(&drbd_notifier); 2306 unregister_reboot_notifier(&drbd_notifier);
2287 2307
@@ -2311,10 +2331,9 @@ static void drbd_cleanup(void)
2311 } 2331 }
2312 2332
2313 /* not _rcu since, no other updater anymore. Genl already unregistered */ 2333 /* not _rcu since, no other updater anymore. Genl already unregistered */
2314 list_for_each_entry_safe(connection, tmp, &drbd_connections, connections) { 2334 for_each_resource_safe(resource, tmp, &drbd_resources) {
2315 list_del(&connection->connections); /* not _rcu no proc, not other threads */ 2335 list_del(&resource->resources);
2316 /* synchronize_rcu(); */ 2336 drbd_free_resource(resource);
2317 kref_put(&connection->kref, drbd_destroy_connection);
2318 } 2337 }
2319 2338
2320 drbd_destroy_mempools(); 2339 drbd_destroy_mempools();
@@ -2391,13 +2410,15 @@ static void drbd_init_workqueue(struct drbd_work_queue* wq)
2391struct drbd_connection *conn_get_by_name(const char *name) 2410struct drbd_connection *conn_get_by_name(const char *name)
2392{ 2411{
2393 struct drbd_connection *connection; 2412 struct drbd_connection *connection;
2413 struct drbd_resource *resource;
2394 2414
2395 if (!name || !name[0]) 2415 if (!name || !name[0])
2396 return NULL; 2416 return NULL;
2397 2417
2398 rcu_read_lock(); 2418 rcu_read_lock();
2399 list_for_each_entry_rcu(connection, &drbd_connections, connections) { 2419 for_each_resource_rcu(resource, &drbd_resources) {
2400 if (!strcmp(connection->name, name)) { 2420 if (!strcmp(resource->name, name)) {
2421 connection = first_connection(resource);
2401 kref_get(&connection->kref); 2422 kref_get(&connection->kref);
2402 goto found; 2423 goto found;
2403 } 2424 }
@@ -2411,16 +2432,19 @@ found:
2411struct drbd_connection *conn_get_by_addrs(void *my_addr, int my_addr_len, 2432struct drbd_connection *conn_get_by_addrs(void *my_addr, int my_addr_len,
2412 void *peer_addr, int peer_addr_len) 2433 void *peer_addr, int peer_addr_len)
2413{ 2434{
2435 struct drbd_resource *resource;
2414 struct drbd_connection *connection; 2436 struct drbd_connection *connection;
2415 2437
2416 rcu_read_lock(); 2438 rcu_read_lock();
2417 list_for_each_entry_rcu(connection, &drbd_connections, connections) { 2439 for_each_resource_rcu(resource, &drbd_resources) {
2418 if (connection->my_addr_len == my_addr_len && 2440 for_each_connection_rcu(connection, resource) {
2419 connection->peer_addr_len == peer_addr_len && 2441 if (connection->my_addr_len == my_addr_len &&
2420 !memcmp(&connection->my_addr, my_addr, my_addr_len) && 2442 connection->peer_addr_len == peer_addr_len &&
2421 !memcmp(&connection->peer_addr, peer_addr, peer_addr_len)) { 2443 !memcmp(&connection->my_addr, my_addr, my_addr_len) &&
2422 kref_get(&connection->kref); 2444 !memcmp(&connection->peer_addr, peer_addr, peer_addr_len)) {
2423 goto found; 2445 kref_get(&connection->kref);
2446 goto found;
2447 }
2424 } 2448 }
2425 } 2449 }
2426 connection = NULL; 2450 connection = NULL;
@@ -2506,19 +2530,34 @@ fail:
2506 2530
2507} 2531}
2508 2532
2533struct drbd_resource *drbd_create_resource(const char *name)
2534{
2535 struct drbd_resource *resource;
2536
2537 resource = kmalloc(sizeof(struct drbd_resource), GFP_KERNEL);
2538 if (!resource)
2539 return NULL;
2540 resource->name = kstrdup(name, GFP_KERNEL);
2541 if (!resource->name) {
2542 kfree(resource);
2543 return NULL;
2544 }
2545 kref_init(&resource->kref);
2546 INIT_LIST_HEAD(&resource->connections);
2547 list_add_tail_rcu(&resource->resources, &drbd_resources);
2548 return resource;
2549}
2550
2509/* caller must be under genl_lock() */ 2551/* caller must be under genl_lock() */
2510struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts) 2552struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts)
2511{ 2553{
2554 struct drbd_resource *resource;
2512 struct drbd_connection *connection; 2555 struct drbd_connection *connection;
2513 2556
2514 connection = kzalloc(sizeof(struct drbd_connection), GFP_KERNEL); 2557 connection = kzalloc(sizeof(struct drbd_connection), GFP_KERNEL);
2515 if (!connection) 2558 if (!connection)
2516 return NULL; 2559 return NULL;
2517 2560
2518 connection->name = kstrdup(name, GFP_KERNEL);
2519 if (!connection->name)
2520 goto fail;
2521
2522 if (drbd_alloc_socket(&connection->data)) 2561 if (drbd_alloc_socket(&connection->data))
2523 goto fail; 2562 goto fail;
2524 if (drbd_alloc_socket(&connection->meta)) 2563 if (drbd_alloc_socket(&connection->meta))
@@ -2545,6 +2584,10 @@ struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts)
2545 connection->send.current_epoch_nr = 0; 2584 connection->send.current_epoch_nr = 0;
2546 connection->send.current_epoch_writes = 0; 2585 connection->send.current_epoch_writes = 0;
2547 2586
2587 resource = drbd_create_resource(name);
2588 if (!resource)
2589 goto fail;
2590
2548 connection->cstate = C_STANDALONE; 2591 connection->cstate = C_STANDALONE;
2549 mutex_init(&connection->cstate_mutex); 2592 mutex_init(&connection->cstate_mutex);
2550 spin_lock_init(&connection->req_lock); 2593 spin_lock_init(&connection->req_lock);
@@ -2561,7 +2604,10 @@ struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts)
2561 drbd_thread_init(connection, &connection->asender, drbd_asender, "asender"); 2604 drbd_thread_init(connection, &connection->asender, drbd_asender, "asender");
2562 2605
2563 kref_init(&connection->kref); 2606 kref_init(&connection->kref);
2564 list_add_tail_rcu(&connection->connections, &drbd_connections); 2607
2608 kref_get(&resource->kref);
2609 connection->resource = resource;
2610 list_add_tail_rcu(&connection->connections, &resource->connections);
2565 2611
2566 return connection; 2612 return connection;
2567 2613
@@ -2570,7 +2616,6 @@ fail:
2570 free_cpumask_var(connection->cpu_mask); 2616 free_cpumask_var(connection->cpu_mask);
2571 drbd_free_socket(&connection->meta); 2617 drbd_free_socket(&connection->meta);
2572 drbd_free_socket(&connection->data); 2618 drbd_free_socket(&connection->data);
2573 kfree(connection->name);
2574 kfree(connection); 2619 kfree(connection);
2575 2620
2576 return NULL; 2621 return NULL;
@@ -2579,6 +2624,7 @@ fail:
2579void drbd_destroy_connection(struct kref *kref) 2624void drbd_destroy_connection(struct kref *kref)
2580{ 2625{
2581 struct drbd_connection *connection = container_of(kref, struct drbd_connection, kref); 2626 struct drbd_connection *connection = container_of(kref, struct drbd_connection, kref);
2627 struct drbd_resource *resource = connection->resource;
2582 2628
2583 if (atomic_read(&connection->current_epoch->epoch_size) != 0) 2629 if (atomic_read(&connection->current_epoch->epoch_size) != 0)
2584 conn_err(connection, "epoch_size:%d\n", atomic_read(&connection->current_epoch->epoch_size)); 2630 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)
2589 free_cpumask_var(connection->cpu_mask); 2635 free_cpumask_var(connection->cpu_mask);
2590 drbd_free_socket(&connection->meta); 2636 drbd_free_socket(&connection->meta);
2591 drbd_free_socket(&connection->data); 2637 drbd_free_socket(&connection->data);
2592 kfree(connection->name);
2593 kfree(connection->int_dig_in); 2638 kfree(connection->int_dig_in);
2594 kfree(connection->int_dig_vv); 2639 kfree(connection->int_dig_vv);
2595 kfree(connection); 2640 kfree(connection);
2641 kref_put(&resource->kref, drbd_destroy_resource);
2596} 2642}
2597 2643
2598static int init_submitter(struct drbd_device *device) 2644static int init_submitter(struct drbd_device *device)
@@ -2775,7 +2821,7 @@ int __init drbd_init(void)
2775 idr_init(&drbd_devices); 2821 idr_init(&drbd_devices);
2776 2822
2777 rwlock_init(&global_state_lock); 2823 rwlock_init(&global_state_lock);
2778 INIT_LIST_HEAD(&drbd_connections); 2824 INIT_LIST_HEAD(&drbd_resources);
2779 2825
2780 err = drbd_genl_register(); 2826 err = drbd_genl_register();
2781 if (err) { 2827 if (err) {
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 83d8c18fb84c..b8eacccbdc5c 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -249,7 +249,7 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
249 first_peer_device(adm_ctx.device)->connection != adm_ctx.connection) { 249 first_peer_device(adm_ctx.device)->connection != adm_ctx.connection) {
250 pr_warning("request: minor=%u, resource=%s; but that minor belongs to connection %s\n", 250 pr_warning("request: minor=%u, resource=%s; but that minor belongs to connection %s\n",
251 adm_ctx.minor, adm_ctx.resource_name, 251 adm_ctx.minor, adm_ctx.resource_name,
252 first_peer_device(adm_ctx.device)->connection->name); 252 first_peer_device(adm_ctx.device)->connection->resource->name);
253 drbd_msg_put_info("minor exists in different resource"); 253 drbd_msg_put_info("minor exists in different resource");
254 return ERR_INVALID_REQUEST; 254 return ERR_INVALID_REQUEST;
255 } 255 }
@@ -258,7 +258,8 @@ static int drbd_adm_prepare(struct sk_buff *skb, struct genl_info *info,
258 adm_ctx.volume != adm_ctx.device->vnr) { 258 adm_ctx.volume != adm_ctx.device->vnr) {
259 pr_warning("request: minor=%u, volume=%u; but that minor is volume %u in %s\n", 259 pr_warning("request: minor=%u, volume=%u; but that minor is volume %u in %s\n",
260 adm_ctx.minor, adm_ctx.volume, 260 adm_ctx.minor, adm_ctx.volume,
261 adm_ctx.device->vnr, first_peer_device(adm_ctx.device)->connection->name); 261 adm_ctx.device->vnr,
262 first_peer_device(adm_ctx.device)->connection->resource->name);
262 drbd_msg_put_info("minor exists as different volume"); 263 drbd_msg_put_info("minor exists as different volume");
263 return ERR_INVALID_REQUEST; 264 return ERR_INVALID_REQUEST;
264 } 265 }
@@ -371,23 +372,24 @@ static int conn_khelper(struct drbd_connection *connection, char *cmd)
371 (char[20]) { }, /* address family */ 372 (char[20]) { }, /* address family */
372 (char[60]) { }, /* address */ 373 (char[60]) { }, /* address */
373 NULL }; 374 NULL };
374 char *argv[] = {usermode_helper, cmd, connection->name, NULL }; 375 char *resource_name = connection->resource->name;
376 char *argv[] = {usermode_helper, cmd, resource_name, NULL };
375 int ret; 377 int ret;
376 378
377 setup_khelper_env(connection, envp); 379 setup_khelper_env(connection, envp);
378 conn_md_sync(connection); 380 conn_md_sync(connection);
379 381
380 conn_info(connection, "helper command: %s %s %s\n", usermode_helper, cmd, connection->name); 382 conn_info(connection, "helper command: %s %s %s\n", usermode_helper, cmd, resource_name);
381 /* TODO: conn_bcast_event() ?? */ 383 /* TODO: conn_bcast_event() ?? */
382 384
383 ret = call_usermodehelper(usermode_helper, argv, envp, UMH_WAIT_PROC); 385 ret = call_usermodehelper(usermode_helper, argv, envp, UMH_WAIT_PROC);
384 if (ret) 386 if (ret)
385 conn_warn(connection, "helper command: %s %s %s exit code %u (0x%x)\n", 387 conn_warn(connection, "helper command: %s %s %s exit code %u (0x%x)\n",
386 usermode_helper, cmd, connection->name, 388 usermode_helper, cmd, resource_name,
387 (ret >> 8) & 0xff, ret); 389 (ret >> 8) & 0xff, ret);
388 else 390 else
389 conn_info(connection, "helper command: %s %s %s exit code %u (0x%x)\n", 391 conn_info(connection, "helper command: %s %s %s exit code %u (0x%x)\n",
390 usermode_helper, cmd, connection->name, 392 usermode_helper, cmd, resource_name,
391 (ret >> 8) & 0xff, ret); 393 (ret >> 8) & 0xff, ret);
392 /* TODO: conn_bcast_event() ?? */ 394 /* TODO: conn_bcast_event() ?? */
393 395
@@ -2143,6 +2145,7 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
2143 struct drbd_device *device; 2145 struct drbd_device *device;
2144 struct net_conf *old_conf, *new_conf = NULL; 2146 struct net_conf *old_conf, *new_conf = NULL;
2145 struct crypto crypto = { }; 2147 struct crypto crypto = { };
2148 struct drbd_resource *resource;
2146 struct drbd_connection *connection; 2149 struct drbd_connection *connection;
2147 enum drbd_ret_code retcode; 2150 enum drbd_ret_code retcode;
2148 int i; 2151 int i;
@@ -2163,17 +2166,21 @@ int drbd_adm_connect(struct sk_buff *skb, struct genl_info *info)
2163 /* No need for _rcu here. All reconfiguration is 2166 /* No need for _rcu here. All reconfiguration is
2164 * strictly serialized on genl_lock(). We are protected against 2167 * strictly serialized on genl_lock(). We are protected against
2165 * concurrent reconfiguration/addition/deletion */ 2168 * concurrent reconfiguration/addition/deletion */
2166 list_for_each_entry(connection, &drbd_connections, connections) { 2169 for_each_resource(resource, &drbd_resources) {
2167 if (nla_len(adm_ctx.my_addr) == connection->my_addr_len && 2170 for_each_connection(connection, resource) {
2168 !memcmp(nla_data(adm_ctx.my_addr), &connection->my_addr, connection->my_addr_len)) { 2171 if (nla_len(adm_ctx.my_addr) == connection->my_addr_len &&
2169 retcode = ERR_LOCAL_ADDR; 2172 !memcmp(nla_data(adm_ctx.my_addr), &connection->my_addr,
2170 goto out; 2173 connection->my_addr_len)) {
2171 } 2174 retcode = ERR_LOCAL_ADDR;
2175 goto out;
2176 }
2172 2177
2173 if (nla_len(adm_ctx.peer_addr) == connection->peer_addr_len && 2178 if (nla_len(adm_ctx.peer_addr) == connection->peer_addr_len &&
2174 !memcmp(nla_data(adm_ctx.peer_addr), &connection->peer_addr, connection->peer_addr_len)) { 2179 !memcmp(nla_data(adm_ctx.peer_addr), &connection->peer_addr,
2175 retcode = ERR_PEER_ADDR; 2180 connection->peer_addr_len)) {
2176 goto out; 2181 retcode = ERR_PEER_ADDR;
2182 goto out;
2183 }
2177 } 2184 }
2178 } 2185 }
2179 2186
@@ -2736,7 +2743,7 @@ static int nla_put_drbd_cfg_context(struct sk_buff *skb, struct drbd_connection
2736 if (vnr != VOLUME_UNSPECIFIED && 2743 if (vnr != VOLUME_UNSPECIFIED &&
2737 nla_put_u32(skb, T_ctx_volume, vnr)) 2744 nla_put_u32(skb, T_ctx_volume, vnr))
2738 goto nla_put_failure; 2745 goto nla_put_failure;
2739 if (nla_put_string(skb, T_ctx_resource_name, connection->name)) 2746 if (nla_put_string(skb, T_ctx_resource_name, connection->resource->name))
2740 goto nla_put_failure; 2747 goto nla_put_failure;
2741 if (connection->my_addr_len && 2748 if (connection->my_addr_len &&
2742 nla_put(skb, T_ctx_my_addr, connection->my_addr_len, &connection->my_addr)) 2749 nla_put(skb, T_ctx_my_addr, connection->my_addr_len, &connection->my_addr))
@@ -2899,18 +2906,20 @@ static int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
2899{ 2906{
2900 struct drbd_device *device; 2907 struct drbd_device *device;
2901 struct drbd_genlmsghdr *dh; 2908 struct drbd_genlmsghdr *dh;
2902 struct drbd_connection *pos = (struct drbd_connection *)cb->args[0]; 2909 struct drbd_resource *pos = (struct drbd_resource *)cb->args[0];
2903 struct drbd_connection *connection = NULL; 2910 struct drbd_resource *resource = NULL;
2904 struct drbd_connection *tmp; 2911 struct drbd_connection *connection;
2912 struct drbd_resource *tmp;
2905 unsigned volume = cb->args[1]; 2913 unsigned volume = cb->args[1];
2906 2914
2907 /* Open coded, deferred, iteration: 2915 /* Open coded, deferred, iteration:
2908 * list_for_each_entry_safe(connection, tmp, &drbd_connections, connections) { 2916 * for_each_resource_safe(resource, tmp, &drbd_resources) {
2917 * connection = "first connection of resource";
2909 * idr_for_each_entry(&connection->volumes, device, i) { 2918 * idr_for_each_entry(&connection->volumes, device, i) {
2910 * ... 2919 * ...
2911 * } 2920 * }
2912 * } 2921 * }
2913 * where connection is cb->args[0]; 2922 * where resource is cb->args[0];
2914 * and i is cb->args[1]; 2923 * and i is cb->args[1];
2915 * 2924 *
2916 * cb->args[2] indicates if we shall loop over all resources, 2925 * cb->args[2] indicates if we shall loop over all resources,
@@ -2927,36 +2936,37 @@ static int get_one_status(struct sk_buff *skb, struct netlink_callback *cb)
2927 /* synchronize with conn_create()/drbd_destroy_connection() */ 2936 /* synchronize with conn_create()/drbd_destroy_connection() */
2928 rcu_read_lock(); 2937 rcu_read_lock();
2929 /* revalidate iterator position */ 2938 /* revalidate iterator position */
2930 list_for_each_entry_rcu(tmp, &drbd_connections, connections) { 2939 for_each_resource_rcu(tmp, &drbd_resources) {
2931 if (pos == NULL) { 2940 if (pos == NULL) {
2932 /* first iteration */ 2941 /* first iteration */
2933 pos = tmp; 2942 pos = tmp;
2934 connection = pos; 2943 resource = pos;
2935 break; 2944 break;
2936 } 2945 }
2937 if (tmp == pos) { 2946 if (tmp == pos) {
2938 connection = pos; 2947 resource = pos;
2939 break; 2948 break;
2940 } 2949 }
2941 } 2950 }
2942 if (connection) { 2951 if (resource) {
2943next_connection: 2952next_resource:
2953 connection = first_connection(resource);
2944 device = idr_get_next(&connection->volumes, &volume); 2954 device = idr_get_next(&connection->volumes, &volume);
2945 if (!device) { 2955 if (!device) {
2946 /* No more volumes to dump on this connection. 2956 /* No more volumes to dump on this resource.
2947 * Advance connection iterator. */ 2957 * Advance resource iterator. */
2948 pos = list_entry_rcu(connection->connections.next, 2958 pos = list_entry_rcu(resource->resources.next,
2949 struct drbd_connection, connections); 2959 struct drbd_resource, resources);
2950 /* Did we dump any volume on this connection yet? */ 2960 /* Did we dump any volume of this resource yet? */
2951 if (volume != 0) { 2961 if (volume != 0) {
2952 /* If we reached the end of the list, 2962 /* If we reached the end of the list,
2953 * or only a single resource dump was requested, 2963 * or only a single resource dump was requested,
2954 * we are done. */ 2964 * we are done. */
2955 if (&pos->connections == &drbd_connections || cb->args[2]) 2965 if (&pos->resources == &drbd_resources || cb->args[2])
2956 goto out; 2966 goto out;
2957 volume = 0; 2967 volume = 0;
2958 connection = pos; 2968 resource = pos;
2959 goto next_connection; 2969 goto next_resource;
2960 } 2970 }
2961 } 2971 }
2962 2972
@@ -3000,9 +3010,9 @@ out:
3000 rcu_read_unlock(); 3010 rcu_read_unlock();
3001 /* where to start the next iteration */ 3011 /* where to start the next iteration */
3002 cb->args[0] = (long)pos; 3012 cb->args[0] = (long)pos;
3003 cb->args[1] = (pos == connection) ? volume + 1 : 0; 3013 cb->args[1] = (pos == resource) ? volume + 1 : 0;
3004 3014
3005 /* No more connections/volumes/minors found results in an empty skb. 3015 /* No more resources/volumes/minors found results in an empty skb.
3006 * Which will terminate the dump. */ 3016 * Which will terminate the dump. */
3007 return skb->len; 3017 return skb->len;
3008} 3018}
@@ -3399,9 +3409,11 @@ int drbd_adm_down(struct sk_buff *skb, struct genl_info *info)
3399 3409
3400 /* delete connection */ 3410 /* delete connection */
3401 if (conn_lowest_minor(adm_ctx.connection) < 0) { 3411 if (conn_lowest_minor(adm_ctx.connection) < 0) {
3402 list_del_rcu(&adm_ctx.connection->connections); 3412 struct drbd_resource *resource = adm_ctx.connection->resource;
3413
3414 list_del_rcu(&resource->resources);
3403 synchronize_rcu(); 3415 synchronize_rcu();
3404 kref_put(&adm_ctx.connection->kref, drbd_destroy_connection); 3416 drbd_free_resource(resource);
3405 3417
3406 retcode = NO_ERROR; 3418 retcode = NO_ERROR;
3407 } else { 3419 } else {
@@ -3417,6 +3429,8 @@ out:
3417 3429
3418int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info) 3430int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info)
3419{ 3431{
3432 struct drbd_resource *resource;
3433 struct drbd_connection *connection;
3420 enum drbd_ret_code retcode; 3434 enum drbd_ret_code retcode;
3421 3435
3422 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE); 3436 retcode = drbd_adm_prepare(skb, info, DRBD_ADM_NEED_RESOURCE);
@@ -3425,18 +3439,24 @@ int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info)
3425 if (retcode != NO_ERROR) 3439 if (retcode != NO_ERROR)
3426 goto out; 3440 goto out;
3427 3441
3428 if (conn_lowest_minor(adm_ctx.connection) < 0) { 3442 resource = adm_ctx.resource;
3429 list_del_rcu(&adm_ctx.connection->connections); 3443 for_each_connection(connection, resource) {
3430 synchronize_rcu(); 3444 if (connection->cstate > C_STANDALONE) {
3431 kref_put(&adm_ctx.connection->kref, drbd_destroy_connection); 3445 retcode = ERR_NET_CONFIGURED;
3432 3446 goto out;
3433 retcode = NO_ERROR; 3447 }
3434 } else { 3448 }
3449 if (!idr_is_empty(&resource->devices)) {
3435 retcode = ERR_RES_IN_USE; 3450 retcode = ERR_RES_IN_USE;
3451 goto out;
3436 } 3452 }
3437 3453
3438 if (retcode == NO_ERROR) 3454 list_del_rcu(&resource->resources);
3439 drbd_thread_stop(&adm_ctx.connection->worker); 3455 for_each_connection(connection, resource)
3456 drbd_thread_stop(&connection->worker);
3457 synchronize_rcu();
3458 drbd_free_resource(resource);
3459 retcode = NO_ERROR;
3440out: 3460out:
3441 drbd_adm_finish(info, retcode); 3461 drbd_adm_finish(info, retcode);
3442 return 0; 3462 return 0;