diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -443,6 +443,26 @@ raid5_end_read_request(struct bio *bi, int error);
 static void
 raid5_end_write_request(struct bio *bi, int error);
 
+static inline void r5dev_switch_page(struct r5dev *dev, struct page *page)
+{
+	BUG_ON(dev->page_save != NULL);
+	BUG_ON(dev->page != bio_iovec_idx(&dev->req, 0)->bv_page);
+	/* The pointer must be restored whenever the LOCKED gets cleared. */
+	dev->page_save = dev->page;
+	dev->page = bio_iovec_idx(&dev->req, 0)->bv_page = page;
+	kmap(dev->page); /* for sync_xor on 32-bit systems */
+}
+
+static inline void r5dev_restore_page(struct r5dev *dev)
+{
+	BUG_ON(dev->page_save == NULL);
+	BUG_ON(dev->page != bio_iovec_idx(&dev->req, 0)->bv_page);
+	BUG_ON(dev->page == dev->page_save);
+	kunmap(dev->page_save);
+	dev->page = bio_iovec_idx(&dev->req, 0)->bv_page = dev->page_save;
+	dev->page_save = NULL;
+}
+
 static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
 {
 	raid5_conf_t *conf = sh->raid_conf;
@@ -509,12 +529,8 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
 			pr_debug("skip op %ld on disc %d for sector %llu\n",
 				bi->bi_rw, i, (unsigned long long)sh->sector);
 
-			if (test_bit(R5_Direct, &sh->dev[i].flags)) {
-				struct page *page = bio_iovec_idx(&sh->dev[i].req, 0)->bv_page;
-				BUG_ON(page == sh->dev[i].page);
-				bio_iovec_idx(&sh->dev[i].req, 0)->bv_page = sh->dev[i].page;
-				kunmap(page);
-			}
+			if (test_bit(R5_Direct, &sh->dev[i].flags))
+				r5dev_restore_page(&sh->dev[i]);
 
 			clear_bit(R5_LOCKED, &sh->dev[i].flags);
 			set_bit(STRIPE_HANDLE, &sh->state);
@@ -978,11 +994,8 @@ static int try_reuse_data_page(struct r5dev *dev)
 	    test_bit(R5_Insync, &dev->flags)) {
 		page = zero_copy_data(wbi, sector);
 		if (page) {
-			/* The pointer must be restored whenever the LOCKED
-			 * gets cleared. */
-			kmap(page); /* for sync_xor on 32-bit systems */
-			bio_iovec_idx(&dev->req, 0)->bv_page = page;
 			set_bit(R5_Direct, &dev->flags);
+			r5dev_switch_page(dev, page);
 			clear_bit(R5_UPTODATE, &dev->flags);
 			clear_bit(R5_OVERWRITE, &dev->flags);
 			return 1;
@@ -1653,14 +1664,8 @@ static void raid5_end_write_request(struct bio *bi, int error)
 
 	rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
 	
-	if (test_bit(R5_Direct, &sh->dev[i].flags)) {
-		struct page *page = bio_iovec_idx(&sh->dev[i].req, 0)->bv_page;
-		BUG_ON(page == sh->dev[i].page);
-		bio_iovec_idx(&sh->dev[i].req, 0)->bv_page = sh->dev[i].page;
-		kunmap(page);
-	} else {
-		BUG_ON(bio_iovec_idx(&sh->dev[i].req, 0)->bv_page != sh->dev[i].page);
-	}
+	if (test_bit(R5_Direct, &sh->dev[i].flags))
+		r5dev_restore_page(&sh->dev[i]);
 	clear_bit(R5_LOCKED, &sh->dev[i].flags);
 	set_bit(STRIPE_HANDLE, &sh->state);
 	release_stripe(sh);
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -232,7 +232,7 @@ struct stripe_head {
 	struct r5dev {
 		struct bio	req;
 		struct bio_vec	vec;
-		struct page	*page;
+		struct page	*page, *page_save;
 		struct bio	*toread, *read, *towrite, *written;
 		sector_t	sector;			/* sector of this page */
 		unsigned long	flags;
-- 
1.7.1