btrfs: fix wrong free space information of btrfs
[pandora-kernel.git] / fs / btrfs / volumes.c
index c22784b..0c7f478 100644 (file)
@@ -728,6 +728,90 @@ error:
        return ret;
 }
 
+/* helper to account the used device space in the range */
+int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start,
+                                  u64 end, u64 *length)
+{
+       struct btrfs_key key;
+       struct btrfs_root *root = device->dev_root;
+       struct btrfs_dev_extent *dev_extent;
+       struct btrfs_path *path;
+       u64 extent_end;
+       int ret;
+       int slot;
+       struct extent_buffer *l;
+
+       *length = 0;
+
+       if (start >= device->total_bytes)
+               return 0;
+
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+       path->reada = 2;
+
+       key.objectid = device->devid;
+       key.offset = start;
+       key.type = BTRFS_DEV_EXTENT_KEY;
+
+       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+       if (ret < 0)
+               goto out;
+       if (ret > 0) {
+               ret = btrfs_previous_item(root, path, key.objectid, key.type);
+               if (ret < 0)
+                       goto out;
+       }
+
+       while (1) {
+               l = path->nodes[0];
+               slot = path->slots[0];
+               if (slot >= btrfs_header_nritems(l)) {
+                       ret = btrfs_next_leaf(root, path);
+                       if (ret == 0)
+                               continue;
+                       if (ret < 0)
+                               goto out;
+
+                       break;
+               }
+               btrfs_item_key_to_cpu(l, &key, slot);
+
+               if (key.objectid < device->devid)
+                       goto next;
+
+               if (key.objectid > device->devid)
+                       break;
+
+               if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY)
+                       goto next;
+
+               dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
+               extent_end = key.offset + btrfs_dev_extent_length(l,
+                                                                 dev_extent);
+               if (key.offset <= start && extent_end > end) {
+                       *length = end - start + 1;
+                       break;
+               } else if (key.offset <= start && extent_end > start)
+                       *length += extent_end - start;
+               else if (key.offset > start && extent_end <= end)
+                       *length += extent_end - key.offset;
+               else if (key.offset > start && key.offset <= end) {
+                       *length += end - key.offset + 1;
+                       break;
+               } else if (key.offset > end)
+                       break;
+
+next:
+               path->slots[0]++;
+       }
+       ret = 0;
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
 /*
  * find_free_dev_extent - find free space in the specified device
  * @trans:     transaction handler