aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
authorJeff Mahoney <jeffm@suse.com>2013-11-15 15:33:55 -0500
committerChris Mason <clm@fb.com>2014-01-28 16:19:23 -0500
commit2eaa055fab4e3127c9f572fda1b710cbb2acdf1c (patch)
tree43ec0254e30315288d03196054ff3fff534ed06c /fs/btrfs/ioctl.c
parent9e5ac13acbb9e806a54f131432501bf462248c35 (diff)
btrfs: add ioctls to query/change feature bits online
There are some feature bits that require no offline setup and can be enabled online. I've only reviewed extended irefs, but there will probably be more. We introduce three new ioctls: - BTRFS_IOC_GET_SUPPORTED_FEATURES: query the kernel for supported features. - BTRFS_IOC_GET_FEATURES: query the kernel for enabled features on a per-fs basis, as well as querying for which features are changeable with mounted. - BTRFS_IOC_SET_FEATURES: change features on a per-fs basis. We introduce two new masks per feature set (_SAFE_SET and _SAFE_CLEAR) that allow us to define which features are safe to change at runtime. The failure modes for BTRFS_IOC_SET_FEATURES are as follows: - Enabling a completely unsupported feature: warns and returns -ENOTSUPP - Enabling a feature that can only be done offline: warns and returns -EPERM Signed-off-by: Jeff Mahoney <jeffm@suse.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r--fs/btrfs/ioctl.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 21da5762b0b1..d4e105b54091 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -4480,6 +4480,142 @@ out_unlock:
4480 return ret; 4480 return ret;
4481} 4481}
4482 4482
4483#define INIT_FEATURE_FLAGS(suffix) \
4484 { .compat_flags = BTRFS_FEATURE_COMPAT_##suffix, \
4485 .compat_ro_flags = BTRFS_FEATURE_COMPAT_RO_##suffix, \
4486 .incompat_flags = BTRFS_FEATURE_INCOMPAT_##suffix }
4487
4488static int btrfs_ioctl_get_supported_features(struct file *file,
4489 void __user *arg)
4490{
4491 static struct btrfs_ioctl_feature_flags features[3] = {
4492 INIT_FEATURE_FLAGS(SUPP),
4493 INIT_FEATURE_FLAGS(SAFE_SET),
4494 INIT_FEATURE_FLAGS(SAFE_CLEAR)
4495 };
4496
4497 if (copy_to_user(arg, &features, sizeof(features)))
4498 return -EFAULT;
4499
4500 return 0;
4501}
4502
4503static int btrfs_ioctl_get_features(struct file *file, void __user *arg)
4504{
4505 struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
4506 struct btrfs_super_block *super_block = root->fs_info->super_copy;
4507 struct btrfs_ioctl_feature_flags features;
4508
4509 features.compat_flags = btrfs_super_compat_flags(super_block);
4510 features.compat_ro_flags = btrfs_super_compat_ro_flags(super_block);
4511 features.incompat_flags = btrfs_super_incompat_flags(super_block);
4512
4513 if (copy_to_user(arg, &features, sizeof(features)))
4514 return -EFAULT;
4515
4516 return 0;
4517}
4518
4519static int check_feature_bits(struct btrfs_root *root, const char *type,
4520 u64 change_mask, u64 flags, u64 supported_flags,
4521 u64 safe_set, u64 safe_clear)
4522{
4523 u64 disallowed, unsupported;
4524 u64 set_mask = flags & change_mask;
4525 u64 clear_mask = ~flags & change_mask;
4526
4527 unsupported = set_mask & ~supported_flags;
4528 if (unsupported) {
4529 btrfs_warn(root->fs_info,
4530 "this kernel does not support %s bits 0x%llx",
4531 type, unsupported);
4532 return -EOPNOTSUPP;
4533 }
4534
4535 disallowed = set_mask & ~safe_set;
4536 if (disallowed) {
4537 btrfs_warn(root->fs_info,
4538 "can't set %s bits 0x%llx while mounted",
4539 type, disallowed);
4540 return -EPERM;
4541 }
4542
4543 disallowed = clear_mask & ~safe_clear;
4544 if (disallowed) {
4545 btrfs_warn(root->fs_info,
4546 "can't clear %s bits 0x%llx while mounted",
4547 type, disallowed);
4548 return -EPERM;
4549 }
4550
4551 return 0;
4552}
4553
4554#define check_feature(root, change_mask, flags, mask_base) \
4555check_feature_bits(root, # mask_base, change_mask, flags, \
4556 BTRFS_FEATURE_ ## mask_base ## _SUPP, \
4557 BTRFS_FEATURE_ ## mask_base ## _SAFE_SET, \
4558 BTRFS_FEATURE_ ## mask_base ## _SAFE_CLEAR)
4559
4560static int btrfs_ioctl_set_features(struct file *file, void __user *arg)
4561{
4562 struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
4563 struct btrfs_super_block *super_block = root->fs_info->super_copy;
4564 struct btrfs_ioctl_feature_flags flags[2];
4565 struct btrfs_trans_handle *trans;
4566 u64 newflags;
4567 int ret;
4568
4569 if (!capable(CAP_SYS_ADMIN))
4570 return -EPERM;
4571
4572 if (copy_from_user(flags, arg, sizeof(flags)))
4573 return -EFAULT;
4574
4575 /* Nothing to do */
4576 if (!flags[0].compat_flags && !flags[0].compat_ro_flags &&
4577 !flags[0].incompat_flags)
4578 return 0;
4579
4580 ret = check_feature(root, flags[0].compat_flags,
4581 flags[1].compat_flags, COMPAT);
4582 if (ret)
4583 return ret;
4584
4585 ret = check_feature(root, flags[0].compat_ro_flags,
4586 flags[1].compat_ro_flags, COMPAT_RO);
4587 if (ret)
4588 return ret;
4589
4590 ret = check_feature(root, flags[0].incompat_flags,
4591 flags[1].incompat_flags, INCOMPAT);
4592 if (ret)
4593 return ret;
4594
4595 trans = btrfs_start_transaction(root, 1);
4596 if (IS_ERR(trans))
4597 return PTR_ERR(trans);
4598
4599 spin_lock(&root->fs_info->super_lock);
4600 newflags = btrfs_super_compat_flags(super_block);
4601 newflags |= flags[0].compat_flags & flags[1].compat_flags;
4602 newflags &= ~(flags[0].compat_flags & ~flags[1].compat_flags);
4603 btrfs_set_super_compat_flags(super_block, newflags);
4604
4605 newflags = btrfs_super_compat_ro_flags(super_block);
4606 newflags |= flags[0].compat_ro_flags & flags[1].compat_ro_flags;
4607 newflags &= ~(flags[0].compat_ro_flags & ~flags[1].compat_ro_flags);
4608 btrfs_set_super_compat_ro_flags(super_block, newflags);
4609
4610 newflags = btrfs_super_incompat_flags(super_block);
4611 newflags |= flags[0].incompat_flags & flags[1].incompat_flags;
4612 newflags &= ~(flags[0].incompat_flags & ~flags[1].incompat_flags);
4613 btrfs_set_super_incompat_flags(super_block, newflags);
4614 spin_unlock(&root->fs_info->super_lock);
4615
4616 return btrfs_end_transaction(trans, root);
4617}
4618
4483long btrfs_ioctl(struct file *file, unsigned int 4619long btrfs_ioctl(struct file *file, unsigned int
4484 cmd, unsigned long arg) 4620 cmd, unsigned long arg)
4485{ 4621{
@@ -4598,6 +4734,12 @@ long btrfs_ioctl(struct file *file, unsigned int
4598 return btrfs_ioctl_set_fslabel(file, argp); 4734 return btrfs_ioctl_set_fslabel(file, argp);
4599 case BTRFS_IOC_FILE_EXTENT_SAME: 4735 case BTRFS_IOC_FILE_EXTENT_SAME:
4600 return btrfs_ioctl_file_extent_same(file, argp); 4736 return btrfs_ioctl_file_extent_same(file, argp);
4737 case BTRFS_IOC_GET_SUPPORTED_FEATURES:
4738 return btrfs_ioctl_get_supported_features(file, argp);
4739 case BTRFS_IOC_GET_FEATURES:
4740 return btrfs_ioctl_get_features(file, argp);
4741 case BTRFS_IOC_SET_FEATURES:
4742 return btrfs_ioctl_set_features(file, argp);
4601 } 4743 }
4602 4744
4603 return -ENOTTY; 4745 return -ENOTTY;