aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp Reisner <philipp.reisner@linbit.com>2010-05-31 04:14:17 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2010-10-14 08:52:53 -0400
commit265be2d09853d425ad14a61cda0ca63345613d0c (patch)
treecc2f419d8aaa41fd088f3d24ca134c4d7f51aa64
parent905cd7d8ac9b18e1f122b90dbebe1246b1c364fd (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.h1
-rw-r--r--drivers/block/drbd/drbd_main.c26
-rw-r--r--drivers/block/drbd/drbd_nl.c13
-rw-r--r--drivers/block/drbd/drbd_req.c24
-rw-r--r--drivers/block/drbd/drbd_req.h2
-rw-r--r--drivers/block/drbd/drbd_worker.c18
-rw-r--r--include/linux/drbd.h5
-rw-r--r--include/linux/drbd_limits.h1
-rw-r--r--include/linux/drbd_nl.h1
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);
1469extern int w_send_read_req(struct drbd_conf *, struct drbd_work *, int); 1469extern int w_send_read_req(struct drbd_conf *, struct drbd_work *, int);
1470extern int w_prev_work_done(struct drbd_conf *, struct drbd_work *, int); 1470extern int w_prev_work_done(struct drbd_conf *, struct drbd_work *, int);
1471extern int w_e_reissue(struct drbd_conf *, struct drbd_work *, int); 1471extern int w_e_reissue(struct drbd_conf *, struct drbd_work *, int);
1472extern int w_restart_disk_io(struct drbd_conf *, struct drbd_work *, int);
1472 1473
1473extern void resync_timer_fn(unsigned long data); 1474extern 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)
494void drbd_suspend_io(struct drbd_conf *mdev) 495void 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
1765static int drbd_nl_resume_io(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, 1769static 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
1176int 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
1176static int _drbd_may_sync_now(struct drbd_conf *mdev) 1194static 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
94enum 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. */
95enum drbd_ret_codes { 100enum 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
92NL_PACKET(invalidate, 9, ) 93NL_PACKET(invalidate, 9, )