diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-30 23:08:20 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-30 23:08:20 -0500 |
commit | e7651b819e90da924991d727d3c007200a18670d (patch) | |
tree | e7a943b5bb56c384972944fd86767a3f079b8a98 /fs/btrfs/ioctl.c | |
parent | 060e8e3b6f8fc0ba97de2276249fbd80fa25b0a2 (diff) | |
parent | cf93da7bcf450cb4595055d491a0519cb39e68ed (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
Pull btrfs updates from Chris Mason:
"This is a pretty big pull, and most of these changes have been
floating in btrfs-next for a long time. Filipe's properties work is a
cool building block for inheriting attributes like compression down on
a per inode basis.
Jeff Mahoney kicked in code to export filesystem info into sysfs.
Otherwise, lots of performance improvements, cleanups and bug fixes.
Looks like there are still a few other small pending incrementals, but
I wanted to get the bulk of this in first"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (149 commits)
Btrfs: fix spin_unlock in check_ref_cleanup
Btrfs: setup inode location during btrfs_init_inode_locked
Btrfs: don't use ram_bytes for uncompressed inline items
Btrfs: fix btrfs_search_slot_for_read backwards iteration
Btrfs: do not export ulist functions
Btrfs: rework ulist with list+rb_tree
Btrfs: fix memory leaks on walking backrefs failure
Btrfs: fix send file hole detection leading to data corruption
Btrfs: add a reschedule point in btrfs_find_all_roots()
Btrfs: make send's file extent item search more efficient
Btrfs: fix to catch all errors when resolving indirect ref
Btrfs: fix protection between walking backrefs and root deletion
btrfs: fix warning while merging two adjacent extents
Btrfs: fix infinite path build loops in incremental send
btrfs: undo sysfs when open_ctree() fails
Btrfs: fix snprintf usage by send's gen_unique_name
btrfs: fix defrag 32-bit integer overflow
btrfs: sysfs: list the NO_HOLES feature
btrfs: sysfs: don't show reserved incompat feature
btrfs: call permission checks earlier in ioctls and return EPERM
...
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 348 |
1 files changed, 295 insertions, 53 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index ad27dcea319c..b0134892dc70 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 | } |
@@ -2838,12 +2887,14 @@ static int btrfs_clone(struct inode *src, struct inode *inode, | |||
2838 | * note the key will change type as we walk through the | 2887 | * note the key will change type as we walk through the |
2839 | * tree. | 2888 | * tree. |
2840 | */ | 2889 | */ |
2890 | path->leave_spinning = 1; | ||
2841 | ret = btrfs_search_slot(NULL, BTRFS_I(src)->root, &key, path, | 2891 | ret = btrfs_search_slot(NULL, BTRFS_I(src)->root, &key, path, |
2842 | 0, 0); | 2892 | 0, 0); |
2843 | if (ret < 0) | 2893 | if (ret < 0) |
2844 | goto out; | 2894 | goto out; |
2845 | 2895 | ||
2846 | nritems = btrfs_header_nritems(path->nodes[0]); | 2896 | nritems = btrfs_header_nritems(path->nodes[0]); |
2897 | process_slot: | ||
2847 | if (path->slots[0] >= nritems) { | 2898 | if (path->slots[0] >= nritems) { |
2848 | ret = btrfs_next_leaf(BTRFS_I(src)->root, path); | 2899 | ret = btrfs_next_leaf(BTRFS_I(src)->root, path); |
2849 | if (ret < 0) | 2900 | if (ret < 0) |
@@ -2870,11 +2921,6 @@ static int btrfs_clone(struct inode *src, struct inode *inode, | |||
2870 | u8 comp; | 2921 | u8 comp; |
2871 | u64 endoff; | 2922 | u64 endoff; |
2872 | 2923 | ||
2873 | size = btrfs_item_size_nr(leaf, slot); | ||
2874 | read_extent_buffer(leaf, buf, | ||
2875 | btrfs_item_ptr_offset(leaf, slot), | ||
2876 | size); | ||
2877 | |||
2878 | extent = btrfs_item_ptr(leaf, slot, | 2924 | extent = btrfs_item_ptr(leaf, slot, |
2879 | struct btrfs_file_extent_item); | 2925 | struct btrfs_file_extent_item); |
2880 | comp = btrfs_file_extent_compression(leaf, extent); | 2926 | comp = btrfs_file_extent_compression(leaf, extent); |
@@ -2893,11 +2939,20 @@ static int btrfs_clone(struct inode *src, struct inode *inode, | |||
2893 | datal = btrfs_file_extent_ram_bytes(leaf, | 2939 | datal = btrfs_file_extent_ram_bytes(leaf, |
2894 | extent); | 2940 | extent); |
2895 | } | 2941 | } |
2896 | btrfs_release_path(path); | ||
2897 | 2942 | ||
2898 | if (key.offset + datal <= off || | 2943 | if (key.offset + datal <= off || |
2899 | key.offset >= off + len - 1) | 2944 | key.offset >= off + len - 1) { |
2900 | 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; | ||
2901 | 2956 | ||
2902 | memcpy(&new_key, &key, sizeof(new_key)); | 2957 | memcpy(&new_key, &key, sizeof(new_key)); |
2903 | new_key.objectid = btrfs_ino(inode); | 2958 | new_key.objectid = btrfs_ino(inode); |
@@ -3068,7 +3123,6 @@ static int btrfs_clone(struct inode *src, struct inode *inode, | |||
3068 | } | 3123 | } |
3069 | ret = btrfs_end_transaction(trans, root); | 3124 | ret = btrfs_end_transaction(trans, root); |
3070 | } | 3125 | } |
3071 | next: | ||
3072 | btrfs_release_path(path); | 3126 | btrfs_release_path(path); |
3073 | key.offset++; | 3127 | key.offset++; |
3074 | } | 3128 | } |
@@ -3196,9 +3250,17 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
3196 | 3250 | ||
3197 | unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1); | 3251 | unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1); |
3198 | out_unlock: | 3252 | out_unlock: |
3199 | mutex_unlock(&src->i_mutex); | 3253 | if (!same_inode) { |
3200 | if (!same_inode) | 3254 | if (inode < src) { |
3201 | 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 | } | ||
3202 | out_fput: | 3264 | out_fput: |
3203 | fdput(src_file); | 3265 | fdput(src_file); |
3204 | out_drop_write: | 3266 | out_drop_write: |
@@ -3321,8 +3383,8 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) | |||
3321 | if (IS_ERR_OR_NULL(di)) { | 3383 | if (IS_ERR_OR_NULL(di)) { |
3322 | btrfs_free_path(path); | 3384 | btrfs_free_path(path); |
3323 | btrfs_end_transaction(trans, root); | 3385 | btrfs_end_transaction(trans, root); |
3324 | 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" |
3325 | "this isn't going to work\n"); | 3387 | "item, this isn't going to work"); |
3326 | ret = -ENOENT; | 3388 | ret = -ENOENT; |
3327 | goto out; | 3389 | goto out; |
3328 | } | 3390 | } |
@@ -3475,6 +3537,20 @@ out: | |||
3475 | return ret; | 3537 | return ret; |
3476 | } | 3538 | } |
3477 | 3539 | ||
3540 | static long btrfs_ioctl_global_rsv(struct btrfs_root *root, void __user *arg) | ||
3541 | { | ||
3542 | struct btrfs_block_rsv *block_rsv = &root->fs_info->global_block_rsv; | ||
3543 | u64 reserved; | ||
3544 | |||
3545 | spin_lock(&block_rsv->lock); | ||
3546 | reserved = block_rsv->reserved; | ||
3547 | spin_unlock(&block_rsv->lock); | ||
3548 | |||
3549 | if (arg && copy_to_user(arg, &reserved, sizeof(reserved))) | ||
3550 | return -EFAULT; | ||
3551 | return 0; | ||
3552 | } | ||
3553 | |||
3478 | /* | 3554 | /* |
3479 | * there are many ways the trans_start and trans_end ioctls can lead | 3555 | * there are many ways the trans_start and trans_end ioctls can lead |
3480 | * to deadlocks. They should only be used by applications that | 3556 | * to deadlocks. They should only be used by applications that |
@@ -4303,6 +4379,9 @@ static long btrfs_ioctl_set_received_subvol(struct file *file, | |||
4303 | int ret = 0; | 4379 | int ret = 0; |
4304 | int received_uuid_changed; | 4380 | int received_uuid_changed; |
4305 | 4381 | ||
4382 | if (!inode_owner_or_capable(inode)) | ||
4383 | return -EPERM; | ||
4384 | |||
4306 | ret = mnt_want_write_file(file); | 4385 | ret = mnt_want_write_file(file); |
4307 | if (ret < 0) | 4386 | if (ret < 0) |
4308 | return ret; | 4387 | return ret; |
@@ -4319,11 +4398,6 @@ static long btrfs_ioctl_set_received_subvol(struct file *file, | |||
4319 | goto out; | 4398 | goto out; |
4320 | } | 4399 | } |
4321 | 4400 | ||
4322 | if (!inode_owner_or_capable(inode)) { | ||
4323 | ret = -EACCES; | ||
4324 | goto out; | ||
4325 | } | ||
4326 | |||
4327 | sa = memdup_user(arg, sizeof(*sa)); | 4401 | sa = memdup_user(arg, sizeof(*sa)); |
4328 | if (IS_ERR(sa)) { | 4402 | if (IS_ERR(sa)) { |
4329 | ret = PTR_ERR(sa); | 4403 | ret = PTR_ERR(sa); |
@@ -4409,8 +4483,8 @@ static int btrfs_ioctl_get_fslabel(struct file *file, void __user *arg) | |||
4409 | len = strnlen(label, BTRFS_LABEL_SIZE); | 4483 | len = strnlen(label, BTRFS_LABEL_SIZE); |
4410 | 4484 | ||
4411 | if (len == BTRFS_LABEL_SIZE) { | 4485 | if (len == BTRFS_LABEL_SIZE) { |
4412 | pr_warn("btrfs: label is too long, return the first %zu bytes\n", | 4486 | btrfs_warn(root->fs_info, |
4413 | --len); | 4487 | "label is too long, return the first %zu bytes", --len); |
4414 | } | 4488 | } |
4415 | 4489 | ||
4416 | ret = copy_to_user(arg, label, len); | 4490 | ret = copy_to_user(arg, label, len); |
@@ -4433,7 +4507,7 @@ static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg) | |||
4433 | return -EFAULT; | 4507 | return -EFAULT; |
4434 | 4508 | ||
4435 | if (strnlen(label, BTRFS_LABEL_SIZE) == BTRFS_LABEL_SIZE) { | 4509 | if (strnlen(label, BTRFS_LABEL_SIZE) == BTRFS_LABEL_SIZE) { |
4436 | pr_err("btrfs: unable to set label with more than %d bytes\n", | 4510 | btrfs_err(root->fs_info, "unable to set label with more than %d bytes", |
4437 | BTRFS_LABEL_SIZE - 1); | 4511 | BTRFS_LABEL_SIZE - 1); |
4438 | return -EINVAL; | 4512 | return -EINVAL; |
4439 | } | 4513 | } |
@@ -4458,6 +4532,166 @@ out_unlock: | |||
4458 | return ret; | 4532 | return ret; |
4459 | } | 4533 | } |
4460 | 4534 | ||
4535 | #define INIT_FEATURE_FLAGS(suffix) \ | ||
4536 | { .compat_flags = BTRFS_FEATURE_COMPAT_##suffix, \ | ||
4537 | .compat_ro_flags = BTRFS_FEATURE_COMPAT_RO_##suffix, \ | ||
4538 | .incompat_flags = BTRFS_FEATURE_INCOMPAT_##suffix } | ||
4539 | |||
4540 | static int btrfs_ioctl_get_supported_features(struct file *file, | ||
4541 | void __user *arg) | ||
4542 | { | ||
4543 | static struct btrfs_ioctl_feature_flags features[3] = { | ||
4544 | INIT_FEATURE_FLAGS(SUPP), | ||
4545 | INIT_FEATURE_FLAGS(SAFE_SET), | ||
4546 | INIT_FEATURE_FLAGS(SAFE_CLEAR) | ||
4547 | }; | ||
4548 | |||
4549 | if (copy_to_user(arg, &features, sizeof(features))) | ||
4550 | return -EFAULT; | ||
4551 | |||
4552 | return 0; | ||
4553 | } | ||
4554 | |||
4555 | static int btrfs_ioctl_get_features(struct file *file, void __user *arg) | ||
4556 | { | ||
4557 | struct btrfs_root *root = BTRFS_I(file_inode(file))->root; | ||
4558 | struct btrfs_super_block *super_block = root->fs_info->super_copy; | ||
4559 | struct btrfs_ioctl_feature_flags features; | ||
4560 | |||
4561 | features.compat_flags = btrfs_super_compat_flags(super_block); | ||
4562 | features.compat_ro_flags = btrfs_super_compat_ro_flags(super_block); | ||
4563 | features.incompat_flags = btrfs_super_incompat_flags(super_block); | ||
4564 | |||
4565 | if (copy_to_user(arg, &features, sizeof(features))) | ||
4566 | return -EFAULT; | ||
4567 | |||
4568 | return 0; | ||
4569 | } | ||
4570 | |||
4571 | static int check_feature_bits(struct btrfs_root *root, | ||
4572 | enum btrfs_feature_set set, | ||
4573 | u64 change_mask, u64 flags, u64 supported_flags, | ||
4574 | u64 safe_set, u64 safe_clear) | ||
4575 | { | ||
4576 | const char *type = btrfs_feature_set_names[set]; | ||
4577 | char *names; | ||
4578 | u64 disallowed, unsupported; | ||
4579 | u64 set_mask = flags & change_mask; | ||
4580 | u64 clear_mask = ~flags & change_mask; | ||
4581 | |||
4582 | unsupported = set_mask & ~supported_flags; | ||
4583 | if (unsupported) { | ||
4584 | names = btrfs_printable_features(set, unsupported); | ||
4585 | if (names) { | ||
4586 | btrfs_warn(root->fs_info, | ||
4587 | "this kernel does not support the %s feature bit%s", | ||
4588 | names, strchr(names, ',') ? "s" : ""); | ||
4589 | kfree(names); | ||
4590 | } else | ||
4591 | btrfs_warn(root->fs_info, | ||
4592 | "this kernel does not support %s bits 0x%llx", | ||
4593 | type, unsupported); | ||
4594 | return -EOPNOTSUPP; | ||
4595 | } | ||
4596 | |||
4597 | disallowed = set_mask & ~safe_set; | ||
4598 | if (disallowed) { | ||
4599 | names = btrfs_printable_features(set, disallowed); | ||
4600 | if (names) { | ||
4601 | btrfs_warn(root->fs_info, | ||
4602 | "can't set the %s feature bit%s while mounted", | ||
4603 | names, strchr(names, ',') ? "s" : ""); | ||
4604 | kfree(names); | ||
4605 | } else | ||
4606 | btrfs_warn(root->fs_info, | ||
4607 | "can't set %s bits 0x%llx while mounted", | ||
4608 | type, disallowed); | ||
4609 | return -EPERM; | ||
4610 | } | ||
4611 | |||
4612 | disallowed = clear_mask & ~safe_clear; | ||
4613 | if (disallowed) { | ||
4614 | names = btrfs_printable_features(set, disallowed); | ||
4615 | if (names) { | ||
4616 | btrfs_warn(root->fs_info, | ||
4617 | "can't clear the %s feature bit%s while mounted", | ||
4618 | names, strchr(names, ',') ? "s" : ""); | ||
4619 | kfree(names); | ||
4620 | } else | ||
4621 | btrfs_warn(root->fs_info, | ||
4622 | "can't clear %s bits 0x%llx while mounted", | ||
4623 | type, disallowed); | ||
4624 | return -EPERM; | ||
4625 | } | ||
4626 | |||
4627 | return 0; | ||
4628 | } | ||
4629 | |||
4630 | #define check_feature(root, change_mask, flags, mask_base) \ | ||
4631 | check_feature_bits(root, FEAT_##mask_base, change_mask, flags, \ | ||
4632 | BTRFS_FEATURE_ ## mask_base ## _SUPP, \ | ||
4633 | BTRFS_FEATURE_ ## mask_base ## _SAFE_SET, \ | ||
4634 | BTRFS_FEATURE_ ## mask_base ## _SAFE_CLEAR) | ||
4635 | |||
4636 | static int btrfs_ioctl_set_features(struct file *file, void __user *arg) | ||
4637 | { | ||
4638 | struct btrfs_root *root = BTRFS_I(file_inode(file))->root; | ||
4639 | struct btrfs_super_block *super_block = root->fs_info->super_copy; | ||
4640 | struct btrfs_ioctl_feature_flags flags[2]; | ||
4641 | struct btrfs_trans_handle *trans; | ||
4642 | u64 newflags; | ||
4643 | int ret; | ||
4644 | |||
4645 | if (!capable(CAP_SYS_ADMIN)) | ||
4646 | return -EPERM; | ||
4647 | |||
4648 | if (copy_from_user(flags, arg, sizeof(flags))) | ||
4649 | return -EFAULT; | ||
4650 | |||
4651 | /* Nothing to do */ | ||
4652 | if (!flags[0].compat_flags && !flags[0].compat_ro_flags && | ||
4653 | !flags[0].incompat_flags) | ||
4654 | return 0; | ||
4655 | |||
4656 | ret = check_feature(root, flags[0].compat_flags, | ||
4657 | flags[1].compat_flags, COMPAT); | ||
4658 | if (ret) | ||
4659 | return ret; | ||
4660 | |||
4661 | ret = check_feature(root, flags[0].compat_ro_flags, | ||
4662 | flags[1].compat_ro_flags, COMPAT_RO); | ||
4663 | if (ret) | ||
4664 | return ret; | ||
4665 | |||
4666 | ret = check_feature(root, flags[0].incompat_flags, | ||
4667 | flags[1].incompat_flags, INCOMPAT); | ||
4668 | if (ret) | ||
4669 | return ret; | ||
4670 | |||
4671 | trans = btrfs_start_transaction(root, 1); | ||
4672 | if (IS_ERR(trans)) | ||
4673 | return PTR_ERR(trans); | ||
4674 | |||
4675 | spin_lock(&root->fs_info->super_lock); | ||
4676 | newflags = btrfs_super_compat_flags(super_block); | ||
4677 | newflags |= flags[0].compat_flags & flags[1].compat_flags; | ||
4678 | newflags &= ~(flags[0].compat_flags & ~flags[1].compat_flags); | ||
4679 | btrfs_set_super_compat_flags(super_block, newflags); | ||
4680 | |||
4681 | newflags = btrfs_super_compat_ro_flags(super_block); | ||
4682 | newflags |= flags[0].compat_ro_flags & flags[1].compat_ro_flags; | ||
4683 | newflags &= ~(flags[0].compat_ro_flags & ~flags[1].compat_ro_flags); | ||
4684 | btrfs_set_super_compat_ro_flags(super_block, newflags); | ||
4685 | |||
4686 | newflags = btrfs_super_incompat_flags(super_block); | ||
4687 | newflags |= flags[0].incompat_flags & flags[1].incompat_flags; | ||
4688 | newflags &= ~(flags[0].incompat_flags & ~flags[1].incompat_flags); | ||
4689 | btrfs_set_super_incompat_flags(super_block, newflags); | ||
4690 | spin_unlock(&root->fs_info->super_lock); | ||
4691 | |||
4692 | return btrfs_end_transaction(trans, root); | ||
4693 | } | ||
4694 | |||
4461 | long btrfs_ioctl(struct file *file, unsigned int | 4695 | long btrfs_ioctl(struct file *file, unsigned int |
4462 | cmd, unsigned long arg) | 4696 | cmd, unsigned long arg) |
4463 | { | 4697 | { |
@@ -4523,6 +4757,8 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
4523 | return btrfs_ioctl_logical_to_ino(root, argp); | 4757 | return btrfs_ioctl_logical_to_ino(root, argp); |
4524 | case BTRFS_IOC_SPACE_INFO: | 4758 | case BTRFS_IOC_SPACE_INFO: |
4525 | return btrfs_ioctl_space_info(root, argp); | 4759 | return btrfs_ioctl_space_info(root, argp); |
4760 | case BTRFS_IOC_GLOBAL_RSV: | ||
4761 | return btrfs_ioctl_global_rsv(root, argp); | ||
4526 | case BTRFS_IOC_SYNC: { | 4762 | case BTRFS_IOC_SYNC: { |
4527 | int ret; | 4763 | int ret; |
4528 | 4764 | ||
@@ -4576,6 +4812,12 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
4576 | return btrfs_ioctl_set_fslabel(file, argp); | 4812 | return btrfs_ioctl_set_fslabel(file, argp); |
4577 | case BTRFS_IOC_FILE_EXTENT_SAME: | 4813 | case BTRFS_IOC_FILE_EXTENT_SAME: |
4578 | return btrfs_ioctl_file_extent_same(file, argp); | 4814 | return btrfs_ioctl_file_extent_same(file, argp); |
4815 | case BTRFS_IOC_GET_SUPPORTED_FEATURES: | ||
4816 | return btrfs_ioctl_get_supported_features(file, argp); | ||
4817 | case BTRFS_IOC_GET_FEATURES: | ||
4818 | return btrfs_ioctl_get_features(file, argp); | ||
4819 | case BTRFS_IOC_SET_FEATURES: | ||
4820 | return btrfs_ioctl_set_features(file, argp); | ||
4579 | } | 4821 | } |
4580 | 4822 | ||
4581 | return -ENOTTY; | 4823 | return -ENOTTY; |