diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-03-24 15:01:59 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:01 -0400 |
commit | 6324fbf334f4586325057197da7752f4ffa409d3 (patch) | |
tree | af67d90c3a58f48b91f73ac23f753f4f3907a453 /fs/btrfs/volumes.c | |
parent | 0b86a832a1f38abec695864ec2eaedc9d2383f1b (diff) |
Btrfs: Dynamic chunk and block group allocation
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 87 |
1 files changed, 53 insertions, 34 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 90a8d45dc6d7..a52a13f365d6 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -131,7 +131,7 @@ check_pending: | |||
131 | btrfs_release_path(root, path); | 131 | btrfs_release_path(root, path); |
132 | BUG_ON(*start < search_start); | 132 | BUG_ON(*start < search_start); |
133 | 133 | ||
134 | if (*start + num_bytes >= search_end) { | 134 | if (*start + num_bytes > search_end) { |
135 | ret = -ENOSPC; | 135 | ret = -ENOSPC; |
136 | goto error; | 136 | goto error; |
137 | } | 137 | } |
@@ -159,8 +159,9 @@ int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans, | |||
159 | return -ENOMEM; | 159 | return -ENOMEM; |
160 | 160 | ||
161 | ret = find_free_dev_extent(trans, device, path, num_bytes, start); | 161 | ret = find_free_dev_extent(trans, device, path, num_bytes, start); |
162 | if (ret) | 162 | if (ret) { |
163 | goto err; | 163 | goto err; |
164 | } | ||
164 | 165 | ||
165 | key.objectid = device->devid; | 166 | key.objectid = device->devid; |
166 | key.offset = *start; | 167 | key.offset = *start; |
@@ -214,22 +215,6 @@ error: | |||
214 | return ret; | 215 | return ret; |
215 | } | 216 | } |
216 | 217 | ||
217 | static struct btrfs_device *next_device(struct list_head *head, | ||
218 | struct list_head *last) | ||
219 | { | ||
220 | struct list_head *next = last->next; | ||
221 | struct btrfs_device *dev; | ||
222 | |||
223 | if (list_empty(head)) | ||
224 | return NULL; | ||
225 | |||
226 | if (next == head) | ||
227 | next = next->next; | ||
228 | |||
229 | dev = list_entry(next, struct btrfs_device, dev_list); | ||
230 | return dev; | ||
231 | } | ||
232 | |||
233 | static int find_next_devid(struct btrfs_root *root, struct btrfs_path *path, | 218 | static int find_next_devid(struct btrfs_root *root, struct btrfs_path *path, |
234 | u64 *objectid) | 219 | u64 *objectid) |
235 | { | 220 | { |
@@ -397,31 +382,63 @@ int btrfs_add_system_chunk(struct btrfs_trans_handle *trans, | |||
397 | 382 | ||
398 | int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | 383 | int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, |
399 | struct btrfs_root *extent_root, u64 *start, | 384 | struct btrfs_root *extent_root, u64 *start, |
400 | u64 *num_bytes, u32 type) | 385 | u64 *num_bytes, u64 type) |
401 | { | 386 | { |
402 | u64 dev_offset; | 387 | u64 dev_offset; |
403 | struct btrfs_root *chunk_root = extent_root->fs_info->chunk_root; | 388 | struct btrfs_root *chunk_root = extent_root->fs_info->chunk_root; |
404 | struct btrfs_stripe *stripes; | 389 | struct btrfs_stripe *stripes; |
405 | struct btrfs_device *device = NULL; | 390 | struct btrfs_device *device = NULL; |
406 | struct btrfs_chunk *chunk; | 391 | struct btrfs_chunk *chunk; |
392 | struct list_head private_devs; | ||
407 | struct list_head *dev_list = &extent_root->fs_info->devices; | 393 | struct list_head *dev_list = &extent_root->fs_info->devices; |
408 | struct list_head *last_dev = extent_root->fs_info->last_device; | 394 | struct list_head *cur; |
409 | struct extent_map_tree *em_tree; | 395 | struct extent_map_tree *em_tree; |
410 | struct map_lookup *map; | 396 | struct map_lookup *map; |
411 | struct extent_map *em; | 397 | struct extent_map *em; |
412 | u64 physical; | 398 | u64 physical; |
413 | u64 calc_size = 1024 * 1024 * 1024; | 399 | u64 calc_size = 1024 * 1024 * 1024; |
414 | int num_stripes; | 400 | u64 avail; |
401 | u64 max_avail = 0; | ||
402 | int num_stripes = 1; | ||
403 | int looped = 0; | ||
415 | int ret; | 404 | int ret; |
416 | int index = 0; | 405 | int index; |
417 | struct btrfs_key key; | 406 | struct btrfs_key key; |
418 | 407 | ||
408 | if (list_empty(dev_list)) | ||
409 | return -ENOSPC; | ||
410 | again: | ||
411 | INIT_LIST_HEAD(&private_devs); | ||
412 | cur = dev_list->next; | ||
413 | index = 0; | ||
414 | /* build a private list of devices we will allocate from */ | ||
415 | while(index < num_stripes) { | ||
416 | device = list_entry(cur, struct btrfs_device, dev_list); | ||
417 | avail = device->total_bytes - device->bytes_used; | ||
418 | cur = cur->next; | ||
419 | if (avail > max_avail) | ||
420 | max_avail = avail; | ||
421 | if (avail >= calc_size) { | ||
422 | list_move_tail(&device->dev_list, &private_devs); | ||
423 | index++; | ||
424 | } | ||
425 | if (cur == dev_list) | ||
426 | break; | ||
427 | } | ||
428 | if (index < num_stripes) { | ||
429 | list_splice(&private_devs, dev_list); | ||
430 | if (!looped && max_avail > 0) { | ||
431 | looped = 1; | ||
432 | calc_size = max_avail; | ||
433 | goto again; | ||
434 | } | ||
435 | return -ENOSPC; | ||
436 | } | ||
419 | 437 | ||
420 | ret = find_next_chunk(chunk_root, &key.objectid); | 438 | ret = find_next_chunk(chunk_root, &key.objectid); |
421 | if (ret) | 439 | if (ret) |
422 | return ret; | 440 | return ret; |
423 | 441 | ||
424 | num_stripes = 1; | ||
425 | chunk = kmalloc(btrfs_chunk_item_size(num_stripes), GFP_NOFS); | 442 | chunk = kmalloc(btrfs_chunk_item_size(num_stripes), GFP_NOFS); |
426 | if (!chunk) | 443 | if (!chunk) |
427 | return -ENOMEM; | 444 | return -ENOMEM; |
@@ -429,11 +446,12 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
429 | stripes = &chunk->stripe; | 446 | stripes = &chunk->stripe; |
430 | 447 | ||
431 | *num_bytes = calc_size; | 448 | *num_bytes = calc_size; |
449 | index = 0; | ||
432 | while(index < num_stripes) { | 450 | while(index < num_stripes) { |
433 | device = next_device(dev_list, last_dev); | 451 | BUG_ON(list_empty(&private_devs)); |
434 | BUG_ON(!device); | 452 | cur = private_devs.next; |
435 | last_dev = &device->dev_list; | 453 | device = list_entry(cur, struct btrfs_device, dev_list); |
436 | extent_root->fs_info->last_device = last_dev; | 454 | list_move_tail(&device->dev_list, dev_list); |
437 | 455 | ||
438 | ret = btrfs_alloc_dev_extent(trans, device, | 456 | ret = btrfs_alloc_dev_extent(trans, device, |
439 | key.objectid, | 457 | key.objectid, |
@@ -449,6 +467,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, | |||
449 | physical = dev_offset; | 467 | physical = dev_offset; |
450 | index++; | 468 | index++; |
451 | } | 469 | } |
470 | BUG_ON(!list_empty(&private_devs)); | ||
452 | 471 | ||
453 | /* key.objectid was set above */ | 472 | /* key.objectid was set above */ |
454 | key.offset = *num_bytes; | 473 | key.offset = *num_bytes; |
@@ -692,17 +711,17 @@ static int read_one_dev(struct btrfs_root *root, struct btrfs_key *key, | |||
692 | int ret; | 711 | int ret; |
693 | 712 | ||
694 | devid = btrfs_device_id(leaf, dev_item); | 713 | devid = btrfs_device_id(leaf, dev_item); |
695 | if (btrfs_find_device(root, devid)) | 714 | device = btrfs_find_device(root, devid); |
696 | return 0; | 715 | if (!device) { |
697 | 716 | device = kmalloc(sizeof(*device), GFP_NOFS); | |
698 | device = kmalloc(sizeof(*device), GFP_NOFS); | 717 | if (!device) |
699 | if (!device) | 718 | return -ENOMEM; |
700 | return -ENOMEM; | 719 | list_add(&device->dev_list, &root->fs_info->devices); |
720 | } | ||
701 | 721 | ||
702 | fill_device_from_item(leaf, dev_item, device); | 722 | fill_device_from_item(leaf, dev_item, device); |
703 | device->dev_root = root->fs_info->dev_root; | 723 | device->dev_root = root->fs_info->dev_root; |
704 | device->bdev = root->fs_info->sb->s_bdev; | 724 | device->bdev = root->fs_info->sb->s_bdev; |
705 | list_add(&device->dev_list, &root->fs_info->devices); | ||
706 | memcpy(&device->dev_key, key, sizeof(*key)); | 725 | memcpy(&device->dev_key, key, sizeof(*key)); |
707 | ret = 0; | 726 | ret = 0; |
708 | #if 0 | 727 | #if 0 |