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 | |
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>
-rw-r--r-- | fs/btrfs/disk-io.c | 118 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 1 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 8 | ||||
-rw-r--r-- | fs/btrfs/volumes.h | 3 |
4 files changed, 122 insertions, 8 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 | ||
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 4fac0ccbf8f8..60b01902db79 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #define __DISKIO__ | 20 | #define __DISKIO__ |
21 | 21 | ||
22 | #define BTRFS_SUPER_INFO_OFFSET (16 * 1024) | 22 | #define BTRFS_SUPER_INFO_OFFSET (16 * 1024) |
23 | #define BTRFS_SUPER_INFO_SIZE 4096 | ||
23 | struct btrfs_device; | 24 | struct btrfs_device; |
24 | struct btrfs_fs_devices; | 25 | struct btrfs_fs_devices; |
25 | 26 | ||
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 3b927f698320..07d43553141c 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -125,6 +125,7 @@ static int device_list_add(const char *path, | |||
125 | return -ENOMEM; | 125 | return -ENOMEM; |
126 | } | 126 | } |
127 | device->devid = devid; | 127 | device->devid = devid; |
128 | device->barriers = 1; | ||
128 | device->name = kstrdup(path, GFP_NOFS); | 129 | device->name = kstrdup(path, GFP_NOFS); |
129 | if (!device->name) { | 130 | if (!device->name) { |
130 | kfree(device); | 131 | kfree(device); |
@@ -208,6 +209,7 @@ int btrfs_scan_one_device(const char *path, int flags, void *holder, | |||
208 | struct buffer_head *bh; | 209 | struct buffer_head *bh; |
209 | int ret; | 210 | int ret; |
210 | u64 devid; | 211 | u64 devid; |
212 | u64 transid; | ||
211 | 213 | ||
212 | mutex_lock(&uuid_mutex); | 214 | mutex_lock(&uuid_mutex); |
213 | 215 | ||
@@ -236,14 +238,14 @@ int btrfs_scan_one_device(const char *path, int flags, void *holder, | |||
236 | goto error_brelse; | 238 | goto error_brelse; |
237 | } | 239 | } |
238 | devid = le64_to_cpu(disk_super->dev_item.devid); | 240 | devid = le64_to_cpu(disk_super->dev_item.devid); |
239 | printk("found device %Lu on %s\n", devid, path); | 241 | transid = btrfs_super_generation(disk_super); |
242 | printk("found device %Lu transid %Lu on %s\n", devid, transid, path); | ||
240 | ret = device_list_add(path, disk_super, devid, fs_devices_ret); | 243 | ret = device_list_add(path, disk_super, devid, fs_devices_ret); |
241 | 244 | ||
242 | error_brelse: | 245 | error_brelse: |
243 | brelse(bh); | 246 | brelse(bh); |
244 | error_close: | 247 | error_close: |
245 | close_bdev_excl(bdev); | 248 | close_bdev_excl(bdev); |
246 | printk("scan one closes bdev %s\n", path); | ||
247 | error: | 249 | error: |
248 | mutex_unlock(&uuid_mutex); | 250 | mutex_unlock(&uuid_mutex); |
249 | return ret; | 251 | return ret; |
@@ -1143,7 +1145,7 @@ static int read_one_dev(struct btrfs_root *root, | |||
1143 | device = btrfs_find_device(root, devid); | 1145 | device = btrfs_find_device(root, devid); |
1144 | if (!device) { | 1146 | if (!device) { |
1145 | printk("warning devid %Lu not found already\n", devid); | 1147 | printk("warning devid %Lu not found already\n", devid); |
1146 | device = kmalloc(sizeof(*device), GFP_NOFS); | 1148 | device = kzalloc(sizeof(*device), GFP_NOFS); |
1147 | if (!device) | 1149 | if (!device) |
1148 | return -ENOMEM; | 1150 | return -ENOMEM; |
1149 | list_add(&device->dev_list, | 1151 | list_add(&device->dev_list, |
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 3d5d0a9cb827..89548837a1cc 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h | |||
@@ -21,9 +21,12 @@ | |||
21 | 21 | ||
22 | #include <linux/bio.h> | 22 | #include <linux/bio.h> |
23 | 23 | ||
24 | struct buffer_head; | ||
24 | struct btrfs_device { | 25 | struct btrfs_device { |
25 | struct list_head dev_list; | 26 | struct list_head dev_list; |
26 | struct btrfs_root *dev_root; | 27 | struct btrfs_root *dev_root; |
28 | struct buffer_head *pending_io; | ||
29 | int barriers; | ||
27 | spinlock_t io_lock; | 30 | spinlock_t io_lock; |
28 | 31 | ||
29 | struct block_device *bdev; | 32 | struct block_device *bdev; |