aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/send.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/send.c')
-rw-r--r--fs/btrfs/send.c62
1 files changed, 41 insertions, 21 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 8d358c547c59..6a8c86074aa4 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -5939,6 +5939,7 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
5939 u32 i; 5939 u32 i;
5940 u64 *clone_sources_tmp = NULL; 5940 u64 *clone_sources_tmp = NULL;
5941 int clone_sources_to_rollback = 0; 5941 int clone_sources_to_rollback = 0;
5942 unsigned alloc_size;
5942 int sort_clone_roots = 0; 5943 int sort_clone_roots = 0;
5943 int index; 5944 int index;
5944 5945
@@ -5978,6 +5979,12 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
5978 goto out; 5979 goto out;
5979 } 5980 }
5980 5981
5982 if (arg->clone_sources_count >
5983 ULLONG_MAX / sizeof(*arg->clone_sources)) {
5984 ret = -EINVAL;
5985 goto out;
5986 }
5987
5981 if (!access_ok(VERIFY_READ, arg->clone_sources, 5988 if (!access_ok(VERIFY_READ, arg->clone_sources,
5982 sizeof(*arg->clone_sources) * 5989 sizeof(*arg->clone_sources) *
5983 arg->clone_sources_count)) { 5990 arg->clone_sources_count)) {
@@ -6022,40 +6029,53 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
6022 sctx->clone_roots_cnt = arg->clone_sources_count; 6029 sctx->clone_roots_cnt = arg->clone_sources_count;
6023 6030
6024 sctx->send_max_size = BTRFS_SEND_BUF_SIZE; 6031 sctx->send_max_size = BTRFS_SEND_BUF_SIZE;
6025 sctx->send_buf = vmalloc(sctx->send_max_size); 6032 sctx->send_buf = kmalloc(sctx->send_max_size, GFP_KERNEL | __GFP_NOWARN);
6026 if (!sctx->send_buf) { 6033 if (!sctx->send_buf) {
6027 ret = -ENOMEM; 6034 sctx->send_buf = vmalloc(sctx->send_max_size);
6028 goto out; 6035 if (!sctx->send_buf) {
6036 ret = -ENOMEM;
6037 goto out;
6038 }
6029 } 6039 }
6030 6040
6031 sctx->read_buf = vmalloc(BTRFS_SEND_READ_SIZE); 6041 sctx->read_buf = kmalloc(BTRFS_SEND_READ_SIZE, GFP_KERNEL | __GFP_NOWARN);
6032 if (!sctx->read_buf) { 6042 if (!sctx->read_buf) {
6033 ret = -ENOMEM; 6043 sctx->read_buf = vmalloc(BTRFS_SEND_READ_SIZE);
6034 goto out; 6044 if (!sctx->read_buf) {
6045 ret = -ENOMEM;
6046 goto out;
6047 }
6035 } 6048 }
6036 6049
6037 sctx->pending_dir_moves = RB_ROOT; 6050 sctx->pending_dir_moves = RB_ROOT;
6038 sctx->waiting_dir_moves = RB_ROOT; 6051 sctx->waiting_dir_moves = RB_ROOT;
6039 sctx->orphan_dirs = RB_ROOT; 6052 sctx->orphan_dirs = RB_ROOT;
6040 6053
6041 sctx->clone_roots = vzalloc(sizeof(struct clone_root) * 6054 alloc_size = sizeof(struct clone_root) * (arg->clone_sources_count + 1);
6042 (arg->clone_sources_count + 1)); 6055
6056 sctx->clone_roots = kzalloc(alloc_size, GFP_KERNEL | __GFP_NOWARN);
6043 if (!sctx->clone_roots) { 6057 if (!sctx->clone_roots) {
6044 ret = -ENOMEM; 6058 sctx->clone_roots = vzalloc(alloc_size);
6045 goto out; 6059 if (!sctx->clone_roots) {
6060 ret = -ENOMEM;
6061 goto out;
6062 }
6046 } 6063 }
6047 6064
6065 alloc_size = arg->clone_sources_count * sizeof(*arg->clone_sources);
6066
6048 if (arg->clone_sources_count) { 6067 if (arg->clone_sources_count) {
6049 clone_sources_tmp = vmalloc(arg->clone_sources_count * 6068 clone_sources_tmp = kmalloc(alloc_size, GFP_KERNEL | __GFP_NOWARN);
6050 sizeof(*arg->clone_sources));
6051 if (!clone_sources_tmp) { 6069 if (!clone_sources_tmp) {
6052 ret = -ENOMEM; 6070 clone_sources_tmp = vmalloc(alloc_size);
6053 goto out; 6071 if (!clone_sources_tmp) {
6072 ret = -ENOMEM;
6073 goto out;
6074 }
6054 } 6075 }
6055 6076
6056 ret = copy_from_user(clone_sources_tmp, arg->clone_sources, 6077 ret = copy_from_user(clone_sources_tmp, arg->clone_sources,
6057 arg->clone_sources_count * 6078 alloc_size);
6058 sizeof(*arg->clone_sources));
6059 if (ret) { 6079 if (ret) {
6060 ret = -EFAULT; 6080 ret = -EFAULT;
6061 goto out; 6081 goto out;
@@ -6089,7 +6109,7 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
6089 sctx->clone_roots[i].root = clone_root; 6109 sctx->clone_roots[i].root = clone_root;
6090 clone_sources_to_rollback = i + 1; 6110 clone_sources_to_rollback = i + 1;
6091 } 6111 }
6092 vfree(clone_sources_tmp); 6112 kvfree(clone_sources_tmp);
6093 clone_sources_tmp = NULL; 6113 clone_sources_tmp = NULL;
6094 } 6114 }
6095 6115
@@ -6207,15 +6227,15 @@ out:
6207 btrfs_root_dec_send_in_progress(sctx->parent_root); 6227 btrfs_root_dec_send_in_progress(sctx->parent_root);
6208 6228
6209 kfree(arg); 6229 kfree(arg);
6210 vfree(clone_sources_tmp); 6230 kvfree(clone_sources_tmp);
6211 6231
6212 if (sctx) { 6232 if (sctx) {
6213 if (sctx->send_filp) 6233 if (sctx->send_filp)
6214 fput(sctx->send_filp); 6234 fput(sctx->send_filp);
6215 6235
6216 vfree(sctx->clone_roots); 6236 kvfree(sctx->clone_roots);
6217 vfree(sctx->send_buf); 6237 kvfree(sctx->send_buf);
6218 vfree(sctx->read_buf); 6238 kvfree(sctx->read_buf);
6219 6239
6220 name_cache_free(sctx); 6240 name_cache_free(sctx);
6221 6241