diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 211 |
1 files changed, 163 insertions, 48 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index c3f09f71bedd..c83086fdda05 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -42,12 +42,12 @@ | |||
42 | #include <linux/slab.h> | 42 | #include <linux/slab.h> |
43 | #include <linux/blkdev.h> | 43 | #include <linux/blkdev.h> |
44 | #include <linux/uuid.h> | 44 | #include <linux/uuid.h> |
45 | #include <linux/btrfs.h> | ||
45 | #include "compat.h" | 46 | #include "compat.h" |
46 | #include "ctree.h" | 47 | #include "ctree.h" |
47 | #include "disk-io.h" | 48 | #include "disk-io.h" |
48 | #include "transaction.h" | 49 | #include "transaction.h" |
49 | #include "btrfs_inode.h" | 50 | #include "btrfs_inode.h" |
50 | #include "ioctl.h" | ||
51 | #include "print-tree.h" | 51 | #include "print-tree.h" |
52 | #include "volumes.h" | 52 | #include "volumes.h" |
53 | #include "locking.h" | 53 | #include "locking.h" |
@@ -363,46 +363,52 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) | |||
363 | return 0; | 363 | return 0; |
364 | } | 364 | } |
365 | 365 | ||
366 | static noinline int create_subvol(struct btrfs_root *root, | 366 | static noinline int create_subvol(struct inode *dir, |
367 | struct dentry *dentry, | 367 | struct dentry *dentry, |
368 | char *name, int namelen, | 368 | char *name, int namelen, |
369 | u64 *async_transid, | 369 | u64 *async_transid, |
370 | struct btrfs_qgroup_inherit **inherit) | 370 | struct btrfs_qgroup_inherit *inherit) |
371 | { | 371 | { |
372 | struct btrfs_trans_handle *trans; | 372 | struct btrfs_trans_handle *trans; |
373 | struct btrfs_key key; | 373 | struct btrfs_key key; |
374 | struct btrfs_root_item root_item; | 374 | struct btrfs_root_item root_item; |
375 | struct btrfs_inode_item *inode_item; | 375 | struct btrfs_inode_item *inode_item; |
376 | struct extent_buffer *leaf; | 376 | struct extent_buffer *leaf; |
377 | struct btrfs_root *root = BTRFS_I(dir)->root; | ||
377 | struct btrfs_root *new_root; | 378 | struct btrfs_root *new_root; |
378 | struct dentry *parent = dentry->d_parent; | 379 | struct btrfs_block_rsv block_rsv; |
379 | struct inode *dir; | ||
380 | struct timespec cur_time = CURRENT_TIME; | 380 | struct timespec cur_time = CURRENT_TIME; |
381 | int ret; | 381 | int ret; |
382 | int err; | 382 | int err; |
383 | u64 objectid; | 383 | u64 objectid; |
384 | u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; | 384 | u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; |
385 | u64 index = 0; | 385 | u64 index = 0; |
386 | u64 qgroup_reserved; | ||
386 | uuid_le new_uuid; | 387 | uuid_le new_uuid; |
387 | 388 | ||
388 | ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid); | 389 | ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid); |
389 | if (ret) | 390 | if (ret) |
390 | return ret; | 391 | return ret; |
391 | 392 | ||
392 | dir = parent->d_inode; | 393 | btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP); |
393 | |||
394 | /* | 394 | /* |
395 | * 1 - inode item | 395 | * The same as the snapshot creation, please see the comment |
396 | * 2 - refs | 396 | * of create_snapshot(). |
397 | * 1 - root item | ||
398 | * 2 - dir items | ||
399 | */ | 397 | */ |
400 | trans = btrfs_start_transaction(root, 6); | 398 | ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, |
401 | if (IS_ERR(trans)) | 399 | 7, &qgroup_reserved); |
402 | return PTR_ERR(trans); | 400 | if (ret) |
401 | return ret; | ||
402 | |||
403 | trans = btrfs_start_transaction(root, 0); | ||
404 | if (IS_ERR(trans)) { | ||
405 | ret = PTR_ERR(trans); | ||
406 | goto out; | ||
407 | } | ||
408 | trans->block_rsv = &block_rsv; | ||
409 | trans->bytes_reserved = block_rsv.size; | ||
403 | 410 | ||
404 | ret = btrfs_qgroup_inherit(trans, root->fs_info, 0, objectid, | 411 | ret = btrfs_qgroup_inherit(trans, root->fs_info, 0, objectid, inherit); |
405 | inherit ? *inherit : NULL); | ||
406 | if (ret) | 412 | if (ret) |
407 | goto fail; | 413 | goto fail; |
408 | 414 | ||
@@ -516,6 +522,8 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
516 | BUG_ON(ret); | 522 | BUG_ON(ret); |
517 | 523 | ||
518 | fail: | 524 | fail: |
525 | trans->block_rsv = NULL; | ||
526 | trans->bytes_reserved = 0; | ||
519 | if (async_transid) { | 527 | if (async_transid) { |
520 | *async_transid = trans->transid; | 528 | *async_transid = trans->transid; |
521 | err = btrfs_commit_transaction_async(trans, root, 1); | 529 | err = btrfs_commit_transaction_async(trans, root, 1); |
@@ -527,13 +535,15 @@ fail: | |||
527 | 535 | ||
528 | if (!ret) | 536 | if (!ret) |
529 | d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); | 537 | d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); |
530 | 538 | out: | |
539 | btrfs_subvolume_release_metadata(root, &block_rsv, qgroup_reserved); | ||
531 | return ret; | 540 | return ret; |
532 | } | 541 | } |
533 | 542 | ||
534 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | 543 | static int create_snapshot(struct btrfs_root *root, struct inode *dir, |
535 | char *name, int namelen, u64 *async_transid, | 544 | struct dentry *dentry, char *name, int namelen, |
536 | bool readonly, struct btrfs_qgroup_inherit **inherit) | 545 | u64 *async_transid, bool readonly, |
546 | struct btrfs_qgroup_inherit *inherit) | ||
537 | { | 547 | { |
538 | struct inode *inode; | 548 | struct inode *inode; |
539 | struct btrfs_pending_snapshot *pending_snapshot; | 549 | struct btrfs_pending_snapshot *pending_snapshot; |
@@ -549,23 +559,31 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | |||
549 | 559 | ||
550 | btrfs_init_block_rsv(&pending_snapshot->block_rsv, | 560 | btrfs_init_block_rsv(&pending_snapshot->block_rsv, |
551 | BTRFS_BLOCK_RSV_TEMP); | 561 | BTRFS_BLOCK_RSV_TEMP); |
562 | /* | ||
563 | * 1 - parent dir inode | ||
564 | * 2 - dir entries | ||
565 | * 1 - root item | ||
566 | * 2 - root ref/backref | ||
567 | * 1 - root of snapshot | ||
568 | */ | ||
569 | ret = btrfs_subvolume_reserve_metadata(BTRFS_I(dir)->root, | ||
570 | &pending_snapshot->block_rsv, 7, | ||
571 | &pending_snapshot->qgroup_reserved); | ||
572 | if (ret) | ||
573 | goto out; | ||
574 | |||
552 | pending_snapshot->dentry = dentry; | 575 | pending_snapshot->dentry = dentry; |
553 | pending_snapshot->root = root; | 576 | pending_snapshot->root = root; |
554 | pending_snapshot->readonly = readonly; | 577 | pending_snapshot->readonly = readonly; |
555 | if (inherit) { | 578 | pending_snapshot->dir = dir; |
556 | pending_snapshot->inherit = *inherit; | 579 | pending_snapshot->inherit = inherit; |
557 | *inherit = NULL; /* take responsibility to free it */ | ||
558 | } | ||
559 | 580 | ||
560 | trans = btrfs_start_transaction(root->fs_info->extent_root, 6); | 581 | trans = btrfs_start_transaction(root, 0); |
561 | if (IS_ERR(trans)) { | 582 | if (IS_ERR(trans)) { |
562 | ret = PTR_ERR(trans); | 583 | ret = PTR_ERR(trans); |
563 | goto fail; | 584 | goto fail; |
564 | } | 585 | } |
565 | 586 | ||
566 | ret = btrfs_snap_reserve_metadata(trans, pending_snapshot); | ||
567 | BUG_ON(ret); | ||
568 | |||
569 | spin_lock(&root->fs_info->trans_lock); | 587 | spin_lock(&root->fs_info->trans_lock); |
570 | list_add(&pending_snapshot->list, | 588 | list_add(&pending_snapshot->list, |
571 | &trans->transaction->pending_snapshots); | 589 | &trans->transaction->pending_snapshots); |
@@ -602,6 +620,10 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, | |||
602 | d_instantiate(dentry, inode); | 620 | d_instantiate(dentry, inode); |
603 | ret = 0; | 621 | ret = 0; |
604 | fail: | 622 | fail: |
623 | btrfs_subvolume_release_metadata(BTRFS_I(dir)->root, | ||
624 | &pending_snapshot->block_rsv, | ||
625 | pending_snapshot->qgroup_reserved); | ||
626 | out: | ||
605 | kfree(pending_snapshot); | 627 | kfree(pending_snapshot); |
606 | return ret; | 628 | return ret; |
607 | } | 629 | } |
@@ -695,7 +717,7 @@ static noinline int btrfs_mksubvol(struct path *parent, | |||
695 | char *name, int namelen, | 717 | char *name, int namelen, |
696 | struct btrfs_root *snap_src, | 718 | struct btrfs_root *snap_src, |
697 | u64 *async_transid, bool readonly, | 719 | u64 *async_transid, bool readonly, |
698 | struct btrfs_qgroup_inherit **inherit) | 720 | struct btrfs_qgroup_inherit *inherit) |
699 | { | 721 | { |
700 | struct inode *dir = parent->dentry->d_inode; | 722 | struct inode *dir = parent->dentry->d_inode; |
701 | struct dentry *dentry; | 723 | struct dentry *dentry; |
@@ -732,11 +754,11 @@ static noinline int btrfs_mksubvol(struct path *parent, | |||
732 | goto out_up_read; | 754 | goto out_up_read; |
733 | 755 | ||
734 | if (snap_src) { | 756 | if (snap_src) { |
735 | error = create_snapshot(snap_src, dentry, name, namelen, | 757 | error = create_snapshot(snap_src, dir, dentry, name, namelen, |
736 | async_transid, readonly, inherit); | 758 | async_transid, readonly, inherit); |
737 | } else { | 759 | } else { |
738 | error = create_subvol(BTRFS_I(dir)->root, dentry, | 760 | error = create_subvol(dir, dentry, name, namelen, |
739 | name, namelen, async_transid, inherit); | 761 | async_transid, inherit); |
740 | } | 762 | } |
741 | if (!error) | 763 | if (!error) |
742 | fsnotify_mkdir(dir, dentry); | 764 | fsnotify_mkdir(dir, dentry); |
@@ -818,7 +840,7 @@ static int find_new_extents(struct btrfs_root *root, | |||
818 | 840 | ||
819 | while(1) { | 841 | while(1) { |
820 | ret = btrfs_search_forward(root, &min_key, &max_key, | 842 | ret = btrfs_search_forward(root, &min_key, &max_key, |
821 | path, 0, newer_than); | 843 | path, newer_than); |
822 | if (ret != 0) | 844 | if (ret != 0) |
823 | goto none; | 845 | goto none; |
824 | if (min_key.objectid != ino) | 846 | if (min_key.objectid != ino) |
@@ -1206,6 +1228,12 @@ int btrfs_defrag_file(struct inode *inode, struct file *file, | |||
1206 | if (!(inode->i_sb->s_flags & MS_ACTIVE)) | 1228 | if (!(inode->i_sb->s_flags & MS_ACTIVE)) |
1207 | break; | 1229 | break; |
1208 | 1230 | ||
1231 | if (btrfs_defrag_cancelled(root->fs_info)) { | ||
1232 | printk(KERN_DEBUG "btrfs: defrag_file cancelled\n"); | ||
1233 | ret = -EAGAIN; | ||
1234 | break; | ||
1235 | } | ||
1236 | |||
1209 | if (!should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT, | 1237 | if (!should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT, |
1210 | extent_thresh, &last_len, &skip, | 1238 | extent_thresh, &last_len, &skip, |
1211 | &defrag_end, range->flags & | 1239 | &defrag_end, range->flags & |
@@ -1329,9 +1357,6 @@ static noinline int btrfs_ioctl_resize(struct file *file, | |||
1329 | int ret = 0; | 1357 | int ret = 0; |
1330 | int mod = 0; | 1358 | int mod = 0; |
1331 | 1359 | ||
1332 | if (root->fs_info->sb->s_flags & MS_RDONLY) | ||
1333 | return -EROFS; | ||
1334 | |||
1335 | if (!capable(CAP_SYS_ADMIN)) | 1360 | if (!capable(CAP_SYS_ADMIN)) |
1336 | return -EPERM; | 1361 | return -EPERM; |
1337 | 1362 | ||
@@ -1363,6 +1388,10 @@ static noinline int btrfs_ioctl_resize(struct file *file, | |||
1363 | *devstr = '\0'; | 1388 | *devstr = '\0'; |
1364 | devstr = vol_args->name; | 1389 | devstr = vol_args->name; |
1365 | devid = simple_strtoull(devstr, &end, 10); | 1390 | devid = simple_strtoull(devstr, &end, 10); |
1391 | if (!devid) { | ||
1392 | ret = -EINVAL; | ||
1393 | goto out_free; | ||
1394 | } | ||
1366 | printk(KERN_INFO "btrfs: resizing devid %llu\n", | 1395 | printk(KERN_INFO "btrfs: resizing devid %llu\n", |
1367 | (unsigned long long)devid); | 1396 | (unsigned long long)devid); |
1368 | } | 1397 | } |
@@ -1371,7 +1400,7 @@ static noinline int btrfs_ioctl_resize(struct file *file, | |||
1371 | if (!device) { | 1400 | if (!device) { |
1372 | printk(KERN_INFO "btrfs: resizer unable to find device %llu\n", | 1401 | printk(KERN_INFO "btrfs: resizer unable to find device %llu\n", |
1373 | (unsigned long long)devid); | 1402 | (unsigned long long)devid); |
1374 | ret = -EINVAL; | 1403 | ret = -ENODEV; |
1375 | goto out_free; | 1404 | goto out_free; |
1376 | } | 1405 | } |
1377 | 1406 | ||
@@ -1379,7 +1408,7 @@ static noinline int btrfs_ioctl_resize(struct file *file, | |||
1379 | printk(KERN_INFO "btrfs: resizer unable to apply on " | 1408 | printk(KERN_INFO "btrfs: resizer unable to apply on " |
1380 | "readonly device %llu\n", | 1409 | "readonly device %llu\n", |
1381 | (unsigned long long)devid); | 1410 | (unsigned long long)devid); |
1382 | ret = -EINVAL; | 1411 | ret = -EPERM; |
1383 | goto out_free; | 1412 | goto out_free; |
1384 | } | 1413 | } |
1385 | 1414 | ||
@@ -1401,7 +1430,7 @@ static noinline int btrfs_ioctl_resize(struct file *file, | |||
1401 | } | 1430 | } |
1402 | 1431 | ||
1403 | if (device->is_tgtdev_for_dev_replace) { | 1432 | if (device->is_tgtdev_for_dev_replace) { |
1404 | ret = -EINVAL; | 1433 | ret = -EPERM; |
1405 | goto out_free; | 1434 | goto out_free; |
1406 | } | 1435 | } |
1407 | 1436 | ||
@@ -1457,7 +1486,7 @@ out: | |||
1457 | static noinline int btrfs_ioctl_snap_create_transid(struct file *file, | 1486 | static noinline int btrfs_ioctl_snap_create_transid(struct file *file, |
1458 | char *name, unsigned long fd, int subvol, | 1487 | char *name, unsigned long fd, int subvol, |
1459 | u64 *transid, bool readonly, | 1488 | u64 *transid, bool readonly, |
1460 | struct btrfs_qgroup_inherit **inherit) | 1489 | struct btrfs_qgroup_inherit *inherit) |
1461 | { | 1490 | { |
1462 | int namelen; | 1491 | int namelen; |
1463 | int ret = 0; | 1492 | int ret = 0; |
@@ -1566,7 +1595,7 @@ static noinline int btrfs_ioctl_snap_create_v2(struct file *file, | |||
1566 | 1595 | ||
1567 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, | 1596 | ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, |
1568 | vol_args->fd, subvol, ptr, | 1597 | vol_args->fd, subvol, ptr, |
1569 | readonly, &inherit); | 1598 | readonly, inherit); |
1570 | 1599 | ||
1571 | if (ret == 0 && ptr && | 1600 | if (ret == 0 && ptr && |
1572 | copy_to_user(arg + | 1601 | copy_to_user(arg + |
@@ -1863,7 +1892,7 @@ static noinline int search_ioctl(struct inode *inode, | |||
1863 | path->keep_locks = 1; | 1892 | path->keep_locks = 1; |
1864 | 1893 | ||
1865 | while(1) { | 1894 | while(1) { |
1866 | ret = btrfs_search_forward(root, &key, &max_key, path, 0, | 1895 | ret = btrfs_search_forward(root, &key, &max_key, path, |
1867 | sk->min_transid); | 1896 | sk->min_transid); |
1868 | if (ret != 0) { | 1897 | if (ret != 0) { |
1869 | if (ret > 0) | 1898 | if (ret > 0) |
@@ -2035,6 +2064,8 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, | |||
2035 | struct btrfs_root *dest = NULL; | 2064 | struct btrfs_root *dest = NULL; |
2036 | struct btrfs_ioctl_vol_args *vol_args; | 2065 | struct btrfs_ioctl_vol_args *vol_args; |
2037 | struct btrfs_trans_handle *trans; | 2066 | struct btrfs_trans_handle *trans; |
2067 | struct btrfs_block_rsv block_rsv; | ||
2068 | u64 qgroup_reserved; | ||
2038 | int namelen; | 2069 | int namelen; |
2039 | int ret; | 2070 | int ret; |
2040 | int err = 0; | 2071 | int err = 0; |
@@ -2124,12 +2155,23 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, | |||
2124 | if (err) | 2155 | if (err) |
2125 | goto out_up_write; | 2156 | goto out_up_write; |
2126 | 2157 | ||
2158 | btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP); | ||
2159 | /* | ||
2160 | * One for dir inode, two for dir entries, two for root | ||
2161 | * ref/backref. | ||
2162 | */ | ||
2163 | err = btrfs_subvolume_reserve_metadata(root, &block_rsv, | ||
2164 | 5, &qgroup_reserved); | ||
2165 | if (err) | ||
2166 | goto out_up_write; | ||
2167 | |||
2127 | trans = btrfs_start_transaction(root, 0); | 2168 | trans = btrfs_start_transaction(root, 0); |
2128 | if (IS_ERR(trans)) { | 2169 | if (IS_ERR(trans)) { |
2129 | err = PTR_ERR(trans); | 2170 | err = PTR_ERR(trans); |
2130 | goto out_up_write; | 2171 | goto out_release; |
2131 | } | 2172 | } |
2132 | trans->block_rsv = &root->fs_info->global_block_rsv; | 2173 | trans->block_rsv = &block_rsv; |
2174 | trans->bytes_reserved = block_rsv.size; | ||
2133 | 2175 | ||
2134 | ret = btrfs_unlink_subvol(trans, root, dir, | 2176 | ret = btrfs_unlink_subvol(trans, root, dir, |
2135 | dest->root_key.objectid, | 2177 | dest->root_key.objectid, |
@@ -2159,10 +2201,14 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, | |||
2159 | } | 2201 | } |
2160 | } | 2202 | } |
2161 | out_end_trans: | 2203 | out_end_trans: |
2204 | trans->block_rsv = NULL; | ||
2205 | trans->bytes_reserved = 0; | ||
2162 | ret = btrfs_end_transaction(trans, root); | 2206 | ret = btrfs_end_transaction(trans, root); |
2163 | if (ret && !err) | 2207 | if (ret && !err) |
2164 | err = ret; | 2208 | err = ret; |
2165 | inode->i_flags |= S_DEAD; | 2209 | inode->i_flags |= S_DEAD; |
2210 | out_release: | ||
2211 | btrfs_subvolume_release_metadata(root, &block_rsv, qgroup_reserved); | ||
2166 | out_up_write: | 2212 | out_up_write: |
2167 | up_write(&root->fs_info->subvol_sem); | 2213 | up_write(&root->fs_info->subvol_sem); |
2168 | out_unlock: | 2214 | out_unlock: |
@@ -2171,6 +2217,12 @@ out_unlock: | |||
2171 | shrink_dcache_sb(root->fs_info->sb); | 2217 | shrink_dcache_sb(root->fs_info->sb); |
2172 | btrfs_invalidate_inodes(dest); | 2218 | btrfs_invalidate_inodes(dest); |
2173 | d_delete(dentry); | 2219 | d_delete(dentry); |
2220 | |||
2221 | /* the last ref */ | ||
2222 | if (dest->cache_inode) { | ||
2223 | iput(dest->cache_inode); | ||
2224 | dest->cache_inode = NULL; | ||
2225 | } | ||
2174 | } | 2226 | } |
2175 | out_dput: | 2227 | out_dput: |
2176 | dput(dentry); | 2228 | dput(dentry); |
@@ -2211,10 +2263,10 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp) | |||
2211 | ret = -EPERM; | 2263 | ret = -EPERM; |
2212 | goto out; | 2264 | goto out; |
2213 | } | 2265 | } |
2214 | ret = btrfs_defrag_root(root, 0); | 2266 | ret = btrfs_defrag_root(root); |
2215 | if (ret) | 2267 | if (ret) |
2216 | goto out; | 2268 | goto out; |
2217 | ret = btrfs_defrag_root(root->fs_info->extent_root, 0); | 2269 | ret = btrfs_defrag_root(root->fs_info->extent_root); |
2218 | break; | 2270 | break; |
2219 | case S_IFREG: | 2271 | case S_IFREG: |
2220 | if (!(file->f_mode & FMODE_WRITE)) { | 2272 | if (!(file->f_mode & FMODE_WRITE)) { |
@@ -3111,7 +3163,7 @@ static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root, | |||
3111 | u64 transid; | 3163 | u64 transid; |
3112 | int ret; | 3164 | int ret; |
3113 | 3165 | ||
3114 | trans = btrfs_attach_transaction(root); | 3166 | trans = btrfs_attach_transaction_barrier(root); |
3115 | if (IS_ERR(trans)) { | 3167 | if (IS_ERR(trans)) { |
3116 | if (PTR_ERR(trans) != -ENOENT) | 3168 | if (PTR_ERR(trans) != -ENOENT) |
3117 | return PTR_ERR(trans); | 3169 | return PTR_ERR(trans); |
@@ -3289,7 +3341,7 @@ static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg) | |||
3289 | struct inode_fs_paths *ipath = NULL; | 3341 | struct inode_fs_paths *ipath = NULL; |
3290 | struct btrfs_path *path; | 3342 | struct btrfs_path *path; |
3291 | 3343 | ||
3292 | if (!capable(CAP_SYS_ADMIN)) | 3344 | if (!capable(CAP_DAC_READ_SEARCH)) |
3293 | return -EPERM; | 3345 | return -EPERM; |
3294 | 3346 | ||
3295 | path = btrfs_alloc_path(); | 3347 | path = btrfs_alloc_path(); |
@@ -3914,6 +3966,65 @@ out: | |||
3914 | return ret; | 3966 | return ret; |
3915 | } | 3967 | } |
3916 | 3968 | ||
3969 | static int btrfs_ioctl_get_fslabel(struct file *file, void __user *arg) | ||
3970 | { | ||
3971 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; | ||
3972 | const char *label = root->fs_info->super_copy->label; | ||
3973 | size_t len = strnlen(label, BTRFS_LABEL_SIZE); | ||
3974 | int ret; | ||
3975 | |||
3976 | if (len == BTRFS_LABEL_SIZE) { | ||
3977 | pr_warn("btrfs: label is too long, return the first %zu bytes\n", | ||
3978 | --len); | ||
3979 | } | ||
3980 | |||
3981 | mutex_lock(&root->fs_info->volume_mutex); | ||
3982 | ret = copy_to_user(arg, label, len); | ||
3983 | mutex_unlock(&root->fs_info->volume_mutex); | ||
3984 | |||
3985 | return ret ? -EFAULT : 0; | ||
3986 | } | ||
3987 | |||
3988 | static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg) | ||
3989 | { | ||
3990 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; | ||
3991 | struct btrfs_super_block *super_block = root->fs_info->super_copy; | ||
3992 | struct btrfs_trans_handle *trans; | ||
3993 | char label[BTRFS_LABEL_SIZE]; | ||
3994 | int ret; | ||
3995 | |||
3996 | if (!capable(CAP_SYS_ADMIN)) | ||
3997 | return -EPERM; | ||
3998 | |||
3999 | if (copy_from_user(label, arg, sizeof(label))) | ||
4000 | return -EFAULT; | ||
4001 | |||
4002 | if (strnlen(label, BTRFS_LABEL_SIZE) == BTRFS_LABEL_SIZE) { | ||
4003 | pr_err("btrfs: unable to set label with more than %d bytes\n", | ||
4004 | BTRFS_LABEL_SIZE - 1); | ||
4005 | return -EINVAL; | ||
4006 | } | ||
4007 | |||
4008 | ret = mnt_want_write_file(file); | ||
4009 | if (ret) | ||
4010 | return ret; | ||
4011 | |||
4012 | mutex_lock(&root->fs_info->volume_mutex); | ||
4013 | trans = btrfs_start_transaction(root, 0); | ||
4014 | if (IS_ERR(trans)) { | ||
4015 | ret = PTR_ERR(trans); | ||
4016 | goto out_unlock; | ||
4017 | } | ||
4018 | |||
4019 | strcpy(super_block->label, label); | ||
4020 | ret = btrfs_end_transaction(trans, root); | ||
4021 | |||
4022 | out_unlock: | ||
4023 | mutex_unlock(&root->fs_info->volume_mutex); | ||
4024 | mnt_drop_write_file(file); | ||
4025 | return ret; | ||
4026 | } | ||
4027 | |||
3917 | long btrfs_ioctl(struct file *file, unsigned int | 4028 | long btrfs_ioctl(struct file *file, unsigned int |
3918 | cmd, unsigned long arg) | 4029 | cmd, unsigned long arg) |
3919 | { | 4030 | { |
@@ -4014,6 +4125,10 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
4014 | return btrfs_ioctl_qgroup_limit(file, argp); | 4125 | return btrfs_ioctl_qgroup_limit(file, argp); |
4015 | case BTRFS_IOC_DEV_REPLACE: | 4126 | case BTRFS_IOC_DEV_REPLACE: |
4016 | return btrfs_ioctl_dev_replace(root, argp); | 4127 | return btrfs_ioctl_dev_replace(root, argp); |
4128 | case BTRFS_IOC_GET_FSLABEL: | ||
4129 | return btrfs_ioctl_get_fslabel(file, argp); | ||
4130 | case BTRFS_IOC_SET_FSLABEL: | ||
4131 | return btrfs_ioctl_set_fslabel(file, argp); | ||
4017 | } | 4132 | } |
4018 | 4133 | ||
4019 | return -ENOTTY; | 4134 | return -ENOTTY; |