@@ -3325,6 +3325,25 @@ int btrfs_fileattr_set(struct user_namespace *mnt_userns,
int btrfs_ioctl_get_supported_features(void __user *arg);
void btrfs_sync_inode_flags_to_i_flags(struct inode *inode);
int __pure btrfs_is_empty_uuid(u8 *uuid);
+
+struct btrfs_defrag_ctrl {
+ /* Input, read-only fields */
+ u64 start;
+ u64 len;
+ u32 extent_thresh;
+ u64 newer_than;
+ u64 max_sectors_to_defrag;
+ u8 compress;
+ u8 flags;
+
+ /* Output fields */
+ u64 sectors_defragged;
+ u64 last_scanned; /* Exclusive bytenr */
+};
+int btrfs_defrag_ioctl_args_to_ctrl(struct btrfs_fs_info *fs_info,
+ struct btrfs_ioctl_defrag_range_args *args,
+ struct btrfs_defrag_ctrl *ctrl,
+ u64 max_sectors_to_defrag, u64 newer_than);
int btrfs_defrag_file(struct inode *inode, struct file_ra_state *ra,
struct btrfs_ioctl_defrag_range_args *range,
u64 newer_than, unsigned long max_to_defrag);
@@ -1749,6 +1749,47 @@ static int defrag_one_cluster(struct btrfs_inode *inode,
return ret;
}
+/*
+ * Convert the old ioctl format to the new btrfs_defrag_ctrl structure.
+ *
+ * Will also do basic tasks like setting default values and sanity checks.
+ */
+int btrfs_defrag_ioctl_args_to_ctrl(struct btrfs_fs_info *fs_info,
+ struct btrfs_ioctl_defrag_range_args *args,
+ struct btrfs_defrag_ctrl *ctrl,
+ u64 max_sectors_to_defrag, u64 newer_than)
+{
+ u64 range_end;
+
+ if (args->flags & ~BTRFS_DEFRAG_RANGE_FLAGS_MASK)
+ return -EOPNOTSUPP;
+ if (args->compress_type >= BTRFS_NR_COMPRESS_TYPES)
+ return -EOPNOTSUPP;
+
+ ctrl->start = round_down(args->start, fs_info->sectorsize);
+ /*
+ * If @len does not overflow with @start nor is -1, align the length.
+ * Otherwise set it to (u64)-1 so later btrfs_defrag_file() will
+ * determine the length using isize.
+ */
+ if (!check_add_overflow(args->start, args->len, &range_end) &&
+ args->len != (u64)-1)
+ ctrl->len = round_up(range_end, fs_info->sectorsize) -
+ ctrl->start;
+ else
+ ctrl->len = -1;
+ ctrl->flags = args->flags;
+ ctrl->compress = args->compress_type;
+ if (args->extent_thresh == 0)
+ ctrl->extent_thresh = SZ_256K;
+ else
+ ctrl->extent_thresh = args->extent_thresh;
+ ctrl->newer_than = newer_than;
+ ctrl->last_scanned = 0;
+ ctrl->sectors_defragged = 0;
+ return 0;
+}
+
/*
* Entry point to file defragmentation.
*