mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Philipp Reisner <philipp.reisner@linbit.com>
To: Jens Axboe <axboe@fb.com>, linux-kernel@vger.kernel.org
Cc: drbd-dev@lists.linbit.com
Subject: [PATCH 38/38] drbd: fix error path during resize
Date: Wed, 25 Nov 2015 11:54:11 +0100	[thread overview]
Message-ID: <1448448851-10343-39-git-send-email-philipp.reisner@linbit.com> (raw)
In-Reply-To: <1448448851-10343-1-git-send-email-philipp.reisner@linbit.com>

From: Lars Ellenberg <lars.ellenberg@linbit.com>

In case the lower level device size changed, but some other internal
details of the resize did not work out, drbd_determine_dev_size() would
try to restore the previous settings, trusting
drbd_md_set_sector_offsets() to "do the right thing", but overlooked
that this internally may set the meta data base offset based on device size.

This could end up with incomplete on-disk meta data layout change, and
ultimately lead to data corruption (if the failure was not noticed or
ignored by the operator, and other things go wrong as well).

Just remember all meta data related offsets/sizes,
and on error restore them all.

Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
---
 drivers/block/drbd/drbd_nl.c | 68 +++++++++++++++++++++++++-------------------
 1 file changed, 38 insertions(+), 30 deletions(-)

diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index f4ca273..c055c5e 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -891,12 +891,18 @@ void drbd_resume_io(struct drbd_device *device)
 enum determine_dev_size
 drbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct resize_parms *rs) __must_hold(local)
 {
-	sector_t prev_first_sect, prev_size; /* previous meta location */
-	sector_t la_size_sect, u_size;
+	struct md_offsets_and_sizes {
+		u64 last_agreed_sect;
+		u64 md_offset;
+		s32 al_offset;
+		s32 bm_offset;
+		u32 md_size_sect;
+
+		u32 al_stripes;
+		u32 al_stripe_size_4k;
+	} prev;
+	sector_t u_size, size;
 	struct drbd_md *md = &device->ldev->md;
-	u32 prev_al_stripe_size_4k;
-	u32 prev_al_stripes;
-	sector_t size;
 	char ppb[10];
 	void *buffer;
 
@@ -918,16 +924,17 @@ drbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct
 		return DS_ERROR;
 	}
 
