summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/disk-io.c25
-rw-r--r--fs/btrfs/volumes.c12
-rw-r--r--fs/btrfs/volumes.h1
3 files changed, 20 insertions, 18 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 2ac0a35f4450..bfcbab3a7607 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3481,9 +3481,7 @@ static int write_dev_supers(struct btrfs_device *device,
*/
static void btrfs_end_empty_barrier(struct bio *bio)
{
- if (bio->bi_private)
- complete(bio->bi_private);
- bio_put(bio);
+ complete(bio->bi_private);
}
/*
@@ -3493,26 +3491,20 @@ static void btrfs_end_empty_barrier(struct bio *bio)
static void write_dev_flush(struct btrfs_device *device)
{
struct request_queue *q = bdev_get_queue(device->bdev);
- struct bio *bio;
+ struct bio *bio = device->flush_bio;
if (!test_bit(QUEUE_FLAG_WC, &q->queue_flags))
return;
- /*
- * one reference for us, and we leave it for the
- * caller
- */
- device->flush_bio = NULL;
- bio = btrfs_io_bio_alloc(0);
+ bio_reset(bio);
bio->bi_end_io = btrfs_end_empty_barrier;
bio->bi_bdev = device->bdev;
bio->bi_opf = REQ_OP_WRITE | REQ_SYNC | REQ_PREFLUSH;
init_completion(&device->flush_wait);
bio->bi_private = &device->flush_wait;
- device->flush_bio = bio;
- bio_get(bio);
- btrfsic_submit_bio(bio);
+ submit_bio(bio);
+ device->flush_bio_sent = 1;
}
/*
@@ -3523,9 +3515,10 @@ static int wait_dev_flush(struct btrfs_device *device)
int ret = 0;
struct bio *bio = device->flush_bio;
- if (!bio)
+ if (!device->flush_bio_sent)
return 0;
+ device->flush_bio_sent = 0;
wait_for_completion(&device->flush_wait);
if (bio->bi_error) {
@@ -3534,10 +3527,6 @@ static int wait_dev_flush(struct btrfs_device *device)
BTRFS_DEV_STAT_FLUSH_ERRS);
}
- /* drop the reference from the wait == 0 run */
- bio_put(bio);
- device->flush_bio = NULL;
-
return ret;
}
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 2090245e8f06..c95f018d4a1e 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -242,6 +242,17 @@ static struct btrfs_device *__alloc_device(void)
if (!dev)
return ERR_PTR(-ENOMEM);
+ /*
+ * Preallocate a bio that's always going to be used for flushing device
+ * barriers and matches the device lifespan
+ */
+ dev->flush_bio = bio_alloc_bioset(GFP_KERNEL, 0, NULL);
+ if (!dev->flush_bio) {
+ kfree(dev);
+ return ERR_PTR(-ENOMEM);
+ }
+ bio_get(dev->flush_bio);
+
INIT_LIST_HEAD(&dev->dev_list);
INIT_LIST_HEAD(&dev->dev_alloc_list);
INIT_LIST_HEAD(&dev->resized_list);
@@ -838,6 +849,7 @@ static void __free_device(struct work_struct *work)
device = container_of(work, struct btrfs_device, rcu_work);
rcu_string_free(device->name);
+ bio_put(device->flush_bio);
kfree(device);
}
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 35327efecdbb..6f45fd60d15a 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -75,6 +75,7 @@ struct btrfs_device {
int can_discard;
int is_tgtdev_for_dev_replace;
int last_flush_error;
+ int flush_bio_sent;
#ifdef __BTRFS_NEED_DEVICE_DATA_ORDERED
seqcount_t data_seqcount;