diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2011-06-27 09:29:16 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-05-09 09:10:33 -0400 |
commit | 9e58c4dad70bfba86f016bcc98fa19f468d0b777 (patch) | |
tree | c67117886829bfe77699498940c434a560fc4b64 /drivers/block/drbd/drbd_bitmap.c | |
parent | d1f3779bbeae70b9552c9ac70d6ec8c4d3545615 (diff) |
drbd: Bitmap IO functions can now return prematurely if the disk breaks
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 | 40 |
1 files changed, 30 insertions, 10 deletions
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index a2c337b38d6e..e5e756dbc434 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c | |||
@@ -886,7 +886,7 @@ void drbd_bm_clear_all(struct drbd_conf *mdev) | |||
886 | struct bm_aio_ctx { | 886 | struct bm_aio_ctx { |
887 | struct drbd_conf *mdev; | 887 | struct drbd_conf *mdev; |
888 | atomic_t in_flight; | 888 | atomic_t in_flight; |
889 | struct completion done; | 889 | unsigned int done; |
890 | unsigned flags; | 890 | unsigned flags; |
891 | #define BM_AIO_COPY_PAGES 1 | 891 | #define BM_AIO_COPY_PAGES 1 |
892 | int error; | 892 | int error; |
@@ -897,6 +897,7 @@ static void bm_aio_ctx_destroy(struct kref *kref) | |||
897 | { | 897 | { |
898 | struct bm_aio_ctx *ctx = container_of(kref, struct bm_aio_ctx, kref); | 898 | struct bm_aio_ctx *ctx = container_of(kref, struct bm_aio_ctx, kref); |
899 | 899 | ||
900 | put_ldev(ctx->mdev); | ||
900 | kfree(ctx); | 901 | kfree(ctx); |
901 | } | 902 | } |
902 | 903 | ||
@@ -945,7 +946,8 @@ static void bm_async_io_complete(struct bio *bio, int error) | |||
945 | bio_put(bio); | 946 | bio_put(bio); |
946 | 947 | ||
947 | if (atomic_dec_and_test(&ctx->in_flight)) { | 948 | if (atomic_dec_and_test(&ctx->in_flight)) { |
948 | complete(&ctx->done); | 949 | ctx->done = 1; |
950 | wake_up(&mdev->misc_wait); | ||
949 | kref_put(&ctx->kref, &bm_aio_ctx_destroy); | 951 | kref_put(&ctx->kref, &bm_aio_ctx_destroy); |
950 | } | 952 | } |
951 | } | 953 | } |
@@ -1034,12 +1036,18 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_id | |||
1034 | *ctx = (struct bm_aio_ctx) { | 1036 | *ctx = (struct bm_aio_ctx) { |
1035 | .mdev = mdev, | 1037 | .mdev = mdev, |
1036 | .in_flight = ATOMIC_INIT(1), | 1038 | .in_flight = ATOMIC_INIT(1), |
1037 | .done = COMPLETION_INITIALIZER(ctx->done), | 1039 | .done = 0, |
1038 | .flags = lazy_writeout_upper_idx ? BM_AIO_COPY_PAGES : 0, | 1040 | .flags = lazy_writeout_upper_idx ? BM_AIO_COPY_PAGES : 0, |
1039 | .error = 0, | 1041 | .error = 0, |
1040 | .kref = { ATOMIC_INIT(2) }, | 1042 | .kref = { ATOMIC_INIT(2) }, |
1041 | }; | 1043 | }; |
1042 | 1044 | ||
1045 | if (!get_ldev_if_state(mdev, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */ | ||
1046 | dev_err(DEV, "ASSERT FAILED: get_ldev_if_state() == 1 in bm_rw()\n"); | ||
1047 | kfree(ctx); | ||
1048 | return -ENODEV; | ||
1049 | } | ||
1050 | |||
1043 | if (!ctx->flags) | 1051 | if (!ctx->flags) |
1044 | WARN_ON(!(BM_LOCKED_MASK & b->bm_flags)); | 1052 | WARN_ON(!(BM_LOCKED_MASK & b->bm_flags)); |
1045 | 1053 | ||
@@ -1073,11 +1081,16 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_id | |||
1073 | 1081 | ||
1074 | /* | 1082 | /* |
1075 | * We initialize ctx->in_flight to one to make sure bm_async_io_complete | 1083 | * We initialize ctx->in_flight to one to make sure bm_async_io_complete |
1076 | * will not complete() early, and decrement / test it here. If there | 1084 | * will not set ctx->done early, and decrement / test it here. If there |
1077 | * are still some bios in flight, we need to wait for them here. | 1085 | * are still some bios in flight, we need to wait for them here. |
1086 | * If all IO is done already (or nothing had been submitted), there is | ||
1087 | * no need to wait. Still, we need to put the kref associated with the | ||
1088 | * "in_flight reached zero, all done" event. | ||
1078 | */ | 1089 | */ |
1079 | if (!atomic_dec_and_test(&ctx->in_flight)) | 1090 | if (!atomic_dec_and_test(&ctx->in_flight)) |
1080 | wait_for_completion(&ctx->done); | 1091 | wait_until_done_or_disk_failure(mdev, &ctx->done); |
1092 | else | ||
1093 | kref_put(&ctx->kref, &bm_aio_ctx_destroy); | ||
1081 | 1094 | ||
1082 | dev_info(DEV, "bitmap %s of %u pages took %lu jiffies\n", | 1095 | dev_info(DEV, "bitmap %s of %u pages took %lu jiffies\n", |
1083 | rw == WRITE ? "WRITE" : "READ", | 1096 | rw == WRITE ? "WRITE" : "READ", |
@@ -1089,6 +1102,9 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_id | |||
1089 | err = -EIO; /* ctx->error ? */ | 1102 | err = -EIO; /* ctx->error ? */ |
1090 | } | 1103 | } |
1091 | 1104 | ||
1105 | if (atomic_read(&ctx->in_flight)) | ||
1106 | err = -EIO; /* Disk failed during IO... */ | ||
1107 | |||
1092 | now = jiffies; | 1108 | now = jiffies; |
1093 | if (rw == WRITE) { | 1109 | if (rw == WRITE) { |
1094 | drbd_md_flush(mdev); | 1110 | drbd_md_flush(mdev); |
@@ -1103,7 +1119,6 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned lazy_writeout_upper_id | |||
1103 | ppsize(ppb, now << (BM_BLOCK_SHIFT-10)), now); | 1119 | ppsize(ppb, now << (BM_BLOCK_SHIFT-10)), now); |
1104 | 1120 | ||
1105 | kref_put(&ctx->kref, &bm_aio_ctx_destroy); | 1121 | kref_put(&ctx->kref, &bm_aio_ctx_destroy); |
1106 | |||
1107 | return err; | 1122 | return err; |
1108 | } | 1123 | } |
1109 | 1124 | ||
@@ -1167,14 +1182,20 @@ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(loc | |||
1167 | *ctx = (struct bm_aio_ctx) { | 1182 | *ctx = (struct bm_aio_ctx) { |
1168 | .mdev = mdev, | 1183 | .mdev = mdev, |
1169 | .in_flight = ATOMIC_INIT(1), | 1184 | .in_flight = ATOMIC_INIT(1), |
1170 | .done = COMPLETION_INITIALIZER(ctx->done), | 1185 | .done = 0, |
1171 | .flags = BM_AIO_COPY_PAGES, | 1186 | .flags = BM_AIO_COPY_PAGES, |
1172 | .error = 0, | 1187 | .error = 0, |
1173 | .kref = { ATOMIC_INIT(2) }, | 1188 | .kref = { ATOMIC_INIT(2) }, |
1174 | }; | 1189 | }; |
1175 | 1190 | ||
1191 | if (!get_ldev_if_state(mdev, D_ATTACHING)) { /* put is in bm_aio_ctx_destroy() */ | ||
1192 | dev_err(DEV, "ASSERT FAILED: get_ldev_if_state() == 1 in drbd_bm_write_page()\n"); | ||
1193 | kfree(ctx); | ||
1194 | return -ENODEV; | ||
1195 | } | ||
1196 | |||
1176 | bm_page_io_async(ctx, idx, WRITE_SYNC); | 1197 | bm_page_io_async(ctx, idx, WRITE_SYNC); |
1177 | wait_for_completion(&ctx->done); | 1198 | wait_until_done_or_disk_failure(mdev, &ctx->done); |
1178 | 1199 | ||
1179 | if (ctx->error) | 1200 | if (ctx->error) |
1180 | drbd_chk_io_error(mdev, 1, true); | 1201 | drbd_chk_io_error(mdev, 1, true); |
@@ -1182,9 +1203,8 @@ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(loc | |||
1182 | * gone in a moment as well. */ | 1203 | * gone in a moment as well. */ |
1183 | 1204 | ||
1184 | mdev->bm_writ_cnt++; | 1205 | mdev->bm_writ_cnt++; |
1185 | err = ctx->error; | 1206 | err = atomic_read(&ctx->in_flight) ? -EIO : ctx->error; |
1186 | kref_put(&ctx->kref, &bm_aio_ctx_destroy); | 1207 | kref_put(&ctx->kref, &bm_aio_ctx_destroy); |
1187 | |||
1188 | return err; | 1208 | return err; |
1189 | } | 1209 | } |
1190 | 1210 | ||