-	prev_first_sect = drbd_md_first_sector(device->ldev);
-	prev_size = device->ldev->md.md_size_sect;
-	la_size_sect = device->ldev->md.la_size_sect;
+	/* remember current offset and sizes */
+	prev.last_agreed_sect = md->la_size_sect;
+	prev.md_offset = md->md_offset;
+	prev.al_offset = md->al_offset;
+	prev.bm_offset = md->bm_offset;
+	prev.md_size_sect = md->md_size_sect;
+	prev.al_stripes = md->al_stripes;
+	prev.al_stripe_size_4k = md->al_stripe_size_4k;
 
 	if (rs) {
 		/* rs is non NULL if we should change the AL layout only */
-
-		prev_al_stripes = md->al_stripes;
-		prev_al_stripe_size_4k = md->al_stripe_size_4k;
-
 		md->al_stripes = rs->al_stripes;
 		md->al_stripe_size_4k = rs->al_stripe_size / 4;
 		md->al_size_4k = (u64)rs->al_stripes * rs->al_stripe_size / 4;
@@ -940,7 +947,7 @@ drbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct
 	rcu_read_unlock();
 	size = drbd_new_dev_size(device, device->ldev, u_size, flags & DDSF_FORCED);
 
-	if (size < la_size_sect) {
+	if (size < prev.last_agreed_sect) {
 		if (rs && u_size == 0) {
 			/* Remove "rs &&" later. This check should always be active, but
 			   right now the receiver expects the permissive behavior */
@@ -961,30 +968,29 @@ drbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct
 		err = drbd_bm_resize(device, size, !(flags & DDSF_NO_RESYNC));
 		if (unlikely(err)) {
 			/* currently there is only one error: ENOMEM! */
-			size = drbd_bm_capacity(device)>>1;
+			size = drbd_bm_capacity(device);
 			if (size == 0) {
 				drbd_err(device, "OUT OF MEMORY! "
 				    "Could not allocate bitmap!\n");
 			} else {
 				drbd_err(device, "BM resizing failed. "
-				    "Leaving size unchanged at size = %lu KB\n",
-				    (unsigned long)size);
+				    "Leaving size unchanged\n");
 			}
 			rv = DS_ERROR;
 		}
 		/* racy, see comments above. */
 		drbd_set_my_capacity(device, size);
-		device->ldev->md.la_size_sect = size;
+		md->la_size_sect = size;
 		drbd_info(device, "size = %s (%llu KB)\n", ppsize(ppb, size>>1),
 		     (unsigned long long)size>>1);
 	}
 	if (rv <= DS_ERROR)
 		goto err_out;
 
-	la_size_changed = (la_size_sect != device->ldev->md.la_size_sect);
+	la_size_changed = (prev.last_agreed_sect != md->la_size_sect);
 
-	md_moved = prev_first_sect != drbd_md_first_sector(device->ldev)
-		|| prev_size	   != device->ldev->md.md_size_sect;
+	md_moved = prev.md_offset    != md->md_offset
+		|| prev.md_size_sect != md->md_size_sect;
 
 	if (la_size_changed || md_moved || rs) {
 		u32 prev_flags;
@@ -1024,20 +1030,22 @@ drbd_determine_dev_size(struct drbd_device *device, enum dds_flags flags, struct
 				  md->al_stripes, md->al_stripe_size_4k * 4);
 	}
 
-	if (size > la_size_sect)
-		rv = la_size_sect ? DS_GREW : DS_GREW_FROM_ZERO;
-	if (size < la_size_sect)
+	if (size > prev.last_agreed_sect)
+		rv = prev.last_agreed_sect ? DS_GREW : DS_GREW_FROM_ZERO;
+	if (size < prev.last_agreed_sect)
 		rv = DS_SHRUNK;
 
 	if (0) {
 	err_out:
-		if (rs) {
-			md->al_stripes = prev_al_stripes;
-			md->al_stripe_size_4k = prev_al_stripe_size_4k;
-			md->al_size_4k = (u64)prev_al_stripes * prev_al_stripe_size_4k;
-
-			drbd_md_set_sector_offsets(device, device->ldev);
-		}
+		/* restore previous offset and sizes */
+		md->la_size_sect = prev.last_agreed_sect;
+		md->md_offset = prev.md_offset;
+		md->al_offset = prev.al_offset;
+		md->bm_offset = prev.bm_offset;
+		md->md_size_sect = prev.md_size_sect;
+		md->al_stripes = prev.al_stripes;
+		md->al_stripe_size_4k = prev.al_stripe_size_4k;
+		md->al_size_4k = (u64)prev.al_stripes * prev.al_stripe_size_4k;
 	}
 	lc_unlock(device->act_log);
 	wake_up(&device->al_wait);
-- 
1.9.1


  parent reply	other threads:[~2015-11-25 11:13 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-25 10:53 [PATCH 00/38] DRBD update Philipp Reisner
2015-11-25 10:53 ` [PATCH 01/38] MAINTAINERS: Updated information for DRBD DRIVER Philipp Reisner
2015-11-25 10:53 ` [PATCH 02/38] drbd: Remove pointless check Philipp Reisner
2015-11-25 10:53 ` [PATCH 03/38] drbd: De-inline drbd_should_do_remote() and drbd_should_send_out_of_sync() Philipp Reisner
2015-11-25 10:53 ` [PATCH 04/38] drbd: Get rid of some first_peer_device() calls Philipp Reisner
2015-11-25 10:53 ` [PATCH 05/38] drbd: Move enum write_ordering_e to drbd.h Philipp Reisner
2015-11-25 10:53 ` [PATCH 06/38] drbd: drbd_adm_attach(): Add missing drbd_resync_after_changed() Philipp Reisner
2015-11-25 10:53 ` [PATCH 07/38] drbd: Fix locking across all resources Philipp Reisner
2015-11-25 10:53 ` [PATCH 08/38] drbd: Backport the "events2" command Philipp Reisner
2015-11-25 10:53 ` [PATCH 09/38] drbd: Backport the "status" command Philipp Reisner
2015-11-25 10:53 ` [PATCH 10/38] drbd: Deletion of an unnecessary check before the function call "lc_destroy" Philipp Reisner
2015-11-25 10:53 ` [PATCH 11/38] drbd: Replace 0 with the more meaningful GFP_NOWAIT Philipp Reisner
2015-11-25 10:53 ` [PATCH 12/38] drbd: Fix spurious disk-timeout Philipp Reisner
2015-11-25 10:53 ` [PATCH 13/38] drbd: drop remnants of connector -- we don't use it anymore in drbd 8.4 Philipp Reisner
2015-11-25 10:53 ` [PATCH 14/38] drbd: drbdsetup detach of an unresponsive local disk should not block IO "forever" Philipp Reisner
2015-11-25 10:53 ` [PATCH 15/38] drbd: also bump UUIDs if a diskless primary connects Philipp Reisner
2015-11-25 10:53 ` [PATCH 16/38] drbd: add comment why we want to first call local-io-error, then send state Philipp Reisner
2015-11-25 10:53 ` [PATCH 17/38] drbd: drbd_panic_after_delayed_completion_of_aborted_request() Philipp Reisner
2015-11-25 10:53 ` [PATCH 18/38] drbd: improve network timeout detection Philipp Reisner
2015-11-25 10:53 ` [PATCH 19/38] drbd: fix NULL deref in remember_new_state Philipp Reisner
2015-11-25 10:53 ` [PATCH 20/38] drbd: fix refcount error during detach of an already failed disk Philipp Reisner
2015-11-25 10:53 ` [PATCH 21/38] drbd: Rename asender to ack_receiver Philipp Reisner
2015-11-25 10:53 ` [PATCH 22/38] drbd: Create a dedicated workqueue for sending acks on the control connection Philipp Reisner
2015-11-25 10:53 ` [PATCH 23/38] drbd: prevent NULL pointer deref when resuming diskless primary Philipp Reisner
2015-11-25 10:53 ` [PATCH 24/38] drbd: debugfs: expose ed_data_gen_id Philipp Reisner
2015-11-25 10:53 ` [PATCH 25/38] drbd: use resource name in workqueue Philipp Reisner
2015-11-25 10:53 ` [PATCH 26/38] drbd: avoid redefinition of BITS_PER_PAGE Philipp Reisner
2015-11-25 10:54 ` [PATCH 27/38] drbd: use bitmap_weight() helper, don't open code Philipp Reisner
2015-11-25 10:54 ` [PATCH 28/38] drbd: fix spurious alert level printk Philipp Reisner
2015-11-25 10:54 ` [PATCH 29/38] drbd: fix queue limit setup for discard Philipp Reisner
2015-11-25 10:54 ` [PATCH 30/38] drbd: make drbd known to lsblk: use bd_link_disk_holder Philipp Reisner
2015-11-25 10:54 ` [PATCH 31/38] lru_cache: Converted lc_seq_printf_status to return void Philipp Reisner
2015-11-25 10:54 ` [PATCH 32/38] drbd: don't block forever in disconnect during resync if fencing=r-a-stonith Philipp Reisner
2015-11-25 10:54 ` [PATCH 33/38] drbd: fix memory leak in drbd_adm_resize Philipp Reisner
2015-11-25 10:54 ` [PATCH 34/38] drbd: fix "endless" transfer log walk in protocol A Philipp Reisner
2015-11-25 10:54 ` [PATCH 35/38] drbd: make suspend_io() / resume_io() must be thread and recursion safe Philipp Reisner
2015-11-25 10:54 ` [PATCH 36/38] drbd: separate out __al_write_transaction helper function Philipp Reisner
2015-11-25 10:54 ` [PATCH 37/38] drbd: avoid potential deadlock during handshake Philipp Reisner
2015-11-25 10:54 ` Philipp Reisner [this message]
2015-11-25 18:01 ` [PATCH 00/38] DRBD update Jens Axboe

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1448448851-10343-39-git-send-email-philipp.reisner@linbit.com \
    --to=philipp.reisner@linbit.com \
    --cc=axboe@fb.com \
    --cc=drbd-dev@lists.linbit.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®