aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
authorHugo Mills <hugo@carfax.org.uk>2014-01-30 15:17:00 -0500
committerJosef Bacik <jbacik@fb.com>2014-03-10 15:15:40 -0400
commitabccd00f8af27c585be48904515bad5658130e48 (patch)
tree123068ed0cc192d6a719a98ad94f422d4aef1f64 /fs/btrfs/ioctl.c
parentd86477b303da51832002eec1cdec2938c42fccc3 (diff)
btrfs: Fix 32/64-bit problem with BTRFS_SET_RECEIVED_SUBVOL ioctl
The structure for BTRFS_SET_RECEIVED_IOCTL packs differently on 32-bit and 64-bit systems. This means that it is impossible to use btrfs receive on a system with a 64-bit kernel and 32-bit userspace, because the structure size (and hence the ioctl number) is different. This patch adds a compatibility structure and ioctl to deal with the above case. Signed-off-by: Hugo Mills <hugo@carfax.org.uk> Signed-off-by: Josef Bacik <jbacik@fb.com>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r--fs/btrfs/ioctl.c123
1 files changed, 111 insertions, 12 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index a692aad8fa5a..d4c179502775 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -59,6 +59,32 @@
59#include "props.h" 59#include "props.h"
60#include "sysfs.h" 60#include "sysfs.h"
61 61
62#ifdef CONFIG_64BIT
63/* If we have a 32-bit userspace and 64-bit kernel, then the UAPI
64 * structures are incorrect, as the timespec structure from userspace
65 * is 4 bytes too small. We define these alternatives here to teach
66 * the kernel about the 32-bit struct packing.
67 */
68struct btrfs_ioctl_timespec_32 {
69 __u64 sec;
70 __u32 nsec;
71} __attribute__ ((__packed__));
72
73struct btrfs_ioctl_received_subvol_args_32 {
74 char uuid[BTRFS_UUID_SIZE]; /* in */
75 __u64 stransid; /* in */
76 __u64 rtransid; /* out */
77 struct btrfs_ioctl_timespec_32 stime; /* in */
78 struct btrfs_ioctl_timespec_32 rtime; /* out */
79 __u64 flags; /* in */
80 __u64 reserved[16]; /* in */
81} __attribute__ ((__packed__));
82
83#define BTRFS_IOC_SET_RECEIVED_SUBVOL_32 _IOWR(BTRFS_IOCTL_MAGIC, 37, \
84 struct btrfs_ioctl_received_subvol_args_32)
85#endif
86
87
62static int btrfs_clone(struct inode *src, struct inode *inode, 88static int btrfs_clone(struct inode *src, struct inode *inode,
63 u64 off, u64 olen, u64 olen_aligned, u64 destoff); 89 u64 off, u64 olen, u64 olen_aligned, u64 destoff);
64 90
@@ -4375,10 +4401,9 @@ static long btrfs_ioctl_quota_rescan_wait(struct file *file, void __user *arg)
4375 return btrfs_qgroup_wait_for_completion(root->fs_info); 4401 return btrfs_qgroup_wait_for_completion(root->fs_info);
4376} 4402}
4377 4403
4378static long btrfs_ioctl_set_received_subvol(struct file *file, 4404static long _btrfs_ioctl_set_received_subvol(struct file *file,
4379 void __user *arg) 4405 struct btrfs_ioctl_received_subvol_args *sa)
4380{ 4406{
4381 struct btrfs_ioctl_received_subvol_args *sa = NULL;
4382 struct inode *inode = file_inode(file); 4407 struct inode *inode = file_inode(file);
4383 struct btrfs_root *root = BTRFS_I(inode)->root; 4408 struct btrfs_root *root = BTRFS_I(inode)->root;
4384 struct btrfs_root_item *root_item = &root->root_item; 4409 struct btrfs_root_item *root_item = &root->root_item;
@@ -4406,13 +4431,6 @@ static long btrfs_ioctl_set_received_subvol(struct file *file,
4406 goto out; 4431 goto out;
4407 } 4432 }
4408 4433
4409 sa = memdup_user(arg, sizeof(*sa));
4410 if (IS_ERR(sa)) {
4411 ret = PTR_ERR(sa);
4412 sa = NULL;
4413 goto out;
4414 }
4415
4416 /* 4434 /*
4417 * 1 - root item 4435 * 1 - root item
4418 * 2 - uuid items (received uuid + subvol uuid) 4436 * 2 - uuid items (received uuid + subvol uuid)
@@ -4466,14 +4484,91 @@ static long btrfs_ioctl_set_received_subvol(struct file *file,
4466 goto out; 4484 goto out;
4467 } 4485 }
4468 4486
4487out:
4488 up_write(&root->fs_info->subvol_sem);
4489 mnt_drop_write_file(file);
4490 return ret;
4491}
4492
4493#ifdef CONFIG_64BIT
4494static long btrfs_ioctl_set_received_subvol_32(struct file *file,
4495 void __user *arg)
4496{
4497 struct btrfs_ioctl_received_subvol_args_32 *args32 = NULL;
4498 struct btrfs_ioctl_received_subvol_args *args64 = NULL;
4499 int ret = 0;
4500
4501 args32 = memdup_user(arg, sizeof(*args32));
4502 if (IS_ERR(args32)) {
4503 ret = PTR_ERR(args32);
4504 args32 = NULL;
4505 goto out;
4506 }
4507
4508 args64 = kmalloc(sizeof(*args64), GFP_NOFS);
4509 if (IS_ERR(args64)) {
4510 ret = PTR_ERR(args64);
4511 args64 = NULL;
4512 goto out;
4513 }
4514
4515 memcpy(args64->uuid, args32->uuid, BTRFS_UUID_SIZE);
4516 args64->stransid = args32->stransid;
4517 args64->rtransid = args32->rtransid;
4518 args64->stime.sec = args32->stime.sec;
4519 args64->stime.nsec = args32->stime.nsec;
4520 args64->rtime.sec = args32->rtime.sec;
4521 args64->rtime.nsec = args32->rtime.nsec;
4522 args64->flags = args32->flags;
4523
4524 ret = _btrfs_ioctl_set_received_subvol(file, args64);
4525 if (ret)
4526 goto out;
4527
4528 memcpy(args32->uuid, args64->uuid, BTRFS_UUID_SIZE);
4529 args32->stransid = args64->stransid;
4530 args32->rtransid = args64->rtransid;
4531 args32->stime.sec = args64->stime.sec;
4532 args32->stime.nsec = args64->stime.nsec;
4533 args32->rtime.sec = args64->rtime.sec;
4534 args32->rtime.nsec = args64->rtime.nsec;
4535 args32->flags = args64->flags;
4536
4537 ret = copy_to_user(arg, args32, sizeof(*args32));
4538 if (ret)
4539 ret = -EFAULT;
4540
4541out:
4542 kfree(args32);
4543 kfree(args64);
4544 return ret;
4545}
4546#endif
4547
4548static long btrfs_ioctl_set_received_subvol(struct file *file,
4549 void __user *arg)
4550{
4551 struct btrfs_ioctl_received_subvol_args *sa = NULL;
4552 int ret = 0;
4553
4554 sa = memdup_user(arg, sizeof(*sa));
4555 if (IS_ERR(sa)) {
4556 ret = PTR_ERR(sa);
4557 sa = NULL;
4558 goto out;
4559 }
4560
4561 ret = _btrfs_ioctl_set_received_subvol(file, sa);
4562
4563 if (ret)
4564 goto out;
4565
4469 ret = copy_to_user(arg, sa, sizeof(*sa)); 4566 ret = copy_to_user(arg, sa, sizeof(*sa));
4470 if (ret) 4567 if (ret)
4471 ret = -EFAULT; 4568 ret = -EFAULT;
4472 4569
4473out: 4570out:
4474 kfree(sa); 4571 kfree(sa);
4475 up_write(&root->fs_info->subvol_sem);
4476 mnt_drop_write_file(file);
4477 return ret; 4572 return ret;
4478} 4573}
4479 4574
@@ -4792,6 +4887,10 @@ long btrfs_ioctl(struct file *file, unsigned int
4792 return btrfs_ioctl_balance_progress(root, argp); 4887 return btrfs_ioctl_balance_progress(root, argp);
4793 case BTRFS_IOC_SET_RECEIVED_SUBVOL: 4888 case BTRFS_IOC_SET_RECEIVED_SUBVOL:
4794 return btrfs_ioctl_set_received_subvol(file, argp); 4889 return btrfs_ioctl_set_received_subvol(file, argp);
4890#ifdef CONFIG_64BIT
4891 case BTRFS_IOC_SET_RECEIVED_SUBVOL_32:
4892 return btrfs_ioctl_set_received_subvol_32(file, argp);
4893#endif
4795 case BTRFS_IOC_SEND: 4894 case BTRFS_IOC_SEND:
4796 return btrfs_ioctl_send(file, argp); 4895 return btrfs_ioctl_send(file, argp);
4797 case BTRFS_IOC_GET_DEV_STATS: 4896 case BTRFS_IOC_GET_DEV_STATS: