btrfs: raid56: catch errors from full_stripe_write
[sfrench/cifs-2.6.git] / fs / btrfs / raid56.c
index 5e4ad134b9ad12881edb33b7962e13155edc9d45..df41d7049936fd385edb7bdd46852bdbf7507b86 100644 (file)
@@ -5,32 +5,19 @@
  */
 
 #include <linux/sched.h>
-#include <linux/wait.h>
 #include <linux/bio.h>
 #include <linux/slab.h>
-#include <linux/buffer_head.h>
 #include <linux/blkdev.h>
-#include <linux/random.h>
-#include <linux/iocontext.h>
-#include <linux/capability.h>
-#include <linux/ratelimit.h>
-#include <linux/kthread.h>
 #include <linux/raid/pq.h>
 #include <linux/hash.h>
 #include <linux/list_sort.h>
 #include <linux/raid/xor.h>
 #include <linux/mm.h>
-#include <asm/div64.h>
 #include "ctree.h"
-#include "extent_map.h"
 #include "disk-io.h"
-#include "transaction.h"
-#include "print-tree.h"
 #include "volumes.h"
 #include "raid56.h"
 #include "async-thread.h"
-#include "check-integrity.h"
-#include "rcu-string.h"
 
 /* set when additional merges to this rbio are not allowed */
 #define RBIO_RMW_LOCKED_BIT    1
@@ -175,8 +162,6 @@ static int __raid56_parity_recover(struct btrfs_raid_bio *rbio);
 static noinline void finish_rmw(struct btrfs_raid_bio *rbio);
 static void rmw_work(struct btrfs_work *work);
 static void read_rebuild_work(struct btrfs_work *work);
-static void async_rmw_stripe(struct btrfs_raid_bio *rbio);
-static void async_read_rebuild(struct btrfs_raid_bio *rbio);
 static int fail_bio_stripe(struct btrfs_raid_bio *rbio, struct bio *bio);
 static int fail_rbio_index(struct btrfs_raid_bio *rbio, int failed);
 static void __free_raid_bio(struct btrfs_raid_bio *rbio);
@@ -185,7 +170,13 @@ static int alloc_rbio_pages(struct btrfs_raid_bio *rbio);
 
 static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio,
                                         int need_check);
-static void async_scrub_parity(struct btrfs_raid_bio *rbio);
+static void scrub_parity_work(struct btrfs_work *work);
+
+static void start_async_work(struct btrfs_raid_bio *rbio, btrfs_func_t work_func)
+{
+       btrfs_init_work(&rbio->work, btrfs_rmw_helper, work_func, NULL, NULL);
+       btrfs_queue_work(rbio->fs_info->rmw_workers, &rbio->work);
+}
 
 /*
  * the stripe hash table is used for locking, and to collect
@@ -260,7 +251,7 @@ static void cache_rbio_pages(struct btrfs_raid_bio *rbio)
                s = kmap(rbio->bio_pages[i]);
                d = kmap(rbio->stripe_pages[i]);
 
-               memcpy(d, s, PAGE_SIZE);
+               copy_page(d, s);
 
                kunmap(rbio->bio_pages[i]);
                kunmap(rbio->stripe_pages[i]);
@@ -516,32 +507,21 @@ static void run_xor(void **pages, int src_cnt, ssize_t len)
 }
 
 /*
- * returns true if the bio list inside this rbio
- * covers an entire stripe (no rmw required).
- * Must be called with the bio list lock held, or
- * at a time when you know it is impossible to add
- * new bios into the list
+ * Returns true if the bio list inside this rbio covers an entire stripe (no
+ * rmw required).
  */
