summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/disk-io.c43
1 files changed, 29 insertions, 14 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index b7ddc77fa568..0d50d49d990a 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2020,6 +2020,17 @@ struct buffer_head *btrfs_read_dev_super(struct block_device *bdev)
return latest;
}
+/*
+ * this should be called twice, once with wait == 0 and
+ * once with wait == 1. When wait == 0 is done, all the buffer heads
+ * we write are pinned.
+ *
+ * They are released when wait == 1 is done.
+ * max_mirrors must be the same for both runs, and it indicates how
+ * many supers on this one device should be written.
+ *
+ * max_mirrors == 0 means to write them all.
+ */
static int write_dev_supers(struct btrfs_device *device,
struct btrfs_super_block *sb,
int do_barriers, int wait, int max_mirrors)
@@ -2055,12 +2066,16 @@ static int write_dev_supers(struct btrfs_device *device,
bh = __find_get_block(device->bdev, bytenr / 4096,
BTRFS_SUPER_INFO_SIZE);
BUG_ON(!bh);
- brelse(bh);
wait_on_buffer(bh);
- if (buffer_uptodate(bh)) {
- brelse(bh);
- continue;
- }
+ if (!buffer_uptodate(bh))
+ errors++;
+
+ /* drop our reference */
+ brelse(bh);
+
+ /* drop the reference from the wait == 0 run */
+ brelse(bh);
+ continue;
} else {
btrfs_set_super_bytenr(sb, bytenr);
@@ -2071,12 +2086,18 @@ static int write_dev_supers(struct btrfs_device *device,
BTRFS_CSUM_SIZE);
btrfs_csum_final(crc, sb->csum);
+ /*
+ * one reference for us, and we leave it for the
+ * caller
+ */
bh = __getblk(device->bdev, bytenr / 4096,
BTRFS_SUPER_INFO_SIZE);
memcpy(bh->b_data, sb, BTRFS_SUPER_INFO_SIZE);
- set_buffer_uptodate(bh);
+ /* one reference for submit_bh */
get_bh(bh);
+
+ set_buffer_uptodate(bh);
lock_buffer(bh);
bh->b_end_io = btrfs_end_buffer_write_sync;
}
@@ -2088,6 +2109,7 @@ static int write_dev_supers(struct btrfs_device *device,
device->name);
set_buffer_uptodate(bh);
device->barriers = 0;
+ /* one reference for submit_bh */
get_bh(bh);
lock_buffer(bh);
ret = submit_bh(WRITE_SYNC, bh);
@@ -2096,15 +2118,8 @@ static int write_dev_supers(struct btrfs_device *device,
ret = submit_bh(WRITE_SYNC, bh);
}
- if (!ret && wait) {
- wait_on_buffer(bh);
- if (!buffer_uptodate(bh))
- errors++;
- } else if (ret) {
+ if (ret)
errors++;
- }
- if (wait)
- brelse(bh);
}
return errors < i ? 0 : -1;
}