|
@@ -282,6 +282,7 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
|
|
struct fstrim_range range;
|
|
struct fstrim_range range;
|
|
u64 minlen = ULLONG_MAX;
|
|
u64 minlen = ULLONG_MAX;
|
|
u64 num_devices = 0;
|
|
u64 num_devices = 0;
|
|
|
|
+ u64 total_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
if (!capable(CAP_SYS_ADMIN))
|
|
@@ -300,12 +301,15 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
|
|
+
|
|
if (!num_devices)
|
|
if (!num_devices)
|
|
return -EOPNOTSUPP;
|
|
return -EOPNOTSUPP;
|
|
-
|
|
|
|
if (copy_from_user(&range, arg, sizeof(range)))
|
|
if (copy_from_user(&range, arg, sizeof(range)))
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
|
|
+ if (range.start > total_bytes)
|
|
|
|
+ return -EINVAL;
|
|
|
|
|
|
|
|
+ range.len = min(range.len, total_bytes - range.start);
|
|
range.minlen = max(range.minlen, minlen);
|
|
range.minlen = max(range.minlen, minlen);
|
|
ret = btrfs_trim_fs(root, &range);
|
|
ret = btrfs_trim_fs(root, &range);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
@@ -765,7 +769,7 @@ static int should_defrag_range(struct inode *inode, u64 start, u64 len,
|
|
int ret = 1;
|
|
int ret = 1;
|
|
|
|
|
|
/*
|
|
/*
|
|
- * make sure that once we start defragging and extent, we keep on
|
|
|
|
|
|
+ * make sure that once we start defragging an extent, we keep on
|
|
* defragging it
|
|
* defragging it
|
|
*/
|
|
*/
|
|
if (start < *defrag_end)
|
|
if (start < *defrag_end)
|
|
@@ -810,7 +814,6 @@ static int should_defrag_range(struct inode *inode, u64 start, u64 len,
|
|
* extent will force at least part of that big extent to be defragged.
|
|
* extent will force at least part of that big extent to be defragged.
|
|
*/
|
|
*/
|
|
if (ret) {
|
|
if (ret) {
|
|
- *last_len += len;
|
|
|
|
*defrag_end = extent_map_end(em);
|
|
*defrag_end = extent_map_end(em);
|
|
} else {
|
|
} else {
|
|
*last_len = 0;
|
|
*last_len = 0;
|
|
@@ -978,18 +981,20 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
|
|
struct btrfs_super_block *disk_super;
|
|
struct btrfs_super_block *disk_super;
|
|
struct file_ra_state *ra = NULL;
|
|
struct file_ra_state *ra = NULL;
|
|
unsigned long last_index;
|
|
unsigned long last_index;
|
|
|
|
+ u64 isize = i_size_read(inode);
|
|
u64 features;
|
|
u64 features;
|
|
u64 last_len = 0;
|
|
u64 last_len = 0;
|
|
u64 skip = 0;
|
|
u64 skip = 0;
|
|
u64 defrag_end = 0;
|
|
u64 defrag_end = 0;
|
|
u64 newer_off = range->start;
|
|
u64 newer_off = range->start;
|
|
- int newer_left = 0;
|
|
|
|
unsigned long i;
|
|
unsigned long i;
|
|
|
|
+ unsigned long ra_index = 0;
|
|
int ret;
|
|
int ret;
|
|
int defrag_count = 0;
|
|
int defrag_count = 0;
|
|
int compress_type = BTRFS_COMPRESS_ZLIB;
|
|
int compress_type = BTRFS_COMPRESS_ZLIB;
|
|
int extent_thresh = range->extent_thresh;
|
|
int extent_thresh = range->extent_thresh;
|
|
- int newer_cluster = (256 * 1024) >> PAGE_CACHE_SHIFT;
|
|
|
|
|
|
+ int max_cluster = (256 * 1024) >> PAGE_CACHE_SHIFT;
|
|
|
|
+ int cluster = max_cluster;
|
|
u64 new_align = ~((u64)128 * 1024 - 1);
|
|
u64 new_align = ~((u64)128 * 1024 - 1);
|
|
struct page **pages = NULL;
|
|
struct page **pages = NULL;
|
|
|
|
|
|
@@ -1003,7 +1008,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
|
|
compress_type = range->compress_type;
|
|
compress_type = range->compress_type;
|
|
}
|
|
}
|
|
|
|
|
|
- if (inode->i_size == 0)
|
|
|
|
|
|
+ if (isize == 0)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -1019,7 +1024,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
|
|
ra = &file->f_ra;
|
|
ra = &file->f_ra;
|
|
}
|
|
}
|
|
|
|
|
|
- pages = kmalloc(sizeof(struct page *) * newer_cluster,
|
|
|
|
|
|
+ pages = kmalloc(sizeof(struct page *) * max_cluster,
|
|
GFP_NOFS);
|
|
GFP_NOFS);
|
|
if (!pages) {
|
|
if (!pages) {
|
|
ret = -ENOMEM;
|
|
ret = -ENOMEM;
|
|
@@ -1028,10 +1033,10 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
|
|
|
|
|
|
/* find the last page to defrag */
|
|
/* find the last page to defrag */
|
|
if (range->start + range->len > range->start) {
|
|
if (range->start + range->len > range->start) {
|
|
- last_index = min_t(u64, inode->i_size - 1,
|
|
|
|
|
|
+ last_index = min_t(u64, isize - 1,
|
|
range->start + range->len - 1) >> PAGE_CACHE_SHIFT;
|
|
range->start + range->len - 1) >> PAGE_CACHE_SHIFT;
|
|
} else {
|
|
} else {
|
|
- last_index = (inode->i_size - 1) >> PAGE_CACHE_SHIFT;
|
|
|
|
|
|
+ last_index = (isize - 1) >> PAGE_CACHE_SHIFT;
|
|
}
|
|
}
|
|
|
|
|
|
if (newer_than) {
|
|
if (newer_than) {
|
|
@@ -1044,14 +1049,13 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
|
|
* the extents in the file evenly spaced
|
|
* the extents in the file evenly spaced
|
|
*/
|
|
*/
|
|
i = (newer_off & new_align) >> PAGE_CACHE_SHIFT;
|
|
i = (newer_off & new_align) >> PAGE_CACHE_SHIFT;
|
|
- newer_left = newer_cluster;
|
|
|
|
} else
|
|
} else
|
|
goto out_ra;
|
|
goto out_ra;
|
|
} else {
|
|
} else {
|
|
i = range->start >> PAGE_CACHE_SHIFT;
|
|
i = range->start >> PAGE_CACHE_SHIFT;
|
|
}
|
|
}
|
|
if (!max_to_defrag)
|
|
if (!max_to_defrag)
|
|
- max_to_defrag = last_index - 1;
|
|
|
|
|
|
+ max_to_defrag = last_index;
|
|
|
|
|
|
/*
|
|
/*
|
|
* make writeback starts from i, so the defrag range can be
|
|
* make writeback starts from i, so the defrag range can be
|
|
@@ -1085,18 +1089,31 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
|
|
i = max(i + 1, next);
|
|
i = max(i + 1, next);
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (!newer_than) {
|
|
|
|
+ cluster = (PAGE_CACHE_ALIGN(defrag_end) >>
|
|
|
|
+ PAGE_CACHE_SHIFT) - i;
|
|
|
|
+ cluster = min(cluster, max_cluster);
|
|
|
|
+ } else {
|
|
|
|
+ cluster = max_cluster;
|
|
|
|
+ }
|
|
|
|
+
|
|
if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)
|
|
if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)
|
|
BTRFS_I(inode)->force_compress = compress_type;
|
|
BTRFS_I(inode)->force_compress = compress_type;
|
|
|
|
|
|
- btrfs_force_ra(inode->i_mapping, ra, file, i, newer_cluster);
|
|
|
|
|
|
+ if (i + cluster > ra_index) {
|
|
|
|
+ ra_index = max(i, ra_index);
|
|
|
|
+ btrfs_force_ra(inode->i_mapping, ra, file, ra_index,
|
|
|
|
+ cluster);
|
|
|
|
+ ra_index += max_cluster;
|
|
|
|
+ }
|
|
|
|
|
|
- ret = cluster_pages_for_defrag(inode, pages, i, newer_cluster);
|
|
|
|
|
|
+ ret = cluster_pages_for_defrag(inode, pages, i, cluster);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
goto out_ra;
|
|
goto out_ra;
|
|
|
|
|
|
defrag_count += ret;
|
|
defrag_count += ret;
|
|
balance_dirty_pages_ratelimited_nr(inode->i_mapping, ret);
|
|
balance_dirty_pages_ratelimited_nr(inode->i_mapping, ret);
|
|
- i += ret;
|
|
|
|
|
|
|
|
if (newer_than) {
|
|
if (newer_than) {
|
|
if (newer_off == (u64)-1)
|
|
if (newer_off == (u64)-1)
|
|
@@ -1111,12 +1128,17 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
|
|
if (!ret) {
|
|
if (!ret) {
|
|
range->start = newer_off;
|
|
range->start = newer_off;
|
|
i = (newer_off & new_align) >> PAGE_CACHE_SHIFT;
|
|
i = (newer_off & new_align) >> PAGE_CACHE_SHIFT;
|
|
- newer_left = newer_cluster;
|
|
|
|
} else {
|
|
} else {
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
} else {
|
|
- i++;
|
|
|
|
|
|
+ if (ret > 0) {
|
|
|
|
+ i += ret;
|
|
|
|
+ last_len += ret << PAGE_CACHE_SHIFT;
|
|
|
|
+ } else {
|
|
|
|
+ i++;
|
|
|
|
+ last_len = 0;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1149,9 +1171,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
|
|
btrfs_set_super_incompat_flags(disk_super, features);
|
|
btrfs_set_super_incompat_flags(disk_super, features);
|
|
}
|
|
}
|
|
|
|
|
|
- if (!file)
|
|
|
|
- kfree(ra);
|
|
|
|
- return defrag_count;
|
|
|
|
|
|
+ ret = defrag_count;
|
|
|
|
|
|
out_ra:
|
|
out_ra:
|
|
if (!file)
|
|
if (!file)
|