diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2011-07-05 09:38:59 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-08 10:57:50 -0500 |
commit | cdfda633d235028e9b27381dedb65416409e8729 (patch) | |
tree | c2b07a9b0f1bfb2bb04dd118df15a53ff2592ade /drivers/block/drbd/drbd_bitmap.c | |
parent | 2fcb8f307f6014de9e771799d9ec0f050802c0ac (diff) |
drbd: detach from frozen backing device
* drbd-8.3:
documentation: Documented detach's --force and disk's --disk-timeout
drbd: Implemented the disk-timeout option
drbd: Force flag for the detach operation
drbd: Allow new IOs while the local disk in in FAILED state
drbd: Bitmap IO functions can not return prematurely if the disk breaks
drbd: Added a kref to bm_aio_ctx
drbd: Hold a reference to ldev while doing meta-data IO
drbd: Keep a reference to the bio until the completion handler finished
drbd: Implemented wait_until_done_or_disk_failure()
drbd: Replaced md_io_mutex by an atomic: md_io_in_use
drbd: moved md_io into mdev
drbd: Immediately allow completion of IOs, that wait for IO completions on a failed disk
drbd: Keep a reference to barrier acked requests
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd/drbd_bitmap.c')
-rw-r--r-- | drivers/block/drbd/drbd_bitmap.c | 115 |
1 files changed, 85 insertions, 30 deletions
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index 52c48143b22a..706e5220dd4a 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c | |||
@@ -918,13 +918,22 @@ void drbd_bm_clear_all(struct drbd_conf *mdev) | |||
918 | struct bm_aio_ctx { | 918 | struct bm_aio_ctx { |
919 | struct drbd_conf *mdev; | 919 | struct drbd_conf *mdev; |
920 | atomic_t in_flight; | 920 | atomic_t in_flight; |
921 | struct completion done; | 921 | unsigned int done; |
922 | unsigned flags; | 922 | unsigned flags; |
923 | #define BM_AIO_COPY_PAGES 1 | 923 | #define BM_AIO_COPY_PAGES 1 |
924 | #define BM_AIO_WRITE_HINTED 2 | 924 | #define BM_AIO_WRITE_HINTED 2 |
925 | int error; | 925 | int error; |
926 | struct kref kref; | ||
926 | }; | 927 | }; |
927 | 928 | ||
929 | static void bm_aio_ctx_destroy(struct kref *kref) | ||
930 | { | ||
931 | struct bm_aio_ctx *ctx = container_of(kref, struct bm_aio_ctx, kref); | ||
932 | |||
933 | put_ldev(ctx->mdev); | ||
934 | kfree(ctx); | ||
935 | } | ||
936 | |||
928 | /* bv_page may be a copy, or may be the original */ | 937 | /* bv_page may be a copy, or may be the original */ |
929 | static void bm_async_io_complete(struct bio *bio, int error) | 938 | static void bm_async_io_complete(struct bio *bio, int error) |
930 | { | 939 | { |
@@ -968,13 +977,16 @@ static void bm_async_io_complete(struct bio *bio, int error) | |||
968 | 977 | ||
969 | bio_put(bio); | 978 | bio_put(bio); |
970 | 979 | ||
971 | if (atomic_dec_and_test(&ctx->in_flight)) | 980 | if (atomic_dec_and_test(&ctx->in_flight)) { |
972 | complete(&ctx->done); | 981 | ctx->done = 1; |
982 | wake_up(&mdev->misc_wait); | ||
983 | kref_put(&ctx->kref, &bm_aio_ctx_destroy); | ||
984 | } | ||
973 | } | 985 | } |
974 | 986 | ||
975 | static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must_hold(local) | 987 | static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must_hold(local) |
976 | { | 988 | { |
977 | struct bio *bio = bio_alloc_drbd(GFP_KERNEL); | 989 | struct bio *bio = bio_alloc_drbd(GFP_NOIO); |
978 | struct drbd_conf *mdev = ctx->mdev; | 990 | struct drbd_conf *mdev = ctx->mdev; |
979 | struct drbd_bitmap *b = mdev->bitmap; | 991 | struct drbd_bitmap *b = mdev->bitmap; |
980 | struct page *page; | 992 | struct page *page; |
@@ -1032,12 +1044,7 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must | |||
1032 | */ | 1044 | */ |
1033 | static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_writeout_upper_idx) __must_hold(local) | 1045 | static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_writeout_upper_idx) __must_hold(local) |
1034 | { | 1046 | { |
1035 | struct bm_aio_ctx ctx = { | 1047 | struct bm_aio_ctx *ctx; |
1036 | .mdev = mdev, | ||
1037 | .in_flight = ATOMIC_INIT(1), | ||
1038 | .done = COMPLETION_INITIALIZER_ONSTACK(ctx.done), | ||
1039 | .flags = flags, | ||
1040 | }; | ||
1041 | struct drbd_bitmap *b = mdev->bitmap; | 1048 | struct drbd_bitmap *b = mdev->bitmap; |
1042 | int num_pages, i, count = 0; | 1049 | int num_pages, i, count = 0; |
1043 | unsigned long now; | 1050 | unsigned long now; |
@@ -1052,7 +1059,27 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w | |||
1052 | * For lazy writeout, we don't care for ongoing changes to the bitmap, | 1059 | * For lazy writeout, we don't care for ongoing changes to the bitmap, |
1053 | * as we submit copies of pages anyways. | 1060 | * as we submit copies of pages anyways. |
1054 | */ | 1061 | */ |
1055 | if (!ctx.flags) | 1062 | |
1063 | ctx = kmalloc(sizeof(struct bm_aio_ctx), GFP_NOIO); | ||
1064 | if (!ctx) | ||
1065 | return -ENOMEM; | ||
1066 | |||
1067 | *ctx = (struct bm_aio_ctx) { | ||
1068 | .mdev = mdev, | ||
1069 | .in_flight = ATOMIC_INIT(1), | ||
1070 | .done = 0, | ||
1071 | .flags = flags, | ||
1072 | .error = 0, | ||
1073 | .kref = { ATOMIC_INIT(2) }, | ||
1074 | }; | ||
1075 | |||
1076 | if (!get_ldev_if_state(mdev, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */ | ||
1077 | dev_err(DEV, "ASSERT FAILED: get_ldev_if_state() == 1 in bm_rw()\n"); | ||
1078 | err = -ENODEV; | ||
1079 | goto out; | ||
1080 | } | ||
1081 | |||
1082 | if (!ctx->flags) | ||
1056 | WARN_ON(!(BM_LOCKED_MASK & b->bm_flags)); | 1083 | WARN_ON(!(BM_LOCKED_MASK & b->bm_flags)); |
1057 | 1084 | ||
1058 | num_pages = b->bm_number_of_pages; | 1085 | num_pages = b->bm_number_of_pages; |
@@ -1081,32 +1108,40 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w | |||
1081 | continue; | 1108 | continue; |
1082 | } | 1109 | } |
1083 | } | 1110 | } |
1084 | atomic_inc(&ctx.in_flight); | 1111 | atomic_inc(&ctx->in_flight); |
1085 | bm_page_io_async(&ctx, i, rw); | 1112 | bm_page_io_async(ctx, i, rw); |
1086 | ++count; | 1113 | ++count; |
1087 | cond_resched(); | 1114 | cond_resched(); |
1088 | } | 1115 | } |
1089 | 1116 | ||
1090 | /* | 1117 | /* |
1091 | * We initialize ctx.in_flight to one to make sure bm_async_io_complete | 1118 | * We initialize ctx->in_flight to one to make sure bm_async_io_complete |
1092 | * will not complete() early, and decrement / test it here. If there | 1119 | * will not set ctx->done early, and decrement / test it here. If there |
1093 | * are still some bios in flight, we need to wait for them here. | 1120 | * are still some bios in flight, we need to wait for them here. |
1121 | * If all IO is done already (or nothing had been submitted), there is | ||
1122 | * no need to wait. Still, we need to put the kref associated with the | ||
1123 | * "in_flight reached zero, all done" event. | ||
1094 | */ | 1124 | */ |
1095 | if (!atomic_dec_and_test(&ctx.in_flight)) | 1125 | if (!atomic_dec_and_test(&ctx->in_flight)) |
1096 | wait_for_completion(&ctx.done); | 1126 | wait_until_done_or_disk_failure(mdev, &ctx->done); |
1127 | else | ||
1128 | kref_put(&ctx->kref, &bm_aio_ctx_destroy); | ||
1097 | 1129 | ||
1098 | /* summary for global bitmap IO */ | 1130 | /* summary for global bitmap IO */ |
1099 | if (flags == 0) | 1131 | if (flags == 0) |
1100 | dev_info(DEV, "bitmap %s of %u pages took %lu jiffies\n", | 1132 | dev_info(DEV, "bitmap %s of %u pages took %lu jiffies\n", |
1101 | rw == WRITE ? "WRITE" : "READ", | 1133 | rw == WRITE ? "WRITE" : "READ", |
1102 | count, jiffies - now); | 1134 | count, jiffies - now); |
1103 | 1135 | ||
1104 | if (ctx.error) { | 1136 | if (ctx->error) { |
1105 | dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n"); | 1137 | dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n"); |
1106 | drbd_chk_io_error(mdev, 1, true); | 1138 | drbd_chk_io_error(mdev, 1, true); |
1107 | err = -EIO; /* ctx.error ? */ | 1139 | err = -EIO; /* ctx->error ? */ |
1108 | } | 1140 | } |
1109 | 1141 | ||
1142 | if (atomic_read(&ctx->in_flight)) | ||
1143 | err = -EIO; /* Disk failed during IO... */ | ||
1144 | |||
1110 | now = jiffies; | 1145 | now = jiffies; |
1111 | if (rw == WRITE) { | 1146 | if (rw == WRITE) { |
1112 | drbd_md_flush(mdev); | 1147 | drbd_md_flush(mdev); |
@@ -1121,6 +1156,8 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w | |||
1121 | dev_info(DEV, "%s (%lu bits) marked out-of-sync by on disk bit-map.\n", | 1156 | dev_info(DEV, "%s (%lu bits) marked out-of-sync by on disk bit-map.\n", |
1122 | ppsize(ppb, now << (BM_BLOCK_SHIFT-10)), now); | 1157 | ppsize(ppb, now << (BM_BLOCK_SHIFT-10)), now); |
1123 | 1158 | ||
1159 | out: | ||
1160 | kref_put(&ctx->kref, &bm_aio_ctx_destroy); | ||
1124 | return err; | 1161 | return err; |
1125 | } | 1162 | } |
1126 | 1163 | ||
@@ -1177,28 +1214,46 @@ int drbd_bm_write_hinted(struct drbd_conf *mdev) __must_hold(local) | |||
1177 | */ | 1214 | */ |
1178 | int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local) | 1215 | int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(local) |
1179 | { | 1216 | { |
1180 | struct bm_aio_ctx ctx = { | 1217 | struct bm_aio_ctx *ctx; |
1218 | int err; | ||
1219 | |||
1220 | if (bm_test_page_unchanged(mdev->bitmap->bm_pages[idx])) { | ||
1221 | dynamic_dev_dbg(DEV, "skipped bm page write for idx %u\n", idx); | ||
1222 | return 0; | ||
1223 | } | ||
1224 | |||
1225 | ctx = kmalloc(sizeof(struct bm_aio_ctx), GFP_NOIO); | ||
1226 | if (!ctx) | ||
1227 | return -ENOMEM; | ||
1228 | |||
1229 | *ctx = (struct bm_aio_ctx) { | ||
1181 | .mdev = mdev, | 1230 | .mdev = mdev, |
1182 | .in_flight = ATOMIC_INIT(1), | 1231 | .in_flight = ATOMIC_INIT(1), |
1183 | .done = COMPLETION_INITIALIZER_ONSTACK(ctx.done), | 1232 | .done = 0, |
1184 | .flags = BM_AIO_COPY_PAGES, | 1233 | .flags = BM_AIO_COPY_PAGES, |
1234 | .error = 0, | ||
1235 | .kref = { ATOMIC_INIT(2) }, | ||
1185 | }; | 1236 | }; |
1186 | 1237 | ||
1187 | if (bm_test_page_unchanged(mdev->bitmap->bm_pages[idx])) { | 1238 | if (!get_ldev_if_state(mdev, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */ |
1188 | dynamic_dev_dbg(DEV, "skipped bm page write for idx %u\n", idx); | 1239 | dev_err(DEV, "ASSERT FAILED: get_ldev_if_state() == 1 in drbd_bm_write_page()\n"); |
1189 | return 0; | 1240 | err = -ENODEV; |
1241 | goto out; | ||
1190 | } | 1242 | } |
1191 | 1243 | ||
1192 | bm_page_io_async(&ctx, idx, WRITE_SYNC); | 1244 | bm_page_io_async(ctx, idx, WRITE_SYNC); |
1193 | wait_for_completion(&ctx.done); | 1245 | wait_until_done_or_disk_failure(mdev, &ctx->done); |
1194 | 1246 | ||
1195 | if (ctx.error) | 1247 | if (ctx->error) |
1196 | drbd_chk_io_error(mdev, 1, true); | 1248 | drbd_chk_io_error(mdev, 1, true); |
1197 | /* that should force detach, so the in memory bitmap will be | 1249 | /* that should force detach, so the in memory bitmap will be |
1198 | * gone in a moment as well. */ | 1250 | * gone in a moment as well. */ |
1199 | 1251 | ||
1200 | mdev->bm_writ_cnt++; | 1252 | mdev->bm_writ_cnt++; |
1201 | return ctx.error; | 1253 | err = atomic_read(&ctx->in_flight) ? -EIO : ctx->error; |
1254 | out: | ||
1255 | kref_put(&ctx->kref, &bm_aio_ctx_destroy); | ||
1256 | return err; | ||
1202 | } | 1257 | } |
1203 | 1258 | ||
1204 | /* NOTE | 1259 | /* NOTE |