diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-04-10 16:19:33 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:01 -0400 |
commit | f29844623de29a12358d7fba35d0959465b64adf (patch) | |
tree | 0268addb1a152cc1dbfdef1a50e32d6a7e97bdcf /fs/btrfs/disk-io.c | |
parent | 16432985920f3c45af82da214e2498f3e2f9066b (diff) |
Btrfs: Write out all super blocks on commit, and bring back proper barrier support
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r-- | fs/btrfs/disk-io.c | 118 |
1 files changed, 113 insertions, 5 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 59bdf0474be3..cf1de75f088a 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -382,7 +382,7 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, | |||
382 | BUG_ON(ret); | 382 | BUG_ON(ret); |
383 | 383 | ||
384 | if (offset == BTRFS_SUPER_INFO_OFFSET) { | 384 | if (offset == BTRFS_SUPER_INFO_OFFSET) { |
385 | bio->bi_bdev = root->fs_info->sb->s_bdev; | 385 | bio->bi_bdev = root->fs_info->fs_devices->latest_bdev; |
386 | submit_bio(rw, bio); | 386 | submit_bio(rw, bio); |
387 | return 0; | 387 | return 0; |
388 | } | 388 | } |
@@ -988,7 +988,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
988 | spin_lock_init(&fs_info->new_trans_lock); | 988 | spin_lock_init(&fs_info->new_trans_lock); |
989 | 989 | ||
990 | init_completion(&fs_info->kobj_unregister); | 990 | init_completion(&fs_info->kobj_unregister); |
991 | sb_set_blocksize(sb, 4096); | 991 | sb_set_blocksize(sb, BTRFS_SUPER_INFO_SIZE); |
992 | fs_info->tree_root = tree_root; | 992 | fs_info->tree_root = tree_root; |
993 | fs_info->extent_root = extent_root; | 993 | fs_info->extent_root = extent_root; |
994 | fs_info->chunk_root = chunk_root; | 994 | fs_info->chunk_root = chunk_root; |
@@ -1169,14 +1169,121 @@ fail: | |||
1169 | return ERR_PTR(err); | 1169 | return ERR_PTR(err); |
1170 | } | 1170 | } |
1171 | 1171 | ||
1172 | static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate) | ||
1173 | { | ||
1174 | char b[BDEVNAME_SIZE]; | ||
1175 | |||
1176 | if (uptodate) { | ||
1177 | set_buffer_uptodate(bh); | ||
1178 | } else { | ||
1179 | if (!buffer_eopnotsupp(bh) && printk_ratelimit()) { | ||
1180 | printk(KERN_WARNING "lost page write due to " | ||
1181 | "I/O error on %s\n", | ||
1182 | bdevname(bh->b_bdev, b)); | ||
1183 | } | ||
1184 | set_buffer_write_io_error(bh); | ||
1185 | clear_buffer_uptodate(bh); | ||
1186 | } | ||
1187 | unlock_buffer(bh); | ||
1188 | put_bh(bh); | ||
1189 | } | ||
1190 | |||
1191 | int write_all_supers(struct btrfs_root *root) | ||
1192 | { | ||
1193 | struct list_head *cur; | ||
1194 | struct list_head *head = &root->fs_info->fs_devices->devices; | ||
1195 | struct btrfs_device *dev; | ||
1196 | struct extent_buffer *sb; | ||
1197 | struct btrfs_dev_item *dev_item; | ||
1198 | struct buffer_head *bh; | ||
1199 | int ret; | ||
1200 | int do_barriers; | ||
1201 | |||
1202 | do_barriers = !btrfs_test_opt(root, NOBARRIER); | ||
1203 | |||
1204 | sb = root->fs_info->sb_buffer; | ||
1205 | dev_item = (struct btrfs_dev_item *)offsetof(struct btrfs_super_block, | ||
1206 | dev_item); | ||
1207 | list_for_each(cur, head) { | ||
1208 | dev = list_entry(cur, struct btrfs_device, dev_list); | ||
1209 | btrfs_set_device_type(sb, dev_item, dev->type); | ||
1210 | btrfs_set_device_id(sb, dev_item, dev->devid); | ||
1211 | btrfs_set_device_total_bytes(sb, dev_item, dev->total_bytes); | ||
1212 | btrfs_set_device_bytes_used(sb, dev_item, dev->bytes_used); | ||
1213 | btrfs_set_device_io_align(sb, dev_item, dev->io_align); | ||
1214 | btrfs_set_device_io_width(sb, dev_item, dev->io_width); | ||
1215 | btrfs_set_device_sector_size(sb, dev_item, dev->sector_size); | ||
1216 | write_extent_buffer(sb, dev->uuid, | ||
1217 | (unsigned long)btrfs_device_uuid(dev_item), | ||
1218 | BTRFS_DEV_UUID_SIZE); | ||
1219 | |||
1220 | btrfs_set_header_flag(sb, BTRFS_HEADER_FLAG_WRITTEN); | ||
1221 | csum_tree_block(root, sb, 0); | ||
1222 | |||
1223 | bh = __getblk(dev->bdev, BTRFS_SUPER_INFO_OFFSET / | ||
1224 | root->fs_info->sb->s_blocksize, | ||
1225 | BTRFS_SUPER_INFO_SIZE); | ||
1226 | |||
1227 | read_extent_buffer(sb, bh->b_data, 0, BTRFS_SUPER_INFO_SIZE); | ||
1228 | dev->pending_io = bh; | ||
1229 | |||
1230 | get_bh(bh); | ||
1231 | set_buffer_uptodate(bh); | ||
1232 | lock_buffer(bh); | ||
1233 | bh->b_end_io = btrfs_end_buffer_write_sync; | ||
1234 | |||
1235 | if (do_barriers && dev->barriers) { | ||
1236 | ret = submit_bh(WRITE_BARRIER, bh); | ||
1237 | if (ret == -EOPNOTSUPP) { | ||
1238 | printk("btrfs: disabling barriers on dev %s\n", | ||
1239 | dev->name); | ||
1240 | set_buffer_uptodate(bh); | ||
1241 | dev->barriers = 0; | ||
1242 | get_bh(bh); | ||
1243 | lock_buffer(bh); | ||
1244 | ret = submit_bh(WRITE, bh); | ||
1245 | } | ||
1246 | } else { | ||
1247 | ret = submit_bh(WRITE, bh); | ||
1248 | } | ||
1249 | BUG_ON(ret); | ||
1250 | } | ||
1251 | |||
1252 | list_for_each(cur, head) { | ||
1253 | dev = list_entry(cur, struct btrfs_device, dev_list); | ||
1254 | BUG_ON(!dev->pending_io); | ||
1255 | bh = dev->pending_io; | ||
1256 | wait_on_buffer(bh); | ||
1257 | if (!buffer_uptodate(dev->pending_io)) { | ||
1258 | if (do_barriers && dev->barriers) { | ||
1259 | printk("btrfs: disabling barriers on dev %s\n", | ||
1260 | dev->name); | ||
1261 | set_buffer_uptodate(bh); | ||
1262 | get_bh(bh); | ||
1263 | lock_buffer(bh); | ||
1264 | dev->barriers = 0; | ||
1265 | ret = submit_bh(WRITE, bh); | ||
1266 | BUG_ON(ret); | ||
1267 | wait_on_buffer(bh); | ||
1268 | BUG_ON(!buffer_uptodate(bh)); | ||
1269 | } else { | ||
1270 | BUG(); | ||
1271 | } | ||
1272 | |||
1273 | } | ||
1274 | dev->pending_io = NULL; | ||
1275 | brelse(bh); | ||
1276 | } | ||
1277 | return 0; | ||
1278 | } | ||
1279 | |||
1172 | int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root | 1280 | int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root |
1173 | *root) | 1281 | *root) |
1174 | { | 1282 | { |
1175 | int ret; | 1283 | int ret; |
1176 | struct extent_buffer *super = root->fs_info->sb_buffer; | ||
1177 | struct inode *btree_inode = root->fs_info->btree_inode; | ||
1178 | struct super_block *sb = root->fs_info->sb; | ||
1179 | 1284 | ||
1285 | ret = write_all_supers(root); | ||
1286 | #if 0 | ||
1180 | if (!btrfs_test_opt(root, NOBARRIER)) | 1287 | if (!btrfs_test_opt(root, NOBARRIER)) |
1181 | blkdev_issue_flush(sb->s_bdev, NULL); | 1288 | blkdev_issue_flush(sb->s_bdev, NULL); |
1182 | set_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree, super); | 1289 | set_extent_buffer_dirty(&BTRFS_I(btree_inode)->io_tree, super); |
@@ -1184,6 +1291,7 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1184 | super->start, super->len); | 1291 | super->start, super->len); |
1185 | if (!btrfs_test_opt(root, NOBARRIER)) | 1292 | if (!btrfs_test_opt(root, NOBARRIER)) |
1186 | blkdev_issue_flush(sb->s_bdev, NULL); | 1293 | blkdev_issue_flush(sb->s_bdev, NULL); |
1294 | #endif | ||
1187 | return ret; | 1295 | return ret; |
1188 | } | 1296 | } |
1189 | 1297 | ||