diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 398 |
1 files changed, 320 insertions, 78 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 9254b3d58dbe..463d91b4dd3a 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -224,7 +224,8 @@ static int btrfs_ioctl_getversion(struct file *file, int __user *arg) | |||
224 | 224 | ||
225 | static noinline int create_subvol(struct btrfs_root *root, | 225 | static noinline int create_subvol(struct btrfs_root *root, |
226 | struct dentry *dentry, | 226 | struct dentry *dentry, |
227 | char *name, int namelen) | 227 | char *name, int namelen, |
228 | u64 *async_transid) | ||
228 | { | 229 | { |
229 | struct btrfs_trans_handle *trans; | 230 | struct btrfs_trans_handle *trans; |
230 | struct btrfs_key key; | 231 | struct btrfs_key key; |
@@ -338,13 +339,19 @@ static noinline int create_subvol(struct btrfs_root *root, | |||
338 | 339 | ||
339 | d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); | 340 | d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); |
340 | fail: | 341 | fail: |
341 | err = btrfs_commit_transaction(trans, root); | 342 | if (async_transid) { |
343 | *async_transid = trans->transid; | ||
344 | err = btrfs_commit_transaction_async(trans, root, 1); | ||
345 | } else { | ||
346 | err = btrfs_commit_transaction(trans, root); | ||
347 | } | ||
342 | if (err && !ret) | 348 | if (err && !ret) |
343 | ret = err; | 349 | ret = err; |
344 | return ret; | 350 | return ret; |
345 | } | 351 | } |
346 | 352 | ||
347 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry) | 353 | static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, |
354 | char *name, int namelen, u64 *async_transid) | ||
348 | { | 355 | { |
349 | struct inode *inode; | 356 | struct inode *inode; |
350 | struct btrfs_pending_snapshot *pending_snapshot; | 357 | struct btrfs_pending_snapshot *pending_snapshot; |
@@ -373,7 +380,14 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry) | |||
373 | 380 | ||
374 | list_add(&pending_snapshot->list, | 381 | list_add(&pending_snapshot->list, |
375 | &trans->transaction->pending_snapshots); | 382 | &trans->transaction->pending_snapshots); |
376 | ret = btrfs_commit_transaction(trans, root->fs_info->extent_root); | 383 | if (async_transid) { |
384 | *async_transid = trans->transid; | ||
385 | ret = btrfs_commit_transaction_async(trans, | ||
386 | root->fs_info->extent_root, 1); | ||
387 | } else { | ||
388 | ret = btrfs_commit_transaction(trans, | ||
389 | root->fs_info->extent_root); | ||
390 | } | ||
377 | BUG_ON(ret); | 391 | BUG_ON(ret); |
378 | 392 | ||
379 | ret = pending_snapshot->error; | 393 | ret = pending_snapshot->error; |
@@ -395,6 +409,76 @@ fail: | |||
395 | return ret; | 409 | return ret; |
396 | } | 410 | } |
397 | 411 | ||
412 | /* copy of check_sticky in fs/namei.c() | ||
413 | * It's inline, so penalty for filesystems that don't use sticky bit is | ||
414 | * minimal. | ||
415 | */ | ||
416 | static inline int btrfs_check_sticky(struct inode *dir, struct inode *inode) | ||
417 | { | ||
418 | uid_t fsuid = current_fsuid(); | ||
419 | |||
420 | if (!(dir->i_mode & S_ISVTX)) | ||
421 | return 0; | ||
422 | if (inode->i_uid == fsuid) | ||
423 | return 0; | ||
424 | if (dir->i_uid == fsuid) | ||
425 | return 0; | ||
426 | return !capable(CAP_FOWNER); | ||
427 | } | ||
428 | |||
429 | /* copy of may_delete in fs/namei.c() | ||
430 | * Check whether we can remove a link victim from directory dir, check | ||
431 | * whether the type of victim is right. | ||
432 | * 1. We can't do it if dir is read-only (done in permission()) | ||
433 | * 2. We should have write and exec permissions on dir | ||
434 | * 3. We can't remove anything from append-only dir | ||
435 | * 4. We can't do anything with immutable dir (done in permission()) | ||
436 | * 5. If the sticky bit on dir is set we should either | ||
437 | * a. be owner of dir, or | ||
438 | * b. be owner of victim, or | ||
439 | * c. have CAP_FOWNER capability | ||
440 | * 6. If the victim is append-only or immutable we can't do antyhing with | ||
441 | * links pointing to it. | ||
442 | * 7. If we were asked to remove a directory and victim isn't one - ENOTDIR. | ||
443 | * 8. If we were asked to remove a non-directory and victim isn't one - EISDIR. | ||
444 | * 9. We can't remove a root or mountpoint. | ||
445 | * 10. We don't allow removal of NFS sillyrenamed files; it's handled by | ||
446 | * nfs_async_unlink(). | ||
447 | */ | ||
448 | |||
449 | static int btrfs_may_delete(struct inode *dir,struct dentry *victim,int isdir) | ||
450 | { | ||
451 | int error; | ||
452 | |||
453 | if (!victim->d_inode) | ||
454 | return -ENOENT; | ||
455 | |||
456 | BUG_ON(victim->d_parent->d_inode != dir); | ||
457 | audit_inode_child(victim, dir); | ||
458 | |||
459 | error = inode_permission(dir, MAY_WRITE | MAY_EXEC); | ||
460 | if (error) | ||
461 | return error; | ||
462 | if (IS_APPEND(dir)) | ||
463 | return -EPERM; | ||
464 | if (btrfs_check_sticky(dir, victim->d_inode)|| | ||
465 | IS_APPEND(victim->d_inode)|| | ||
466 | IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode)) | ||
467 | return -EPERM; | ||
468 | if (isdir) { | ||
469 | if (!S_ISDIR(victim->d_inode->i_mode)) | ||
470 | return -ENOTDIR; | ||
471 | if (IS_ROOT(victim)) | ||
472 | return -EBUSY; | ||
473 | } else if (S_ISDIR(victim->d_inode->i_mode)) | ||
474 | return -EISDIR; | ||
475 | if (IS_DEADDIR(dir)) | ||
476 | return -ENOENT; | ||
477 | if (victim->d_flags & DCACHE_NFSFS_RENAMED) | ||
478 | return -EBUSY; | ||
479 | return 0; | ||
480 | } | ||
481 | |||
398 | /* copy of may_create in fs/namei.c() */ | 482 | /* copy of may_create in fs/namei.c() */ |
399 | static inline int btrfs_may_create(struct inode *dir, struct dentry *child) | 483 | static inline int btrfs_may_create(struct inode *dir, struct dentry *child) |
400 | { | 484 | { |
@@ -412,7 +496,8 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child) | |||
412 | */ | 496 | */ |
413 | static noinline int btrfs_mksubvol(struct path *parent, | 497 | static noinline int btrfs_mksubvol(struct path *parent, |
414 | char *name, int namelen, | 498 | char *name, int namelen, |
415 | struct btrfs_root *snap_src) | 499 | struct btrfs_root *snap_src, |
500 | u64 *async_transid) | ||
416 | { | 501 | { |
417 | struct inode *dir = parent->dentry->d_inode; | 502 | struct inode *dir = parent->dentry->d_inode; |
418 | struct dentry *dentry; | 503 | struct dentry *dentry; |
@@ -443,10 +528,11 @@ static noinline int btrfs_mksubvol(struct path *parent, | |||
443 | goto out_up_read; | 528 | goto out_up_read; |
444 | 529 | ||
445 | if (snap_src) { | 530 | if (snap_src) { |
446 | error = create_snapshot(snap_src, dentry); | 531 | error = create_snapshot(snap_src, dentry, |
532 | name, namelen, async_transid); | ||
447 | } else { | 533 | } else { |
448 | error = create_subvol(BTRFS_I(dir)->root, dentry, | 534 | error = create_subvol(BTRFS_I(dir)->root, dentry, |
449 | name, namelen); | 535 | name, namelen, async_transid); |
450 | } | 536 | } |
451 | if (!error) | 537 | if (!error) |
452 | fsnotify_mkdir(dir, dentry); | 538 | fsnotify_mkdir(dir, dentry); |
@@ -708,7 +794,6 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
708 | char *sizestr; | 794 | char *sizestr; |
709 | char *devstr = NULL; | 795 | char *devstr = NULL; |
710 | int ret = 0; | 796 | int ret = 0; |
711 | int namelen; | ||
712 | int mod = 0; | 797 | int mod = 0; |
713 | 798 | ||
714 | if (root->fs_info->sb->s_flags & MS_RDONLY) | 799 | if (root->fs_info->sb->s_flags & MS_RDONLY) |
@@ -722,7 +807,6 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root, | |||
722 | return PTR_ERR(vol_args); | 807 | return PTR_ERR(vol_args); |
723 | 808 | ||
724 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | 809 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
725 | namelen = strlen(vol_args->name); | ||
726 | 810 | ||
727 | mutex_lock(&root->fs_info->volume_mutex); | 811 | mutex_lock(&root->fs_info->volume_mutex); |
728 | sizestr = vol_args->name; | 812 | sizestr = vol_args->name; |
@@ -801,11 +885,13 @@ out_unlock: | |||
801 | return ret; | 885 | return ret; |
802 | } | 886 | } |
803 | 887 | ||
804 | static noinline int btrfs_ioctl_snap_create(struct file *file, | 888 | static noinline int btrfs_ioctl_snap_create_transid(struct file *file, |
805 | void __user *arg, int subvol) | 889 | char *name, |
890 | unsigned long fd, | ||
891 | int subvol, | ||
892 | u64 *transid) | ||
806 | { | 893 | { |
807 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; | 894 | struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; |
808 | struct btrfs_ioctl_vol_args *vol_args; | ||
809 | struct file *src_file; | 895 | struct file *src_file; |
810 | int namelen; | 896 | int namelen; |
811 | int ret = 0; | 897 | int ret = 0; |
@@ -813,23 +899,18 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
813 | if (root->fs_info->sb->s_flags & MS_RDONLY) | 899 | if (root->fs_info->sb->s_flags & MS_RDONLY) |
814 | return -EROFS; | 900 | return -EROFS; |
815 | 901 | ||
816 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 902 | namelen = strlen(name); |
817 | if (IS_ERR(vol_args)) | 903 | if (strchr(name, '/')) { |
818 | return PTR_ERR(vol_args); | ||
819 | |||
820 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | ||
821 | namelen = strlen(vol_args->name); | ||
822 | if (strchr(vol_args->name, '/')) { | ||
823 | ret = -EINVAL; | 904 | ret = -EINVAL; |
824 | goto out; | 905 | goto out; |
825 | } | 906 | } |
826 | 907 | ||
827 | if (subvol) { | 908 | if (subvol) { |
828 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, namelen, | 909 | ret = btrfs_mksubvol(&file->f_path, name, namelen, |
829 | NULL); | 910 | NULL, transid); |
830 | } else { | 911 | } else { |
831 | struct inode *src_inode; | 912 | struct inode *src_inode; |
832 | src_file = fget(vol_args->fd); | 913 | src_file = fget(fd); |
833 | if (!src_file) { | 914 | if (!src_file) { |
834 | ret = -EINVAL; | 915 | ret = -EINVAL; |
835 | goto out; | 916 | goto out; |
@@ -843,12 +924,56 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
843 | fput(src_file); | 924 | fput(src_file); |
844 | goto out; | 925 | goto out; |
845 | } | 926 | } |
846 | ret = btrfs_mksubvol(&file->f_path, vol_args->name, namelen, | 927 | ret = btrfs_mksubvol(&file->f_path, name, namelen, |
847 | BTRFS_I(src_inode)->root); | 928 | BTRFS_I(src_inode)->root, |
929 | transid); | ||
848 | fput(src_file); | 930 | fput(src_file); |
849 | } | 931 | } |
850 | out: | 932 | out: |
933 | return ret; | ||
934 | } | ||
935 | |||
936 | static noinline int btrfs_ioctl_snap_create(struct file *file, | ||
937 | void __user *arg, int subvol, | ||
938 | int async) | ||
939 | { | ||
940 | struct btrfs_ioctl_vol_args *vol_args = NULL; | ||
941 | struct btrfs_ioctl_async_vol_args *async_vol_args = NULL; | ||
942 | char *name; | ||
943 | u64 fd; | ||
944 | u64 transid = 0; | ||
945 | int ret; | ||
946 | |||
947 | if (async) { | ||
948 | async_vol_args = memdup_user(arg, sizeof(*async_vol_args)); | ||
949 | if (IS_ERR(async_vol_args)) | ||
950 | return PTR_ERR(async_vol_args); | ||
951 | |||
952 | name = async_vol_args->name; | ||
953 | fd = async_vol_args->fd; | ||
954 | async_vol_args->name[BTRFS_SNAPSHOT_NAME_MAX] = '\0'; | ||
955 | } else { | ||
956 | vol_args = memdup_user(arg, sizeof(*vol_args)); | ||
957 | if (IS_ERR(vol_args)) | ||
958 | return PTR_ERR(vol_args); | ||
959 | name = vol_args->name; | ||
960 | fd = vol_args->fd; | ||
961 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | ||
962 | } | ||
963 | |||
964 | ret = btrfs_ioctl_snap_create_transid(file, name, fd, | ||
965 | subvol, &transid); | ||
966 | |||
967 | if (!ret && async) { | ||
968 | if (copy_to_user(arg + | ||
969 | offsetof(struct btrfs_ioctl_async_vol_args, | ||
970 | transid), &transid, sizeof(transid))) | ||
971 | return -EFAULT; | ||
972 | } | ||
973 | |||
851 | kfree(vol_args); | 974 | kfree(vol_args); |
975 | kfree(async_vol_args); | ||
976 | |||
852 | return ret; | 977 | return ret; |
853 | } | 978 | } |
854 | 979 | ||
@@ -1073,14 +1198,10 @@ static noinline int btrfs_ioctl_tree_search(struct file *file, | |||
1073 | if (!capable(CAP_SYS_ADMIN)) | 1198 | if (!capable(CAP_SYS_ADMIN)) |
1074 | return -EPERM; | 1199 | return -EPERM; |
1075 | 1200 | ||
1076 | args = kmalloc(sizeof(*args), GFP_KERNEL); | 1201 | args = memdup_user(argp, sizeof(*args)); |
1077 | if (!args) | 1202 | if (IS_ERR(args)) |
1078 | return -ENOMEM; | 1203 | return PTR_ERR(args); |
1079 | 1204 | ||
1080 | if (copy_from_user(args, argp, sizeof(*args))) { | ||
1081 | kfree(args); | ||
1082 | return -EFAULT; | ||
1083 | } | ||
1084 | inode = fdentry(file)->d_inode; | 1205 | inode = fdentry(file)->d_inode; |
1085 | ret = search_ioctl(inode, args); | 1206 | ret = search_ioctl(inode, args); |
1086 | if (ret == 0 && copy_to_user(argp, args, sizeof(*args))) | 1207 | if (ret == 0 && copy_to_user(argp, args, sizeof(*args))) |
@@ -1188,14 +1309,10 @@ static noinline int btrfs_ioctl_ino_lookup(struct file *file, | |||
1188 | if (!capable(CAP_SYS_ADMIN)) | 1309 | if (!capable(CAP_SYS_ADMIN)) |
1189 | return -EPERM; | 1310 | return -EPERM; |
1190 | 1311 | ||
1191 | args = kmalloc(sizeof(*args), GFP_KERNEL); | 1312 | args = memdup_user(argp, sizeof(*args)); |
1192 | if (!args) | 1313 | if (IS_ERR(args)) |
1193 | return -ENOMEM; | 1314 | return PTR_ERR(args); |
1194 | 1315 | ||
1195 | if (copy_from_user(args, argp, sizeof(*args))) { | ||
1196 | kfree(args); | ||
1197 | return -EFAULT; | ||
1198 | } | ||
1199 | inode = fdentry(file)->d_inode; | 1316 | inode = fdentry(file)->d_inode; |
1200 | 1317 | ||
1201 | if (args->treeid == 0) | 1318 | if (args->treeid == 0) |
@@ -1227,9 +1344,6 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, | |||
1227 | int ret; | 1344 | int ret; |
1228 | int err = 0; | 1345 | int err = 0; |
1229 | 1346 | ||
1230 | if (!capable(CAP_SYS_ADMIN)) | ||
1231 | return -EPERM; | ||
1232 | |||
1233 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 1347 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
1234 | if (IS_ERR(vol_args)) | 1348 | if (IS_ERR(vol_args)) |
1235 | return PTR_ERR(vol_args); | 1349 | return PTR_ERR(vol_args); |
@@ -1259,13 +1373,51 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, | |||
1259 | } | 1373 | } |
1260 | 1374 | ||
1261 | inode = dentry->d_inode; | 1375 | inode = dentry->d_inode; |
1376 | dest = BTRFS_I(inode)->root; | ||
1377 | if (!capable(CAP_SYS_ADMIN)){ | ||
1378 | /* | ||
1379 | * Regular user. Only allow this with a special mount | ||
1380 | * option, when the user has write+exec access to the | ||
1381 | * subvol root, and when rmdir(2) would have been | ||
1382 | * allowed. | ||
1383 | * | ||
1384 | * Note that this is _not_ check that the subvol is | ||
1385 | * empty or doesn't contain data that we wouldn't | ||
1386 | * otherwise be able to delete. | ||
1387 | * | ||
1388 | * Users who want to delete empty subvols should try | ||
1389 | * rmdir(2). | ||
1390 | */ | ||
1391 | err = -EPERM; | ||
1392 | if (!btrfs_test_opt(root, USER_SUBVOL_RM_ALLOWED)) | ||
1393 | goto out_dput; | ||
1394 | |||
1395 | /* | ||
1396 | * Do not allow deletion if the parent dir is the same | ||
1397 | * as the dir to be deleted. That means the ioctl | ||
1398 | * must be called on the dentry referencing the root | ||
1399 | * of the subvol, not a random directory contained | ||
1400 | * within it. | ||
1401 | */ | ||
1402 | err = -EINVAL; | ||
1403 | if (root == dest) | ||
1404 | goto out_dput; | ||
1405 | |||
1406 | err = inode_permission(inode, MAY_WRITE | MAY_EXEC); | ||
1407 | if (err) | ||
1408 | goto out_dput; | ||
1409 | |||
1410 | /* check if subvolume may be deleted by a non-root user */ | ||
1411 | err = btrfs_may_delete(dir, dentry, 1); | ||
1412 | if (err) | ||
1413 | goto out_dput; | ||
1414 | } | ||
1415 | |||
1262 | if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) { | 1416 | if (inode->i_ino != BTRFS_FIRST_FREE_OBJECTID) { |
1263 | err = -EINVAL; | 1417 | err = -EINVAL; |
1264 | goto out_dput; | 1418 | goto out_dput; |
1265 | } | 1419 | } |
1266 | 1420 | ||
1267 | dest = BTRFS_I(inode)->root; | ||
1268 | |||
1269 | mutex_lock(&inode->i_mutex); | 1421 | mutex_lock(&inode->i_mutex); |
1270 | err = d_invalidate(dentry); | 1422 | err = d_invalidate(dentry); |
1271 | if (err) | 1423 | if (err) |
@@ -1304,7 +1456,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file, | |||
1304 | BUG_ON(ret); | 1456 | BUG_ON(ret); |
1305 | } | 1457 | } |
1306 | 1458 | ||
1307 | ret = btrfs_commit_transaction(trans, root); | 1459 | ret = btrfs_end_transaction(trans, root); |
1308 | BUG_ON(ret); | 1460 | BUG_ON(ret); |
1309 | inode->i_flags |= S_DEAD; | 1461 | inode->i_flags |= S_DEAD; |
1310 | out_up_write: | 1462 | out_up_write: |
@@ -1502,11 +1654,11 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1502 | path->reada = 2; | 1654 | path->reada = 2; |
1503 | 1655 | ||
1504 | if (inode < src) { | 1656 | if (inode < src) { |
1505 | mutex_lock(&inode->i_mutex); | 1657 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); |
1506 | mutex_lock(&src->i_mutex); | 1658 | mutex_lock_nested(&src->i_mutex, I_MUTEX_CHILD); |
1507 | } else { | 1659 | } else { |
1508 | mutex_lock(&src->i_mutex); | 1660 | mutex_lock_nested(&src->i_mutex, I_MUTEX_PARENT); |
1509 | mutex_lock(&inode->i_mutex); | 1661 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); |
1510 | } | 1662 | } |
1511 | 1663 | ||
1512 | /* determine range to clone */ | 1664 | /* determine range to clone */ |
@@ -1530,13 +1682,15 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1530 | while (1) { | 1682 | while (1) { |
1531 | struct btrfs_ordered_extent *ordered; | 1683 | struct btrfs_ordered_extent *ordered; |
1532 | lock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS); | 1684 | lock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS); |
1533 | ordered = btrfs_lookup_first_ordered_extent(inode, off+len); | 1685 | ordered = btrfs_lookup_first_ordered_extent(src, off+len); |
1534 | if (BTRFS_I(src)->delalloc_bytes == 0 && !ordered) | 1686 | if (!ordered && |
1687 | !test_range_bit(&BTRFS_I(src)->io_tree, off, off+len, | ||
1688 | EXTENT_DELALLOC, 0, NULL)) | ||
1535 | break; | 1689 | break; |
1536 | unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS); | 1690 | unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS); |
1537 | if (ordered) | 1691 | if (ordered) |
1538 | btrfs_put_ordered_extent(ordered); | 1692 | btrfs_put_ordered_extent(ordered); |
1539 | btrfs_wait_ordered_range(src, off, off+len); | 1693 | btrfs_wait_ordered_range(src, off, len); |
1540 | } | 1694 | } |
1541 | 1695 | ||
1542 | /* clone data */ | 1696 | /* clone data */ |
@@ -1605,7 +1759,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, | |||
1605 | } | 1759 | } |
1606 | btrfs_release_path(root, path); | 1760 | btrfs_release_path(root, path); |
1607 | 1761 | ||
1608 | if (key.offset + datal < off || | 1762 | if (key.offset + datal <= off || |
1609 | key.offset >= off+len) | 1763 | key.offset >= off+len) |
1610 | goto next; | 1764 | goto next; |
1611 | 1765 | ||
@@ -1879,6 +2033,22 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) | |||
1879 | return 0; | 2033 | return 0; |
1880 | } | 2034 | } |
1881 | 2035 | ||
2036 | static void get_block_group_info(struct list_head *groups_list, | ||
2037 | struct btrfs_ioctl_space_info *space) | ||
2038 | { | ||
2039 | struct btrfs_block_group_cache *block_group; | ||
2040 | |||
2041 | space->total_bytes = 0; | ||
2042 | space->used_bytes = 0; | ||
2043 | space->flags = 0; | ||
2044 | list_for_each_entry(block_group, groups_list, list) { | ||
2045 | space->flags = block_group->flags; | ||
2046 | space->total_bytes += block_group->key.offset; | ||
2047 | space->used_bytes += | ||
2048 | btrfs_block_group_used(&block_group->item); | ||
2049 | } | ||
2050 | } | ||
2051 | |||
1882 | long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) | 2052 | long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) |
1883 | { | 2053 | { |
1884 | struct btrfs_ioctl_space_args space_args; | 2054 | struct btrfs_ioctl_space_args space_args; |
@@ -1887,27 +2057,56 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) | |||
1887 | struct btrfs_ioctl_space_info *dest_orig; | 2057 | struct btrfs_ioctl_space_info *dest_orig; |
1888 | struct btrfs_ioctl_space_info *user_dest; | 2058 | struct btrfs_ioctl_space_info *user_dest; |
1889 | struct btrfs_space_info *info; | 2059 | struct btrfs_space_info *info; |
2060 | u64 types[] = {BTRFS_BLOCK_GROUP_DATA, | ||
2061 | BTRFS_BLOCK_GROUP_SYSTEM, | ||
2062 | BTRFS_BLOCK_GROUP_METADATA, | ||
2063 | BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA}; | ||
2064 | int num_types = 4; | ||
1890 | int alloc_size; | 2065 | int alloc_size; |
1891 | int ret = 0; | 2066 | int ret = 0; |
1892 | int slot_count = 0; | 2067 | int slot_count = 0; |
2068 | int i, c; | ||
1893 | 2069 | ||
1894 | if (copy_from_user(&space_args, | 2070 | if (copy_from_user(&space_args, |
1895 | (struct btrfs_ioctl_space_args __user *)arg, | 2071 | (struct btrfs_ioctl_space_args __user *)arg, |
1896 | sizeof(space_args))) | 2072 | sizeof(space_args))) |
1897 | return -EFAULT; | 2073 | return -EFAULT; |
1898 | 2074 | ||
1899 | /* first we count slots */ | 2075 | for (i = 0; i < num_types; i++) { |
1900 | rcu_read_lock(); | 2076 | struct btrfs_space_info *tmp; |
1901 | list_for_each_entry_rcu(info, &root->fs_info->space_info, list) | 2077 | |
1902 | slot_count++; | 2078 | info = NULL; |
1903 | rcu_read_unlock(); | 2079 | rcu_read_lock(); |
2080 | list_for_each_entry_rcu(tmp, &root->fs_info->space_info, | ||
2081 | list) { | ||
2082 | if (tmp->flags == types[i]) { | ||
2083 | info = tmp; | ||
2084 | break; | ||
2085 | } | ||
2086 | } | ||
2087 | rcu_read_unlock(); | ||
2088 | |||
2089 | if (!info) | ||
2090 | continue; | ||
2091 | |||
2092 | down_read(&info->groups_sem); | ||
2093 | for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) { | ||
2094 | if (!list_empty(&info->block_groups[c])) | ||
2095 | slot_count++; | ||
2096 | } | ||
2097 | up_read(&info->groups_sem); | ||
2098 | } | ||
1904 | 2099 | ||
1905 | /* space_slots == 0 means they are asking for a count */ | 2100 | /* space_slots == 0 means they are asking for a count */ |
1906 | if (space_args.space_slots == 0) { | 2101 | if (space_args.space_slots == 0) { |
1907 | space_args.total_spaces = slot_count; | 2102 | space_args.total_spaces = slot_count; |
1908 | goto out; | 2103 | goto out; |
1909 | } | 2104 | } |
2105 | |||
2106 | slot_count = min_t(int, space_args.space_slots, slot_count); | ||
2107 | |||
1910 | alloc_size = sizeof(*dest) * slot_count; | 2108 | alloc_size = sizeof(*dest) * slot_count; |
2109 | |||
1911 | /* we generally have at most 6 or so space infos, one for each raid | 2110 | /* we generally have at most 6 or so space infos, one for each raid |
1912 | * level. So, a whole page should be more than enough for everyone | 2111 | * level. So, a whole page should be more than enough for everyone |
1913 | */ | 2112 | */ |
@@ -1921,27 +2120,34 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) | |||
1921 | dest_orig = dest; | 2120 | dest_orig = dest; |
1922 | 2121 | ||
1923 | /* now we have a buffer to copy into */ | 2122 | /* now we have a buffer to copy into */ |
1924 | rcu_read_lock(); | 2123 | for (i = 0; i < num_types; i++) { |
1925 | list_for_each_entry_rcu(info, &root->fs_info->space_info, list) { | 2124 | struct btrfs_space_info *tmp; |
1926 | /* make sure we don't copy more than we allocated | 2125 | |
1927 | * in our buffer | 2126 | info = NULL; |
1928 | */ | 2127 | rcu_read_lock(); |
1929 | if (slot_count == 0) | 2128 | list_for_each_entry_rcu(tmp, &root->fs_info->space_info, |
1930 | break; | 2129 | list) { |
1931 | slot_count--; | 2130 | if (tmp->flags == types[i]) { |
1932 | 2131 | info = tmp; | |
1933 | /* make sure userland has enough room in their buffer */ | 2132 | break; |
1934 | if (space_args.total_spaces >= space_args.space_slots) | 2133 | } |
1935 | break; | 2134 | } |
2135 | rcu_read_unlock(); | ||
1936 | 2136 | ||
1937 | space.flags = info->flags; | 2137 | if (!info) |
1938 | space.total_bytes = info->total_bytes; | 2138 | continue; |
1939 | space.used_bytes = info->bytes_used; | 2139 | down_read(&info->groups_sem); |
1940 | memcpy(dest, &space, sizeof(space)); | 2140 | for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) { |
1941 | dest++; | 2141 | if (!list_empty(&info->block_groups[c])) { |
1942 | space_args.total_spaces++; | 2142 | get_block_group_info(&info->block_groups[c], |
2143 | &space); | ||
2144 | memcpy(dest, &space, sizeof(space)); | ||
2145 | dest++; | ||
2146 | space_args.total_spaces++; | ||
2147 | } | ||
2148 | } | ||
2149 | up_read(&info->groups_sem); | ||
1943 | } | 2150 | } |
1944 | rcu_read_unlock(); | ||
1945 | 2151 | ||
1946 | user_dest = (struct btrfs_ioctl_space_info *) | 2152 | user_dest = (struct btrfs_ioctl_space_info *) |
1947 | (arg + sizeof(struct btrfs_ioctl_space_args)); | 2153 | (arg + sizeof(struct btrfs_ioctl_space_args)); |
@@ -1984,6 +2190,36 @@ long btrfs_ioctl_trans_end(struct file *file) | |||
1984 | return 0; | 2190 | return 0; |
1985 | } | 2191 | } |
1986 | 2192 | ||
2193 | static noinline long btrfs_ioctl_start_sync(struct file *file, void __user *argp) | ||
2194 | { | ||
2195 | struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root; | ||
2196 | struct btrfs_trans_handle *trans; | ||
2197 | u64 transid; | ||
2198 | |||
2199 | trans = btrfs_start_transaction(root, 0); | ||
2200 | transid = trans->transid; | ||
2201 | btrfs_commit_transaction_async(trans, root, 0); | ||
2202 | |||
2203 | if (argp) | ||
2204 | if (copy_to_user(argp, &transid, sizeof(transid))) | ||
2205 | return -EFAULT; | ||
2206 | return 0; | ||
2207 | } | ||
2208 | |||
2209 | static noinline long btrfs_ioctl_wait_sync(struct file *file, void __user *argp) | ||
2210 | { | ||
2211 | struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root; | ||
2212 | u64 transid; | ||
2213 | |||
2214 | if (argp) { | ||
2215 | if (copy_from_user(&transid, argp, sizeof(transid))) | ||
2216 | return -EFAULT; | ||
2217 | } else { | ||
2218 | transid = 0; /* current trans */ | ||
2219 | } | ||
2220 | return btrfs_wait_for_commit(root, transid); | ||
2221 | } | ||
2222 | |||
1987 | long btrfs_ioctl(struct file *file, unsigned int | 2223 | long btrfs_ioctl(struct file *file, unsigned int |
1988 | cmd, unsigned long arg) | 2224 | cmd, unsigned long arg) |
1989 | { | 2225 | { |
@@ -1998,9 +2234,11 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
1998 | case FS_IOC_GETVERSION: | 2234 | case FS_IOC_GETVERSION: |
1999 | return btrfs_ioctl_getversion(file, argp); | 2235 | return btrfs_ioctl_getversion(file, argp); |
2000 | case BTRFS_IOC_SNAP_CREATE: | 2236 | case BTRFS_IOC_SNAP_CREATE: |
2001 | return btrfs_ioctl_snap_create(file, argp, 0); | 2237 | return btrfs_ioctl_snap_create(file, argp, 0, 0); |
2238 | case BTRFS_IOC_SNAP_CREATE_ASYNC: | ||
2239 | return btrfs_ioctl_snap_create(file, argp, 0, 1); | ||
2002 | case BTRFS_IOC_SUBVOL_CREATE: | 2240 | case BTRFS_IOC_SUBVOL_CREATE: |
2003 | return btrfs_ioctl_snap_create(file, argp, 1); | 2241 | return btrfs_ioctl_snap_create(file, argp, 1, 0); |
2004 | case BTRFS_IOC_SNAP_DESTROY: | 2242 | case BTRFS_IOC_SNAP_DESTROY: |
2005 | return btrfs_ioctl_snap_destroy(file, argp); | 2243 | return btrfs_ioctl_snap_destroy(file, argp); |
2006 | case BTRFS_IOC_DEFAULT_SUBVOL: | 2244 | case BTRFS_IOC_DEFAULT_SUBVOL: |
@@ -2034,6 +2272,10 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
2034 | case BTRFS_IOC_SYNC: | 2272 | case BTRFS_IOC_SYNC: |
2035 | btrfs_sync_fs(file->f_dentry->d_sb, 1); | 2273 | btrfs_sync_fs(file->f_dentry->d_sb, 1); |
2036 | return 0; | 2274 | return 0; |
2275 | case BTRFS_IOC_START_SYNC: | ||
2276 | return btrfs_ioctl_start_sync(file, argp); | ||
2277 | case BTRFS_IOC_WAIT_SYNC: | ||
2278 | return btrfs_ioctl_wait_sync(file, argp); | ||
2037 | } | 2279 | } |
2038 | 2280 | ||
2039 | return -ENOTTY; | 2281 | return -ENOTTY; |