-static int __rbio_is_full(struct btrfs_raid_bio *rbio)
+static int rbio_is_full(struct btrfs_raid_bio *rbio)
 {
+       unsigned long flags;
        unsigned long size = rbio->bio_list_bytes;
        int ret = 1;
 
+       spin_lock_irqsave(&rbio->bio_list_lock, flags);
        if (size != rbio->nr_data * rbio->stripe_len)
                ret = 0;
-
        BUG_ON(size > rbio->nr_data * rbio->stripe_len);
-       return ret;
-}
-
-static int rbio_is_full(struct btrfs_raid_bio *rbio)
-{
-       unsigned long flags;
-       int ret;
-
-       spin_lock_irqsave(&rbio->bio_list_lock, flags);
-       ret = __rbio_is_full(rbio);
        spin_unlock_irqrestore(&rbio->bio_list_lock, flags);
+
        return ret;
 }
 
@@ -812,16 +792,16 @@ static noinline void unlock_stripe(struct btrfs_raid_bio *rbio)
                        spin_unlock_irqrestore(&h->lock, flags);
 
                        if (next->operation == BTRFS_RBIO_READ_REBUILD)
-                               async_read_rebuild(next);
+                               start_async_work(next, read_rebuild_work);
                        else if (next->operation == BTRFS_RBIO_REBUILD_MISSING) {
                                steal_rbio(rbio, next);
-                               async_read_rebuild(next);
+                               start_async_work(next, read_rebuild_work);
                        } else if (next->operation == BTRFS_RBIO_WRITE) {
                                steal_rbio(rbio, next);
-                               async_rmw_stripe(next);
+                               start_async_work(next, rmw_work);
                        } else if (next->operation == BTRFS_RBIO_PARITY_SCRUB) {
                                steal_rbio(rbio, next);
-                               async_scrub_parity(next);
+                               start_async_work(next, scrub_parity_work);
                        }
 
                        goto done_nolock;
@@ -1275,7 +1255,7 @@ static noinline void finish_rmw(struct btrfs_raid_bio *rbio)
                                                pointers);
                } else {
                        /* raid5 */
-                       memcpy(pointers[nr_data], pointers[0], PAGE_SIZE);
+                       copy_page(pointers[nr_data], pointers[0]);
                        run_xor(pointers + 1, nr_data - 1, PAGE_SIZE);
                }
 
@@ -1343,7 +1323,7 @@ write_data:
 
                bio->bi_private = rbio;
                bio->bi_end_io = raid_write_end_io;
-               bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
+               bio->bi_opf = REQ_OP_WRITE;
 
                submit_bio(bio);
        }
@@ -1508,20 +1488,6 @@ cleanup:
        rbio_orig_end_io(rbio, BLK_STS_IOERR);
 }
 
-static void async_rmw_stripe(struct btrfs_raid_bio *rbio)
-{
-       btrfs_init_work(&rbio->work, btrfs_rmw_helper, rmw_work, NULL, NULL);
-       btrfs_queue_work(rbio->fs_info->rmw_workers, &rbio->work);
-}
-
-static void async_read_rebuild(struct btrfs_raid_bio *rbio)
-{
-       btrfs_init_work(&rbio->work, btrfs_rmw_helper,
-                       read_rebuild_work, NULL, NULL);
-
-       btrfs_queue_work(rbio->fs_info->rmw_workers, &rbio->work);
-}
-
 /*
  * the stripe must be locked by the caller.  It will
  * unlock after all the writes are done
@@ -1599,7 +1565,7 @@ static int raid56_rmw_stripe(struct btrfs_raid_bio *rbio)
 
                bio->bi_private = rbio;
                bio->bi_end_io = raid_rmw_end_io;
-               bio_set_op_attrs(bio, REQ_OP_READ, 0);
+               bio->bi_opf = REQ_OP_READ;
 
                btrfs_bio_wq_end_io(rbio->fs_info, bio, BTRFS_WQ_ENDIO_RAID56);
 
@@ -1652,7 +1618,7 @@ static int partial_stripe_write(struct btrfs_raid_bio *rbio)
 
        ret = lock_stripe_add(rbio);
        if (ret == 0)
-               async_rmw_stripe(rbio);
+               start_async_work(rbio, rmw_work);
        return 0;
 }
 
@@ -1720,8 +1686,11 @@ static void run_plug(struct btrfs_plug_cb *plug)
                list_del_init(&cur->plug_list);
 
                if (rbio_is_full(cur)) {
+                       int ret;
+
                        /* we have a full stripe, send it down */
