return sh;
 }
 
-static void shrink_buffers(struct stripe_head *sh)
+#if PAGE_SIZE != DEFAULT_STRIPE_SIZE
+static void free_stripe_pages(struct stripe_head *sh)
+{
+       int i;
+       struct page *p;
+
+       /* Have not allocate page pool */
+       if (!sh->pages)
+               return;
+
+       for (i = 0; i < sh->nr_pages; i++) {
+               p = sh->pages[i];
+               if (p)
+                       put_page(p);
+               sh->pages[i] = NULL;
+       }
+}
+
+static int alloc_stripe_pages(struct stripe_head *sh, gfp_t gfp)
 {
+       int i;
        struct page *p;
+
+       for (i = 0; i < sh->nr_pages; i++) {
+               /* The page have allocated. */
+               if (sh->pages[i])
+                       continue;
+
+               p = alloc_page(gfp);
+               if (!p) {
+                       free_stripe_pages(sh);
+                       return -ENOMEM;
+               }
+               sh->pages[i] = p;
+       }
+       return 0;
+}
+
+static int
+init_stripe_shared_pages(struct stripe_head *sh, struct r5conf *conf, int disks)
+{
+       int nr_pages, cnt;
+
+       if (sh->pages)
+               return 0;
+
+       /* Each of the sh->dev[i] need one conf->stripe_size */
+       cnt = PAGE_SIZE / conf->stripe_size;
+       nr_pages = (disks + cnt - 1) / cnt;
+
+       sh->pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL);
+       if (!sh->pages)
+               return -ENOMEM;
+       sh->nr_pages = nr_pages;
+       sh->stripes_per_page = cnt;
+       return 0;
+}
+#endif
+
+static void shrink_buffers(struct stripe_head *sh)
+{
        int i;
        int num = sh->raid_conf->pool_size;
 
+#if PAGE_SIZE == DEFAULT_STRIPE_SIZE
        for (i = 0; i < num ; i++) {
+               struct page *p;
+
                WARN_ON(sh->dev[i].page != sh->dev[i].orig_page);
                p = sh->dev[i].page;
                if (!p)
                sh->dev[i].page = NULL;
                put_page(p);
        }
+#else
+       for (i = 0; i < num; i++)
+               sh->dev[i].page = NULL;
+       free_stripe_pages(sh); /* Free pages */
+#endif
 }
 
 static int grow_buffers(struct stripe_head *sh, gfp_t gfp)
        int i;
        int num = sh->raid_conf->pool_size;
 
+#if PAGE_SIZE == DEFAULT_STRIPE_SIZE
        for (i = 0; i < num; i++) {
                struct page *page;
 
                sh->dev[i].orig_page = page;
                sh->dev[i].offset = 0;
        }
+#else
+       if (alloc_stripe_pages(sh, gfp))
+               return -ENOMEM;
 
+       for (i = 0; i < num; i++) {
+               sh->dev[i].page = raid5_get_dev_page(sh, i);
+               sh->dev[i].orig_page = sh->dev[i].page;
+               sh->dev[i].offset = raid5_get_page_offset(sh, i);
+       }
+#endif
        return 0;
 }
 
 
 static void free_stripe(struct kmem_cache *sc, struct stripe_head *sh)
 {
+#if PAGE_SIZE != DEFAULT_STRIPE_SIZE
+       kfree(sh->pages);
+#endif
        if (sh->ppl_page)
                __free_page(sh->ppl_page);
        kmem_cache_free(sc, sh);
                        sh->ppl_page = alloc_page(gfp);
                        if (!sh->ppl_page) {
                                free_stripe(sc, sh);
-                               sh = NULL;
+                               return NULL;
                        }
                }
+#if PAGE_SIZE != DEFAULT_STRIPE_SIZE
+               if (init_stripe_shared_pages(sh, conf, disks)) {
+                       free_stripe(sc, sh);
+                       return NULL;
+               }
+#endif
        }
        return sh;
 }
 
        reconstruct_state_result,
 };
 
+#define DEFAULT_STRIPE_SIZE    4096
 struct stripe_head {
        struct hlist_node       hash;
        struct list_head        lru;          /* inactive_list or handle_list */
                int                  target, target2;
                enum sum_check_flags zero_sum_result;
        } ops;
+
+#if PAGE_SIZE != DEFAULT_STRIPE_SIZE
+       /* These pages will be used by bios in dev[i] */
+       struct page     **pages;
+       int     nr_pages;       /* page array size */
+       int     stripes_per_page;
+#endif
        struct r5dev {
                /* rreq and rvec are used for the replacement device when
                 * writing data to both devices.
  */
 
 #define NR_STRIPES             256
-#define DEFAULT_STRIPE_SIZE    4096
 
 #if PAGE_SIZE == DEFAULT_STRIPE_SIZE
 #define STRIPE_SIZE            PAGE_SIZE
        return layout >= 8 && layout <= 10;
 }
 
+#if PAGE_SIZE != DEFAULT_STRIPE_SIZE
+/*
+ * Return offset of the corresponding page for r5dev.
+ */
+static inline int raid5_get_page_offset(struct stripe_head *sh, int disk_idx)
+{
+       return (disk_idx % sh->stripes_per_page) * RAID5_STRIPE_SIZE(sh->raid_conf);
+}
+
+/*
+ * Return corresponding page address for r5dev.
+ */
+static inline struct page *
+raid5_get_dev_page(struct stripe_head *sh, int disk_idx)
+{
+       return sh->pages[disk_idx / sh->stripes_per_page];
+}
+#endif
+
 extern void md_raid5_kick_device(struct r5conf *conf);
 extern int raid5_set_cache_size(struct mddev *mddev, int size);
 extern sector_t raid5_compute_blocknr(struct stripe_head *sh, int i, int previous);