diff options
| author | Chris Mason <chris.mason@oracle.com> | 2010-03-11 09:42:04 -0500 |
|---|---|---|
| committer | Chris Mason <chris.mason@oracle.com> | 2010-03-15 11:00:10 -0400 |
| commit | 1e701a3292e25a6c4939cad9f24951dc6b6ad853 (patch) | |
| tree | 899887a99aae82fe113bffedccb90a76e5473f8b | |
| parent | 940100a4a7b78b27e60a3e72340fb9b5397dcdb2 (diff) | |
Btrfs: add new defrag-range ioctl.
The btrfs defrag ioctl was limited to doing the entire file. This
commit adds a new interface that can defrag a specific range inside
the file.
It can also force compression on the file, allowing you to selectively
compress individual files after they were created, even when mount -o
compress isn't turned on.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
| -rw-r--r-- | fs/btrfs/btrfs_inode.h | 5 | ||||
| -rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
| -rw-r--r-- | fs/btrfs/inode.c | 11 | ||||
| -rw-r--r-- | fs/btrfs/ioctl.c | 83 | ||||
| -rw-r--r-- | fs/btrfs/ioctl.h | 31 |
5 files changed, 117 insertions, 14 deletions
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index 3f1f50d9d916..7a4dee199832 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h | |||
| @@ -153,6 +153,11 @@ struct btrfs_inode { | |||
| 153 | unsigned ordered_data_close:1; | 153 | unsigned ordered_data_close:1; |
| 154 | unsigned dummy_inode:1; | 154 | unsigned dummy_inode:1; |
| 155 | 155 | ||
| 156 | /* | ||
| 157 | * always compress this one file | ||
| 158 | */ | ||
| 159 | unsigned force_compress:1; | ||
| 160 | |||
| 156 | struct inode vfs_inode; | 161 | struct inode vfs_inode; |
| 157 | }; | 162 | }; |
| 158 | 163 | ||
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 1166b15e9bf6..3a36b1fb553a 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -1184,7 +1184,6 @@ struct btrfs_root { | |||
| 1184 | #define BTRFS_INODE_NOATIME (1 << 9) | 1184 | #define BTRFS_INODE_NOATIME (1 << 9) |
| 1185 | #define BTRFS_INODE_DIRSYNC (1 << 10) | 1185 | #define BTRFS_INODE_DIRSYNC (1 << 10) |
| 1186 | 1186 | ||
| 1187 | |||
| 1188 | /* some macros to generate set/get funcs for the struct fields. This | 1187 | /* some macros to generate set/get funcs for the struct fields. This |
| 1189 | * assumes there is a lefoo_to_cpu for every type, so lets make a simple | 1188 | * assumes there is a lefoo_to_cpu for every type, so lets make a simple |
| 1190 | * one for u8: | 1189 | * one for u8: |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 7d10d1ccb0fe..3657925c2461 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
| @@ -379,7 +379,8 @@ again: | |||
| 379 | * change at any time if we discover bad compression ratios. | 379 | * change at any time if we discover bad compression ratios. |
| 380 | */ | 380 | */ |
| 381 | if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS) && | 381 | if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS) && |
| 382 | btrfs_test_opt(root, COMPRESS)) { | 382 | (btrfs_test_opt(root, COMPRESS) || |
| 383 | (BTRFS_I(inode)->force_compress))) { | ||
| 383 | WARN_ON(pages); | 384 | WARN_ON(pages); |
| 384 | pages = kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS); | 385 | pages = kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS); |
| 385 | 386 | ||
| @@ -483,8 +484,10 @@ again: | |||
| 483 | nr_pages_ret = 0; | 484 | nr_pages_ret = 0; |
| 484 | 485 | ||
| 485 | /* flag the file so we don't compress in the future */ | 486 | /* flag the file so we don't compress in the future */ |
| 486 | if (!btrfs_test_opt(root, FORCE_COMPRESS)) | 487 | if (!btrfs_test_opt(root, FORCE_COMPRESS) && |
| 488 | !(BTRFS_I(inode)->force_compress)) { | ||
| 487 | BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS; | 489 | BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS; |
| 490 | } | ||
| 488 | } | 491 | } |
| 489 | if (will_compress) { | 492 | if (will_compress) { |
| 490 | *num_added += 1; | 493 | *num_added += 1; |
| @@ -1211,7 +1214,8 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page, | |||
| 1211 | else if (BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC) | 1214 | else if (BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC) |
| 1212 | ret = run_delalloc_nocow(inode, locked_page, start, end, | 1215 | ret = run_delalloc_nocow(inode, locked_page, start, end, |
| 1213 | page_started, 0, nr_written); | 1216 | page_started, 0, nr_written); |
| 1214 | else if (!btrfs_test_opt(root, COMPRESS)) | 1217 | else if (!btrfs_test_opt(root, COMPRESS) && |
| 1218 | !(BTRFS_I(inode)->force_compress)) | ||
| 1215 | ret = cow_file_range(inode, locked_page, start, end, | 1219 | ret = cow_file_range(inode, locked_page, start, end, |
| 1216 | page_started, nr_written, 1); | 1220 | page_started, nr_written, 1); |
| 1217 | else | 1221 | else |
| @@ -3639,6 +3643,7 @@ static noinline void init_btrfs_i(struct inode *inode) | |||
| 3639 | bi->index_cnt = (u64)-1; | 3643 | bi->index_cnt = (u64)-1; |
| 3640 | bi->last_unlink_trans = 0; | 3644 | bi->last_unlink_trans = 0; |
| 3641 | bi->ordered_data_close = 0; | 3645 | bi->ordered_data_close = 0; |
| 3646 | bi->force_compress = 0; | ||
| 3642 | extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS); | 3647 | extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS); |
| 3643 | extent_io_tree_init(&BTRFS_I(inode)->io_tree, | 3648 | extent_io_tree_init(&BTRFS_I(inode)->io_tree, |
| 3644 | inode->i_mapping, GFP_NOFS); | 3649 | inode->i_mapping, GFP_NOFS); |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 3a89cd77f307..d866b460c26e 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
| @@ -476,13 +476,18 @@ out_unlock: | |||
| 476 | } | 476 | } |
| 477 | 477 | ||
| 478 | static int should_defrag_range(struct inode *inode, u64 start, u64 len, | 478 | static int should_defrag_range(struct inode *inode, u64 start, u64 len, |
| 479 | u64 *last_len, u64 *skip, u64 *defrag_end) | 479 | int thresh, u64 *last_len, u64 *skip, |
| 480 | u64 *defrag_end) | ||
| 480 | { | 481 | { |
| 481 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | 482 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; |
| 482 | struct extent_map *em = NULL; | 483 | struct extent_map *em = NULL; |
| 483 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | 484 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; |
| 484 | int ret = 1; | 485 | int ret = 1; |
| 485 | 486 | ||
| 487 | |||
| 488 | if (thresh == 0) | ||
| 489 | thresh = 256 * 1024; | ||
| 490 | |||
| 486 | /* | 491 | /* |
| 487 | * make sure that once we start defragging and extent, we keep on | 492 | * make sure that once we start defragging and extent, we keep on |
| 488 | * defragging it | 493 | * defragging it |
| @@ -517,8 +522,7 @@ static int should_defrag_range(struct inode *inode, u64 start, u64 len, | |||
| 517 | /* | 522 | /* |
| 518 | * we hit a real extent, if it is big don't bother defragging it again | 523 | * we hit a real extent, if it is big don't bother defragging it again |
| 519 | */ | 524 | */ |
| 520 | if ((*last_len == 0 || *last_len >= 256 * 1024) && | 525 | if ((*last_len == 0 || *last_len >= thresh) && em->len >= thresh) |
| 521 | em->len >= 256 * 1024) | ||
| 522 | ret = 0; | 526 | ret = 0; |
| 523 | 527 | ||
| 524 | /* | 528 | /* |
| @@ -542,7 +546,8 @@ static int should_defrag_range(struct inode *inode, u64 start, u64 len, | |||
| 542 | return ret; | 546 | return ret; |
| 543 | } | 547 | } |
| 544 | 548 | ||
| 545 | static int btrfs_defrag_file(struct file *file) | 549 | static int btrfs_defrag_file(struct file *file, |
| 550 | struct btrfs_ioctl_defrag_range_args *range) | ||
| 546 | { | 551 | { |
| 547 | struct inode *inode = fdentry(file)->d_inode; | 552 | struct inode *inode = fdentry(file)->d_inode; |
| 548 | struct btrfs_root *root = BTRFS_I(inode)->root; | 553 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| @@ -563,11 +568,19 @@ static int btrfs_defrag_file(struct file *file) | |||
| 563 | if (inode->i_size == 0) | 568 | if (inode->i_size == 0) |
| 564 | return 0; | 569 | return 0; |
| 565 | 570 | ||
| 566 | last_index = (inode->i_size - 1) >> PAGE_CACHE_SHIFT; | 571 | if (range->start + range->len > range->start) { |
| 567 | i = 0; | 572 | last_index = min_t(u64, inode->i_size - 1, |
| 573 | range->start + range->len - 1) >> PAGE_CACHE_SHIFT; | ||
| 574 | } else { | ||
| 575 | last_index = (inode->i_size - 1) >> PAGE_CACHE_SHIFT; | ||
| 576 | } | ||
| 577 | |||
| 578 | i = range->start >> PAGE_CACHE_SHIFT; | ||
| 568 | while (i <= last_index) { | 579 | while (i <= last_index) { |
| 569 | if (!should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT, | 580 | if (!should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT, |
| 570 | PAGE_CACHE_SIZE, &last_len, &skip, | 581 | PAGE_CACHE_SIZE, |
| 582 | range->extent_thresh, | ||
| 583 | &last_len, &skip, | ||
| 571 | &defrag_end)) { | 584 | &defrag_end)) { |
| 572 | unsigned long next; | 585 | unsigned long next; |
| 573 | /* | 586 | /* |
| @@ -585,6 +598,8 @@ static int btrfs_defrag_file(struct file *file) | |||
| 585 | } | 598 | } |
| 586 | total_read++; | 599 | total_read++; |
| 587 | mutex_lock(&inode->i_mutex); | 600 | mutex_lock(&inode->i_mutex); |
| 601 | if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) | ||
| 602 | BTRFS_I(inode)->force_compress = 1; | ||
| 588 | 603 | ||
| 589 | ret = btrfs_check_data_free_space(root, inode, PAGE_CACHE_SIZE); | 604 | ret = btrfs_check_data_free_space(root, inode, PAGE_CACHE_SIZE); |
| 590 | if (ret) { | 605 | if (ret) { |
| @@ -673,6 +688,28 @@ loop_unlock: | |||
| 673 | i++; | 688 | i++; |
| 674 | } | 689 | } |
| 675 | 690 | ||
| 691 | if ((range->flags & BTRFS_DEFRAG_RANGE_START_IO)) | ||
| 692 | filemap_flush(inode->i_mapping); | ||
| 693 | |||
| 694 | if ((range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)) { | ||
| 695 | /* the filemap_flush will queue IO into the worker threads, but | ||
| 696 | * we have to make sure the IO is actually started and that | ||
| 697 | * ordered extents get created before we return | ||
| 698 | */ | ||
| 699 | atomic_inc(&root->fs_info->async_submit_draining); | ||
| 700 | while (atomic_read(&root->fs_info->nr_async_submits) || | ||
| 701 | atomic_read(&root->fs_info->async_delalloc_pages)) { | ||
| 702 | wait_event(root->fs_info->async_submit_wait, | ||
| 703 | (atomic_read(&root->fs_info->nr_async_submits) == 0 && | ||
| 704 | atomic_read(&root->fs_info->async_delalloc_pages) == 0)); | ||
| 705 | } | ||
| 706 | atomic_dec(&root->fs_info->async_submit_draining); | ||
| 707 | |||
| 708 | mutex_lock(&inode->i_mutex); | ||
| 709 | BTRFS_I(inode)->force_compress = 0; | ||
| 710 | mutex_unlock(&inode->i_mutex); | ||
| 711 | } | ||
| 712 | |||
| 676 | return 0; | 713 | return 0; |
| 677 | 714 | ||
| 678 | err_reservations: | 715 | err_reservations: |
| @@ -1284,10 +1321,11 @@ out: | |||
| 1284 | return err; | 1321 | return err; |
| 1285 | } | 1322 | } |
| 1286 | 1323 | ||
| 1287 | static int btrfs_ioctl_defrag(struct file *file) | 1324 | static int btrfs_ioctl_defrag(struct file *file, void __user *argp) |
| 1288 | { | 1325 | { |
| 1289 | struct inode *inode = fdentry(file)->d_inode; | 1326 | struct inode *inode = fdentry(file)->d_inode; |
| 1290 | struct btrfs_root *root = BTRFS_I(inode)->root; | 1327 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| 1328 | struct btrfs_ioctl_defrag_range_args *range; | ||
| 1291 | int ret; | 1329 | int ret; |
| 1292 | 1330 | ||
| 1293 | ret = mnt_want_write(file->f_path.mnt); | 1331 | ret = mnt_want_write(file->f_path.mnt); |
| @@ -1308,7 +1346,30 @@ static int btrfs_ioctl_defrag(struct file *file) | |||
| 1308 | ret = -EINVAL; | 1346 | ret = -EINVAL; |
| 1309 | goto out; | 1347 | goto out; |
| 1310 | } | 1348 | } |
| 1311 | btrfs_defrag_file(file); | 1349 | |
| 1350 | range = kzalloc(sizeof(*range), GFP_KERNEL); | ||
| 1351 | if (!range) { | ||
| 1352 | ret = -ENOMEM; | ||
| 1353 | goto out; | ||
| 1354 | } | ||
| 1355 | |||
| 1356 | if (argp) { | ||
| 1357 | if (copy_from_user(range, argp, | ||
| 1358 | sizeof(*range))) { | ||
| 1359 | ret = -EFAULT; | ||
| 1360 | kfree(range); | ||
| 1361 | } | ||
| 1362 | /* compression requires us to start the IO */ | ||
| 1363 | if ((range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)) { | ||
| 1364 | range->flags |= BTRFS_DEFRAG_RANGE_START_IO; | ||
| 1365 | range->extent_thresh = (u32)-1; | ||
| 1366 | } | ||
| 1367 | } else { | ||
| 1368 | /* the rest are all set to zero by kzalloc */ | ||
| 1369 | range->len = (u64)-1; | ||
| 1370 | } | ||
| 1371 | btrfs_defrag_file(file, range); | ||
| 1372 | kfree(range); | ||
| 1312 | break; | 1373 | break; |
| 1313 | } | 1374 | } |
| 1314 | out: | 1375 | out: |
| @@ -1831,7 +1892,9 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
| 1831 | case BTRFS_IOC_DEFAULT_SUBVOL: | 1892 | case BTRFS_IOC_DEFAULT_SUBVOL: |
| 1832 | return btrfs_ioctl_default_subvol(file, argp); | 1893 | return btrfs_ioctl_default_subvol(file, argp); |
| 1833 | case BTRFS_IOC_DEFRAG: | 1894 | case BTRFS_IOC_DEFRAG: |
| 1834 | return btrfs_ioctl_defrag(file); | 1895 | return btrfs_ioctl_defrag(file, NULL); |
| 1896 | case BTRFS_IOC_DEFRAG_RANGE: | ||
| 1897 | return btrfs_ioctl_defrag(file, argp); | ||
| 1835 | case BTRFS_IOC_RESIZE: | 1898 | case BTRFS_IOC_RESIZE: |
| 1836 | return btrfs_ioctl_resize(root, argp); | 1899 | return btrfs_ioctl_resize(root, argp); |
| 1837 | case BTRFS_IOC_ADD_DEV: | 1900 | case BTRFS_IOC_ADD_DEV: |
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index f1923e0260e3..2d64a65842f3 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h | |||
| @@ -99,6 +99,35 @@ struct btrfs_ioctl_clone_range_args { | |||
| 99 | __u64 dest_offset; | 99 | __u64 dest_offset; |
| 100 | }; | 100 | }; |
| 101 | 101 | ||
| 102 | /* flags for the defrag range ioctl */ | ||
| 103 | #define BTRFS_DEFRAG_RANGE_COMPRESS 1 | ||
| 104 | #define BTRFS_DEFRAG_RANGE_START_IO 2 | ||
| 105 | |||
| 106 | struct btrfs_ioctl_defrag_range_args { | ||
| 107 | /* start of the defrag operation */ | ||
| 108 | __u64 start; | ||
| 109 | |||
| 110 | /* number of bytes to defrag, use (u64)-1 to say all */ | ||
| 111 | __u64 len; | ||
| 112 | |||
| 113 | /* | ||
| 114 | * flags for the operation, which can include turning | ||
| 115 | * on compression for this one defrag | ||
| 116 | */ | ||
| 117 | __u64 flags; | ||
| 118 | |||
| 119 | /* | ||
| 120 | * any extent bigger than this will be considered | ||
| 121 | * already defragged. Use 0 to take the kernel default | ||
| 122 | * Use 1 to say every single extent must be rewritten | ||
| 123 | */ | ||
| 124 | __u32 extent_thresh; | ||
| 125 | |||
| 126 | /* spare for later */ | ||
| 127 | __u32 unused[5]; | ||
| 128 | }; | ||
| 129 | |||
| 130 | |||
| 102 | #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ | 131 | #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ |
| 103 | struct btrfs_ioctl_vol_args) | 132 | struct btrfs_ioctl_vol_args) |
| 104 | #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ | 133 | #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ |
| @@ -130,6 +159,8 @@ struct btrfs_ioctl_clone_range_args { | |||
| 130 | struct btrfs_ioctl_vol_args) | 159 | struct btrfs_ioctl_vol_args) |
| 131 | #define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \ | 160 | #define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \ |
| 132 | struct btrfs_ioctl_vol_args) | 161 | struct btrfs_ioctl_vol_args) |
| 162 | #define BTRFS_IOC_DEFRAG_RANGE _IOW(BTRFS_IOCTL_MAGIC, 16, \ | ||
| 163 | struct btrfs_ioctl_defrag_range_args) | ||
| 133 | #define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \ | 164 | #define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \ |
| 134 | struct btrfs_ioctl_search_args) | 165 | struct btrfs_ioctl_search_args) |
| 135 | #define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \ | 166 | #define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \ |
