aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/disk-io.c
diff options
context:
space:
mode:
authorHisashi Hifumi <hifumi.hisashi@oss.ntt.co.jp>2009-06-10 15:28:55 -0400
committerChris Mason <chris.mason@oracle.com>2009-06-10 16:49:25 -0400
commit4eedeb75e7f15ffdb12d1ad559b565e7505bdbaf (patch)
tree2f78c56c30d5f4f96b85d012bcb412262f6a735c /fs/btrfs/disk-io.c
parente5e9a5206a171b2c467e494aebcdcf70c47289bc (diff)
Btrfs: pin buffers during write_dev_supers
write_dev_supers is called in sequence. First is it called with wait == 0, which starts IO on all of the super blocks for a given device. Then it is called with wait == 1 to make sure they all reach the disk. It doesn't currently pin the buffers between the two calls, and it also assumes the buffers won't go away between the two calls, leading to an oops if the VM manages to free the buffers in the middle of the sync. This fixes that assumption and updates the code to return an error if things are not up to date when the wait == 1 run is done. Signed-off-by: Hisashi Hifumi <hifumi.hisashi@oss.ntt.co.jp> Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-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)
2020 return latest; 2020 return latest;
2021} 2021}
2022 2022
2023/*
2024 * this should be called twice, once with wait == 0 and
2025 * once with wait == 1. When wait == 0 is done, all the buffer heads
2026 * we write are pinned.
2027 *
2028 * They are released when wait == 1 is done.
2029 * max_mirrors must be the same for both runs, and it indicates how
2030 * many supers on this one device should be written.
2031 *
2032 * max_mirrors == 0 means to write them all.
2033 */
2023static int write_dev_supers(struct btrfs_device *device, 2034static int write_dev_supers(struct btrfs_device *device,
2024 struct btrfs_super_block *sb, 2035 struct btrfs_super_block *sb,
2025 int do_barriers, int wait, int max_mirrors) 2036 int do_barriers, int wait, int max_mirrors)
@@ -2055,12 +2066,16 @@ static int write_dev_supers(struct btrfs_device *device,
2055 bh = __find_get_block(device->bdev, bytenr / 4096, 2066 bh = __find_get_block(device->bdev, bytenr / 4096,
2056 BTRFS_SUPER_INFO_SIZE); 2067 BTRFS_SUPER_INFO_SIZE);
2057 BUG_ON(!bh); 2068 BUG_ON(!bh);
2058 brelse(bh);
2059 wait_on_buffer(bh); 2069 wait_on_buffer(bh);
2060 if (buffer_uptodate(bh)) { 2070 if (!buffer_uptodate(bh))
2061 brelse(bh); 2071 errors++;
2062 continue; 2072
2063 } 2073 /* drop our reference */
2074 brelse(bh);
2075
2076 /* drop the reference from the wait == 0 run */
2077 brelse(bh);
2078 continue;
2064 } else { 2079 } else {
2065 btrfs_set_super_bytenr(sb, bytenr); 2080 btrfs_set_super_bytenr(sb, bytenr);
2066 2081
@@ -2071,12 +2086,18 @@ static int write_dev_supers(struct btrfs_device *device,
2071 BTRFS_CSUM_SIZE); 2086 BTRFS_CSUM_SIZE);
2072 btrfs_csum_final(crc, sb->csum); 2087 btrfs_csum_final(crc, sb->csum);
2073 2088
2089 /*
2090 * one reference for us, and we leave it for the
2091 * caller
2092 */
2074 bh = __getblk(device->bdev, bytenr / 4096, 2093 bh = __getblk(device->bdev, bytenr / 4096,
2075 BTRFS_SUPER_INFO_SIZE); 2094 BTRFS_SUPER_INFO_SIZE);
2076 memcpy(bh->b_data, sb, BTRFS_SUPER_INFO_SIZE); 2095 memcpy(bh->b_data, sb, BTRFS_SUPER_INFO_SIZE);
2077 2096
2078 set_buffer_uptodate(bh); 2097 /* one reference for submit_bh */
2079 get_bh(bh); 2098 get_bh(bh);
2099
2100 set_buffer_uptodate(bh);
2080 lock_buffer(bh); 2101 lock_buffer(bh);
2081 bh->b_end_io = btrfs_end_buffer_write_sync; 2102 bh->b_end_io = btrfs_end_buffer_write_sync;
2082 } 2103 }
@@ -2088,6 +2109,7 @@ static int write_dev_supers(struct btrfs_device *device,
2088 device->name); 2109 device->name);
2089 set_buffer_uptodate(bh); 2110 set_buffer_uptodate(bh);
2090 device->barriers = 0; 2111 device->barriers = 0;
2112 /* one reference for submit_bh */
2091 get_bh(bh); 2113 get_bh(bh);
2092 lock_buffer(bh); 2114 lock_buffer(bh);
2093 ret = submit_bh(WRITE_SYNC, bh); 2115 ret = submit_bh(WRITE_SYNC, bh);
@@ -2096,15 +2118,8 @@ static int write_dev_supers(struct btrfs_device *device,
2096 ret = submit_bh(WRITE_SYNC, bh); 2118 ret = submit_bh(WRITE_SYNC, bh);
2097 } 2119 }
2098 2120
2099 if (!ret && wait) { 2121 if (ret)
2100 wait_on_buffer(bh);
2101 if (!buffer_uptodate(bh))
2102 errors++;
2103 } else if (ret) {
2104 errors++; 2122 errors++;
2105 }
2106 if (wait)
2107 brelse(bh);
2108 } 2123 }
2109 return errors < i ? 0 : -1; 2124 return errors < i ? 0 : -1;
2110} 2125}