diff options
-rw-r--r-- | drivers/block/drbd/drbd_int.h | 45 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 96 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 116 |
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 | ||
168 | extern struct ratelimit_state drbd_ratelimit_state; | 168 | extern struct ratelimit_state drbd_ratelimit_state; |
169 | extern struct idr drbd_devices; /* RCU, updates: genl_lock() */ | 169 | extern struct idr drbd_devices; /* RCU, updates: genl_lock() */ |
170 | extern struct list_head drbd_connections; /* RCU, updates: genl_lock() */ | 170 | extern struct list_head drbd_resources; /* RCU, updates: genl_lock() */ |
171 | 171 | ||
172 | extern const char *cmdname(enum drbd_packet cmd); | 172 | extern const char *cmdname(enum drbd_packet cmd); |
173 | 173 | ||
@@ -536,9 +536,16 @@ enum { | |||
536 | DISCONNECT_SENT, | 536 | DISCONNECT_SENT, |
537 | }; | 537 | }; |
538 | 538 | ||
539 | struct drbd_connection { /* is a resource from the config file */ | 539 | struct 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 | |||
546 | struct 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); | |||
1177 | enum drbd_ret_code drbd_create_minor(struct drbd_connection *connection, unsigned int minor, int vnr); | 1202 | enum drbd_ret_code drbd_create_minor(struct drbd_connection *connection, unsigned int minor, int vnr); |
1178 | extern void drbd_destroy_device(struct kref *kref); | 1203 | extern void drbd_destroy_device(struct kref *kref); |
1179 | 1204 | ||
1205 | extern struct drbd_resource *drbd_create_resource(const char *name); | ||
1206 | extern void drbd_free_resource(struct drbd_resource *resource); | ||
1207 | |||
1180 | extern int set_resource_options(struct drbd_connection *connection, struct res_opts *res_opts); | 1208 | extern int set_resource_options(struct drbd_connection *connection, struct res_opts *res_opts); |
1181 | extern struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts); | 1209 | extern struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts); |
1182 | extern void drbd_destroy_connection(struct kref *kref); | 1210 | extern void drbd_destroy_connection(struct kref *kref); |
1183 | struct drbd_connection *conn_get_by_name(const char *name); | 1211 | struct drbd_connection *conn_get_by_name(const char *name); |
1184 | extern struct drbd_connection *conn_get_by_addrs(void *my_addr, int my_addr_len, | 1212 | extern 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); |
1214 | extern void drbd_destroy_resource(struct kref *kref); | ||
1186 | extern void conn_free_crypto(struct drbd_connection *connection); | 1215 | extern void conn_free_crypto(struct drbd_connection *connection); |
1187 | 1216 | ||
1188 | extern int proc_details; | 1217 | extern int proc_details; |
@@ -2082,4 +2111,10 @@ static inline void drbd_md_flush(struct drbd_device *device) | |||
2082 | } | 2111 | } |
2083 | } | 2112 | } |
2084 | 2113 | ||
2114 | static 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 | */ |
120 | struct idr drbd_devices; | 120 | struct idr drbd_devices; |
121 | struct list_head drbd_connections; /* list of struct drbd_connection */ | 121 | struct list_head drbd_resources; |
122 | 122 | ||
123 | struct kmem_cache *drbd_request_cache; | 123 | struct kmem_cache *drbd_request_cache; |
124 | struct kmem_cache *drbd_ee_cache; /* peer requests */ | 124 | struct 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 | ||
335 | restart: | 336 | restart: |
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 | ||
2280 | void 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 | |||
2289 | void 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 | ||
2280 | static void drbd_cleanup(void) | 2300 | static 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) | |||
2391 | struct drbd_connection *conn_get_by_name(const char *name) | 2410 | struct 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: | |||
2411 | struct drbd_connection *conn_get_by_addrs(void *my_addr, int my_addr_len, | 2432 | struct 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 | ||
2533 | struct 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() */ |
2510 | struct drbd_connection *conn_create(const char *name, struct res_opts *res_opts) | 2552 | struct 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: | |||
2579 | void drbd_destroy_connection(struct kref *kref) | 2624 | void 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 | ||
2598 | static int init_submitter(struct drbd_device *device) | 2644 | static 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) { |
2943 | next_connection: | 2952 | next_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 | ||
3418 | int drbd_adm_del_resource(struct sk_buff *skb, struct genl_info *info) | 3430 | int 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; | ||
3440 | out: | 3460 | out: |
3441 | drbd_adm_finish(info, retcode); | 3461 | drbd_adm_finish(info, retcode); |
3442 | return 0; | 3462 | return 0; |