diff options
-rw-r--r-- | fs/btrfs/ctree.h | 9 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 142 | ||||
-rw-r--r-- | include/uapi/linux/btrfs.h | 12 |
3 files changed, 163 insertions, 0 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 1aafccda05d1..498452ebfd37 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -524,7 +524,12 @@ struct btrfs_super_block { | |||
524 | #define BTRFS_FEATURE_INCOMPAT_NO_HOLES (1ULL << 9) | 524 | #define BTRFS_FEATURE_INCOMPAT_NO_HOLES (1ULL << 9) |
525 | 525 | ||
526 | #define BTRFS_FEATURE_COMPAT_SUPP 0ULL | 526 | #define BTRFS_FEATURE_COMPAT_SUPP 0ULL |
527 | #define BTRFS_FEATURE_COMPAT_SAFE_SET 0ULL | ||
528 | #define BTRFS_FEATURE_COMPAT_SAFE_CLEAR 0ULL | ||
527 | #define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL | 529 | #define BTRFS_FEATURE_COMPAT_RO_SUPP 0ULL |
530 | #define BTRFS_FEATURE_COMPAT_RO_SAFE_SET 0ULL | ||
531 | #define BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR 0ULL | ||
532 | |||
528 | #define BTRFS_FEATURE_INCOMPAT_SUPP \ | 533 | #define BTRFS_FEATURE_INCOMPAT_SUPP \ |
529 | (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ | 534 | (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ |
530 | BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \ | 535 | BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \ |
@@ -536,6 +541,10 @@ struct btrfs_super_block { | |||
536 | BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA | \ | 541 | BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA | \ |
537 | BTRFS_FEATURE_INCOMPAT_NO_HOLES) | 542 | BTRFS_FEATURE_INCOMPAT_NO_HOLES) |
538 | 543 | ||
544 | #define BTRFS_FEATURE_INCOMPAT_SAFE_SET \ | ||
545 | (BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF) | ||
546 | #define BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR 0ULL | ||
547 | |||
539 | /* | 548 | /* |
540 | * A leaf is full of items. offset and size tell us where to find | 549 | * A leaf is full of items. offset and size tell us where to find |
541 | * the item in the leaf (relative to the start of the data area) | 550 | * the item in the leaf (relative to the start of the data area) |
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 | |||
4488 | static 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 | |||
4503 | static 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 | |||
4519 | static 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) \ | ||
4555 | check_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 | |||
4560 | static 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 | |||
4483 | long btrfs_ioctl(struct file *file, unsigned int | 4619 | long 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; |
diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h index 45e618921c61..b4d69092fbdb 100644 --- a/include/uapi/linux/btrfs.h +++ b/include/uapi/linux/btrfs.h | |||
@@ -184,6 +184,12 @@ struct btrfs_ioctl_fs_info_args { | |||
184 | __u64 reserved[124]; /* pad to 1k */ | 184 | __u64 reserved[124]; /* pad to 1k */ |
185 | }; | 185 | }; |
186 | 186 | ||
187 | struct btrfs_ioctl_feature_flags { | ||
188 | __u64 compat_flags; | ||
189 | __u64 compat_ro_flags; | ||
190 | __u64 incompat_flags; | ||
191 | }; | ||
192 | |||
187 | /* balance control ioctl modes */ | 193 | /* balance control ioctl modes */ |
188 | #define BTRFS_BALANCE_CTL_PAUSE 1 | 194 | #define BTRFS_BALANCE_CTL_PAUSE 1 |
189 | #define BTRFS_BALANCE_CTL_CANCEL 2 | 195 | #define BTRFS_BALANCE_CTL_CANCEL 2 |
@@ -606,5 +612,11 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code) | |||
606 | struct btrfs_ioctl_dev_replace_args) | 612 | struct btrfs_ioctl_dev_replace_args) |
607 | #define BTRFS_IOC_FILE_EXTENT_SAME _IOWR(BTRFS_IOCTL_MAGIC, 54, \ | 613 | #define BTRFS_IOC_FILE_EXTENT_SAME _IOWR(BTRFS_IOCTL_MAGIC, 54, \ |
608 | struct btrfs_ioctl_same_args) | 614 | struct btrfs_ioctl_same_args) |
615 | #define BTRFS_IOC_GET_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \ | ||
616 | struct btrfs_ioctl_feature_flags) | ||
617 | #define BTRFS_IOC_SET_FEATURES _IOW(BTRFS_IOCTL_MAGIC, 57, \ | ||
618 | struct btrfs_ioctl_feature_flags[2]) | ||
619 | #define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \ | ||
620 | struct btrfs_ioctl_feature_flags[3]) | ||
609 | 621 | ||
610 | #endif /* _UAPI_LINUX_BTRFS_H */ | 622 | #endif /* _UAPI_LINUX_BTRFS_H */ |