Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0c849666 authored by Lars Ellenberg's avatar Lars Ellenberg Committed by Philipp Reisner
Browse files

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: default avatarPhilipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: default avatarLars Ellenberg <lars.ellenberg@linbit.com>
parent bf709c85
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -445,7 +445,7 @@ _al_write_transaction(struct drbd_conf *mdev)
		/* drbd_chk_io_error done already */
	else if (drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) {
		err = -EIO;
		drbd_chk_io_error(mdev, 1, true);
		drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
	} else {
		/* advance ringbuffer position and transaction counter */
		mdev->al_tr_pos = (mdev->al_tr_pos + 1) % (MD_AL_SECTORS*512/MD_BLOCK_SIZE);
+2 −2
Original line number Diff line number Diff line
@@ -1135,7 +1135,7 @@ static int bm_rw(struct drbd_conf *mdev, int rw, unsigned flags, unsigned lazy_w

	if (ctx->error) {
		dev_alert(DEV, "we had at least one MD IO ERROR during bitmap IO\n");
		drbd_chk_io_error(mdev, 1, true);
		drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
		err = -EIO; /* ctx->error ? */
	}

@@ -1260,7 +1260,7 @@ int drbd_bm_write_page(struct drbd_conf *mdev, unsigned int idx) __must_hold(loc
	wait_until_done_or_disk_failure(mdev, mdev->ldev, &ctx->done);

	if (ctx->error)
		drbd_chk_io_error(mdev, 1, true);
		drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
		/* that should force detach, so the in memory bitmap will be
		 * gone in a moment as well. */

+14 −3
Original line number Diff line number Diff line
@@ -689,6 +689,7 @@ enum {
	BITMAP_IO_QUEUED,       /* Started bitmap IO */
	GO_DISKLESS,		/* Disk is being detached, on io-error or admin request. */
	WAS_IO_ERROR,		/* Local disk failed returned IO error */
	FORCE_DETACH,		/* Force-detach from local disk, aborting any pending local IO */
	RESYNC_AFTER_NEG,       /* Resync after online grow after the attach&negotiate finished. */
	RESIZE_PENDING,		/* Size change detected locally, waiting for the response from
				 * the peer, if it changed there as well. */
@@ -1653,8 +1654,16 @@ static inline union drbd_state drbd_read_state(struct drbd_conf *mdev)
	return rv;
}

enum drbd_force_detach_flags {
	DRBD_IO_ERROR,
	DRBD_META_IO_ERROR,
	DRBD_FORCE_DETACH,
};

#define __drbd_chk_io_error(m,f) __drbd_chk_io_error_(m,f, __func__)
static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach, const char *where)
static inline void __drbd_chk_io_error_(struct drbd_conf *mdev,
		enum drbd_force_detach_flags forcedetach,
		const char *where)
{
	enum drbd_io_error_p ep;

@@ -1663,7 +1672,7 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach,
	rcu_read_unlock();
	switch (ep) {
	case EP_PASS_ON: /* FIXME would this be better named "Ignore"? */
		if (!forcedetach) {
		if (forcedetach == DRBD_IO_ERROR) {
			if (__ratelimit(&drbd_ratelimit_state))
				dev_err(DEV, "Local IO failed in %s.\n", where);
			if (mdev->state.disk > D_INCONSISTENT)
@@ -1674,6 +1683,8 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach,
	case EP_DETACH:
	case EP_CALL_HELPER:
		set_bit(WAS_IO_ERROR, &mdev->flags);
		if (forcedetach == DRBD_FORCE_DETACH)
			set_bit(FORCE_DETACH, &mdev->flags);
		if (mdev->state.disk > D_FAILED) {
			_drbd_set_state(_NS(mdev, disk, D_FAILED), CS_HARD, NULL);
			dev_err(DEV,
@@ -1693,7 +1704,7 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach,
 */
#define drbd_chk_io_error(m,e,f) drbd_chk_io_error_(m,e,f, __func__)
static inline void drbd_chk_io_error_(struct drbd_conf *mdev,
	int error, int forcedetach, const char *where)
	int error, enum drbd_force_detach_flags forcedetach, const char *where)
{
	if (error) {
		unsigned long flags;
+1 −1
Original line number Diff line number Diff line
@@ -2866,7 +2866,7 @@ void drbd_md_sync(struct drbd_conf *mdev)
	if (drbd_md_sync_page_io(mdev, mdev->ldev, sector, WRITE)) {
		/* this was a try anyways ... */
		dev_err(DEV, "meta data update failed!\n");
		drbd_chk_io_error(mdev, 1, true);
		drbd_chk_io_error(mdev, 1, DRBD_META_IO_ERROR);
	}

	/* Update mdev->ldev->md.la_size_sect,
+4 −0
Original line number Diff line number Diff line
@@ -1299,6 +1299,9 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
	 * to realize a "hot spare" feature (not that I'd recommend that) */
	wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));

	/* make sure there is no leftover from previous force-detach attempts */
	clear_bit(FORCE_DETACH, &mdev->flags);

	/* allocation not in the IO path, drbdsetup context */
	nbc = kzalloc(sizeof(struct drbd_backing_dev), GFP_KERNEL);
	if (!nbc) {
@@ -1683,6 +1686,7 @@ static int adm_detach(struct drbd_conf *mdev, int force)
	int ret;

	if (force) {
		set_bit(FORCE_DETACH, &mdev->flags);
		drbd_force_state(mdev, NS(disk, D_FAILED));
		retcode = SS_SUCCESS;
		goto out;
Loading