diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2010-05-31 04:14:17 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2010-10-14 08:52:53 -0400 |
commit | 265be2d09853d425ad14a61cda0ca63345613d0c (patch) | |
tree | cc2f419d8aaa41fd088f3d24ca134c4d7f51aa64 | |
parent | 905cd7d8ac9b18e1f122b90dbebe1246b1c364fd (diff) |
drbd: Finished the "on-no-data-accessible suspend-io;" functionality
When no data is accessible (no connection to the peer, nor a local disk)
allow the user to select to freeze all IO operations instead of getting
IO errors.
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.h | 1 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 26 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 13 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_req.c | 24 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_req.h | 2 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_worker.c | 18 | ||||
-rw-r--r-- | include/linux/drbd.h | 5 | ||||
-rw-r--r-- | include/linux/drbd_limits.h | 1 | ||||
-rw-r--r-- | include/linux/drbd_nl.h | 1 |
9 files changed, 90 insertions, 1 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index bef9138f1975..03cc975b9e6c 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h | |||
@@ -1469,6 +1469,7 @@ extern int w_send_barrier(struct drbd_conf *, struct drbd_work *, int); | |||
1469 | extern int w_send_read_req(struct drbd_conf *, struct drbd_work *, int); | 1469 | extern int w_send_read_req(struct drbd_conf *, struct drbd_work *, int); |
1470 | extern int w_prev_work_done(struct drbd_conf *, struct drbd_work *, int); | 1470 | extern int w_prev_work_done(struct drbd_conf *, struct drbd_work *, int); |
1471 | extern int w_e_reissue(struct drbd_conf *, struct drbd_work *, int); | 1471 | extern int w_e_reissue(struct drbd_conf *, struct drbd_work *, int); |
1472 | extern int w_restart_disk_io(struct drbd_conf *, struct drbd_work *, int); | ||
1472 | 1473 | ||
1473 | extern void resync_timer_fn(unsigned long data); | 1474 | extern void resync_timer_fn(unsigned long data); |
1474 | 1475 | ||
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 7d359863ae32..106b9abdc430 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c | |||
@@ -925,7 +925,12 @@ static union drbd_state sanitize_state(struct drbd_conf *mdev, union drbd_state | |||
925 | if (fp == FP_STONITH && | 925 | if (fp == FP_STONITH && |
926 | (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED) && | 926 | (ns.role == R_PRIMARY && ns.conn < C_CONNECTED && ns.pdsk > D_OUTDATED) && |
927 | !(os.role == R_PRIMARY && os.conn < C_CONNECTED && os.pdsk > D_OUTDATED)) | 927 | !(os.role == R_PRIMARY && os.conn < C_CONNECTED && os.pdsk > D_OUTDATED)) |
928 | ns.susp = 1; | 928 | ns.susp = 1; /* Suspend IO while fence-peer handler runs (peer lost) */ |
929 | |||
930 | if (mdev->sync_conf.on_no_data == OND_SUSPEND_IO && | ||
931 | (ns.role == R_PRIMARY && ns.disk < D_UP_TO_DATE && ns.pdsk < D_UP_TO_DATE) && | ||
932 | !(os.role == R_PRIMARY && os.disk < D_UP_TO_DATE && os.pdsk < D_UP_TO_DATE)) | ||
933 | ns.susp = 1; /* Suspend IO while no data available (no accessible data available) */ | ||
929 | 934 | ||
930 | if (ns.aftr_isp || ns.peer_isp || ns.user_isp) { | 935 | if (ns.aftr_isp || ns.peer_isp || ns.user_isp) { |
931 | if (ns.conn == C_SYNC_SOURCE) | 936 | if (ns.conn == C_SYNC_SOURCE) |
@@ -1236,6 +1241,25 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os, | |||
1236 | /* Here we have the actions that are performed after a | 1241 | /* Here we have the actions that are performed after a |
1237 | state change. This function might sleep */ | 1242 | state change. This function might sleep */ |
1238 | 1243 | ||
1244 | if (os.susp && ns.susp && mdev->sync_conf.on_no_data == OND_SUSPEND_IO) { | ||
1245 | if (os.conn < C_CONNECTED && ns.conn >= C_CONNECTED) { | ||
1246 | if (ns.conn == C_CONNECTED) { | ||
1247 | spin_lock_irq(&mdev->req_lock); | ||
1248 | _tl_restart(mdev, resend); | ||
1249 | _drbd_set_state(_NS(mdev, susp, 0), CS_VERBOSE, NULL); | ||
1250 | spin_unlock_irq(&mdev->req_lock); | ||
1251 | } else /* ns.conn > C_CONNECTED */ | ||
1252 | dev_err(DEV, "Unexpected Resynd going on!\n"); | ||
1253 | } | ||
1254 | |||
1255 | if (os.disk == D_ATTACHING && ns.disk > D_ATTACHING) { | ||
1256 | spin_lock_irq(&mdev->req_lock); | ||
1257 | _tl_restart(mdev, restart_frozen_disk_io); | ||
1258 | _drbd_set_state(_NS(mdev, susp, 0), CS_VERBOSE, NULL); | ||
1259 | spin_unlock_irq(&mdev->req_lock); | ||
1260 | } | ||
1261 | } | ||
1262 | |||
1239 | if (fp == FP_STONITH && ns.susp) { | 1263 | if (fp == FP_STONITH && ns.susp) { |
1240 | /* case1: The outdate peer handler is successful: | 1264 | /* case1: The outdate peer handler is successful: |
1241 | * case2: The connection was established again: */ | 1265 | * case2: The connection was established again: */ |
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 73131c5ae339..563a6ade0179 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/blkpg.h> | 33 | #include <linux/blkpg.h> |
34 | #include <linux/cpumask.h> | 34 | #include <linux/cpumask.h> |
35 | #include "drbd_int.h" | 35 | #include "drbd_int.h" |
36 | #include "drbd_req.h" | ||
36 | #include "drbd_wrappers.h" | 37 | #include "drbd_wrappers.h" |
37 | #include <asm/unaligned.h> | 38 | #include <asm/unaligned.h> |
38 | #include <linux/drbd_tag_magic.h> | 39 | #include <linux/drbd_tag_magic.h> |
@@ -494,6 +495,8 @@ char *ppsize(char *buf, unsigned long long size) | |||
494 | void drbd_suspend_io(struct drbd_conf *mdev) | 495 | void drbd_suspend_io(struct drbd_conf *mdev) |
495 | { | 496 | { |
496 | set_bit(SUSPEND_IO, &mdev->flags); | 497 | set_bit(SUSPEND_IO, &mdev->flags); |
498 | if (mdev->state.susp) | ||
499 | return; | ||
497 | wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt)); | 500 | wait_event(mdev->misc_wait, !atomic_read(&mdev->ap_bio_cnt)); |
498 | } | 501 | } |
499 | 502 | ||
@@ -1557,6 +1560,7 @@ static int drbd_nl_syncer_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *n | |||
1557 | sc.rate = DRBD_RATE_DEF; | 1560 | sc.rate = DRBD_RATE_DEF; |
1558 | sc.after = DRBD_AFTER_DEF; | 1561 | sc.after = DRBD_AFTER_DEF; |
1559 | sc.al_extents = DRBD_AL_EXTENTS_DEF; | 1562 | sc.al_extents = DRBD_AL_EXTENTS_DEF; |
1563 | sc.on_no_data = DRBD_ON_NO_DATA_DEF; | ||
1560 | } else | 1564 | } else |
1561 | memcpy(&sc, &mdev->sync_conf, sizeof(struct syncer_conf)); | 1565 | memcpy(&sc, &mdev->sync_conf, sizeof(struct syncer_conf)); |
1562 | 1566 | ||
@@ -1765,7 +1769,16 @@ static int drbd_nl_suspend_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl | |||
1765 | static int drbd_nl_resume_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, | 1769 | static int drbd_nl_resume_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, |
1766 | struct drbd_nl_cfg_reply *reply) | 1770 | struct drbd_nl_cfg_reply *reply) |
1767 | { | 1771 | { |
1772 | drbd_suspend_io(mdev); | ||
1768 | reply->ret_code = drbd_request_state(mdev, NS(susp, 0)); | 1773 | reply->ret_code = drbd_request_state(mdev, NS(susp, 0)); |
1774 | if (reply->ret_code == SS_SUCCESS) { | ||
1775 | if (mdev->state.conn < C_CONNECTED) | ||
1776 | tl_clear(mdev); | ||
1777 | if (mdev->state.disk == D_DISKLESS || mdev->state.disk == D_FAILED) | ||
1778 | tl_restart(mdev, fail_frozen_disk_io); | ||
1779 | } | ||
1780 | drbd_resume_io(mdev); | ||
1781 | |||
1769 | return 0; | 1782 | return 0; |
1770 | } | 1783 | } |
1771 | 1784 | ||
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 48647589aa0d..8259d4f77285 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c | |||
@@ -226,6 +226,8 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m) | |||
226 | return; | 226 | return; |
227 | if (s & RQ_LOCAL_PENDING) | 227 | if (s & RQ_LOCAL_PENDING) |
228 | return; | 228 | return; |
229 | if (mdev->state.susp) | ||
230 | return; | ||
229 | 231 | ||
230 | if (req->master_bio) { | 232 | if (req->master_bio) { |
231 | /* this is data_received (remote read) | 233 | /* this is data_received (remote read) |
@@ -634,6 +636,28 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what, | |||
634 | /* else: done by handed_over_to_network */ | 636 | /* else: done by handed_over_to_network */ |
635 | break; | 637 | break; |
636 | 638 | ||
639 | case fail_frozen_disk_io: | ||
640 | if (!(req->rq_state & RQ_LOCAL_COMPLETED)) | ||
641 | break; | ||
642 | |||
643 | _req_may_be_done(req, m); | ||
644 | break; | ||
645 | |||
646 | case restart_frozen_disk_io: | ||
647 | if (!(req->rq_state & RQ_LOCAL_COMPLETED)) | ||
648 | break; | ||
649 | |||
650 | req->rq_state &= ~RQ_LOCAL_COMPLETED; | ||
651 | |||
652 | rv = MR_READ; | ||
653 | if (bio_data_dir(req->master_bio) == WRITE) | ||
654 | rv = MR_WRITE; | ||
655 | |||
656 | get_ldev(mdev); | ||
657 | req->w.cb = w_restart_disk_io; | ||
658 | drbd_queue_work(&mdev->data.work, &req->w); | ||
659 | break; | ||
660 | |||
637 | case resend: | 661 | case resend: |
638 | /* If RQ_NET_OK is already set, we got a P_WRITE_ACK or P_RECV_ACK | 662 | /* If RQ_NET_OK is already set, we got a P_WRITE_ACK or P_RECV_ACK |
639 | before the connection loss; only P_BARRIER_ACK was missing. | 663 | before the connection loss; only P_BARRIER_ACK was missing. |
diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 07cb3b12edb4..f2e45aaa2cd5 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h | |||
@@ -105,6 +105,8 @@ enum drbd_req_event { | |||
105 | write_completed_with_error, | 105 | write_completed_with_error, |
106 | completed_ok, | 106 | completed_ok, |
107 | resend, | 107 | resend, |
108 | fail_frozen_disk_io, | ||
109 | restart_frozen_disk_io, | ||
108 | nothing, /* for tracing only */ | 110 | nothing, /* for tracing only */ |
109 | }; | 111 | }; |
110 | 112 | ||
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index ca4a16cea2d8..3c1e88480d37 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c | |||
@@ -1173,6 +1173,24 @@ int w_send_read_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) | |||
1173 | return ok; | 1173 | return ok; |
1174 | } | 1174 | } |
1175 | 1175 | ||
1176 | int w_restart_disk_io(struct drbd_conf *mdev, struct drbd_work *w, int cancel) | ||
1177 | { | ||
1178 | struct drbd_request *req = container_of(w, struct drbd_request, w); | ||
1179 | |||
1180 | if (bio_data_dir(req->master_bio) == WRITE) | ||
1181 | drbd_al_begin_io(mdev, req->sector); | ||
1182 | /* Calling drbd_al_begin_io() out of the worker might deadlocks | ||
1183 | theoretically. Practically it can not deadlock, since this is | ||
1184 | only used when unfreezing IOs. All the extents of the requests | ||
1185 | that made it into the TL are already active */ | ||
1186 | |||
1187 | drbd_req_make_private_bio(req, req->master_bio); | ||
1188 | req->private_bio->bi_bdev = mdev->ldev->backing_bdev; | ||
1189 | generic_make_request(req->private_bio); | ||
1190 | |||
1191 | return 1; | ||
1192 | } | ||
1193 | |||
1176 | static int _drbd_may_sync_now(struct drbd_conf *mdev) | 1194 | static int _drbd_may_sync_now(struct drbd_conf *mdev) |
1177 | { | 1195 | { |
1178 | struct drbd_conf *odev = mdev; | 1196 | struct drbd_conf *odev = mdev; |
diff --git a/include/linux/drbd.h b/include/linux/drbd.h index 479ee3a1d901..7be069fcca57 100644 --- a/include/linux/drbd.h +++ b/include/linux/drbd.h | |||
@@ -91,6 +91,11 @@ enum drbd_after_sb_p { | |||
91 | ASB_VIOLENTLY | 91 | ASB_VIOLENTLY |
92 | }; | 92 | }; |
93 | 93 | ||
94 | enum drbd_on_no_data { | ||
95 | OND_IO_ERROR, | ||
96 | OND_SUSPEND_IO | ||
97 | }; | ||
98 | |||
94 | /* KEEP the order, do not delete or insert. Only append. */ | 99 | /* KEEP the order, do not delete or insert. Only append. */ |
95 | enum drbd_ret_codes { | 100 | enum drbd_ret_codes { |
96 | ERR_CODE_BASE = 100, | 101 | ERR_CODE_BASE = 100, |
diff --git a/include/linux/drbd_limits.h b/include/linux/drbd_limits.h index 440b42e38e89..7eb1e98009ec 100644 --- a/include/linux/drbd_limits.h +++ b/include/linux/drbd_limits.h | |||
@@ -128,6 +128,7 @@ | |||
128 | #define DRBD_AFTER_SB_1P_DEF ASB_DISCONNECT | 128 | #define DRBD_AFTER_SB_1P_DEF ASB_DISCONNECT |
129 | #define DRBD_AFTER_SB_2P_DEF ASB_DISCONNECT | 129 | #define DRBD_AFTER_SB_2P_DEF ASB_DISCONNECT |
130 | #define DRBD_RR_CONFLICT_DEF ASB_DISCONNECT | 130 | #define DRBD_RR_CONFLICT_DEF ASB_DISCONNECT |
131 | #define DRBD_ON_NO_DATA_DEF OND_IO_ERROR | ||
131 | 132 | ||
132 | #define DRBD_MAX_BIO_BVECS_MIN 0 | 133 | #define DRBD_MAX_BIO_BVECS_MIN 0 |
133 | #define DRBD_MAX_BIO_BVECS_MAX 128 | 134 | #define DRBD_MAX_BIO_BVECS_MAX 128 |
diff --git a/include/linux/drbd_nl.h b/include/linux/drbd_nl.h index 5f042810a56c..9aebd0d80a5d 100644 --- a/include/linux/drbd_nl.h +++ b/include/linux/drbd_nl.h | |||
@@ -87,6 +87,7 @@ NL_PACKET(syncer_conf, 8, | |||
87 | NL_STRING( 51, T_MAY_IGNORE, cpu_mask, 32) | 87 | NL_STRING( 51, T_MAY_IGNORE, cpu_mask, 32) |
88 | NL_STRING( 64, T_MAY_IGNORE, csums_alg, SHARED_SECRET_MAX) | 88 | NL_STRING( 64, T_MAY_IGNORE, csums_alg, SHARED_SECRET_MAX) |
89 | NL_BIT( 65, T_MAY_IGNORE, use_rle) | 89 | NL_BIT( 65, T_MAY_IGNORE, use_rle) |
90 | NL_INTEGER( 75, T_MAY_IGNORE, on_no_data) | ||
90 | ) | 91 | ) |
91 | 92 | ||
92 | NL_PACKET(invalidate, 9, ) | 93 | NL_PACKET(invalidate, 9, ) |