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

Commit 86aa1397 authored by Song Liu's avatar Song Liu Committed by Shaohua Li
Browse files

md/r5cache: read data into orig_page for prexor of cached data



With write back cache, we use orig_page to do prexor. This patch
makes sure we read data into orig_page for it.

Flag R5_OrigPageUPTDODATE is added to show whether orig_page
has the latest data from raid disk.

We introduce a helper function uptodate_for_rmw() to simplify
the a couple conditions in handle_stripe_dirtying().

Signed-off-by: default avatarSong Liu <songliubraving@fb.com>
Signed-off-by: default avatarShaohua Li <shli@fb.com>
parent d46d29f0
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -2349,6 +2349,8 @@ void r5c_release_extra_page(struct stripe_head *sh)
			struct page *p = sh->dev[i].orig_page;

			sh->dev[i].orig_page = sh->dev[i].page;
			clear_bit(R5_OrigPageUPTDODATE, &sh->dev[i].flags);

			if (!using_disk_info_extra_page)
				put_page(p);
		}
+35 −9
Original line number Diff line number Diff line
@@ -1015,6 +1015,16 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)

			if (test_bit(R5_SkipCopy, &sh->dev[i].flags))
				WARN_ON(test_bit(R5_UPTODATE, &sh->dev[i].flags));

			if (!op_is_write(op) &&
			    test_bit(R5_InJournal, &sh->dev[i].flags))
				/*
				 * issuing read for a page in journal, this
				 * must be preparing for prexor in rmw; read
				 * the data into orig_page
				 */
				sh->dev[i].vec.bv_page = sh->dev[i].orig_page;
			else
				sh->dev[i].vec.bv_page = sh->dev[i].page;
			bi->bi_vcnt = 1;
			bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
@@ -2380,6 +2390,13 @@ static void raid5_end_read_request(struct bio * bi)
		} else if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags))
			clear_bit(R5_ReadNoMerge, &sh->dev[i].flags);

		if (test_bit(R5_InJournal, &sh->dev[i].flags))
			/*
			 * end read for a page in journal, this
			 * must be preparing for prexor in rmw
			 */
			set_bit(R5_OrigPageUPTDODATE, &sh->dev[i].flags);

		if (atomic_read(&rdev->read_errors))
			atomic_set(&rdev->read_errors, 0);
	} else {
@@ -3594,6 +3611,21 @@ static void handle_stripe_clean_event(struct r5conf *conf,
		break_stripe_batch_list(head_sh, STRIPE_EXPAND_SYNC_FLAGS);
}

/*
 * For RMW in write back cache, we need extra page in prexor to store the
 * old data. This page is stored in dev->orig_page.
 *
 * This function checks whether we have data for prexor. The exact logic
 * is:
 *       R5_UPTODATE && (!R5_InJournal || R5_OrigPageUPTDODATE)
 */
static inline bool uptodate_for_rmw(struct r5dev *dev)
{
	return (test_bit(R5_UPTODATE, &dev->flags)) &&
		(!test_bit(R5_InJournal, &dev->flags) ||
		 test_bit(R5_OrigPageUPTDODATE, &dev->flags));
}

static int handle_stripe_dirtying(struct r5conf *conf,
				  struct stripe_head *sh,
				  struct stripe_head_state *s,
@@ -3625,9 +3657,7 @@ static int handle_stripe_dirtying(struct r5conf *conf,
		if ((dev->towrite || i == sh->pd_idx || i == sh->qd_idx ||
		     test_bit(R5_InJournal, &dev->flags)) &&
		    !test_bit(R5_LOCKED, &dev->flags) &&
		    !((test_bit(R5_UPTODATE, &dev->flags) &&
		       (!test_bit(R5_InJournal, &dev->flags) ||
			dev->page != dev->orig_page)) ||
		    !(uptodate_for_rmw(dev) ||
		      test_bit(R5_Wantcompute, &dev->flags))) {
			if (test_bit(R5_Insync, &dev->flags))
				rmw++;
@@ -3639,7 +3669,6 @@ static int handle_stripe_dirtying(struct r5conf *conf,
		    i != sh->pd_idx && i != sh->qd_idx &&
		    !test_bit(R5_LOCKED, &dev->flags) &&
		    !(test_bit(R5_UPTODATE, &dev->flags) ||
		      test_bit(R5_InJournal, &dev->flags) ||
		      test_bit(R5_Wantcompute, &dev->flags))) {
			if (test_bit(R5_Insync, &dev->flags))
				rcw++;
@@ -3693,9 +3722,7 @@ static int handle_stripe_dirtying(struct r5conf *conf,
			     i == sh->pd_idx || i == sh->qd_idx ||
			     test_bit(R5_InJournal, &dev->flags)) &&
			    !test_bit(R5_LOCKED, &dev->flags) &&
			    !((test_bit(R5_UPTODATE, &dev->flags) &&
			       (!test_bit(R5_InJournal, &dev->flags) ||
				dev->page != dev->orig_page)) ||
			    !(uptodate_for_rmw(dev) ||
			      test_bit(R5_Wantcompute, &dev->flags)) &&
			    test_bit(R5_Insync, &dev->flags)) {
				if (test_bit(STRIPE_PREREAD_ACTIVE,
@@ -3722,7 +3749,6 @@ static int handle_stripe_dirtying(struct r5conf *conf,
			    i != sh->pd_idx && i != sh->qd_idx &&
			    !test_bit(R5_LOCKED, &dev->flags) &&
			    !(test_bit(R5_UPTODATE, &dev->flags) ||
			      test_bit(R5_InJournal, &dev->flags) ||
			      test_bit(R5_Wantcompute, &dev->flags))) {
				rcw++;
				if (test_bit(R5_Insync, &dev->flags) &&
+5 −0
Original line number Diff line number Diff line
@@ -322,6 +322,11 @@ enum r5dev_flags {
			 * data and parity being written are in the journal
			 * device
			 */
	R5_OrigPageUPTDODATE,	/* with write back cache, we read old data into
				 * dev->orig_page for prexor. When this flag is
				 * set, orig_page contains latest data in the
				 * raid disk.
				 */
};

/*