/* super.c */
 extern struct buffer_head *ext4_sb_bread(struct super_block *sb,
                                         sector_t block, int op_flags);
+extern struct buffer_head *ext4_sb_bread_unmovable(struct super_block *sb,
+                                                  sector_t block);
 extern void ext4_read_bh_nowait(struct buffer_head *bh, int op_flags,
                                bh_end_io_t *end_io);
 extern int ext4_read_bh(struct buffer_head *bh, int op_flags,
 
 }
 
 /*
- * This works like sb_bread() except it uses ERR_PTR for error
+ * This works like __bread_gfp() except it uses ERR_PTR for error
  * returns.  Currently with sb_bread it's impossible to distinguish
  * between ENOMEM and EIO situations (since both result in a NULL
  * return.
  */
-struct buffer_head *
-ext4_sb_bread(struct super_block *sb, sector_t block, int op_flags)
+static struct buffer_head *__ext4_sb_bread_gfp(struct super_block *sb,
+                                              sector_t block, int op_flags,
+                                              gfp_t gfp)
 {
        struct buffer_head *bh;
        int ret;
 
-       bh = sb_getblk(sb, block);
+       bh = sb_getblk_gfp(sb, block, gfp);
        if (bh == NULL)
                return ERR_PTR(-ENOMEM);
        if (ext4_buffer_uptodate(bh))
        return bh;
 }
 
+struct buffer_head *ext4_sb_bread(struct super_block *sb, sector_t block,
+                                  int op_flags)
+{
+       return __ext4_sb_bread_gfp(sb, block, op_flags, __GFP_MOVABLE);
+}
+
+struct buffer_head *ext4_sb_bread_unmovable(struct super_block *sb,
+                                           sector_t block)
+{
+       return __ext4_sb_bread_gfp(sb, block, 0, 0);
+}
+
 void ext4_sb_breadahead_unmovable(struct super_block *sb, sector_t block)
 {
        struct buffer_head *bh = sb_getblk_gfp(sb, block, 0);
                logical_sb_block = sb_block;
        }
 
-       if (!(bh = sb_bread_unmovable(sb, logical_sb_block))) {
+       bh = ext4_sb_bread_unmovable(sb, logical_sb_block);
+       if (IS_ERR(bh)) {
                ext4_msg(sb, KERN_ERR, "unable to read superblock");
+               ret = PTR_ERR(bh);
+               bh = NULL;
                goto out_fail;
        }
        /*
                brelse(bh);
                logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE;
                offset = do_div(logical_sb_block, blocksize);
-               bh = sb_bread_unmovable(sb, logical_sb_block);
-               if (!bh) {
+               bh = ext4_sb_bread_unmovable(sb, logical_sb_block);
+               if (IS_ERR(bh)) {
                        ext4_msg(sb, KERN_ERR,
                               "Can't read superblock on 2nd try");
+                       ret = PTR_ERR(bh);
+                       bh = NULL;
                        goto failed_mount;
                }
                es = (struct ext4_super_block *)(bh->b_data + offset);
                struct buffer_head *bh;
 
                block = descriptor_loc(sb, logical_sb_block, i);
-               bh = sb_bread_unmovable(sb, block);
-               if (!bh) {
+               bh = ext4_sb_bread_unmovable(sb, block);
+               if (IS_ERR(bh)) {
                        ext4_msg(sb, KERN_ERR,
                               "can't read group descriptor %d", i);
                        db_count = i;
+                       ret = PTR_ERR(bh);
+                       bh = NULL;
                        goto failed_mount2;
                }
                rcu_read_lock();