gfs2: Fix extended attribute readahead optimization
authorAndreas Gruenbacher <agruenba@redhat.com>
Tue, 16 Aug 2016 11:25:22 +0000 (13:25 +0200)
committerBob Peterson <rpeterso@redhat.com>
Thu, 18 Aug 2016 16:36:41 +0000 (11:36 -0500)
Commit 39b0555f didn't check for a failing bio_add_page in
gfs2_submit_bhs. This could cause I/O requests to get lost, and the
affected buffer heads to stay locked forever.  Fix that by submitting
the current bio and allocating another one when bio_add_page fails.  (It
is guaranteed that we can at least add one page to a bio.)

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
fs/gfs2/meta_io.c

index 950b8be68e415435d530196810ac733392c5035f..373639a597823c0b0b58fe129bf3b0118735599a 100644 (file)
@@ -216,23 +216,26 @@ static void gfs2_meta_read_endio(struct bio *bio)
 static void gfs2_submit_bhs(int op, int op_flags, struct buffer_head *bhs[],
                            int num)
 {
-       struct buffer_head *bh = bhs[0];
-       struct bio *bio;
-       int i;
-
-       if (!num)
-               return;
-
-       bio = bio_alloc(GFP_NOIO, num);
-       bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9);
-       bio->bi_bdev = bh->b_bdev;
-       for (i = 0; i < num; i++) {
-               bh = bhs[i];
-               bio_add_page(bio, bh->b_page, bh->b_size, bh_offset(bh));
+       while (num > 0) {
+               struct buffer_head *bh = *bhs;
+               struct bio *bio;
+
+               bio = bio_alloc(GFP_NOIO, num);
+               bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9);
+               bio->bi_bdev = bh->b_bdev;
+               while (num > 0) {
+                       bh = *bhs;
+                       if (!bio_add_page(bio, bh->b_page, bh->b_size, bh_offset(bh))) {
+                               BUG_ON(bio->bi_iter.bi_size == 0);
+                               break;
+                       }
+                       bhs++;
+                       num--;
+               }
+               bio->bi_end_io = gfs2_meta_read_endio;
+               bio_set_op_attrs(bio, op, op_flags);
+               submit_bio(bio);
        }
-       bio->bi_end_io = gfs2_meta_read_endio;
-       bio_set_op_attrs(bio, op, op_flags);
-       submit_bio(bio);
 }
 
 /**