Help with btrfs project
Nick Krause
xerofoify at gmail.com
Tue Aug 19 22:33:28 EDT 2014
Hey Guys,
This commit seems to be needed to fixed up based on what the btrfs
developers, are stating on their wiki.
Other then the TODO list, which we can discuss here, is there any
other parts of this patch that need to
be rewritten, it's merged as of now but I can recreate new patches if
needed from Linus's tree. The project
idea is Clear unallocated space on the btrfs wiki. I AM NOT asking you
to write the code just want to known
is how you want this cleaned up.
Cheers Nick
>From 55ec5c00022be8f2bbed06b99b5f4be5832a5451 Mon Sep 17 00:00:00 2001
From: David Sterba <dsterba at suse.cz>
Date: Thu, 19 Apr 2012 15:09:09 +0200
Subject: [PATCH 1/1] btrfs: ioctl to clear unused space
abuse discard infrastructure and pass down whether we want to trim or
just zero out. works, does not corrupt data.
TODO:
- more options how to clean (ie. a known signature of freed block, 2
types of them, or random garbage, or all zeros)
- what to do for SSD mixed with HDD ?
Signed-off-by: David Sterba <dsterba at suse.cz>
---
fs/btrfs/ctree.h | 5 ++-
fs/btrfs/disk-io.c | 2 +-
fs/btrfs/extent-tree.c | 86 +++++++++++++++++++++++++++++++++++++------
fs/btrfs/free-space-cache.c | 24 +++++++----
fs/btrfs/free-space-cache.h | 3 +-
fs/btrfs/ioctl.c | 29 ++++++++++++++
fs/btrfs/ioctl.h | 9 ++++
7 files changed, 134 insertions(+), 24 deletions(-)
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index fa5c45b..e7a87cb 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -2655,7 +2655,10 @@ u64
btrfs_account_ro_block_groups_free_space(struct btrfs_space_info
*sinfo);
int btrfs_error_unpin_extent_range(struct btrfs_root *root,
u64 start, u64 end);
int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr,
- u64 num_bytes, u64 *actual_bytes);
+ u64 num_bytes, u64 *actual_bytes,
+ int do_trim);
+int btrfs_clear_free_space(struct btrfs_root *root,
+ struct btrfs_ioctl_clear_free_args *range);
int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 type);
int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range);
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 2936ca4..77a704d 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -3580,7 +3580,7 @@ again:
if (btrfs_test_opt(root, DISCARD))
ret = btrfs_error_discard_extent(root, start,
end + 1 - start,
- NULL);
+ NULL, 1);
clear_extent_dirty(unpin, start, end, GFP_NOFS);
btrfs_error_unpin_extent_range(root, start, end);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 6e1d367..26514b9 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1818,35 +1818,50 @@ static int remove_extent_backref(struct
btrfs_trans_handle *trans,
}
static int btrfs_issue_discard(struct block_device *bdev,
- u64 start, u64 len)
+ u64 start, u64 len, int do_trim)
{
- return blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_NOFS, 0);
+ printk(KERN_DEBUG "ISSUE ZERO start %llu len %llu\n",
+ (unsigned long long)start, (unsigned long long)len);
+ if (do_trim) {
+ return blkdev_issue_discard(bdev, start >> 9, len >> 9,
+ GFP_NOFS, 0);
+ } else {
+ return blkdev_issue_zeroout(bdev, start >> 9, len >> 9,
+ GFP_NOFS);
+ }
}
static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
- u64 num_bytes, u64 *actual_bytes)
+ u64 num_bytes, u64 *actual_bytes, int do_trim)
{
int ret;
u64 discarded_bytes = 0;
struct btrfs_bio *bbio = NULL;
+ int rw;
+
+ printk(KERN_DEBUG "discard extent %d: bytenr %llu len %llu\n", do_trim,
+ (unsigned long long)bytenr,
+ (unsigned long long)num_bytes);
+ rw = do_trim ? REQ_DISCARD : REQ_WRITE;
+ rw = REQ_DISCARD;
/* Tell the block device(s) that the sectors can be discarded */
- ret = btrfs_map_block(&root->fs_info->mapping_tree, REQ_DISCARD,
+ ret = btrfs_map_block(&root->fs_info->mapping_tree, rw,
bytenr, &num_bytes, &bbio, 0);
/* Error condition is -ENOMEM */
if (!ret) {
struct btrfs_bio_stripe *stripe = bbio->stripes;
int i;
-
for (i = 0; i < bbio->num_stripes; i++, stripe++) {
- if (!stripe->dev->can_discard)
+ if (do_trim && !stripe->dev->can_discard)
continue;
ret = btrfs_issue_discard(stripe->dev->bdev,
stripe->physical,
- stripe->length);
+ stripe->length,
+ do_trim);
if (!ret)
discarded_bytes += stripe->length;
else if (ret != -EOPNOTSUPP)
@@ -4924,7 +4939,7 @@ int btrfs_finish_extent_commit(struct
btrfs_trans_handle *trans,
if (btrfs_test_opt(root, DISCARD))
ret = btrfs_discard_extent(root, start,
- end + 1 - start, NULL);
+ end + 1 - start, NULL, 1);
clear_extent_dirty(unpin, start, end, GFP_NOFS);
unpin_extent_range(root, start, end);
@@ -5905,7 +5920,7 @@ static int __btrfs_free_reserved_extent(struct
btrfs_root *root,
}
if (btrfs_test_opt(root, DISCARD))
- ret = btrfs_discard_extent(root, start, len, NULL);
+ ret = btrfs_discard_extent(root, start, len, NULL, 1);
if (pin)
pin_down_extent(root, cache, start, len, 1);
@@ -7966,9 +7981,10 @@ int btrfs_error_unpin_extent_range(struct
btrfs_root *root, u64 start, u64 end)
}
int btrfs_error_discard_extent(struct btrfs_root *root, u64 bytenr,
- u64 num_bytes, u64 *actual_bytes)
+ u64 num_bytes, u64 *actual_bytes, int do_trim)
{
- return btrfs_discard_extent(root, bytenr, num_bytes, actual_bytes);
+ return btrfs_discard_extent(root, bytenr, num_bytes, actual_bytes,
+ do_trim);
}
int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range)
@@ -8010,7 +8026,8 @@ int btrfs_trim_fs(struct btrfs_root *root,
struct fstrim_range *range)
&group_trimmed,
start,
end,
- range->minlen);
+ range->minlen,
+ 1);
trimmed += group_trimmed;
if (ret) {
@@ -8025,3 +8042,48 @@ int btrfs_trim_fs(struct btrfs_root *root,
struct fstrim_range *range)
range->len = trimmed;
return ret;
}
+
+int btrfs_clear_free_space(struct btrfs_root *root, struct
btrfs_ioctl_clear_free_args *range)
+{
+ struct btrfs_fs_info *fs_info = root->fs_info;
+ struct btrfs_block_group_cache *cache = NULL;
+ u64 group_trimmed;
+ u64 start;
+ u64 end;
+ int ret = 0;
+
+ range->start = 0;
+ range->length = 1*1024*1024*1024ULL; // 1G
+ range->minlen = 0;
+ cache = btrfs_lookup_first_block_group(fs_info, range->start);
+
+ while (cache) {
+ if (cache->key.objectid >= (range->start + range->length)) {
+ btrfs_put_block_group(cache);
+ break;
+ }
+
+ start = max(range->start, cache->key.objectid);
+ end = min(range->start + range->length,
+ cache->key.objectid + cache->key.offset);
+
+ if (end - start >= range->minlength) {
+ if (!block_group_cache_done(cache)) {
+ ret = cache_block_group(cache, NULL, root, 0);
+ if (!ret)
+ wait_block_group_cache_done(cache);
+ }
+ ret = btrfs_trim_block_group(cache, &group_trimmed,
+ start, end, range->minlen, 0);
+
+ if (ret) {
+ btrfs_put_block_group(cache);
+ break;
+ }
+ }
+
+ cache = next_block_group(fs_info->tree_root, cache);
+ }
+
+ return ret;
+}
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index 6c4e2ba..e109aea 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -2590,7 +2590,8 @@ void btrfs_init_free_cluster(struct
btrfs_free_cluster *cluster)
static int do_trimming(struct btrfs_block_group_cache *block_group,
u64 *total_trimmed, u64 start, u64 bytes,
- u64 reserved_start, u64 reserved_bytes)
+ u64 reserved_start, u64 reserved_bytes,
+ int do_trim)
{
struct btrfs_space_info *space_info = block_group->space_info;
struct btrfs_fs_info *fs_info = block_group->fs_info;
@@ -2609,7 +2610,8 @@ static int do_trimming(struct
btrfs_block_group_cache *block_group,
spin_unlock(&space_info->lock);
ret = btrfs_error_discard_extent(fs_info->extent_root,
- start, bytes, &trimmed);
+ start, bytes, &trimmed,
+ do_trim);
if (!ret)
*total_trimmed += trimmed;
@@ -2630,7 +2632,8 @@ static int do_trimming(struct
btrfs_block_group_cache *block_group,
}
static int trim_no_bitmap(struct btrfs_block_group_cache *block_group,
- u64 *total_trimmed, u64 start, u64 end, u64 minlen)
+ u64 *total_trimmed, u64 start, u64 end, u64 minlen,
+ int do_trim)
{
struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
struct btrfs_free_space *entry;
@@ -2685,7 +2688,7 @@ static int trim_no_bitmap(struct
btrfs_block_group_cache *block_group,
spin_unlock(&ctl->tree_lock);
ret = do_trimming(block_group, total_trimmed, start, bytes,
- extent_start, extent_bytes);
+ extent_start, extent_bytes, do_trim);
if (ret)
break;
next:
@@ -2703,7 +2706,8 @@ out:
}
static int trim_bitmaps(struct btrfs_block_group_cache *block_group,
- u64 *total_trimmed, u64 start, u64 end, u64 minlen)
+ u64 *total_trimmed, u64 start, u64 end, u64 minlen,
+ int do_trim)
{
struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
struct btrfs_free_space *entry;
@@ -2750,7 +2754,7 @@ static int trim_bitmaps(struct
btrfs_block_group_cache *block_group,
spin_unlock(&ctl->tree_lock);
ret = do_trimming(block_group, total_trimmed, start, bytes,
- start, bytes);
+ start, bytes, do_trim);
if (ret)
break;
next:
@@ -2774,17 +2778,19 @@ next:
}
int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
- u64 *trimmed, u64 start, u64 end, u64 minlen)
+ u64 *trimmed, u64 start, u64 end, u64 minlen,
+ int do_trim)
{
int ret;
*trimmed = 0;
- ret = trim_no_bitmap(block_group, trimmed, start, end, minlen);
+ ret = trim_no_bitmap(block_group, trimmed, start, end, minlen,
+ do_trim);
if (ret)
return ret;
- ret = trim_bitmaps(block_group, trimmed, start, end, minlen);
+ ret = trim_bitmaps(block_group, trimmed, start, end, minlen, do_trim);
return ret;
}
diff --git a/fs/btrfs/free-space-cache.h b/fs/btrfs/free-space-cache.h
index 8f2613f..b3b0217 100644
--- a/fs/btrfs/free-space-cache.h
+++ b/fs/btrfs/free-space-cache.h
@@ -109,5 +109,6 @@ int btrfs_return_cluster_to_free_space(
struct btrfs_block_group_cache *block_group,
struct btrfs_free_cluster *cluster);
int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
- u64 *trimmed, u64 start, u64 end, u64 minlen);
+ u64 *trimmed, u64 start, u64 end, u64 minlen,
+ int do_trim);
#endif
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 0e92e57..489791e 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -3390,6 +3390,33 @@ out:
return ret;
}
+static noinline int btrfs_ioctl_clear_free(struct file *file, void __user *arg)
+{
+ struct btrfs_fs_info *fs_info = btrfs_sb(fdentry(file)->d_sb);
+ struct btrfs_ioctl_clear_free_args range;
+ u64 total_bytes = btrfs_super_total_bytes(fs_info->super_copy);
+ int ret;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user(&range, arg, sizeof(range)))
+ return -EFAULT;
+ if (range.start > total_bytes)
+ return -EINVAL;
+
+ /* range ignored */
+ printk(KERN_DEBUG "ioctl: clear free\n");
+ ret = btrfs_clear_free_space(fs_info->tree_root, &range);
+ if (ret < 0)
+ return ret;
+
+ if (copy_to_user(arg, &range, sizeof(range)))
+ return -EFAULT;
+
+ return 0;
+}
+
long btrfs_ioctl(struct file *file, unsigned int
cmd, unsigned long arg)
{
@@ -3476,6 +3503,8 @@ long btrfs_ioctl(struct file *file, unsigned int
return btrfs_ioctl_get_dev_stats(root, argp, 0);
case BTRFS_IOC_GET_AND_RESET_DEV_STATS:
return btrfs_ioctl_get_dev_stats(root, argp, 1);
+ case BTRFS_IOC_CLEAR_FREE:
+ return btrfs_ioctl_clear_free(file, argp);
}
return -ENOTTY;
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
index e440aa6..52af4a9 100644
--- a/fs/btrfs/ioctl.h
+++ b/fs/btrfs/ioctl.h
@@ -295,6 +295,13 @@ struct btrfs_ioctl_get_dev_stats {
__u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */
};
+struct btrfs_ioctl_clear_free_args {
+ __u64 start; /* in */
+ __u64 length; /* in */
+ __u64 minlen; /* in */
+ __u64 reserved[125];
+};
+
#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
struct btrfs_ioctl_vol_args)
#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
@@ -363,5 +370,7 @@ struct btrfs_ioctl_get_dev_stats {
struct btrfs_ioctl_get_dev_stats)
#define BTRFS_IOC_GET_AND_RESET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 53, \
struct btrfs_ioctl_get_dev_stats)
+#define BTRFS_IOC_CLEAR_FREE _IOW(BTRFS_IOCTL_MAGIC, 90, \
+ struct btrfs_ioctl_clear_free_args)
#endif
--
1.7.6.6.GIT
More information about the Kernelnewbies
mailing list