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 | |
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')
-rw-r--r-- | drivers/block/drbd/drbd_actlog.c | 21 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_int.h | 7 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 57 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 137 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 2 |
5 files changed, 172 insertions, 52 deletions
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 6608076dc39e..28c73ca320a8 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c | |||
@@ -659,6 +659,27 @@ void drbd_al_shrink(struct drbd_conf *mdev) | |||
659 | wake_up(&mdev->al_wait); | 659 | wake_up(&mdev->al_wait); |
660 | } | 660 | } |
661 | 661 | ||
662 | int drbd_initialize_al(struct drbd_conf *mdev, void *buffer) | ||
663 | { | ||
664 | struct al_transaction_on_disk *al = buffer; | ||
665 | struct drbd_md *md = &mdev->ldev->md; | ||
666 | sector_t al_base = md->md_offset + md->al_offset; | ||
667 | int al_size_4k = md->al_stripes * md->al_stripe_size_4k; | ||
668 | int i; | ||
669 | |||
670 | memset(al, 0, 4096); | ||
671 | al->magic = cpu_to_be32(DRBD_AL_MAGIC); | ||
672 | al->transaction_type = cpu_to_be16(AL_TR_INITIALIZED); | ||
673 | al->crc32c = cpu_to_be32(crc32c(0, al, 4096)); | ||
674 | |||
675 | for (i = 0; i < al_size_4k; i++) { | ||
676 | int err = drbd_md_sync_page_io(mdev, mdev->ldev, al_base + i * 8, WRITE); | ||
677 | if (err) | ||
678 | return err; | ||
679 | } | ||
680 | return 0; | ||
681 | } | ||
682 | |||
662 | static int w_update_odbm(struct drbd_work *w, int unused) | 683 | static int w_update_odbm(struct drbd_work *w, int unused) |
663 | { | 684 | { |
664 | struct update_odbm_work *udw = container_of(w, struct update_odbm_work, w); | 685 | struct update_odbm_work *udw = container_of(w, struct update_odbm_work, w); |
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 4519d63350fb..2d7f608d181c 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h | |||
@@ -1133,6 +1133,7 @@ extern void drbd_mdev_cleanup(struct drbd_conf *mdev); | |||
1133 | void drbd_print_uuids(struct drbd_conf *mdev, const char *text); | 1133 | void drbd_print_uuids(struct drbd_conf *mdev, const char *text); |
1134 | 1134 | ||
1135 | extern void conn_md_sync(struct drbd_tconn *tconn); | 1135 | extern void conn_md_sync(struct drbd_tconn *tconn); |
1136 | extern void drbd_md_write(struct drbd_conf *mdev, void *buffer); | ||
1136 | extern void drbd_md_sync(struct drbd_conf *mdev); | 1137 | extern void drbd_md_sync(struct drbd_conf *mdev); |
1137 | extern int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev); | 1138 | extern int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev); |
1138 | extern void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local); | 1139 | extern void drbd_uuid_set(struct drbd_conf *mdev, int idx, u64 val) __must_hold(local); |
@@ -1468,12 +1469,15 @@ extern void drbd_resume_io(struct drbd_conf *mdev); | |||
1468 | extern char *ppsize(char *buf, unsigned long long size); | 1469 | extern char *ppsize(char *buf, unsigned long long size); |
1469 | extern sector_t drbd_new_dev_size(struct drbd_conf *, struct drbd_backing_dev *, sector_t, int); | 1470 | extern sector_t drbd_new_dev_size(struct drbd_conf *, struct drbd_backing_dev *, sector_t, int); |
1470 | enum determine_dev_size { | 1471 | enum determine_dev_size { |
1472 | DS_ERROR_SHRINK = -3, | ||
1473 | DS_ERROR_SPACE_MD = -2, | ||
1471 | DS_ERROR = -1, | 1474 | DS_ERROR = -1, |
1472 | DS_UNCHANGED = 0, | 1475 | DS_UNCHANGED = 0, |
1473 | DS_SHRUNK = 1, | 1476 | DS_SHRUNK = 1, |
1474 | DS_GREW = 2 | 1477 | DS_GREW = 2 |
1475 | }; | 1478 | }; |
1476 | extern enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *, enum dds_flags) __must_hold(local); | 1479 | extern enum determine_dev_size |
1480 | drbd_determine_dev_size(struct drbd_conf *, enum dds_flags, struct resize_parms *) __must_hold(local); | ||
1477 | extern void resync_after_online_grow(struct drbd_conf *); | 1481 | extern void resync_after_online_grow(struct drbd_conf *); |
1478 | extern void drbd_reconsider_max_bio_size(struct drbd_conf *mdev); | 1482 | extern void drbd_reconsider_max_bio_size(struct drbd_conf *mdev); |
1479 | extern enum drbd_state_rv drbd_set_role(struct drbd_conf *mdev, | 1483 | extern enum drbd_state_rv drbd_set_role(struct drbd_conf *mdev, |
@@ -1639,6 +1643,7 @@ extern int __drbd_set_out_of_sync(struct drbd_conf *mdev, sector_t sector, | |||
1639 | #define drbd_set_out_of_sync(mdev, sector, size) \ | 1643 | #define drbd_set_out_of_sync(mdev, sector, size) \ |
1640 | __drbd_set_out_of_sync(mdev, sector, size, __FILE__, __LINE__) | 1644 | __drbd_set_out_of_sync(mdev, sector, size, __FILE__, __LINE__) |
1641 | extern void drbd_al_shrink(struct drbd_conf *mdev); | 1645 | extern void drbd_al_shrink(struct drbd_conf *mdev); |
1646 | extern int drbd_initialize_al(struct drbd_conf *, void *); | ||
1642 | 1647 | ||
1643 | /* drbd_nl.c */ | 1648 | /* drbd_nl.c */ |
1644 | /* state info broadcast */ | 1649 | /* state info broadcast */ |
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 49040a336949..55635edf563b 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c | |||
@@ -2879,34 +2879,14 @@ struct meta_data_on_disk { | |||
2879 | u8 reserved_u8[4096 - (7*8 + 10*4)]; | 2879 | u8 reserved_u8[4096 - (7*8 + 10*4)]; |
2880 | } __packed; | 2880 | } __packed; |
2881 | 2881 | ||
2882 | /** | 2882 | |
2883 | * drbd_md_sync() - Writes the meta data super block if the MD_DIRTY flag bit is set | 2883 | |
2884 | * @mdev: DRBD device. | 2884 | void drbd_md_write(struct drbd_conf *mdev, void *b) |
2885 | */ | ||
2886 | void drbd_md_sync(struct drbd_conf *mdev) | ||
2887 | { | 2885 | { |
2888 | struct meta_data_on_disk *buffer; | 2886 | struct meta_data_on_disk *buffer = b; |
2889 | sector_t sector; | 2887 | sector_t sector; |
2890 | int i; | 2888 | int i; |
2891 | 2889 | ||
2892 | /* Don't accidentally change the DRBD meta data layout. */ | ||
2893 | BUILD_BUG_ON(UI_SIZE != 4); | ||
2894 | BUILD_BUG_ON(sizeof(struct meta_data_on_disk) != 4096); | ||
2895 | |||
2896 | del_timer(&mdev->md_sync_timer); | ||
2897 | /* timer may be rearmed by drbd_md_mark_dirty() now. */ | ||
2898 | if (!test_and_clear_bit(MD_DIRTY, &mdev->flags)) | ||
2899 | return; | ||
2900 | |||
2901 | /* We use here D_FAILED and not D_ATTACHING because we try to write | ||
2902 | * metadata even if we detach due to a disk failure! */ | ||
2903 | if (!get_ldev_if_state(mdev, D_FAILED)) | ||
2904 | return; | ||
2905 | |||
2906 | buffer = drbd_md_get_buffer(mdev); | ||
2907 | if (!buffer) | ||
2908 | goto out; | ||
2909 | |||
2910 | memset(buffer, 0, sizeof(*buffer)); | 2890 | memset(buffer, 0, sizeof(*buffer)); |
2911 | 2891 | ||
2912 | buffer->la_size_sect = cpu_to_be64(drbd_get_capacity(mdev->this_bdev)); | 2892 | buffer->la_size_sect = cpu_to_be64(drbd_get_capacity(mdev->this_bdev)); |
@@ -2935,6 +2915,35 @@ void drbd_md_sync(struct drbd_conf *mdev) | |||
2935 | dev_err(DEV, "meta data update failed!\n"); | 2915 | dev_err(DEV, "meta data update failed!\n"); |
2936 | drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR); | 2916 | drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR); |
2937 | } | 2917 | } |
2918 | } | ||
2919 | |||
2920 | /** | ||
2921 | * drbd_md_sync() - Writes the meta data super block if the MD_DIRTY flag bit is set | ||
2922 | * @mdev: DRBD device. | ||
2923 | */ | ||
2924 | void drbd_md_sync(struct drbd_conf *mdev) | ||
2925 | { | ||
2926 | struct meta_data_on_disk *buffer; | ||
2927 | |||
2928 | /* Don't accidentally change the DRBD meta data layout. */ | ||
2929 | BUILD_BUG_ON(UI_SIZE != 4); | ||
2930 | BUILD_BUG_ON(sizeof(struct meta_data_on_disk) != 4096); | ||
2931 | |||
2932 | del_timer(&mdev->md_sync_timer); | ||
2933 | /* timer may be rearmed by drbd_md_mark_dirty() now. */ | ||
2934 | if (!test_and_clear_bit(MD_DIRTY, &mdev->flags)) | ||
2935 | return; | ||
2936 | |||
2937 | /* We use here D_FAILED and not D_ATTACHING because we try to write | ||
2938 | * metadata even if we detach due to a disk failure! */ | ||
2939 | if (!get_ldev_if_state(mdev, D_FAILED)) | ||
2940 | return; | ||
2941 | |||
2942 | buffer = drbd_md_get_buffer(mdev); | ||
2943 | if (!buffer) | ||
2944 | goto out; | ||
2945 | |||
2946 | drbd_md_write(mdev, buffer); | ||
2938 | 2947 | ||
2939 | /* Update mdev->ldev->md.la_size_sect, | 2948 | /* Update mdev->ldev->md.la_size_sect, |
2940 | * since we updated it on metadata. */ | 2949 | * since we updated it on metadata. */ |
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) { |
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 26852b87b034..cc29cd3bf78b 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c | |||
@@ -3617,7 +3617,7 @@ static int receive_sizes(struct drbd_tconn *tconn, struct packet_info *pi) | |||
3617 | 3617 | ||
3618 | ddsf = be16_to_cpu(p->dds_flags); | 3618 | ddsf = be16_to_cpu(p->dds_flags); |
3619 | if (get_ldev(mdev)) { | 3619 | if (get_ldev(mdev)) { |
3620 | dd = drbd_determine_dev_size(mdev, ddsf); | 3620 | dd = drbd_determine_dev_size(mdev, ddsf, NULL); |
3621 | put_ldev(mdev); | 3621 | put_ldev(mdev); |
3622 | if (dd == DS_ERROR) | 3622 | if (dd == DS_ERROR) |
3623 | return -EIO; | 3623 | return -EIO; |