aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/volumes.c
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2011-01-05 05:07:31 -0500
committerChris Mason <chris.mason@oracle.com>2011-01-16 11:30:19 -0500
commit6d07bcec969af335d4e35b3921131b7929bd634e (patch)
tree2d1e0bb5f69bdf9dafa2862b6cad965184d67c84 /fs/btrfs/volumes.c
parentb2117a39fa96cf4814e7cab8c11494149ba6f29d (diff)
btrfs: fix wrong free space information of btrfs
When we store data by raid profile in btrfs with two or more different size disks, df command shows there is some free space in the filesystem, but the user can not write any data in fact, df command shows the wrong free space information of btrfs. # mkfs.btrfs -d raid1 /dev/sda9 /dev/sda10 # btrfs-show Label: none uuid: a95cd49e-6e33-45b8-8741-a36153ce4b64 Total devices 2 FS bytes used 28.00KB devid 1 size 5.01GB used 2.03GB path /dev/sda9 devid 2 size 10.00GB used 2.01GB path /dev/sda10 # btrfs device scan /dev/sda9 /dev/sda10 # mount /dev/sda9 /mnt # dd if=/dev/zero of=tmpfile0 bs=4K count=9999999999 (fill the filesystem) # sync # df -TH Filesystem Type Size Used Avail Use% Mounted on /dev/sda9 btrfs 17G 8.6G 5.4G 62% /mnt # btrfs-show Label: none uuid: a95cd49e-6e33-45b8-8741-a36153ce4b64 Total devices 2 FS bytes used 3.99GB devid 1 size 5.01GB used 5.01GB path /dev/sda9 devid 2 size 10.00GB used 4.99GB path /dev/sda10 It is because btrfs cannot allocate chunks when one of the pairing disks has no space, the free space on the other disks can not be used for ever, and should be subtracted from the total space, but btrfs doesn't subtract this space from the total. It is strange to the user. This patch fixes it by calcing the free space that can be used to allocate chunks. Implementation: 1. get all the devices free space, and align them by stripe length. 2. sort the devices by the free space. 3. check the free space of the devices, 3.1. if it is not zero, and then check the number of the devices that has more free space than this device, if the number of the devices is beyond the min stripe number, the free space can be used, and add into total free space. if the number of the devices is below the min stripe number, we can not use the free space, the check ends. 3.2. if the free space is zero, check the next devices, goto 3.1 This implementation is just likely fake chunk allocation. After appling this patch, df can show correct space information: # df -TH Filesystem Type Size Used Avail Use% Mounted on /dev/sda9 btrfs 17G 8.6G 0 100% /mnt Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/volumes.c')
-rw-r--r--fs/btrfs/volumes.c84
1 files changed, 84 insertions, 0 deletions
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index c22784b989b7..0c7f478cf645 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -728,6 +728,90 @@ error:
728 return ret; 728 return ret;
729} 729}
730 730
731/* helper to account the used device space in the range */
732int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start,
733 u64 end, u64 *length)
734{
735 struct btrfs_key key;
736 struct btrfs_root *root = device->dev_root;
737 struct btrfs_dev_extent *dev_extent;
738 struct btrfs_path *path;
739 u64 extent_end;
740 int ret;
741 int slot;
742 struct extent_buffer *l;
743
744 *length = 0;
745
746 if (start >= device->total_bytes)
747 return 0;
748
749 path = btrfs_alloc_path();
750 if (!path)
751 return -ENOMEM;
752 path->reada = 2;
753
754 key.objectid = device->devid;
755 key.offset = start;
756 key.type = BTRFS_DEV_EXTENT_KEY;
757
758 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
759 if (ret < 0)
760 goto out;
761 if (ret > 0) {
762 ret = btrfs_previous_item(root, path, key.objectid, key.type);
763 if (ret < 0)
764 goto out;
765 }
766
767 while (1) {
768 l = path->nodes[0];
769 slot = path->slots[0];
770 if (slot >= btrfs_header_nritems(l)) {
771 ret = btrfs_next_leaf(root, path);
772 if (ret == 0)
773 continue;
774 if (ret < 0)
775 goto out;
776
777 break;
778 }
779 btrfs_item_key_to_cpu(l, &key, slot);
780
781 if (key.objectid < device->devid)
782 goto next;
783
784 if (key.objectid > device->devid)
785 break;
786
787 if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY)
788 goto next;
789
790 dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
791 extent_end = key.offset + btrfs_dev_extent_length(l,
792 dev_extent);
793 if (key.offset <= start && extent_end > end) {
794 *length = end - start + 1;
795 break;
796 } else if (key.offset <= start && extent_end > start)
797 *length += extent_end - start;
798 else if (key.offset > start && extent_end <= end)
799 *length += extent_end - key.offset;
800 else if (key.offset > start && key.offset <= end) {
801 *length += end - key.offset + 1;
802 break;
803 } else if (key.offset > end)
804 break;
805
806next:
807 path->slots[0]++;
808 }
809 ret = 0;
810out:
811 btrfs_free_path(path);
812 return ret;
813}
814
731/* 815/*
732 * find_free_dev_extent - find free space in the specified device 816 * find_free_dev_extent - find free space in the specified device
733 * @trans: transaction handler 817 * @trans: transaction handler