diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 404 |
1 files changed, 304 insertions, 100 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 21da5762b0b1..a6d8efa46bfe 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -56,6 +56,8 @@ | |||
56 | #include "rcu-string.h" | 56 | #include "rcu-string.h" |
57 | #include "send.h" | 57 | #include "send.h" |
58 | #include "dev-replace.h" | 58 | #include "dev-replace.h" |
59 | #include "props.h" | ||
60 | #include "sysfs.h" | ||
59 | 61 | ||
60 | static int btrfs_clone(struct inode *src, struct inode *inode, | 62 | static int btrfs_clone(struct inode *src, struct inode *inode, |
61 | u64 off, u64 olen, u64 olen_aligned, u64 destoff); | 63 | u64 off, u64 olen, u64 olen_aligned, u64 destoff); |
@@ -190,6 +192,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | |||
190 | unsigned int i_oldflags; | 192 | unsigned int i_oldflags; |
191 | umode_t mode; | 193 | umode_t mode; |
192 | 194 | ||
195 | if (!inode_owner_or_capable(inode)) | ||
196 | return -EPERM; | ||
197 | |||
193 | if (btrfs_root_readonly(root)) | 198 | if (btrfs_root_readonly(root)) |
194 | return -EROFS; | 199 | return -EROFS; |
195 | 200 | ||
@@ -200,9 +205,6 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | |||
200 | if (ret) | 205 | if (ret) |
201 | return ret; | 206 | return ret; |
202 | 207 | ||
203 | if (!inode_owner_or_capable(inode)) | ||
204 | return -EACCES; | ||
205 | |||
206 | ret = mnt_want_write_file(file); | 208 | ret = mnt_want_write_file(file); |
207 | if (ret) | 209 | if (ret) |
208 | return ret; | 210 | return ret; |
@@ -280,9 +282,25 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) | |||
280 | if (flags & FS_NOCOMP_FL) { | 282 | if (flags & FS_NOCOMP_FL) { |
281 | ip->flags &= ~BTRFS_INODE_COMPRESS; | 283 | ip->flags &= ~BTRFS_INODE_COMPRESS; |
282 | ip->flags |= BTRFS_INODE_NOCOMPRESS; | 284 | ip->flags |= BTRFS_INODE_NOCOMPRESS; |
285 | |||
286 | ret = btrfs_set_prop(inode, "btrfs.compression", NULL, 0, 0); | ||
287 | if (ret && ret != -ENODATA) | ||
288 | goto out_drop; | ||
283 | } else if (flags & FS_COMPR_FL) { | 289 | } else if (flags & FS_COMPR_FL) { |
290 | const char *comp; | ||
291 | |||
284 | ip->flags |= BTRFS_INODE_COMPRESS; | 292 | ip->flags |= BTRFS_INODE_COMPRESS; |
285 | ip->flags &= ~BTRFS_INODE_NOCOMPRESS; | 293 | ip->flags &= ~BTRFS_INODE_NOCOMPRESS; |
294 | |||
295 | if (root->fs_info->compress_type == BTRFS_COMPRESS_LZO) | ||
296 | comp = "lzo"; | ||
297 | else | ||
298 | comp = "zlib"; | ||
299 | ret = btrfs_set_prop(inode, "btrfs.compression", | ||
300 | comp, strlen(comp), 0); | ||
301 | if (ret) | ||
302 | goto out_drop; | ||
303 | |||
286 | } else { | 304 | } else { |
287 | ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS); | 305 | ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS); |
288 | } | 306 | } |
@@ -392,6 +410,7 @@ static noinline int create_subvol(struct inode *dir, | |||
392 | struct btrfs_root *new_root; | 410 | struct btrfs_root *new_root; |
393 | struct btrfs_block_rsv block_rsv; | 411 | struct btrfs_block_rsv block_rsv; |
394 | struct timespec cur_time = CURRENT_TIME; | 412 | struct timespec cur_time = CURRENT_TIME; |
413 | struct inode *inode; | ||
395 | int ret; | 414 | int ret; |
396 | int err; | 415 | int err; |
397 | u64 objectid; | 416 | u64 objectid; |
@@ -417,7 +436,9 @@ static noinline int create_subvol(struct inode *dir, | |||
417 | trans = btrfs_start_transaction(root, 0); | 436 | trans = btrfs_start_transaction(root, 0); |
418 | if (IS_ERR(trans)) { | 437 | if (IS_ERR(trans)) { |
419 | ret = PTR_ERR(trans); | 438 | ret = PTR_ERR(trans); |
420 | goto out; | 439 | btrfs_subvolume_release_metadata(root, &block_rsv, |
440 | qgroup_reserved); | ||
441 | return ret; | ||
421 | } | 442 | } |
422 | trans->block_rsv = &block_rsv; | 443 | trans->block_rsv = &block_rsv; |
423 | trans->bytes_reserved = block_rsv.size; | 444 | trans->bytes_reserved = block_rsv.size; |
@@ -500,7 +521,7 @@ static noinline int create_subvol(struct inode *dir, | |||
500 | 521 | ||
501 | btrfs_record_root_in_trans(trans, new_root); | 522 | btrfs_record_root_in_trans(trans, new_root); |
502 | 523 | ||
503 | ret = btrfs_create_subvol_root(trans, new_root, new_dirid); | 524 | ret = btrfs_create_subvol_root(trans, new_root, root, new_dirid); |
504 | if (ret) { | 525 | if (ret) { |
505 | /* We potentially lose an unused inode item here */ | 526 | /* We potentially lose an unused inode item here */ |
506 | btrfs_abort_transaction(trans, root, ret); | 527 | btrfs_abort_transaction(trans, root, ret); |
@@ -542,6 +563,8 @@ static noinline int create_subvol(struct inode *dir, | |||
542 | fail: | 563 | fail: |
543 | trans->block_rsv = NULL; | 564 | trans->block_rsv = NULL; |
544 | trans->bytes_reserved = 0; | 565 | trans->bytes_reserved = 0; |
566 | btrfs_subvolume_release_metadata(root, &block_rsv, qgroup_reserved); | ||
567 | |||
545 | if (async_transid) { | 568 | if (async_transid) { |
546 | *async_transid = trans->transid; | 569 | *async_transid = trans->transid; |
547 | err = btrfs_commit_transaction_async(trans, root, 1); | 570 | err = btrfs_commit_transaction_async(trans, root, 1); |
@@ -553,10 +576,12 @@ fail: | |||
553 | if (err && !ret) | 576 | if (err && !ret) |
554 | ret = err; | 577 | ret = err; |
555 | 578 | ||
556 | if (!ret) | 579 | if (!ret) { |
557 | d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); | 580 | inode = btrfs_lookup_dentry(dir, dentry); |
558 | out: | 581 | if (IS_ERR(inode)) |
559 | btrfs_subvolume_release_metadata(root, &block_rsv, qgroup_reserved); | 582 | return PTR_ERR(inode); |
583 | d_instantiate(dentry, inode); | ||
584 | } | ||
560 | return ret; | 585 | return ret; |
561 | } | 586 | } |
562 | 587 | ||
@@ -642,7 +667,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir, | |||
642 | ret = PTR_ERR(inode); | 667 | ret = PTR_ERR(inode); |
643 | goto fail; | 668 | goto fail; |
644 | } | 669 | } |
645 | BUG_ON(!inode); | 670 | |
646 | d_instantiate(dentry, inode); | 671 | d_instantiate(dentry, inode); |
647 | ret = 0; | 672 | ret = 0; |
648 | fail: | 673 | fail: |
@@ -1011,7 +1036,7 @@ out: | |||
1011 | static int cluster_pages_for_defrag(struct inode *inode, | 1036 | static int cluster_pages_for_defrag(struct inode *inode, |
1012 | struct page **pages, | 1037 | struct page **pages, |
1013 | unsigned long start_index, | 1038 | unsigned long start_index, |
1014 | int num_pages) | 1039 | unsigned long num_pages) |
1015 | { | 1040 | { |
1016 | unsigned long file_end; | 1041 | unsigned long file_end; |
1017 | u64 isize = i_size_read(inode); | 1042 | u64 isize = i_size_read(inode); |
@@ -1169,8 +1194,8 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
1169 | int defrag_count = 0; | 1194 | int defrag_count = 0; |
1170 | int compress_type = BTRFS_COMPRESS_ZLIB; | 1195 | int compress_type = BTRFS_COMPRESS_ZLIB; |
1171 | int extent_thresh = range->extent_thresh; | 1196 | int extent_thresh = range->extent_thresh; |
1172 | int max_cluster = (256 * 1024) >> PAGE_CACHE_SHIFT; | 1197 | unsigned long max_cluster = (256 * 1024) >> PAGE_CACHE_SHIFT; |
1173 | int cluster = max_cluster; | 1198 | unsigned long cluster = max_cluster; |
1174 | u64 new_align = ~((u64)128 * 1024 - 1); | 1199 | u64 new_align = ~((u64)128 * 1024 - 1); |
1175 | struct page **pages = NULL; | 1200 | struct page **pages = NULL; |
1176 | 1201 | ||
@@ -1254,7 +1279,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
1254 | break; | 1279 | break; |
1255 | 1280 | ||
1256 | if (btrfs_defrag_cancelled(root->fs_info)) { | 1281 | if (btrfs_defrag_cancelled(root->fs_info)) { |
1257 | printk(KERN_DEBUG "btrfs: defrag_file cancelled\n"); | 1282 | printk(KERN_DEBUG "BTRFS: defrag_file cancelled\n"); |
1258 | ret = -EAGAIN; | 1283 | ret = -EAGAIN; |
1259 | break; | 1284 | break; |
1260 | } | 1285 | } |
@@ -1416,20 +1441,20 @@ static noinline int btrfs_ioctl_resize(struct file *file, | |||
1416 | ret = -EINVAL; | 1441 | ret = -EINVAL; |
1417 | goto out_free; | 1442 | goto out_free; |
1418 | } | 1443 | } |
1419 | printk(KERN_INFO "btrfs: resizing devid %llu\n", devid); | 1444 | btrfs_info(root->fs_info, "resizing devid %llu", devid); |
1420 | } | 1445 | } |
1421 | 1446 | ||
1422 | device = btrfs_find_device(root->fs_info, devid, NULL, NULL); | 1447 | device = btrfs_find_device(root->fs_info, devid, NULL, NULL); |
1423 | if (!device) { | 1448 | if (!device) { |
1424 | printk(KERN_INFO "btrfs: resizer unable to find device %llu\n", | 1449 | btrfs_info(root->fs_info, "resizer unable to find device %llu", |
1425 | devid); | 1450 | devid); |
1426 | ret = -ENODEV; | 1451 | ret = -ENODEV; |
1427 | goto out_free; | 1452 | goto out_free; |
1428 | } | 1453 | } |
1429 | 1454 | ||
1430 | if (!device->writeable) { | 1455 | if (!device->writeable) { |
1431 | printk(KERN_INFO "btrfs: resizer unable to apply on " | 1456 | btrfs_info(root->fs_info, |
1432 | "readonly device %llu\n", | 1457 | "resizer unable to apply on readonly device %llu", |
1433 | devid); | 1458 | devid); |
1434 | ret = -EPERM; | 1459 | ret = -EPERM; |
1435 | goto out_free; | 1460 | goto out_free; |
@@ -1466,6 +1491,10 @@ static noinline int btrfs_ioctl_resize(struct file *file, | |||
1466 | } | 1491 | } |
1467 | new_size = old_size - new_size; | 1492 | new_size = old_size - new_size; |
1468 | } else if (mod > 0) { | 1493 | } else if (mod > 0) { |
1494 | if (new_size > ULLONG_MAX - old_size) { | ||
1495 | ret = -EINVAL; | ||
1496 | goto out_free; | ||
1497 | } | ||
1469 | new_size = old_size + new_size; | 1498 | new_size = old_size + new_size; |
1470 | } | 1499 | } |
1471 | 1500 | ||
@@ -1481,7 +1510,7 @@ static noinline int btrfs_ioctl_resize(struct file *file, | |||
1481 | do_div(new_size, root->sectorsize); | 1510 | do_div(new_size, root->sectorsize); |
1482 | new_size *= root->sectorsize; | 1511 | new_size *= root->sectorsize; |
1483 | 1512 | ||
1484 | printk_in_rcu(KERN_INFO "btrfs: new size for %s is %llu\n", | 1513 | printk_in_rcu(KERN_INFO "BTRFS: new size for %s is %llu\n", |
1485 | rcu_str_deref(device->name), new_size); | 1514 | rcu_str_deref(device->name), new_size); |
1486 | 1515 | ||
1487 | if (new_size > old_size) { | 1516 | if (new_size > old_size) { |
@@ -1542,9 +1571,15 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file, | |||
1542 | 1571 | ||
1543 | src_inode = file_inode(src.file); | 1572 | src_inode = file_inode(src.file); |
1544 | if (src_inode->i_sb != file_inode(file)->i_sb) { | 1573 | if (src_inode->i_sb != file_inode(file)->i_sb) { |
1545 | printk(KERN_INFO "btrfs: Snapshot src from " | 1574 | btrfs_info(BTRFS_I(src_inode)->root->fs_info, |
1546 | "another FS\n"); | 1575 | "Snapshot src from another FS"); |
1547 | ret = -EINVAL; | 1576 | ret = -EINVAL; |
1577 | } else if (!inode_owner_or_capable(src_inode)) { | ||
1578 | /* | ||
1579 | * Subvolume creation is not restricted, but snapshots | ||
1580 | * are limited to own subvolumes only | ||
1581 | */ | ||
1582 | ret = -EPERM; | ||
1548 | } else { | 1583 | } else { |
1549 | ret = btrfs_mksubvol(&file->f_path, name, namelen, | 1584 | ret = btrfs_mksubvol(&file->f_path, name, namelen, |
1550 | BTRFS_I(src_inode)->root, | 1585 | BTRFS_I(src_inode)->root, |
@@ -1662,6 +1697,9 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file, | |||
1662 | u64 flags; | 1697 | u64 flags; |
1663 | int ret = 0; | 1698 | int ret = 0; |
1664 | 1699 | ||
1700 | if (!inode_owner_or_capable(inode)) | ||
1701 | return -EPERM; | ||
1702 | |||
1665 | ret = mnt_want_write_file(file); | 1703 | ret = mnt_want_write_file(file); |
1666 | if (ret) | 1704 | if (ret) |
1667 | goto out; | 1705 | goto out; |
@@ -1686,11 +1724,6 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file, | |||
1686 | goto out_drop_write; | 1724 | goto out_drop_write; |
1687 | } | 1725 | } |
1688 | 1726 | ||
1689 | if (!inode_owner_or_capable(inode)) { | ||
1690 | ret = -EACCES; | ||
1691 | goto out_drop_write; | ||
1692 | } | ||
1693 | |||
1694 | down_write(&root->fs_info->subvol_sem); | 1727 | down_write(&root->fs_info->subvol_sem); |
1695 | 1728 | ||
1696 | /* nothing to do */ | 1729 | /* nothing to do */ |
@@ -1698,12 +1731,28 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file, | |||
1698 | goto out_drop_sem; | 1731 | goto out_drop_sem; |
1699 | 1732 | ||
1700 | root_flags = btrfs_root_flags(&root->root_item); | 1733 | root_flags = btrfs_root_flags(&root->root_item); |
1701 | if (flags & BTRFS_SUBVOL_RDONLY) | 1734 | if (flags & BTRFS_SUBVOL_RDONLY) { |
1702 | btrfs_set_root_flags(&root->root_item, | 1735 | btrfs_set_root_flags(&root->root_item, |
1703 | root_flags | BTRFS_ROOT_SUBVOL_RDONLY); | 1736 | root_flags | BTRFS_ROOT_SUBVOL_RDONLY); |
1704 | else | 1737 | } else { |
1705 | btrfs_set_root_flags(&root->root_item, | 1738 | /* |
1739 | * Block RO -> RW transition if this subvolume is involved in | ||
1740 | * send | ||
1741 | */ | ||
1742 | spin_lock(&root->root_item_lock); | ||
1743 | if (root->send_in_progress == 0) { | ||
1744 | btrfs_set_root_flags(&root->root_item, | ||
1706 | root_flags & ~BTRFS_ROOT_SUBVOL_RDONLY); | 1745 | root_flags & ~BTRFS_ROOT_SUBVOL_RDONLY); |
1746 | spin_unlock(&root->root_item_lock); | ||
1747 | } else { | ||
1748 | spin_unlock(&root->root_item_lock); | ||
1749 | btrfs_warn(root->fs_info, | ||
1750 | "Attempt to set subvolume %llu read-write during send", | ||
1751 | root->root_key.objectid); | ||
1752 | ret = -EPERM; | ||
1753 | goto out_drop_sem; | ||
1754 | } | ||
1755 | } | ||
1707 | 1756 | ||
1708 | trans = btrfs_start_transaction(root, 1); | 1757 | trans = btrfs_start_transaction(root, 1); |
1709 | if (IS_ERR(trans)) { | 1758 | if (IS_ERR(trans)) { |
@@ -1910,7 +1959,7 @@ static noinline int search_ioctl(struct inode *inode, | |||
1910 | key.offset = (u64)-1; | 1959 | key.offset = (u64)-1; |
1911 | root = btrfs_read_fs_root_no_name(info, &key); | 1960 | root = btrfs_read_fs_root_no_name(info, &key); |
1912 | if (IS_ERR(root)) { | 1961 | if (IS_ERR(root)) { |
1913 | printk(KERN_ERR "could not find root %llu\n", | 1962 | printk(KERN_ERR "BTRFS: could not find root %llu\n", |
1914 | sk->tree_id); | 1963 | sk->tree_id); |
1915 | btrfs_free_path(path); | 1964 | btrfs_free_path(path); |
1916 | return -ENOENT; | 1965 | return -ENOENT; |
@@ -2000,7 +2049,7 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info, | |||
2000 | key.offset = (u64)-1; | 2049 | key.offset = (u64)-1; |
2001 | root = btrfs_read_fs_root_no_name(info, &key); | 2050 | root = btrfs_read_fs_root_no_name(info, &key); |
2002 | if (IS_ERR(root)) { | 2051 | if (IS_ERR(root)) { |
2003 | printk(KERN_ERR "could not find root %llu\n", tree_id); | 2052 | printk(KERN_ERR "BTRFS: could not find root %llu\n", tree_id); |
2004 | ret = -ENOENT; | 2053 | ret = -ENOENT; |
2005 | goto out; | 2054 | goto out; |
2006 | } | 2055 | } |
@@ -2686,14 +2735,11 @@ out_unlock: | |||
2686 | #define BTRFS_MAX_DEDUPE_LEN (16 * 1024 * 1024) | 2735 | #define BTRFS_MAX_DEDUPE_LEN (16 * 1024 * 1024) |
2687 | 2736 | ||
2688 | static long btrfs_ioctl_file_extent_same(struct file *file, | 2737 | static long btrfs_ioctl_file_extent_same(struct file *file, |
2689 | void __user *argp) | 2738 | struct btrfs_ioctl_same_args __user *argp) |
2690 | { | 2739 | { |
2691 | struct btrfs_ioctl_same_args tmp; | ||
2692 | struct btrfs_ioctl_same_args *same; | 2740 | struct btrfs_ioctl_same_args *same; |
2693 | struct btrfs_ioctl_same_extent_info *info; | 2741 | struct btrfs_ioctl_same_extent_info *info; |
2694 | struct inode *src = file->f_dentry->d_inode; | 2742 | struct inode *src = file_inode(file); |
2695 | struct file *dst_file = NULL; | ||
2696 | struct inode *dst; | ||
2697 | u64 off; | 2743 | u64 off; |
2698 | u64 len; | 2744 | u64 len; |
2699 | int i; | 2745 | int i; |
@@ -2701,6 +2747,7 @@ static long btrfs_ioctl_file_extent_same(struct file *file, | |||
2701 | unsigned long size; | 2747 | unsigned long size; |
2702 | u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize; | 2748 | u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize; |
2703 | bool is_admin = capable(CAP_SYS_ADMIN); | 2749 | bool is_admin = capable(CAP_SYS_ADMIN); |
2750 | u16 count; | ||
2704 | 2751 | ||
2705 | if (!(file->f_mode & FMODE_READ)) | 2752 | if (!(file->f_mode & FMODE_READ)) |
2706 | return -EINVAL; | 2753 | return -EINVAL; |
@@ -2709,17 +2756,14 @@ static long btrfs_ioctl_file_extent_same(struct file *file, | |||
2709 | if (ret) | 2756 | if (ret) |
2710 | return ret; | 2757 | return ret; |
2711 | 2758 | ||
2712 | if (copy_from_user(&tmp, | 2759 | if (get_user(count, &argp->dest_count)) { |
2713 | (struct btrfs_ioctl_same_args __user *)argp, | ||
2714 | sizeof(tmp))) { | ||
2715 | ret = -EFAULT; | 2760 | ret = -EFAULT; |
2716 | goto out; | 2761 | goto out; |
2717 | } | 2762 | } |
2718 | 2763 | ||
2719 | size = sizeof(tmp) + | 2764 | size = offsetof(struct btrfs_ioctl_same_args __user, info[count]); |
2720 | tmp.dest_count * sizeof(struct btrfs_ioctl_same_extent_info); | ||
2721 | 2765 | ||
2722 | same = memdup_user((struct btrfs_ioctl_same_args __user *)argp, size); | 2766 | same = memdup_user(argp, size); |
2723 | 2767 | ||
2724 | if (IS_ERR(same)) { | 2768 | if (IS_ERR(same)) { |
2725 | ret = PTR_ERR(same); | 2769 | ret = PTR_ERR(same); |
@@ -2756,52 +2800,35 @@ static long btrfs_ioctl_file_extent_same(struct file *file, | |||
2756 | goto out; | 2800 | goto out; |
2757 | 2801 | ||
2758 | /* pre-format output fields to sane values */ | 2802 | /* pre-format output fields to sane values */ |
2759 | for (i = 0; i < same->dest_count; i++) { | 2803 | for (i = 0; i < count; i++) { |
2760 | same->info[i].bytes_deduped = 0ULL; | 2804 | same->info[i].bytes_deduped = 0ULL; |
2761 | same->info[i].status = 0; | 2805 | same->info[i].status = 0; |
2762 | } | 2806 | } |
2763 | 2807 | ||
2764 | ret = 0; | 2808 | for (i = 0, info = same->info; i < count; i++, info++) { |
2765 | for (i = 0; i < same->dest_count; i++) { | 2809 | struct inode *dst; |
2766 | info = &same->info[i]; | 2810 | struct fd dst_file = fdget(info->fd); |
2767 | 2811 | if (!dst_file.file) { | |
2768 | dst_file = fget(info->fd); | ||
2769 | if (!dst_file) { | ||
2770 | info->status = -EBADF; | 2812 | info->status = -EBADF; |
2771 | goto next; | 2813 | continue; |
2772 | } | 2814 | } |
2815 | dst = file_inode(dst_file.file); | ||
2773 | 2816 | ||
2774 | if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) { | 2817 | if (!(is_admin || (dst_file.file->f_mode & FMODE_WRITE))) { |
2775 | info->status = -EINVAL; | 2818 | info->status = -EINVAL; |
2776 | goto next; | 2819 | } else if (file->f_path.mnt != dst_file.file->f_path.mnt) { |
2777 | } | 2820 | info->status = -EXDEV; |
2778 | 2821 | } else if (S_ISDIR(dst->i_mode)) { | |
2779 | info->status = -EXDEV; | ||
2780 | if (file->f_path.mnt != dst_file->f_path.mnt) | ||
2781 | goto next; | ||
2782 | |||
2783 | dst = dst_file->f_dentry->d_inode; | ||
2784 | if (src->i_sb != dst->i_sb) | ||
2785 | goto next; | ||
2786 | |||
2787 | if (S_ISDIR(dst->i_mode)) { | ||
2788 | info->status = -EISDIR; | 2822 | info->status = -EISDIR; |
2789 | goto next; | 2823 | } else if (!S_ISREG(dst->i_mode)) { |
2790 | } | ||
2791 | |||
2792 | if (!S_ISREG(dst->i_mode)) { | ||
2793 | info->status = -EACCES; | 2824 | info->status = -EACCES; |
2794 | goto next; | 2825 | } else { |
2826 | info->status = btrfs_extent_same(src, off, len, dst, | ||
2827 | info->logical_offset); | ||
2828 | if (info->status == 0) | ||
2829 | info->bytes_deduped += len; | ||
2795 | } | 2830 | } |
2796 | 2831 | fdput(dst_file); | |
2797 | info->status = btrfs_extent_same(src, off, len, dst, | ||
2798 | info->logical_offset); | ||
2799 | if (info->status == 0) | ||
2800 | info->bytes_deduped += len; | ||
2801 | |||
2802 | next: | ||
2803 | if (dst_file) | ||
2804 | fput(dst_file); | ||
2805 | } | 2832 | } |
2806 | 2833 | ||
2807 | ret = copy_to_user(argp, same, size); | 2834 | ret = copy_to_user(argp, same, size); |
@@ -2860,12 +2887,14 @@ static int btrfs_clone(struct inode *src, struct inode *inode, | |||
2860 | * note the key will change type as we walk through the | 2887 | * note the key will change type as we walk through the |
2861 | * tree. | 2888 | * tree. |
2862 | */ | 2889 | */ |
2890 | path->leave_spinning = 1; | ||
2863 | ret = btrfs_search_slot(NULL, BTRFS_I(src)->root, &key, path, | 2891 | ret = btrfs_search_slot(NULL, BTRFS_I(src)->root, &key, path, |
2864 | 0, 0); | 2892 | 0, 0); |
2865 | if (ret < 0) | 2893 | if (ret < 0) |
2866 | goto out; | 2894 | goto out; |
2867 | 2895 | ||
2868 | nritems = btrfs_header_nritems(path->nodes[0]); | 2896 | nritems = btrfs_header_nritems(path->nodes[0]); |
2897 | process_slot: | ||
2869 | if (path->slots[0] >= nritems) { | 2898 | if (path->slots[0] >= nritems) { |
2870 | ret = btrfs_next_leaf(BTRFS_I(src)->root, path); | 2899 | ret = btrfs_next_leaf(BTRFS_I(src)->root, path); |
2871 | if (ret < 0) | 2900 | if (ret < 0) |
@@ -2892,11 +2921,6 @@ static int btrfs_clone(struct inode *src, struct inode *inode, | |||
2892 | u8 comp; | 2921 | u8 comp; |
2893 | u64 endoff; | 2922 | u64 endoff; |
2894 | 2923 | ||
2895 | size = btrfs_item_size_nr(leaf, slot); | ||
2896 | read_extent_buffer(leaf, buf, | ||
2897 | btrfs_item_ptr_offset(leaf, slot), | ||
2898 | size); | ||
2899 | |||
2900 | extent = btrfs_item_ptr(leaf, slot, | 2924 | extent = btrfs_item_ptr(leaf, slot, |
2901 | struct btrfs_file_extent_item); | 2925 | struct btrfs_file_extent_item); |
2902 | comp = btrfs_file_extent_compression(leaf, extent); | 2926 | comp = btrfs_file_extent_compression(leaf, extent); |
@@ -2915,11 +2939,20 @@ static int btrfs_clone(struct inode *src, struct inode *inode, | |||
2915 | datal = btrfs_file_extent_ram_bytes(leaf, | 2939 | datal = btrfs_file_extent_ram_bytes(leaf, |
2916 | extent); | 2940 | extent); |
2917 | } | 2941 | } |
2918 | btrfs_release_path(path); | ||
2919 | 2942 | ||
2920 | if (key.offset + datal <= off || | 2943 | if (key.offset + datal <= off || |
2921 | key.offset >= off + len - 1) | 2944 | key.offset >= off + len - 1) { |
2922 | goto next; | 2945 | path->slots[0]++; |
2946 | goto process_slot; | ||
2947 | } | ||
2948 | |||
2949 | size = btrfs_item_size_nr(leaf, slot); | ||
2950 | read_extent_buffer(leaf, buf, | ||
2951 | btrfs_item_ptr_offset(leaf, slot), | ||
2952 | size); | ||
2953 | |||
2954 | btrfs_release_path(path); | ||
2955 | path->leave_spinning = 0; | ||
2923 | 2956 | ||
2924 | memcpy(&new_key, &key, sizeof(new_key)); | 2957 | memcpy(&new_key, &key, sizeof(new_key)); |
2925 | new_key.objectid = btrfs_ino(inode); | 2958 | new_key.objectid = btrfs_ino(inode); |
@@ -3090,7 +3123,6 @@ static int btrfs_clone(struct inode *src, struct inode *inode, | |||
3090 | } | 3123 | } |
3091 | ret = btrfs_end_transaction(trans, root); | 3124 | ret = btrfs_end_transaction(trans, root); |
3092 | } | 3125 | } |
3093 | next: | ||
3094 | btrfs_release_path(path); | 3126 | btrfs_release_path(path); |
3095 | key.offset++; | 3127 | key.offset++; |
3096 | } | 3128 | } |
@@ -3218,9 +3250,17 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
3218 | 3250 | ||
3219 | unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1); | 3251 | unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1); |
3220 | out_unlock: | 3252 | out_unlock: |
3221 | mutex_unlock(&src->i_mutex); | 3253 | if (!same_inode) { |
3222 | if (!same_inode) | 3254 | if (inode < src) { |
3223 | mutex_unlock(&inode->i_mutex); | 3255 | mutex_unlock(&src->i_mutex); |
3256 | mutex_unlock(&inode->i_mutex); | ||
3257 | } else { | ||
3258 | mutex_unlock(&inode->i_mutex); | ||
3259 | mutex_unlock(&src->i_mutex); | ||
3260 | } | ||
3261 | } else { | ||
3262 | mutex_unlock(&src->i_mutex); | ||
3263 | } | ||
3224 | out_fput: | 3264 | out_fput: |
3225 | fdput(src_file); | 3265 | fdput(src_file); |
3226 | out_drop_write: | 3266 | out_drop_write: |
@@ -3343,8 +3383,8 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) | |||
3343 | if (IS_ERR_OR_NULL(di)) { | 3383 | if (IS_ERR_OR_NULL(di)) { |
3344 | btrfs_free_path(path); | 3384 | btrfs_free_path(path); |
3345 | btrfs_end_transaction(trans, root); | 3385 | btrfs_end_transaction(trans, root); |
3346 | printk(KERN_ERR "Umm, you don't have the default dir item, " | 3386 | btrfs_err(new_root->fs_info, "Umm, you don't have the default dir" |
3347 | "this isn't going to work\n"); | 3387 | "item, this isn't going to work"); |
3348 | ret = -ENOENT; | 3388 | ret = -ENOENT; |
3349 | goto out; | 3389 | goto out; |
3350 | } | 3390 | } |
@@ -4325,6 +4365,9 @@ static long btrfs_ioctl_set_received_subvol(struct file *file, | |||
4325 | int ret = 0; | 4365 | int ret = 0; |
4326 | int received_uuid_changed; | 4366 | int received_uuid_changed; |
4327 | 4367 | ||
4368 | if (!inode_owner_or_capable(inode)) | ||
4369 | return -EPERM; | ||
4370 | |||
4328 | ret = mnt_want_write_file(file); | 4371 | ret = mnt_want_write_file(file); |
4329 | if (ret < 0) | 4372 | if (ret < 0) |
4330 | return ret; | 4373 | return ret; |
@@ -4341,11 +4384,6 @@ static long btrfs_ioctl_set_received_subvol(struct file *file, | |||
4341 | goto out; | 4384 | goto out; |
4342 | } | 4385 | } |
4343 | 4386 | ||
4344 | if (!inode_owner_or_capable(inode)) { | ||
4345 | ret = -EACCES; | ||
4346 | goto out; | ||
4347 | } | ||
4348 | |||
4349 | sa = memdup_user(arg, sizeof(*sa)); | 4387 | sa = memdup_user(arg, sizeof(*sa)); |
4350 | if (IS_ERR(sa)) { | 4388 | if (IS_ERR(sa)) { |
4351 | ret = PTR_ERR(sa); | 4389 | ret = PTR_ERR(sa); |
@@ -4431,8 +4469,8 @@ static int btrfs_ioctl_get_fslabel(struct file *file, void __user *arg) | |||
4431 | len = strnlen(label, BTRFS_LABEL_SIZE); | 4469 | len = strnlen(label, BTRFS_LABEL_SIZE); |
4432 | 4470 | ||
4433 | if (len == BTRFS_LABEL_SIZE) { | 4471 | if (len == BTRFS_LABEL_SIZE) { |
4434 | pr_warn("btrfs: label is too long, return the first %zu bytes\n", | 4472 | btrfs_warn(root->fs_info, |
4435 | --len); | 4473 | "label is too long, return the first %zu bytes", --len); |
4436 | } | 4474 | } |
4437 | 4475 | ||
4438 | ret = copy_to_user(arg, label, len); | 4476 | ret = copy_to_user(arg, label, len); |
@@ -4455,7 +4493,7 @@ static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg) | |||
4455 | return -EFAULT; | 4493 | return -EFAULT; |
4456 | 4494 | ||
4457 | if (strnlen(label, BTRFS_LABEL_SIZE) == BTRFS_LABEL_SIZE) { | 4495 | if (strnlen(label, BTRFS_LABEL_SIZE) == BTRFS_LABEL_SIZE) { |
4458 | pr_err("btrfs: unable to set label with more than %d bytes\n", | 4496 | btrfs_err(root->fs_info, "unable to set label with more than %d bytes", |
4459 | BTRFS_LABEL_SIZE - 1); | 4497 | BTRFS_LABEL_SIZE - 1); |
4460 | return -EINVAL; | 4498 | return -EINVAL; |
4461 | } | 4499 | } |
@@ -4473,13 +4511,173 @@ static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg) | |||
4473 | spin_lock(&root->fs_info->super_lock); | 4511 | spin_lock(&root->fs_info->super_lock); |
4474 | strcpy(super_block->label, label); | 4512 | strcpy(super_block->label, label); |
4475 | spin_unlock(&root->fs_info->super_lock); | 4513 | spin_unlock(&root->fs_info->super_lock); |
4476 | ret = btrfs_end_transaction(trans, root); | 4514 | ret = btrfs_commit_transaction(trans, root); |
4477 | 4515 | ||
4478 | out_unlock: | 4516 | out_unlock: |
4479 | mnt_drop_write_file(file); | 4517 | mnt_drop_write_file(file); |
4480 | return ret; | 4518 | return ret; |
4481 | } | 4519 | } |
4482 | 4520 | ||
4521 | #define INIT_FEATURE_FLAGS(suffix) \ | ||
4522 | { .compat_flags = BTRFS_FEATURE_COMPAT_##suffix, \ | ||
4523 | .compat_ro_flags = BTRFS_FEATURE_COMPAT_RO_##suffix, \ | ||
4524 | .incompat_flags = BTRFS_FEATURE_INCOMPAT_##suffix } | ||
4525 | |||
4526 | static int btrfs_ioctl_get_supported_features(struct file *file, | ||
4527 | void __user *arg) | ||
4528 | { | ||
4529 | static struct btrfs_ioctl_feature_flags features[3] = { | ||
4530 | INIT_FEATURE_FLAGS(SUPP), | ||
4531 | INIT_FEATURE_FLAGS(SAFE_SET), | ||
4532 | INIT_FEATURE_FLAGS(SAFE_CLEAR) | ||
4533 | }; | ||
4534 | |||
4535 | if (copy_to_user(arg, &features, sizeof(features))) | ||
4536 | return -EFAULT; | ||
4537 | |||
4538 | return 0; | ||
4539 | } | ||
4540 | |||
4541 | static int btrfs_ioctl_get_features(struct file *file, void __user *arg) | ||
4542 | { | ||
4543 | struct btrfs_root *root = BTRFS_I(file_inode(file))->root; | ||
4544 | struct btrfs_super_block *super_block = root->fs_info->super_copy; | ||
4545 | struct btrfs_ioctl_feature_flags features; | ||
4546 | |||
4547 | features.compat_flags = btrfs_super_compat_flags(super_block); | ||
4548 | features.compat_ro_flags = btrfs_super_compat_ro_flags(super_block); | ||
4549 | features.incompat_flags = btrfs_super_incompat_flags(super_block); | ||
4550 | |||
4551 | if (copy_to_user(arg, &features, sizeof(features))) | ||
4552 | return -EFAULT; | ||
4553 | |||
4554 | return 0; | ||
4555 | } | ||
4556 | |||
4557 | static int check_feature_bits(struct btrfs_root *root, | ||
4558 | enum btrfs_feature_set set, | ||
4559 | u64 change_mask, u64 flags, u64 supported_flags, | ||
4560 | u64 safe_set, u64 safe_clear) | ||
4561 | { | ||
4562 | const char *type = btrfs_feature_set_names[set]; | ||
4563 | char *names; | ||
4564 | u64 disallowed, unsupported; | ||
4565 | u64 set_mask = flags & change_mask; | ||
4566 | u64 clear_mask = ~flags & change_mask; | ||
4567 | |||
4568 | unsupported = set_mask & ~supported_flags; | ||
4569 | if (unsupported) { | ||
4570 | names = btrfs_printable_features(set, unsupported); | ||
4571 | if (names) { | ||
4572 | btrfs_warn(root->fs_info, | ||
4573 | "this kernel does not support the %s feature bit%s", | ||
4574 | names, strchr(names, ',') ? "s" : ""); | ||
4575 | kfree(names); | ||
4576 | } else | ||
4577 | btrfs_warn(root->fs_info, | ||
4578 | "this kernel does not support %s bits 0x%llx", | ||
4579 | type, unsupported); | ||
4580 | return -EOPNOTSUPP; | ||
4581 | } | ||
4582 | |||
4583 | disallowed = set_mask & ~safe_set; | ||
4584 | if (disallowed) { | ||
4585 | names = btrfs_printable_features(set, disallowed); | ||
4586 | if (names) { | ||
4587 | btrfs_warn(root->fs_info, | ||
4588 | "can't set the %s feature bit%s while mounted", | ||
4589 | names, strchr(names, ',') ? "s" : ""); | ||
4590 | kfree(names); | ||
4591 | } else | ||
4592 | btrfs_warn(root->fs_info, | ||
4593 | "can't set %s bits 0x%llx while mounted", | ||
4594 | type, disallowed); | ||
4595 | return -EPERM; | ||
4596 | } | ||
4597 | |||
4598 | disallowed = clear_mask & ~safe_clear; | ||
4599 | if (disallowed) { | ||
4600 | names = btrfs_printable_features(set, disallowed); | ||
4601 | if (names) { | ||
4602 | btrfs_warn(root->fs_info, | ||
4603 | "can't clear the %s feature bit%s while mounted", | ||
4604 | names, strchr(names, ',') ? "s" : ""); | ||
4605 | kfree(names); | ||
4606 | } else | ||
4607 | btrfs_warn(root->fs_info, | ||
4608 | "can't clear %s bits 0x%llx while mounted", | ||
4609 | type, disallowed); | ||
4610 | return -EPERM; | ||
4611 | } | ||
4612 | |||
4613 | return 0; | ||
4614 | } | ||
4615 | |||
4616 | #define check_feature(root, change_mask, flags, mask_base) \ | ||
4617 | check_feature_bits(root, FEAT_##mask_base, change_mask, flags, \ | ||
4618 | BTRFS_FEATURE_ ## mask_base ## _SUPP, \ | ||
4619 | BTRFS_FEATURE_ ## mask_base ## _SAFE_SET, \ | ||
4620 | BTRFS_FEATURE_ ## mask_base ## _SAFE_CLEAR) | ||
4621 | |||
4622 | static int btrfs_ioctl_set_features(struct file *file, void __user *arg) | ||
4623 | { | ||
4624 | struct btrfs_root *root = BTRFS_I(file_inode(file))->root; | ||
4625 | struct btrfs_super_block *super_block = root->fs_info->super_copy; | ||
4626 | struct btrfs_ioctl_feature_flags flags[2]; | ||
4627 | struct btrfs_trans_handle *trans; | ||
4628 | u64 newflags; | ||
4629 | int ret; | ||
4630 | |||
4631 | if (!capable(CAP_SYS_ADMIN)) | ||
4632 | return -EPERM; | ||
4633 | |||
4634 | if (copy_from_user(flags, arg, sizeof(flags))) | ||
4635 | return -EFAULT; | ||
4636 | |||
4637 | /* Nothing to do */ | ||
4638 | if (!flags[0].compat_flags && !flags[0].compat_ro_flags && | ||
4639 | !flags[0].incompat_flags) | ||
4640 | return 0; | ||
4641 | |||
4642 | ret = check_feature(root, flags[0].compat_flags, | ||
4643 | flags[1].compat_flags, COMPAT); | ||
4644 | if (ret) | ||
4645 | return ret; | ||
4646 | |||
4647 | ret = check_feature(root, flags[0].compat_ro_flags, | ||
4648 | flags[1].compat_ro_flags, COMPAT_RO); | ||
4649 | if (ret) | ||
4650 | return ret; | ||
4651 | |||
4652 | ret = check_feature(root, flags[0].incompat_flags, | ||
4653 | flags[1].incompat_flags, INCOMPAT); | ||
4654 | if (ret) | ||
4655 | return ret; | ||
4656 | |||
4657 | trans = btrfs_start_transaction(root, 0); | ||
4658 | if (IS_ERR(trans)) | ||
4659 | return PTR_ERR(trans); | ||
4660 | |||
4661 | spin_lock(&root->fs_info->super_lock); | ||
4662 | newflags = btrfs_super_compat_flags(super_block); | ||
4663 | newflags |= flags[0].compat_flags & flags[1].compat_flags; | ||
4664 | newflags &= ~(flags[0].compat_flags & ~flags[1].compat_flags); | ||
4665 | btrfs_set_super_compat_flags(super_block, newflags); | ||
4666 | |||
4667 | newflags = btrfs_super_compat_ro_flags(super_block); | ||
4668 | newflags |= flags[0].compat_ro_flags & flags[1].compat_ro_flags; | ||
4669 | newflags &= ~(flags[0].compat_ro_flags & ~flags[1].compat_ro_flags); | ||
4670 | btrfs_set_super_compat_ro_flags(super_block, newflags); | ||
4671 | |||
4672 | newflags = btrfs_super_incompat_flags(super_block); | ||
4673 | newflags |= flags[0].incompat_flags & flags[1].incompat_flags; | ||
4674 | newflags &= ~(flags[0].incompat_flags & ~flags[1].incompat_flags); | ||
4675 | btrfs_set_super_incompat_flags(super_block, newflags); | ||
4676 | spin_unlock(&root->fs_info->super_lock); | ||
4677 | |||
4678 | return btrfs_commit_transaction(trans, root); | ||
4679 | } | ||
4680 | |||
4483 | long btrfs_ioctl(struct file *file, unsigned int | 4681 | long btrfs_ioctl(struct file *file, unsigned int |
4484 | cmd, unsigned long arg) | 4682 | cmd, unsigned long arg) |
4485 | { | 4683 | { |
@@ -4598,6 +4796,12 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
4598 | return btrfs_ioctl_set_fslabel(file, argp); | 4796 | return btrfs_ioctl_set_fslabel(file, argp); |
4599 | case BTRFS_IOC_FILE_EXTENT_SAME: | 4797 | case BTRFS_IOC_FILE_EXTENT_SAME: |
4600 | return btrfs_ioctl_file_extent_same(file, argp); | 4798 | return btrfs_ioctl_file_extent_same(file, argp); |
4799 | case BTRFS_IOC_GET_SUPPORTED_FEATURES: | ||
4800 | return btrfs_ioctl_get_supported_features(file, argp); | ||
4801 | case BTRFS_IOC_GET_FEATURES: | ||
4802 | return btrfs_ioctl_get_features(file, argp); | ||
4803 | case BTRFS_IOC_SET_FEATURES: | ||
4804 | return btrfs_ioctl_set_features(file, argp); | ||
4601 | } | 4805 | } |
4602 | 4806 | ||
4603 | return -ENOTTY; | 4807 | return -ENOTTY; |