aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2012-06-14 08:21:32 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-07-24 08:06:18 -0400
commit383606e0dea6a380097dbcb0c319b09ca372f36b (patch)
tree170c3c95c12bd0a3e6cca0b7d13a4c4cc91f040e /drivers/block
parentd264580145a0aee2f5113c37b178a55b6e1b0b32 (diff)
drbd: differentiate between normal and forced detach
Aborting local requests (not waiting for completion from the lower level disk) is dangerous: if the master bio has been completed to upper layers, data pages may be re-used for other things already. If local IO is still pending and later completes, this may cause crashes or corrupt unrelated data. Only abort local IO if explicitly requested. Intended use case is a lower level device that turned into a tarpit, not completing io requests, not even doing error completion. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/drbd/drbd_actlog.c2
-rw-r--r--drivers/block/drbd/drbd_bitmap.c4
-rw-r--r--drivers/block/drbd/drbd_int.h17
-rw-r--r--drivers/block/drbd/drbd_main.c20
-rw-r--r--drivers/block/drbd/drbd_nl.c4
-rw-r--r--drivers/block/drbd/drbd_req.c6
-rw-r--r--drivers/block/drbd/drbd_worker.c4
7 files changed, 42 insertions, 15 deletions
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c
index e54e31b02b88..6ace11e9e5a1 100644
--- a/drivers/block/drbd/drbd_actlog.c
+++ b/drivers/block/drbd/drbd_actlog.c
@@ -411,7 +411,7 @@ w_al_write_transaction(struct drbd_conf *mdev, struct drbd_work *w, int unused)
411 + mdev->ldev->md.al_offset + mdev->al_tr_pos; 411 + mdev->ldev->md.al_offset + mdev->al_tr_pos;
412 412
413 if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) 413 if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE))
414 drbd_chk_io_error(mdev, 1, true); 414 drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
415 415
416 if (++mdev->al_tr_pos > 416 if (++mdev->al_tr_pos >
417 div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT)) 417 div_ceil(mdev->act_log->nr_elements, AL_EXTENTS_PT))
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c
index fcb956bb4b4c..ba91b408abad 100644
--- a/drivers/block/drbd/drbd_bitmap.c
+++ b/drivers/block/drbd/drbd_bitmap.c
@@ -1096,7 +1096,7 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w
1096 1096
1097 if (ctx->error) { 1097 if (ctx->error) {
1098 dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n"); 1098 dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n");
1099 drbd_chk_io_error(mdev, 1, true); 1099 drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
1100 err = -EIO; /* ctx->error ? */ 1100 err = -EIO; /* ctx->error ? */
1101 } 1101 }
1102 1102
@@ -1212,7 +1212,7 @@ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(loc
1212 wait_until_done_or_disk_failure(mdev, mdev->ldev, &ctx->done); 1212 wait_until_done_or_disk_failure(mdev, mdev->ldev, &ctx->done);
1213 1213
1214 if (ctx->error) 1214 if (ctx->error)
1215 drbd_chk_io_error(mdev, 1, true); 1215 drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
1216 /* that should force detach, so the in memory bitmap will be 1216 /* that should force detach, so the in memory bitmap will be
1217 * gone in a moment as well. */ 1217 * gone in a moment as well. */
1218 1218
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index 356a6e5b4415..79c69ebb0653 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -832,6 +832,7 @@ enum {
832 BITMAP_IO_QUEUED, /* Started bitmap IO */ 832 BITMAP_IO_QUEUED, /* Started bitmap IO */
833 GO_DISKLESS, /* Disk is being detached, on io-error or admin request. */ 833 GO_DISKLESS, /* Disk is being detached, on io-error or admin request. */
834 WAS_IO_ERROR, /* Local disk failed returned IO error */ 834 WAS_IO_ERROR, /* Local disk failed returned IO error */
835 FORCE_DETACH, /* Force-detach from local disk, aborting any pending local IO */
835 RESYNC_AFTER_NEG, /* Resync after online grow after the attach&negotiate finished. */ 836 RESYNC_AFTER_NEG, /* Resync after online grow after the attach&negotiate finished. */
836 NET_CONGESTED, /* The data socket is congested */ 837 NET_CONGESTED, /* The data socket is congested */
837 838
@@ -1838,12 +1839,20 @@ static inline int drbd_request_state(struct drbd_conf *mdev,
1838 return _drbd_request_state(mdev, mask, val, CS_VERBOSE + CS_ORDERED); 1839 return _drbd_request_state(mdev, mask, val, CS_VERBOSE + CS_ORDERED);
1839} 1840}
1840 1841
1842enum drbd_force_detach_flags {
1843 DRBD_IO_ERROR,
1844 DRBD_META_IO_ERROR,
1845 DRBD_FORCE_DETACH,
1846};
1847
1841#define __drbd_chk_io_error(m,f) __drbd_chk_io_error_(m,f, __func__) 1848#define __drbd_chk_io_error(m,f) __drbd_chk_io_error_(m,f, __func__)
1842static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach, const char *where) 1849static inline void __drbd_chk_io_error_(struct drbd_conf *mdev,
1850 enum drbd_force_detach_flags forcedetach,
1851 const char *where)
1843{ 1852{
1844 switch (mdev->ldev->dc.on_io_error) { 1853 switch (mdev->ldev->dc.on_io_error) {
1845 case EP_PASS_ON: 1854 case EP_PASS_ON:
1846 if (!forcedetach) { 1855 if (forcedetach == DRBD_IO_ERROR) {
1847 if (__ratelimit(&drbd_ratelimit_state)) 1856 if (__ratelimit(&drbd_ratelimit_state))
1848 dev_err(DEV, "Local IO failed in %s.\n", where); 1857 dev_err(DEV, "Local IO failed in %s.\n", where);
1849 if (mdev->state.disk > D_INCONSISTENT) 1858 if (mdev->state.disk > D_INCONSISTENT)
@@ -1854,6 +1863,8 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach,
1854 case EP_DETACH: 1863 case EP_DETACH:
1855 case EP_CALL_HELPER: 1864 case EP_CALL_HELPER:
1856 set_bit(WAS_IO_ERROR, &mdev->flags); 1865 set_bit(WAS_IO_ERROR, &mdev->flags);
1866 if (forcedetach == DRBD_FORCE_DETACH)
1867 set_bit(FORCE_DETACH, &mdev->flags);
1857 if (mdev->state.disk > D_FAILED) { 1868 if (mdev->state.disk > D_FAILED) {
1858 _drbd_set_state(_NS(mdev, disk, D_FAILED), CS_HARD, NULL); 1869 _drbd_set_state(_NS(mdev, disk, D_FAILED), CS_HARD, NULL);
1859 dev_err(DEV, 1870 dev_err(DEV,
@@ -1873,7 +1884,7 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach,
1873 */ 1884 */
1874#define drbd_chk_io_error(m,e,f) drbd_chk_io_error_(m,e,f, __func__) 1885#define drbd_chk_io_error(m,e,f) drbd_chk_io_error_(m,e,f, __func__)
1875static inline void drbd_chk_io_error_(struct drbd_conf *mdev, 1886static inline void drbd_chk_io_error_(struct drbd_conf *mdev,
1876 int error, int forcedetach, const char *where) 1887 int error, enum drbd_force_detach_flags forcedetach, const char *where)
1877{ 1888{
1878 if (error) { 1889 if (error) {
1879 unsigned long flags; 1890 unsigned long flags;
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 920ede2829d6..5bebe8d8ace3 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -1630,9 +1630,21 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
1630 eh = mdev->ldev->dc.on_io_error; 1630 eh = mdev->ldev->dc.on_io_error;
1631 was_io_error = test_and_clear_bit(WAS_IO_ERROR, &mdev->flags); 1631 was_io_error = test_and_clear_bit(WAS_IO_ERROR, &mdev->flags);
1632 1632
1633 /* Immediately allow completion of all application IO, that waits 1633 /* Immediately allow completion of all application IO,
1634 for completion from the local disk. */ 1634 * that waits for completion from the local disk,
1635 tl_abort_disk_io(mdev); 1635 * if this was a force-detach due to disk_timeout
1636 * or administrator request (drbdsetup detach --force).
1637 * Do NOT abort otherwise.
1638 * Aborting local requests may cause serious problems,
1639 * if requests are completed to upper layers already,
1640 * and then later the already submitted local bio completes.
1641 * This can cause DMA into former bio pages that meanwhile
1642 * have been re-used for other things.
1643 * So aborting local requests may cause crashes,
1644 * or even worse, silent data corruption.
1645 */
1646 if (test_and_clear_bit(FORCE_DETACH, &mdev->flags))
1647 tl_abort_disk_io(mdev);
1636 1648
1637 /* current state still has to be D_FAILED, 1649 /* current state still has to be D_FAILED,
1638 * there is only one way out: to D_DISKLESS, 1650 * there is only one way out: to D_DISKLESS,
@@ -3870,7 +3882,7 @@ void drbd_md_sync(struct drbd_conf *mdev)
3870 if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) { 3882 if (!drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) {
3871 /* this was a try anyways ... */ 3883 /* this was a try anyways ... */
3872 dev_err(DEV, "meta data update failed!\n"); 3884 dev_err(DEV, "meta data update failed!\n");
3873 drbd_chk_io_error(mdev, 1, true); 3885 drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
3874 } 3886 }
3875 3887
3876 /* Update mdev->ldev->md.la_size_sect, 3888 /* Update mdev->ldev->md.la_size_sect,
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 6d4de6a72e80..40a1c4f07190 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -950,6 +950,9 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
950 * to realize a "hot spare" feature (not that I'd recommend that) */ 950 * to realize a "hot spare" feature (not that I'd recommend that) */
951 wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt)); 951 wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
952 952
953 /* make sure there is no leftover from previous force-detach attempts */
954 clear_bit(FORCE_DETACH, &mdev->flags);
955
953 /* allocation not in the IO path, cqueue thread context */ 956 /* allocation not in the IO path, cqueue thread context */
954 nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL); 957 nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL);
955 if (!nbc) { 958 if (!nbc) {
@@ -1345,6 +1348,7 @@ static int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
1345 } 1348 }
1346 1349
1347 if (dt.detach_force) { 1350 if (dt.detach_force) {
1351 set_bit(FORCE_DETACH, &mdev->flags);
1348 drbd_force_state(mdev, NS(disk, D_FAILED)); 1352 drbd_force_state(mdev, NS(disk, D_FAILED));
1349 reply->ret_code = SS_SUCCESS; 1353 reply->ret_code = SS_SUCCESS;
1350 goto out; 1354 goto out;
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index 8e93a6ac9bb6..1f4b2dbb7d4a 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -455,7 +455,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
455 req->rq_state |= RQ_LOCAL_COMPLETED; 455 req->rq_state |= RQ_LOCAL_COMPLETED;
456 req->rq_state &= ~RQ_LOCAL_PENDING; 456 req->rq_state &= ~RQ_LOCAL_PENDING;
457 457
458 __drbd_chk_io_error(mdev, false); 458 __drbd_chk_io_error(mdev, DRBD_IO_ERROR);
459 _req_may_be_done_not_susp(req, m); 459 _req_may_be_done_not_susp(req, m);
460 break; 460 break;
461 461
@@ -477,7 +477,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
477 break; 477 break;
478 } 478 }
479 479
480 __drbd_chk_io_error(mdev, false); 480 __drbd_chk_io_error(mdev, DRBD_IO_ERROR);
481 481
482 goto_queue_for_net_read: 482 goto_queue_for_net_read:
483 483
@@ -1275,7 +1275,7 @@ void request_timer_fn(unsigned long data)
1275 time_after(now, req->start_time + dt) && 1275 time_after(now, req->start_time + dt) &&
1276 !time_in_range(now, mdev->last_reattach_jif, mdev->last_reattach_jif + dt)) { 1276 !time_in_range(now, mdev->last_reattach_jif, mdev->last_reattach_jif + dt)) {
1277 dev_warn(DEV, "Local backing device failed to meet the disk-timeout\n"); 1277 dev_warn(DEV, "Local backing device failed to meet the disk-timeout\n");
1278 __drbd_chk_io_error(mdev, 1); 1278 __drbd_chk_io_error(mdev, DRBD_FORCE_DETACH);
1279 } 1279 }
1280 nt = (time_after(now, req->start_time + et) ? now : req->start_time) + et; 1280 nt = (time_after(now, req->start_time + et) ? now : req->start_time) + et;
1281 spin_unlock_irq(&mdev->req_lock); 1281 spin_unlock_irq(&mdev->req_lock);
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
index 620c70ff2231..a35393f2fd1b 100644
--- a/drivers/block/drbd/drbd_worker.c
+++ b/drivers/block/drbd/drbd_worker.c
@@ -111,7 +111,7 @@ void drbd_endio_read_sec_final(struct drbd_epoch_entry *e) __releases(local)
111 if (list_empty(&mdev->read_ee)) 111 if (list_empty(&mdev->read_ee))
112 wake_up(&mdev->ee_wait); 112 wake_up(&mdev->ee_wait);
113 if (test_bit(__EE_WAS_ERROR, &e->flags)) 113 if (test_bit(__EE_WAS_ERROR, &e->flags))
114 __drbd_chk_io_error(mdev, false); 114 __drbd_chk_io_error(mdev, DRBD_IO_ERROR);
115 spin_unlock_irqrestore(&mdev->req_lock, flags); 115 spin_unlock_irqrestore(&mdev->req_lock, flags);
116 116
117 drbd_queue_work(&mdev->data.work, &e->w); 117 drbd_queue_work(&mdev->data.work, &e->w);
@@ -154,7 +154,7 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo
154 : list_empty(&mdev->active_ee); 154 : list_empty(&mdev->active_ee);
155 155
156 if (test_bit(__EE_WAS_ERROR, &e->flags)) 156 if (test_bit(__EE_WAS_ERROR, &e->flags))
157 __drbd_chk_io_error(mdev, false); 157 __drbd_chk_io_error(mdev, DRBD_IO_ERROR);
158 spin_unlock_irqrestore(&mdev->req_lock, flags); 158 spin_unlock_irqrestore(&mdev->req_lock, flags);
159 159
160 if (is_syncer_req) 160 if (is_syncer_req)