aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Reisner <philipp.reisner@linbit.com>2011-02-22 02:07:03 -0500
committerPhilipp Reisner <philipp.reisner@linbit.com>2011-10-14 10:48:00 -0400
commit774b305518a68a50df4f479bcf79da2add724e6e (patch)
tree19b0322feebe2aed18cee0eb7ffa3f5e0ad3addc
parent80883197da071239ed9e76bd3b9d8c9c5e19e4e6 (diff)
drbd: Implemented new commands to create/delete connections/minors
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
-rw-r--r--drivers/block/drbd/drbd_int.h4
-rw-r--r--drivers/block/drbd/drbd_main.c68
-rw-r--r--drivers/block/drbd/drbd_nl.c106
-rw-r--r--include/linux/drbd.h3
-rw-r--r--include/linux/drbd_nl.h12
5 files changed, 120 insertions, 73 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index a27e2a4e038d..535d503886d8 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -1258,7 +1258,6 @@ extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev);
1258extern void drbd_go_diskless(struct drbd_conf *mdev); 1258extern void drbd_go_diskless(struct drbd_conf *mdev);
1259extern void drbd_ldev_destroy(struct drbd_conf *mdev); 1259extern void drbd_ldev_destroy(struct drbd_conf *mdev);
1260 1260
1261
1262/* Meta data layout 1261/* Meta data layout
1263 We reserve a 128MB Block (4k aligned) 1262 We reserve a 128MB Block (4k aligned)
1264 * either at the end of the backing device 1263 * either at the end of the backing device
@@ -1476,8 +1475,9 @@ extern wait_queue_head_t drbd_pp_wait;
1476extern rwlock_t global_state_lock; 1475extern rwlock_t global_state_lock;
1477 1476
1478extern int conn_lowest_minor(struct drbd_tconn *tconn); 1477extern int conn_lowest_minor(struct drbd_tconn *tconn);
1479extern struct drbd_conf *drbd_new_device(unsigned int minor); 1478enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, int vnr);
1480extern void drbd_free_mdev(struct drbd_conf *mdev); 1479extern void drbd_free_mdev(struct drbd_conf *mdev);
1480extern void drbd_delete_device(unsigned int minor);
1481 1481
1482struct drbd_tconn *drbd_new_tconn(char *name); 1482struct drbd_tconn *drbd_new_tconn(char *name);
1483extern void drbd_free_tconn(struct drbd_tconn *tconn); 1483extern void drbd_free_tconn(struct drbd_tconn *tconn);
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 2bfd63058f40..ec7d0d98657c 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -614,13 +614,16 @@ char *drbd_task_to_thread_name(struct drbd_tconn *tconn, struct task_struct *tas
614 return thi ? thi->name : task->comm; 614 return thi ? thi->name : task->comm;
615} 615}
616 616
617#ifdef CONFIG_SMP
618int conn_lowest_minor(struct drbd_tconn *tconn) 617int conn_lowest_minor(struct drbd_tconn *tconn)
619{ 618{
620 int minor = 0; 619 int minor = 0;
621 idr_get_next(&tconn->volumes, &minor); 620
621 if (!idr_get_next(&tconn->volumes, &minor))
622 return -1;
622 return minor; 623 return minor;
623} 624}
625
626#ifdef CONFIG_SMP
624/** 627/**
625 * drbd_calc_cpu_mask() - Generate CPU masks, spread over all CPUs 628 * drbd_calc_cpu_mask() - Generate CPU masks, spread over all CPUs
626 * @mdev: DRBD device. 629 * @mdev: DRBD device.
@@ -2078,15 +2081,16 @@ static void drbd_release_ee_lists(struct drbd_conf *mdev)
2078 dev_err(DEV, "%d EEs in net list found!\n", rr); 2081 dev_err(DEV, "%d EEs in net list found!\n", rr);
2079} 2082}
2080 2083
2081/* caution. no locking. 2084/* caution. no locking. */
2082 * currently only used from module cleanup code. */ 2085void drbd_delete_device(unsigned int minor)
2083static void drbd_delete_device(unsigned int minor)
2084{ 2086{
2085 struct drbd_conf *mdev = minor_to_mdev(minor); 2087 struct drbd_conf *mdev = minor_to_mdev(minor);
2086 2088
2087 if (!mdev) 2089 if (!mdev)
2088 return; 2090 return;
2089 2091
2092 idr_remove(&mdev->tconn->volumes, minor);
2093
2090 /* paranoia asserts */ 2094 /* paranoia asserts */
2091 D_ASSERT(mdev->open_cnt == 0); 2095 D_ASSERT(mdev->open_cnt == 0);
2092 D_ASSERT(list_empty(&mdev->tconn->data.work.q)); 2096 D_ASSERT(list_empty(&mdev->tconn->data.work.q));
@@ -2101,7 +2105,6 @@ static void drbd_delete_device(unsigned int minor)
2101 bdput(mdev->this_bdev); 2105 bdput(mdev->this_bdev);
2102 2106
2103 drbd_free_resources(mdev); 2107 drbd_free_resources(mdev);
2104 drbd_free_tconn(mdev->tconn);
2105 2108
2106 drbd_release_ee_lists(mdev); 2109 drbd_release_ee_lists(mdev);
2107 2110
@@ -2223,6 +2226,9 @@ struct drbd_tconn *drbd_new_tconn(char *name)
2223 if (!tconn->name) 2226 if (!tconn->name)
2224 goto fail; 2227 goto fail;
2225 2228
2229 if (!zalloc_cpumask_var(&tconn->cpu_mask, GFP_KERNEL))
2230 goto fail;
2231
2226 if (!tl_init(tconn)) 2232 if (!tl_init(tconn))
2227 goto fail; 2233 goto fail;
2228 2234
@@ -2252,6 +2258,7 @@ struct drbd_tconn *drbd_new_tconn(char *name)
2252 2258
2253fail: 2259fail:
2254 tl_cleanup(tconn); 2260 tl_cleanup(tconn);
2261 free_cpumask_var(tconn->cpu_mask);
2255 kfree(tconn->name); 2262 kfree(tconn->name);
2256 kfree(tconn); 2263 kfree(tconn);
2257 2264
@@ -2265,6 +2272,7 @@ void drbd_free_tconn(struct drbd_tconn *tconn)
2265 write_unlock_irq(&global_state_lock); 2272 write_unlock_irq(&global_state_lock);
2266 idr_destroy(&tconn->volumes); 2273 idr_destroy(&tconn->volumes);
2267 2274
2275 free_cpumask_var(tconn->cpu_mask);
2268 kfree(tconn->name); 2276 kfree(tconn->name);
2269 kfree(tconn->int_dig_out); 2277 kfree(tconn->int_dig_out);
2270 kfree(tconn->int_dig_in); 2278 kfree(tconn->int_dig_in);
@@ -2272,32 +2280,31 @@ void drbd_free_tconn(struct drbd_tconn *tconn)
2272 kfree(tconn); 2280 kfree(tconn);
2273} 2281}
2274 2282
2275struct drbd_conf *drbd_new_device(unsigned int minor) 2283enum drbd_ret_code conn_new_minor(struct drbd_tconn *tconn, unsigned int minor, int vnr)
2276{ 2284{
2277 struct drbd_conf *mdev; 2285 struct drbd_conf *mdev;
2278 struct gendisk *disk; 2286 struct gendisk *disk;
2279 struct request_queue *q; 2287 struct request_queue *q;
2280 char conn_name[9]; /* drbd1234N */ 2288 int vnr_got = vnr;
2281 int vnr; 2289
2290 mdev = minor_to_mdev(minor);
2291 if (mdev)
2292 return ERR_MINOR_EXISTS;
2282 2293
2283 /* GFP_KERNEL, we are outside of all write-out paths */ 2294 /* GFP_KERNEL, we are outside of all write-out paths */
2284 mdev = kzalloc(sizeof(struct drbd_conf), GFP_KERNEL); 2295 mdev = kzalloc(sizeof(struct drbd_conf), GFP_KERNEL);
2285 if (!mdev) 2296 if (!mdev)
2286 return NULL; 2297 return ERR_NOMEM;
2287 sprintf(conn_name, "drbd%d", minor); 2298
2288 mdev->tconn = drbd_new_tconn(conn_name); 2299 mdev->tconn = tconn;
2289 if (!mdev->tconn) 2300 if (!idr_pre_get(&tconn->volumes, GFP_KERNEL))
2290 goto out_no_tconn; 2301 goto out_no_idr;
2291 if (!idr_pre_get(&mdev->tconn->volumes, GFP_KERNEL)) 2302 if (idr_get_new(&tconn->volumes, mdev, &vnr_got))
2292 goto out_no_cpumask; 2303 goto out_no_idr;
2293 if (idr_get_new(&mdev->tconn->volumes, mdev, &vnr)) 2304 if (vnr_got != vnr) {
2294 goto out_no_cpumask; 2305 dev_err(DEV, "vnr_got (%d) != vnr (%d)\n", vnr_got, vnr);
2295 if (vnr != 0) { 2306 goto out_no_q;
2296 dev_err(DEV, "vnr = %d\n", vnr); 2307 }
2297 goto out_no_cpumask;
2298 }
2299 if (!zalloc_cpumask_var(&mdev->tconn->cpu_mask, GFP_KERNEL))
2300 goto out_no_cpumask;
2301 2308
2302 mdev->minor = minor; 2309 mdev->minor = minor;
2303 2310
@@ -2354,7 +2361,10 @@ struct drbd_conf *drbd_new_device(unsigned int minor)
2354 INIT_LIST_HEAD(&mdev->current_epoch->list); 2361 INIT_LIST_HEAD(&mdev->current_epoch->list);
2355 mdev->epochs = 1; 2362 mdev->epochs = 1;
2356 2363
2357 return mdev; 2364 minor_table[minor] = mdev;
2365 add_disk(disk);
2366
2367 return NO_ERROR;
2358 2368
2359/* out_whatever_else: 2369/* out_whatever_else:
2360 kfree(mdev->current_epoch); */ 2370 kfree(mdev->current_epoch); */
@@ -2367,12 +2377,10 @@ out_no_io_page:
2367out_no_disk: 2377out_no_disk:
2368 blk_cleanup_queue(q); 2378 blk_cleanup_queue(q);
2369out_no_q: 2379out_no_q:
2370 free_cpumask_var(mdev->tconn->cpu_mask); 2380 idr_remove(&tconn->volumes, vnr_got);
2371out_no_cpumask: 2381out_no_idr:
2372 drbd_free_tconn(mdev->tconn);
2373out_no_tconn:
2374 kfree(mdev); 2382 kfree(mdev);
2375 return NULL; 2383 return ERR_NOMEM;
2376} 2384}
2377 2385
2378/* counterpart of drbd_new_device. 2386/* counterpart of drbd_new_device.
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 455a51dd364d..f2739fd188a0 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -443,40 +443,6 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force)
443 return rv; 443 return rv;
444} 444}
445 445
446static struct drbd_conf *ensure_mdev(int minor, int create)
447{
448 struct drbd_conf *mdev;
449
450 if (minor >= minor_count)
451 return NULL;
452
453 mdev = minor_to_mdev(minor);
454
455 if (!mdev && create) {
456 struct gendisk *disk = NULL;
457 mdev = drbd_new_device(minor);
458
459 spin_lock_irq(&drbd_pp_lock);
460 if (minor_table[minor] == NULL) {
461 minor_table[minor] = mdev;
462 disk = mdev->vdisk;
463 mdev = NULL;
464 } /* else: we lost the race */
465 spin_unlock_irq(&drbd_pp_lock);
466
467 if (disk) /* we won the race above */
468 /* in case we ever add a drbd_delete_device(),
469 * don't forget the del_gendisk! */
470 add_disk(disk);
471 else /* we lost the race above */
472 drbd_free_mdev(mdev);
473
474 mdev = minor_to_mdev(minor);
475 }
476
477 return mdev;
478}
479
480static int drbd_nl_primary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, 446static int drbd_nl_primary(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
481 struct drbd_nl_cfg_reply *reply) 447 struct drbd_nl_cfg_reply *reply)
482{ 448{
@@ -1789,12 +1755,6 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n
1789 if (!expect(sc.al_extents <= DRBD_AL_EXTENTS_MAX)) 1755 if (!expect(sc.al_extents <= DRBD_AL_EXTENTS_MAX))
1790 sc.al_extents = DRBD_AL_EXTENTS_MAX; 1756 sc.al_extents = DRBD_AL_EXTENTS_MAX;
1791 1757
1792 /* to avoid spurious errors when configuring minors before configuring
1793 * the minors they depend on: if necessary, first create the minor we
1794 * depend on */
1795 if (sc.after >= 0)
1796 ensure_mdev(sc.after, 1);
1797
1798 /* most sanity checks done, try to assign the new sync-after 1758 /* most sanity checks done, try to assign the new sync-after
1799 * dependency. need to hold the global lock in there, 1759 * dependency. need to hold the global lock in there,
1800 * to avoid a race in the dependency loop check. */ 1760 * to avoid a race in the dependency loop check. */
@@ -2184,13 +2144,73 @@ out:
2184 return 0; 2144 return 0;
2185} 2145}
2186 2146
2147static int drbd_nl_new_conn(struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply)
2148{
2149 struct new_connection args;
2150
2151 if (!new_connection_from_tags(nlp->tag_list, &args)) {
2152 reply->ret_code = ERR_MANDATORY_TAG;
2153 return 0;
2154 }
2155
2156 reply->ret_code = NO_ERROR;
2157 if (!drbd_new_tconn(args.name))
2158 reply->ret_code = ERR_NOMEM;
2159
2160 return 0;
2161}
2162
2163static int drbd_nl_new_minor(struct drbd_tconn *tconn,
2164 struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply)
2165{
2166 struct new_minor args;
2167
2168 args.vol_nr = 0;
2169 args.minor = 0;
2170
2171 if (!new_minor_from_tags(nlp->tag_list, &args)) {
2172 reply->ret_code = ERR_MANDATORY_TAG;
2173 return 0;
2174 }
2175
2176 reply->ret_code = conn_new_minor(tconn, args.minor, args.vol_nr);
2177
2178 return 0;
2179}
2180
2181static int drbd_nl_del_minor(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
2182 struct drbd_nl_cfg_reply *reply)
2183{
2184 if (mdev->state.disk == D_DISKLESS &&
2185 mdev->state.conn == C_STANDALONE &&
2186 mdev->state.role == R_SECONDARY) {
2187 drbd_delete_device(mdev_to_minor(mdev));
2188 reply->ret_code = NO_ERROR;
2189 } else {
2190 reply->ret_code = ERR_MINOR_CONFIGURED;
2191 }
2192 return 0;
2193}
2194
2195static int drbd_nl_del_conn(struct drbd_tconn *tconn,
2196 struct drbd_nl_cfg_req *nlp, struct drbd_nl_cfg_reply *reply)
2197{
2198 if (conn_lowest_minor(tconn) < 0) {
2199 drbd_free_tconn(tconn);
2200 reply->ret_code = NO_ERROR;
2201 } else {
2202 reply->ret_code = ERR_CONN_IN_USE;
2203 }
2204
2205 return 0;
2206}
2207
2187enum cn_handler_type { 2208enum cn_handler_type {
2188 CHT_MINOR, 2209 CHT_MINOR,
2189 CHT_CONN, 2210 CHT_CONN,
2190 CHT_CTOR, 2211 CHT_CTOR,
2191 /* CHT_RES, later */ 2212 /* CHT_RES, later */
2192}; 2213};
2193
2194struct cn_handler_struct { 2214struct cn_handler_struct {
2195 enum cn_handler_type type; 2215 enum cn_handler_type type;
2196 union { 2216 union {
@@ -2235,6 +2255,10 @@ static struct cn_handler_struct cnd_table[] = {
2235 sizeof(struct get_timeout_flag_tag_len_struct)}, 2255 sizeof(struct get_timeout_flag_tag_len_struct)},
2236 [ P_start_ov ] = { CHT_MINOR, { &drbd_nl_start_ov }, 0 }, 2256 [ P_start_ov ] = { CHT_MINOR, { &drbd_nl_start_ov }, 0 },
2237 [ P_new_c_uuid ] = { CHT_MINOR, { &drbd_nl_new_c_uuid }, 0 }, 2257 [ P_new_c_uuid ] = { CHT_MINOR, { &drbd_nl_new_c_uuid }, 0 },
2258 [ P_new_connection ] = { CHT_CTOR, { .constructor = &drbd_nl_new_conn }, 0 },
2259 [ P_new_minor ] = { CHT_CONN, { .conn_based = &drbd_nl_new_minor }, 0 },
2260 [ P_del_minor ] = { CHT_MINOR, { &drbd_nl_del_minor }, 0 },
2261 [ P_del_connection ] = { CHT_CONN, { .conn_based = &drbd_nl_del_conn }, 0 },
2238}; 2262};
2239 2263
2240static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms *nsp) 2264static void drbd_connector_callback(struct cn_msg *req, struct netlink_skb_parms *nsp)
diff --git a/include/linux/drbd.h b/include/linux/drbd.h
index 7683b4ab6583..e192167e6145 100644
--- a/include/linux/drbd.h
+++ b/include/linux/drbd.h
@@ -156,6 +156,9 @@ enum drbd_ret_code {
156 ERR_PIC_AFTER_DEP = 156, 156 ERR_PIC_AFTER_DEP = 156,
157 ERR_PIC_PEER_DEP = 157, 157 ERR_PIC_PEER_DEP = 157,
158 ERR_CONN_NOT_KNOWN = 158, 158 ERR_CONN_NOT_KNOWN = 158,
159 ERR_CONN_IN_USE = 159,
160 ERR_MINOR_CONFIGURED = 160,
161 ERR_MINOR_EXISTS = 161,
159 162
160 /* insert new ones above this line */ 163 /* insert new ones above this line */
161 AFTER_LAST_ERR_CODE 164 AFTER_LAST_ERR_CODE
diff --git a/include/linux/drbd_nl.h b/include/linux/drbd_nl.h
index ab6159e4fcf0..1216c7a432c5 100644
--- a/include/linux/drbd_nl.h
+++ b/include/linux/drbd_nl.h
@@ -152,6 +152,18 @@ NL_PACKET(new_c_uuid, 26,
152NL_RESPONSE(return_code_only, 27) 152NL_RESPONSE(return_code_only, 27)
153#endif 153#endif
154 154
155NL_PACKET(new_connection, 28, /* CHT_CTOR */
156 NL_STRING( 85, T_MANDATORY, name, DRBD_NL_OBJ_NAME_LEN)
157)
158
159NL_PACKET(new_minor, 29, /* CHT_CONN */
160 NL_INTEGER( 86, T_MANDATORY, minor)
161 NL_INTEGER( 87, T_MANDATORY, vol_nr)
162)
163
164NL_PACKET(del_minor, 30, ) /* CHT_MINOR */
165NL_PACKET(del_connection, 31, ) /* CHT_CONN */
166
155#undef NL_PACKET 167#undef NL_PACKET
156#undef NL_INTEGER 168#undef NL_INTEGER
157#undef NL_INT64 169#undef NL_INT64