diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2013-06-25 10:50:08 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2013-06-28 10:04:36 -0400 |
commit | d752b2696072ed52fd5afab08b601e2220a3b87e (patch) | |
tree | a6a88c4af1c6e82575d58a68651f0156431d5c09 /drivers/block/drbd/drbd_nl.c | |
parent | e96c96333fe5a4f252cc4e1d7edde8ee7dce7dfe (diff) |
drbd: Allow online change of al-stripes and al-stripe-size
Allow to change the AL layout with an resize operation. For that
the reisze command gets two new fields: al_stripes and al_stripe_size.
In order to make the operation crash save:
1) Lock out all IO and MD-IO
2) Write the super block with MDF_PRIMARY_IND clear
3) write the bitmap to the new location (all zeros, since
we allow only while connected)
4) Initialize the new AL-area
5) Write the super block with the restored MDF_PRIMARY_IND.
6) Unfreeze all IO
Since the AL-layout has no influence on the protocol, this operation
needs to be beforemed on both sides of a resource (if intended).
Signed-off-by: Andreas Gruenbacher <agruen@linbit.com>
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers/block/drbd/drbd_nl.c')
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 137 |
1 files changed, 111 insertions, 26 deletions
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 45d127522e0a..8cc1e640f485 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c | |||
@@ -827,12 +827,17 @@ void drbd_resume_io(struct drbd_conf *mdev) | |||
827 | * Returns 0 on success, negative return values indicate errors. | 827 | * Returns 0 on success, negative return values indicate errors. |
828 | * You should call drbd_md_sync() after calling this function. | 828 | * You should call drbd_md_sync() after calling this function. |
829 | */ | 829 | */ |
830 | enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags) __must_hold(local) | 830 | enum determine_dev_size |
831 | drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags, struct resize_parms *rs) __must_hold(local) | ||
831 | { | 832 | { |
832 | sector_t prev_first_sect, prev_size; /* previous meta location */ | 833 | sector_t prev_first_sect, prev_size; /* previous meta location */ |
833 | sector_t la_size_sect, u_size; | 834 | sector_t la_size_sect, u_size; |
835 | struct drbd_md *md = &mdev->ldev->md; | ||
836 | u32 prev_al_stripe_size_4k; | ||
837 | u32 prev_al_stripes; | ||
834 | sector_t size; | 838 | sector_t size; |
835 | char ppb[10]; | 839 | char ppb[10]; |
840 | void *buffer; | ||
836 | 841 | ||
837 | int md_moved, la_size_changed; | 842 | int md_moved, la_size_changed; |
838 | enum determine_dev_size rv = DS_UNCHANGED; | 843 | enum determine_dev_size rv = DS_UNCHANGED; |
@@ -847,6 +852,11 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds | |||
847 | * still lock the act_log to not trigger ASSERTs there. | 852 | * still lock the act_log to not trigger ASSERTs there. |
848 | */ | 853 | */ |
849 | drbd_suspend_io(mdev); | 854 | drbd_suspend_io(mdev); |
855 | buffer = drbd_md_get_buffer(mdev); /* Lock meta-data IO */ | ||
856 | if (!buffer) { | ||
857 | drbd_resume_io(mdev); | ||
858 | return DS_ERROR; | ||
859 | } | ||
850 | 860 | ||
851 | /* no wait necessary anymore, actually we could assert that */ | 861 | /* no wait necessary anymore, actually we could assert that */ |
852 | wait_event(mdev->al_wait, lc_try_lock(mdev->act_log)); | 862 | wait_event(mdev->al_wait, lc_try_lock(mdev->act_log)); |
@@ -855,7 +865,17 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds | |||
855 | prev_size = mdev->ldev->md.md_size_sect; | 865 | prev_size = mdev->ldev->md.md_size_sect; |
856 | la_size_sect = mdev->ldev->md.la_size_sect; | 866 | la_size_sect = mdev->ldev->md.la_size_sect; |
857 | 867 | ||
858 | /* TODO: should only be some assert here, not (re)init... */ | 868 | if (rs) { |
869 | /* rs is non NULL if we should change the AL layout only */ | ||
870 | |||
871 | prev_al_stripes = md->al_stripes; | ||
872 | prev_al_stripe_size_4k = md->al_stripe_size_4k; | ||
873 | |||
874 | md->al_stripes = rs->al_stripes; | ||
875 | md->al_stripe_size_4k = rs->al_stripe_size / 4; | ||
876 | md->al_size_4k = (u64)rs->al_stripes * rs->al_stripe_size / 4; | ||
877 | } | ||
878 | |||
859 | drbd_md_set_sector_offsets(mdev, mdev->ldev); | 879 | drbd_md_set_sector_offsets(mdev, mdev->ldev); |
860 | 880 | ||
861 | rcu_read_lock(); | 881 | rcu_read_lock(); |
@@ -863,6 +883,21 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds | |||
863 | rcu_read_unlock(); | 883 | rcu_read_unlock(); |
864 | size = drbd_new_dev_size(mdev, mdev->ldev, u_size, flags & DDSF_FORCED); | 884 | size = drbd_new_dev_size(mdev, mdev->ldev, u_size, flags & DDSF_FORCED); |
865 | 885 | ||
886 | if (size < la_size_sect) { | ||
887 | if (rs && u_size == 0) { | ||
888 | /* Remove "rs &&" later. This check should always be active, but | ||
889 | right now the receiver expects the permissive behavior */ | ||
890 | dev_warn(DEV, "Implicit shrink not allowed. " | ||
891 | "Use --size=%llus for explicit shrink.\n", | ||
892 | (unsigned long long)size); | ||
893 | rv = DS_ERROR_SHRINK; | ||
894 | } | ||
895 | if (u_size > size) | ||
896 | rv = DS_ERROR_SPACE_MD; | ||
897 | if (rv != DS_UNCHANGED) | ||
898 | goto err_out; | ||
899 | } | ||
900 | |||
866 | if (drbd_get_capacity(mdev->this_bdev) != size || | 901 | if (drbd_get_capacity(mdev->this_bdev) != size || |
867 | drbd_bm_capacity(mdev) != size) { | 902 | drbd_bm_capacity(mdev) != size) { |
868 | int err; | 903 | int err; |
@@ -886,38 +921,57 @@ enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds | |||
886 | dev_info(DEV, "size = %s (%llu KB)\n", ppsize(ppb, size>>1), | 921 | dev_info(DEV, "size = %s (%llu KB)\n", ppsize(ppb, size>>1), |
887 | (unsigned long long)size>>1); | 922 | (unsigned long long)size>>1); |
888 | } | 923 | } |
889 | if (rv == DS_ERROR) | 924 | if (rv <= DS_ERROR) |
890 | goto out; | 925 | goto err_out; |
891 | 926 | ||
892 | la_size_changed = (la_size_sect != mdev->ldev->md.la_size_sect); | 927 | la_size_changed = (la_size_sect != mdev->ldev->md.la_size_sect); |
893 | 928 | ||
894 | md_moved = prev_first_sect != drbd_md_first_sector(mdev->ldev) | 929 | md_moved = prev_first_sect != drbd_md_first_sector(mdev->ldev) |
895 | || prev_size != mdev->ldev->md.md_size_sect; | 930 | || prev_size != mdev->ldev->md.md_size_sect; |
896 | 931 | ||
897 | if (la_size_changed || md_moved) { | 932 | if (la_size_changed || md_moved || rs) { |
898 | int err; | 933 | u32 prev_flags; |
899 | 934 | ||
900 | drbd_al_shrink(mdev); /* All extents inactive. */ | 935 | drbd_al_shrink(mdev); /* All extents inactive. */ |
936 | |||
937 | prev_flags = md->flags; | ||
938 | md->flags &= ~MDF_PRIMARY_IND; | ||
939 | drbd_md_write(mdev, buffer); | ||
940 | |||
901 | dev_info(DEV, "Writing the whole bitmap, %s\n", | 941 | dev_info(DEV, "Writing the whole bitmap, %s\n", |
902 | la_size_changed && md_moved ? "size changed and md moved" : | 942 | la_size_changed && md_moved ? "size changed and md moved" : |
903 | la_size_changed ? "size changed" : "md moved"); | 943 | la_size_changed ? "size changed" : "md moved"); |
904 | /* next line implicitly does drbd_suspend_io()+drbd_resume_io() */ | 944 | /* next line implicitly does drbd_suspend_io()+drbd_resume_io() */ |
905 | err = drbd_bitmap_io(mdev, md_moved ? &drbd_bm_write_all : &drbd_bm_write, | 945 | drbd_bitmap_io(mdev, md_moved ? &drbd_bm_write_all : &drbd_bm_write, |
906 | "size changed", BM_LOCKED_MASK); | 946 | "size changed", BM_LOCKED_MASK); |
907 | if (err) { | 947 | drbd_initialize_al(mdev, buffer); |
908 | rv = DS_ERROR; | 948 | |
909 | goto out; | 949 | md->flags = prev_flags; |
910 | } | 950 | drbd_md_write(mdev, buffer); |
911 | drbd_md_mark_dirty(mdev); | 951 | |
952 | if (rs) | ||
953 | dev_info(DEV, "Changed AL layout to al-stripes = %d, al-stripe-size-kB = %d\n", | ||
954 | md->al_stripes, md->al_stripe_size_4k * 4); | ||
912 | } | 955 | } |
913 | 956 | ||
914 | if (size > la_size_sect) | 957 | if (size > la_size_sect) |
915 | rv = DS_GREW; | 958 | rv = DS_GREW; |
916 | if (size < la_size_sect) | 959 | if (size < la_size_sect) |
917 | rv = DS_SHRUNK; | 960 | rv = DS_SHRUNK; |
918 | out: | 961 | |
962 | if (0) { | ||
963 | err_out: | ||
964 | if (rs) { | ||
965 | md->al_stripes = prev_al_stripes; | ||
966 | md->al_stripe_size_4k = prev_al_stripe_size_4k; | ||
967 | md->al_size_4k = (u64)prev_al_stripes * prev_al_stripe_size_4k; | ||
968 | |||
969 | drbd_md_set_sector_offsets(mdev, mdev->ldev); | ||
970 | } | ||
971 | } | ||
919 | lc_unlock(mdev->act_log); | 972 | lc_unlock(mdev->act_log); |
920 | wake_up(&mdev->al_wait); | 973 | wake_up(&mdev->al_wait); |
974 | drbd_md_put_buffer(mdev); | ||
921 | drbd_resume_io(mdev); | 975 | drbd_resume_io(mdev); |
922 | 976 | ||
923 | return rv; | 977 | return rv; |
@@ -1618,8 +1672,8 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info) | |||
1618 | !drbd_md_test_flag(mdev->ldev, MDF_CONNECTED_IND)) | 1672 | !drbd_md_test_flag(mdev->ldev, MDF_CONNECTED_IND)) |
1619 | set_bit(USE_DEGR_WFC_T, &mdev->flags); | 1673 | set_bit(USE_DEGR_WFC_T, &mdev->flags); |
1620 | 1674 | ||
1621 | dd = drbd_determine_dev_size(mdev, 0); | 1675 | dd = drbd_determine_dev_size(mdev, 0, NULL); |
1622 | if (dd == DS_ERROR) { | 1676 | if (dd <= DS_ERROR) { |
1623 | retcode = ERR_NOMEM_BITMAP; | 1677 | retcode = ERR_NOMEM_BITMAP; |
1624 | goto force_diskless_dec; | 1678 | goto force_diskless_dec; |
1625 | } else if (dd == DS_GREW) | 1679 | } else if (dd == DS_GREW) |
@@ -2316,6 +2370,7 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info) | |||
2316 | struct drbd_conf *mdev; | 2370 | struct drbd_conf *mdev; |
2317 | enum drbd_ret_code retcode; | 2371 | enum drbd_ret_code retcode; |
2318 | enum determine_dev_size dd; | 2372 | enum determine_dev_size dd; |
2373 | bool change_al_layout = false; | ||
2319 | enum dds_flags ddsf; | 2374 | enum dds_flags ddsf; |
2320 | sector_t u_size; | 2375 | sector_t u_size; |
2321 | int err; | 2376 | int err; |
@@ -2326,31 +2381,33 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info) | |||
2326 | if (retcode != NO_ERROR) | 2381 | if (retcode != NO_ERROR) |
2327 | goto fail; | 2382 | goto fail; |
2328 | 2383 | ||
2384 | mdev = adm_ctx.mdev; | ||
2385 | if (!get_ldev(mdev)) { | ||
2386 | retcode = ERR_NO_DISK; | ||
2387 | goto fail; | ||
2388 | } | ||
2389 | |||
2329 | memset(&rs, 0, sizeof(struct resize_parms)); | 2390 | memset(&rs, 0, sizeof(struct resize_parms)); |
2391 | rs.al_stripes = mdev->ldev->md.al_stripes; | ||
2392 | rs.al_stripe_size = mdev->ldev->md.al_stripe_size_4k * 4; | ||
2330 | if (info->attrs[DRBD_NLA_RESIZE_PARMS]) { | 2393 | if (info->attrs[DRBD_NLA_RESIZE_PARMS]) { |
2331 | err = resize_parms_from_attrs(&rs, info); | 2394 | err = resize_parms_from_attrs(&rs, info); |
2332 | if (err) { | 2395 | if (err) { |
2333 | retcode = ERR_MANDATORY_TAG; | 2396 | retcode = ERR_MANDATORY_TAG; |
2334 | drbd_msg_put_info(from_attrs_err_to_txt(err)); | 2397 | drbd_msg_put_info(from_attrs_err_to_txt(err)); |
2335 | goto fail; | 2398 | goto fail_ldev; |
2336 | } | 2399 | } |
2337 | } | 2400 | } |
2338 | 2401 | ||
2339 | mdev = adm_ctx.mdev; | ||
2340 | if (mdev->state.conn > C_CONNECTED) { | 2402 | if (mdev->state.conn > C_CONNECTED) { |
2341 | retcode = ERR_RESIZE_RESYNC; | 2403 | retcode = ERR_RESIZE_RESYNC; |
2342 | goto fail; | 2404 | goto fail_ldev; |
2343 | } | 2405 | } |
2344 | 2406 | ||
2345 | if (mdev->state.role == R_SECONDARY && | 2407 | if (mdev->state.role == R_SECONDARY && |
2346 | mdev->state.peer == R_SECONDARY) { | 2408 | mdev->state.peer == R_SECONDARY) { |
2347 | retcode = ERR_NO_PRIMARY; | 2409 | retcode = ERR_NO_PRIMARY; |
2348 | goto fail; | 2410 | goto fail_ldev; |
2349 | } | ||
2350 | |||
2351 | if (!get_ldev(mdev)) { | ||
2352 | retcode = ERR_NO_DISK; | ||
2353 | goto fail; | ||
2354 | } | 2411 | } |
2355 | 2412 | ||
2356 | if (rs.no_resync && mdev->tconn->agreed_pro_version < 93) { | 2413 | if (rs.no_resync && mdev->tconn->agreed_pro_version < 93) { |
@@ -2369,6 +2426,28 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info) | |||
2369 | } | 2426 | } |
2370 | } | 2427 | } |
2371 | 2428 | ||
2429 | if (mdev->ldev->md.al_stripes != rs.al_stripes || | ||
2430 | mdev->ldev->md.al_stripe_size_4k != rs.al_stripe_size / 4) { | ||
2431 | u32 al_size_k = rs.al_stripes * rs.al_stripe_size; | ||
2432 | |||
2433 | if (al_size_k > (16 * 1024 * 1024)) { | ||
2434 | retcode = ERR_MD_LAYOUT_TOO_BIG; | ||
2435 | goto fail_ldev; | ||
2436 | } | ||
2437 | |||
2438 | if (al_size_k < MD_32kB_SECT/2) { | ||
2439 | retcode = ERR_MD_LAYOUT_TOO_SMALL; | ||
2440 | goto fail_ldev; | ||
2441 | } | ||
2442 | |||
2443 | if (mdev->state.conn != C_CONNECTED) { | ||
2444 | retcode = ERR_MD_LAYOUT_CONNECTED; | ||
2445 | goto fail_ldev; | ||
2446 | } | ||
2447 | |||
2448 | change_al_layout = true; | ||
2449 | } | ||
2450 | |||
2372 | if (mdev->ldev->known_size != drbd_get_capacity(mdev->ldev->backing_bdev)) | 2451 | if (mdev->ldev->known_size != drbd_get_capacity(mdev->ldev->backing_bdev)) |
2373 | mdev->ldev->known_size = drbd_get_capacity(mdev->ldev->backing_bdev); | 2452 | mdev->ldev->known_size = drbd_get_capacity(mdev->ldev->backing_bdev); |
2374 | 2453 | ||
@@ -2384,12 +2463,18 @@ int drbd_adm_resize(struct sk_buff *skb, struct genl_info *info) | |||
2384 | } | 2463 | } |
2385 | 2464 | ||
2386 | ddsf = (rs.resize_force ? DDSF_FORCED : 0) | (rs.no_resync ? DDSF_NO_RESYNC : 0); | 2465 | ddsf = (rs.resize_force ? DDSF_FORCED : 0) | (rs.no_resync ? DDSF_NO_RESYNC : 0); |
2387 | dd = drbd_determine_dev_size(mdev, ddsf); | 2466 | dd = drbd_determine_dev_size(mdev, ddsf, change_al_layout ? &rs : NULL); |
2388 | drbd_md_sync(mdev); | 2467 | drbd_md_sync(mdev); |
2389 | put_ldev(mdev); | 2468 | put_ldev(mdev); |
2390 | if (dd == DS_ERROR) { | 2469 | if (dd == DS_ERROR) { |
2391 | retcode = ERR_NOMEM_BITMAP; | 2470 | retcode = ERR_NOMEM_BITMAP; |
2392 | goto fail; | 2471 | goto fail; |
2472 | } else if (dd == DS_ERROR_SPACE_MD) { | ||
2473 | retcode = ERR_MD_LAYOUT_NO_FIT; | ||
2474 | goto fail; | ||
2475 | } else if (dd == DS_ERROR_SHRINK) { | ||
2476 | retcode = ERR_IMPLICIT_SHRINK; | ||
2477 | goto fail; | ||
2393 | } | 2478 | } |
2394 | 2479 | ||
2395 | if (mdev->state.conn == C_CONNECTED) { | 2480 | if (mdev->state.conn == C_CONNECTED) { |