-                       full_stripe_write(cur);
+                       ret = full_stripe_write(cur);
+                       BUG_ON(ret);
                        continue;
                }
                if (last) {
@@ -1941,9 +1910,7 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio)
                        BUG_ON(failb != -1);
 pstripe:
                        /* Copy parity block into failed block to start with */
-                       memcpy(pointers[faila],
-                              pointers[rbio->nr_data],
-                              PAGE_SIZE);
+                       copy_page(pointers[faila], pointers[rbio->nr_data]);
 
                        /* rearrange the pointer array */
                        p = pointers[faila];
@@ -2145,7 +2112,7 @@ static int __raid56_parity_recover(struct btrfs_raid_bio *rbio)
 
                bio->bi_private = rbio;
                bio->bi_end_io = raid_recover_end_io;
-               bio_set_op_attrs(bio, REQ_OP_READ, 0);
+               bio->bi_opf = REQ_OP_READ;
 
                btrfs_bio_wq_end_io(rbio->fs_info, bio, BTRFS_WQ_ENDIO_RAID56);
 
@@ -2448,7 +2415,7 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio,
                                                pointers);
                } else {
                        /* raid5 */
-                       memcpy(pointers[nr_data], pointers[0], PAGE_SIZE);
+                       copy_page(pointers[nr_data], pointers[0]);
                        run_xor(pointers + 1, nr_data - 1, PAGE_SIZE);
                }
 
@@ -2456,7 +2423,7 @@ static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio,
                p = rbio_stripe_page(rbio, rbio->scrubp, pagenr);
                parity = kmap(p);
                if (memcmp(parity, pointers[rbio->scrubp], PAGE_SIZE))
-                       memcpy(parity, pointers[rbio->scrubp], PAGE_SIZE);
+                       copy_page(parity, pointers[rbio->scrubp]);
                else
                        /* Parity is right, needn't writeback */
                        bitmap_clear(rbio->dbitmap, pagenr, 1);
@@ -2517,7 +2484,7 @@ submit_write:
 
                bio->bi_private = rbio;
                bio->bi_end_io = raid_write_end_io;
-               bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
+               bio->bi_opf = REQ_OP_WRITE;
 
                submit_bio(bio);
        }
@@ -2699,7 +2666,7 @@ static void raid56_parity_scrub_stripe(struct btrfs_raid_bio *rbio)
 
                bio->bi_private = rbio;
                bio->bi_end_io = raid56_parity_scrub_end_io;
-               bio_set_op_attrs(bio, REQ_OP_READ, 0);
+               bio->bi_opf = REQ_OP_READ;
 
                btrfs_bio_wq_end_io(rbio->fs_info, bio, BTRFS_WQ_ENDIO_RAID56);
 
@@ -2728,18 +2695,10 @@ static void scrub_parity_work(struct btrfs_work *work)
        raid56_parity_scrub_stripe(rbio);
 }
 
-static void async_scrub_parity(struct btrfs_raid_bio *rbio)
-{
-       btrfs_init_work(&rbio->work, btrfs_rmw_helper,
-                       scrub_parity_work, NULL, NULL);
-
-       btrfs_queue_work(rbio->fs_info->rmw_workers, &rbio->work);
-}
-
 void raid56_parity_submit_scrub_rbio(struct btrfs_raid_bio *rbio)
 {
        if (!lock_stripe_add(rbio))
-               async_scrub_parity(rbio);
+               start_async_work(rbio, scrub_parity_work);
 }
 
 /* The following code is used for dev replace of a missing RAID 5/6 device. */
@@ -2781,5 +2740,5 @@ raid56_alloc_missing_rbio(struct btrfs_fs_info *fs_info, struct bio *bio,
 void raid56_submit_missing_rbio(struct btrfs_raid_bio *rbio)
 {
        if (!lock_stripe_add(rbio))
-               async_read_rebuild(rbio);
+               start_async_work(rbio, read_rebuild_work);
 }