diff options
Diffstat (limited to 'fs')
59 files changed, 1348 insertions, 504 deletions
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index f039b104a98e..b03dd23feda8 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c | |||
| @@ -43,23 +43,6 @@ | |||
| 43 | #include "fid.h" | 43 | #include "fid.h" |
| 44 | 44 | ||
| 45 | /** | 45 | /** |
| 46 | * v9fs_dentry_delete - called when dentry refcount equals 0 | ||
| 47 | * @dentry: dentry in question | ||
| 48 | * | ||
| 49 | * By returning 1 here we should remove cacheing of unused | ||
| 50 | * dentry components. | ||
| 51 | * | ||
| 52 | */ | ||
| 53 | |||
| 54 | static int v9fs_dentry_delete(const struct dentry *dentry) | ||
| 55 | { | ||
| 56 | p9_debug(P9_DEBUG_VFS, " dentry: %s (%p)\n", | ||
| 57 | dentry->d_name.name, dentry); | ||
| 58 | |||
| 59 | return 1; | ||
| 60 | } | ||
| 61 | |||
| 62 | /** | ||
| 63 | * v9fs_cached_dentry_delete - called when dentry refcount equals 0 | 46 | * v9fs_cached_dentry_delete - called when dentry refcount equals 0 |
| 64 | * @dentry: dentry in question | 47 | * @dentry: dentry in question |
| 65 | * | 48 | * |
| @@ -134,6 +117,6 @@ const struct dentry_operations v9fs_cached_dentry_operations = { | |||
| 134 | }; | 117 | }; |
| 135 | 118 | ||
| 136 | const struct dentry_operations v9fs_dentry_operations = { | 119 | const struct dentry_operations v9fs_dentry_operations = { |
| 137 | .d_delete = v9fs_dentry_delete, | 120 | .d_delete = always_delete_dentry, |
| 138 | .d_release = v9fs_dentry_release, | 121 | .d_release = v9fs_dentry_release, |
| 139 | }; | 122 | }; |
| @@ -601,7 +601,7 @@ EXPORT_SYMBOL(bio_get_nr_vecs); | |||
| 601 | 601 | ||
| 602 | static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page | 602 | static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page |
| 603 | *page, unsigned int len, unsigned int offset, | 603 | *page, unsigned int len, unsigned int offset, |
| 604 | unsigned short max_sectors) | 604 | unsigned int max_sectors) |
| 605 | { | 605 | { |
| 606 | int retried_segments = 0; | 606 | int retried_segments = 0; |
| 607 | struct bio_vec *bvec; | 607 | struct bio_vec *bvec; |
diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig index f9d5094e1029..aa976eced2d2 100644 --- a/fs/btrfs/Kconfig +++ b/fs/btrfs/Kconfig | |||
| @@ -9,12 +9,17 @@ config BTRFS_FS | |||
| 9 | select XOR_BLOCKS | 9 | select XOR_BLOCKS |
| 10 | 10 | ||
| 11 | help | 11 | help |
| 12 | Btrfs is a new filesystem with extents, writable snapshotting, | 12 | Btrfs is a general purpose copy-on-write filesystem with extents, |
| 13 | support for multiple devices and many more features. | 13 | writable snapshotting, support for multiple devices and many more |
| 14 | features focused on fault tolerance, repair and easy administration. | ||
| 14 | 15 | ||
| 15 | Btrfs is highly experimental, and THE DISK FORMAT IS NOT YET | 16 | The filesystem disk format is no longer unstable, and it's not |
| 16 | FINALIZED. You should say N here unless you are interested in | 17 | expected to change unless there are strong reasons to do so. If there |
| 17 | testing Btrfs with non-critical data. | 18 | is a format change, file systems with a unchanged format will |
| 19 | continue to be mountable and usable by newer kernels. | ||
| 20 | |||
| 21 | For more information, please see the web pages at | ||
| 22 | http://btrfs.wiki.kernel.org. | ||
| 18 | 23 | ||
| 19 | To compile this file system support as a module, choose M here. The | 24 | To compile this file system support as a module, choose M here. The |
| 20 | module will be called btrfs. | 25 | module will be called btrfs. |
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 8aec751fa464..c1e0b0caf9cc 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c | |||
| @@ -495,6 +495,7 @@ static int __btrfs_start_workers(struct btrfs_workers *workers) | |||
| 495 | spin_lock_irq(&workers->lock); | 495 | spin_lock_irq(&workers->lock); |
| 496 | if (workers->stopping) { | 496 | if (workers->stopping) { |
| 497 | spin_unlock_irq(&workers->lock); | 497 | spin_unlock_irq(&workers->lock); |
| 498 | ret = -EINVAL; | ||
| 498 | goto fail_kthread; | 499 | goto fail_kthread; |
| 499 | } | 500 | } |
| 500 | list_add_tail(&worker->worker_list, &workers->idle_list); | 501 | list_add_tail(&worker->worker_list, &workers->idle_list); |
diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index e0aab4456974..b50764bef141 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c | |||
| @@ -77,6 +77,15 @@ | |||
| 77 | * the integrity of (super)-block write requests, do not | 77 | * the integrity of (super)-block write requests, do not |
| 78 | * enable the config option BTRFS_FS_CHECK_INTEGRITY to | 78 | * enable the config option BTRFS_FS_CHECK_INTEGRITY to |
| 79 | * include and compile the integrity check tool. | 79 | * include and compile the integrity check tool. |
| 80 | * | ||
| 81 | * Expect millions of lines of information in the kernel log with an | ||
| 82 | * enabled check_int_print_mask. Therefore set LOG_BUF_SHIFT in the | ||
| 83 | * kernel config to at least 26 (which is 64MB). Usually the value is | ||
| 84 | * limited to 21 (which is 2MB) in init/Kconfig. The file needs to be | ||
| 85 | * changed like this before LOG_BUF_SHIFT can be set to a high value: | ||
| 86 | * config LOG_BUF_SHIFT | ||
| 87 | * int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" | ||
| 88 | * range 12 30 | ||
| 80 | */ | 89 | */ |
| 81 | 90 | ||
| 82 | #include <linux/sched.h> | 91 | #include <linux/sched.h> |
| @@ -124,6 +133,7 @@ | |||
| 124 | #define BTRFSIC_PRINT_MASK_INITIAL_DATABASE 0x00000400 | 133 | #define BTRFSIC_PRINT_MASK_INITIAL_DATABASE 0x00000400 |
| 125 | #define BTRFSIC_PRINT_MASK_NUM_COPIES 0x00000800 | 134 | #define BTRFSIC_PRINT_MASK_NUM_COPIES 0x00000800 |
| 126 | #define BTRFSIC_PRINT_MASK_TREE_WITH_ALL_MIRRORS 0x00001000 | 135 | #define BTRFSIC_PRINT_MASK_TREE_WITH_ALL_MIRRORS 0x00001000 |
| 136 | #define BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH_VERBOSE 0x00002000 | ||
| 127 | 137 | ||
| 128 | struct btrfsic_dev_state; | 138 | struct btrfsic_dev_state; |
| 129 | struct btrfsic_state; | 139 | struct btrfsic_state; |
| @@ -3015,6 +3025,7 @@ void btrfsic_submit_bio(int rw, struct bio *bio) | |||
| 3015 | (rw & WRITE) && NULL != bio->bi_io_vec) { | 3025 | (rw & WRITE) && NULL != bio->bi_io_vec) { |
| 3016 | unsigned int i; | 3026 | unsigned int i; |
| 3017 | u64 dev_bytenr; | 3027 | u64 dev_bytenr; |
| 3028 | u64 cur_bytenr; | ||
| 3018 | int bio_is_patched; | 3029 | int bio_is_patched; |
| 3019 | char **mapped_datav; | 3030 | char **mapped_datav; |
| 3020 | 3031 | ||
| @@ -3033,6 +3044,7 @@ void btrfsic_submit_bio(int rw, struct bio *bio) | |||
| 3033 | GFP_NOFS); | 3044 | GFP_NOFS); |
| 3034 | if (!mapped_datav) | 3045 | if (!mapped_datav) |
| 3035 | goto leave; | 3046 | goto leave; |
| 3047 | cur_bytenr = dev_bytenr; | ||
| 3036 | for (i = 0; i < bio->bi_vcnt; i++) { | 3048 | for (i = 0; i < bio->bi_vcnt; i++) { |
| 3037 | BUG_ON(bio->bi_io_vec[i].bv_len != PAGE_CACHE_SIZE); | 3049 | BUG_ON(bio->bi_io_vec[i].bv_len != PAGE_CACHE_SIZE); |
| 3038 | mapped_datav[i] = kmap(bio->bi_io_vec[i].bv_page); | 3050 | mapped_datav[i] = kmap(bio->bi_io_vec[i].bv_page); |
| @@ -3044,16 +3056,13 @@ void btrfsic_submit_bio(int rw, struct bio *bio) | |||
| 3044 | kfree(mapped_datav); | 3056 | kfree(mapped_datav); |
| 3045 | goto leave; | 3057 | goto leave; |
| 3046 | } | 3058 | } |
| 3047 | if ((BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH | | 3059 | if (dev_state->state->print_mask & |
| 3048 | BTRFSIC_PRINT_MASK_VERBOSE) == | 3060 | BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH_VERBOSE) |
| 3049 | (dev_state->state->print_mask & | ||
| 3050 | (BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH | | ||
| 3051 | BTRFSIC_PRINT_MASK_VERBOSE))) | ||
| 3052 | printk(KERN_INFO | 3061 | printk(KERN_INFO |
| 3053 | "#%u: page=%p, len=%u, offset=%u\n", | 3062 | "#%u: bytenr=%llu, len=%u, offset=%u\n", |
| 3054 | i, bio->bi_io_vec[i].bv_page, | 3063 | i, cur_bytenr, bio->bi_io_vec[i].bv_len, |
| 3055 | bio->bi_io_vec[i].bv_len, | ||
| 3056 | bio->bi_io_vec[i].bv_offset); | 3064 | bio->bi_io_vec[i].bv_offset); |
| 3065 | cur_bytenr += bio->bi_io_vec[i].bv_len; | ||
| 3057 | } | 3066 | } |
| 3058 | btrfsic_process_written_block(dev_state, dev_bytenr, | 3067 | btrfsic_process_written_block(dev_state, dev_bytenr, |
| 3059 | mapped_datav, bio->bi_vcnt, | 3068 | mapped_datav, bio->bi_vcnt, |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index f9aeb2759a64..54ab86127f7a 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -3613,9 +3613,6 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, | |||
| 3613 | struct btrfs_ordered_sum *sums); | 3613 | struct btrfs_ordered_sum *sums); |
| 3614 | int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, | 3614 | int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, |
| 3615 | struct bio *bio, u64 file_start, int contig); | 3615 | struct bio *bio, u64 file_start, int contig); |
| 3616 | int btrfs_csum_truncate(struct btrfs_trans_handle *trans, | ||
| 3617 | struct btrfs_root *root, struct btrfs_path *path, | ||
| 3618 | u64 isize); | ||
| 3619 | int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, | 3616 | int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, |
| 3620 | struct list_head *list, int search_commit); | 3617 | struct list_head *list, int search_commit); |
| 3621 | /* inode.c */ | 3618 | /* inode.c */ |
| @@ -3744,9 +3741,6 @@ void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info); | |||
| 3744 | int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync); | 3741 | int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync); |
| 3745 | void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, | 3742 | void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, |
| 3746 | int skip_pinned); | 3743 | int skip_pinned); |
| 3747 | int btrfs_replace_extent_cache(struct inode *inode, struct extent_map *replace, | ||
| 3748 | u64 start, u64 end, int skip_pinned, | ||
| 3749 | int modified); | ||
| 3750 | extern const struct file_operations btrfs_file_operations; | 3744 | extern const struct file_operations btrfs_file_operations; |
| 3751 | int __btrfs_drop_extents(struct btrfs_trans_handle *trans, | 3745 | int __btrfs_drop_extents(struct btrfs_trans_handle *trans, |
| 3752 | struct btrfs_root *root, struct inode *inode, | 3746 | struct btrfs_root *root, struct inode *inode, |
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 342f9fd411e3..2cfc3dfff64f 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c | |||
| @@ -366,7 +366,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root, | |||
| 366 | dev_replace->tgtdev = tgt_device; | 366 | dev_replace->tgtdev = tgt_device; |
| 367 | 367 | ||
| 368 | printk_in_rcu(KERN_INFO | 368 | printk_in_rcu(KERN_INFO |
| 369 | "btrfs: dev_replace from %s (devid %llu) to %s) started\n", | 369 | "btrfs: dev_replace from %s (devid %llu) to %s started\n", |
| 370 | src_device->missing ? "<missing disk>" : | 370 | src_device->missing ? "<missing disk>" : |
| 371 | rcu_str_deref(src_device->name), | 371 | rcu_str_deref(src_device->name), |
| 372 | src_device->devid, | 372 | src_device->devid, |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 4c4ed0bb3da1..8072cfa8a3b1 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -3517,7 +3517,6 @@ int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info) | |||
| 3517 | int btrfs_commit_super(struct btrfs_root *root) | 3517 | int btrfs_commit_super(struct btrfs_root *root) |
| 3518 | { | 3518 | { |
| 3519 | struct btrfs_trans_handle *trans; | 3519 | struct btrfs_trans_handle *trans; |
| 3520 | int ret; | ||
| 3521 | 3520 | ||
| 3522 | mutex_lock(&root->fs_info->cleaner_mutex); | 3521 | mutex_lock(&root->fs_info->cleaner_mutex); |
| 3523 | btrfs_run_delayed_iputs(root); | 3522 | btrfs_run_delayed_iputs(root); |
| @@ -3531,25 +3530,7 @@ int btrfs_commit_super(struct btrfs_root *root) | |||
| 3531 | trans = btrfs_join_transaction(root); | 3530 | trans = btrfs_join_transaction(root); |
| 3532 | if (IS_ERR(trans)) | 3531 | if (IS_ERR(trans)) |
| 3533 | return PTR_ERR(trans); | 3532 | return PTR_ERR(trans); |
| 3534 | ret = btrfs_commit_transaction(trans, root); | 3533 | return btrfs_commit_transaction(trans, root); |
| 3535 | if (ret) | ||
| 3536 | return ret; | ||
| 3537 | /* run commit again to drop the original snapshot */ | ||
| 3538 | trans = btrfs_join_transaction(root); | ||
| 3539 | if (IS_ERR(trans)) | ||
| 3540 | return PTR_ERR(trans); | ||
| 3541 | ret = btrfs_commit_transaction(trans, root); | ||
| 3542 | if (ret) | ||
| 3543 | return ret; | ||
| 3544 | ret = btrfs_write_and_wait_transaction(NULL, root); | ||
| 3545 | if (ret) { | ||
| 3546 | btrfs_error(root->fs_info, ret, | ||
| 3547 | "Failed to sync btree inode to disk."); | ||
| 3548 | return ret; | ||
| 3549 | } | ||
| 3550 | |||
| 3551 | ret = write_ctree_super(NULL, root, 0); | ||
| 3552 | return ret; | ||
| 3553 | } | 3534 | } |
| 3554 | 3535 | ||
| 3555 | int close_ctree(struct btrfs_root *root) | 3536 | int close_ctree(struct btrfs_root *root) |
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 856bc2b2192c..8e457fca0a0b 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
| @@ -1980,6 +1980,7 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start, | |||
| 1980 | struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; | 1980 | struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; |
| 1981 | int ret; | 1981 | int ret; |
| 1982 | 1982 | ||
| 1983 | ASSERT(!(fs_info->sb->s_flags & MS_RDONLY)); | ||
| 1983 | BUG_ON(!mirror_num); | 1984 | BUG_ON(!mirror_num); |
| 1984 | 1985 | ||
| 1985 | /* we can't repair anything in raid56 yet */ | 1986 | /* we can't repair anything in raid56 yet */ |
| @@ -2036,6 +2037,9 @@ int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb, | |||
| 2036 | unsigned long i, num_pages = num_extent_pages(eb->start, eb->len); | 2037 | unsigned long i, num_pages = num_extent_pages(eb->start, eb->len); |
| 2037 | int ret = 0; | 2038 | int ret = 0; |
| 2038 | 2039 | ||
| 2040 | if (root->fs_info->sb->s_flags & MS_RDONLY) | ||
| 2041 | return -EROFS; | ||
| 2042 | |||
| 2039 | for (i = 0; i < num_pages; i++) { | 2043 | for (i = 0; i < num_pages; i++) { |
| 2040 | struct page *p = extent_buffer_page(eb, i); | 2044 | struct page *p = extent_buffer_page(eb, i); |
| 2041 | ret = repair_io_failure(root->fs_info, start, PAGE_CACHE_SIZE, | 2045 | ret = repair_io_failure(root->fs_info, start, PAGE_CACHE_SIZE, |
| @@ -2057,12 +2061,12 @@ static int clean_io_failure(u64 start, struct page *page) | |||
| 2057 | u64 private; | 2061 | u64 private; |
| 2058 | u64 private_failure; | 2062 | u64 private_failure; |
| 2059 | struct io_failure_record *failrec; | 2063 | struct io_failure_record *failrec; |
| 2060 | struct btrfs_fs_info *fs_info; | 2064 | struct inode *inode = page->mapping->host; |
| 2065 | struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; | ||
| 2061 | struct extent_state *state; | 2066 | struct extent_state *state; |
| 2062 | int num_copies; | 2067 | int num_copies; |
| 2063 | int did_repair = 0; | 2068 | int did_repair = 0; |
| 2064 | int ret; | 2069 | int ret; |
| 2065 | struct inode *inode = page->mapping->host; | ||
| 2066 | 2070 | ||
| 2067 | private = 0; | 2071 | private = 0; |
| 2068 | ret = count_range_bits(&BTRFS_I(inode)->io_failure_tree, &private, | 2072 | ret = count_range_bits(&BTRFS_I(inode)->io_failure_tree, &private, |
| @@ -2085,6 +2089,8 @@ static int clean_io_failure(u64 start, struct page *page) | |||
| 2085 | did_repair = 1; | 2089 | did_repair = 1; |
| 2086 | goto out; | 2090 | goto out; |
| 2087 | } | 2091 | } |
| 2092 | if (fs_info->sb->s_flags & MS_RDONLY) | ||
| 2093 | goto out; | ||
| 2088 | 2094 | ||
| 2089 | spin_lock(&BTRFS_I(inode)->io_tree.lock); | 2095 | spin_lock(&BTRFS_I(inode)->io_tree.lock); |
| 2090 | state = find_first_extent_bit_state(&BTRFS_I(inode)->io_tree, | 2096 | state = find_first_extent_bit_state(&BTRFS_I(inode)->io_tree, |
| @@ -2094,7 +2100,6 @@ static int clean_io_failure(u64 start, struct page *page) | |||
| 2094 | 2100 | ||
| 2095 | if (state && state->start <= failrec->start && | 2101 | if (state && state->start <= failrec->start && |
| 2096 | state->end >= failrec->start + failrec->len - 1) { | 2102 | state->end >= failrec->start + failrec->len - 1) { |
| 2097 | fs_info = BTRFS_I(inode)->root->fs_info; | ||
| 2098 | num_copies = btrfs_num_copies(fs_info, failrec->logical, | 2103 | num_copies = btrfs_num_copies(fs_info, failrec->logical, |
| 2099 | failrec->len); | 2104 | failrec->len); |
| 2100 | if (num_copies > 1) { | 2105 | if (num_copies > 1) { |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index da8d2f696ac5..f1a77449d032 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
| @@ -2129,7 +2129,8 @@ static noinline bool record_extent_backrefs(struct btrfs_path *path, | |||
| 2129 | old->extent_offset, fs_info, | 2129 | old->extent_offset, fs_info, |
| 2130 | path, record_one_backref, | 2130 | path, record_one_backref, |
| 2131 | old); | 2131 | old); |
| 2132 | BUG_ON(ret < 0 && ret != -ENOENT); | 2132 | if (ret < 0 && ret != -ENOENT) |
| 2133 | return false; | ||
| 2133 | 2134 | ||
| 2134 | /* no backref to be processed for this extent */ | 2135 | /* no backref to be processed for this extent */ |
| 2135 | if (!old->count) { | 2136 | if (!old->count) { |
| @@ -6186,8 +6187,7 @@ insert: | |||
| 6186 | write_unlock(&em_tree->lock); | 6187 | write_unlock(&em_tree->lock); |
| 6187 | out: | 6188 | out: |
| 6188 | 6189 | ||
| 6189 | if (em) | 6190 | trace_btrfs_get_extent(root, em); |
| 6190 | trace_btrfs_get_extent(root, em); | ||
| 6191 | 6191 | ||
| 6192 | if (path) | 6192 | if (path) |
| 6193 | btrfs_free_path(path); | 6193 | btrfs_free_path(path); |
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index 25a8f3812f14..69582d5b69d1 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c | |||
| @@ -638,6 +638,7 @@ void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr) | |||
| 638 | WARN_ON(nr < 0); | 638 | WARN_ON(nr < 0); |
| 639 | } | 639 | } |
| 640 | } | 640 | } |
| 641 | list_splice_tail(&splice, &fs_info->ordered_roots); | ||
| 641 | spin_unlock(&fs_info->ordered_root_lock); | 642 | spin_unlock(&fs_info->ordered_root_lock); |
| 642 | } | 643 | } |
| 643 | 644 | ||
| @@ -803,7 +804,7 @@ int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len) | |||
| 803 | btrfs_put_ordered_extent(ordered); | 804 | btrfs_put_ordered_extent(ordered); |
| 804 | break; | 805 | break; |
| 805 | } | 806 | } |
| 806 | if (ordered->file_offset + ordered->len < start) { | 807 | if (ordered->file_offset + ordered->len <= start) { |
| 807 | btrfs_put_ordered_extent(ordered); | 808 | btrfs_put_ordered_extent(ordered); |
| 808 | break; | 809 | break; |
| 809 | } | 810 | } |
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 2544805544f0..561e2f16ba3e 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c | |||
| @@ -938,8 +938,10 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) | |||
| 938 | BTRFS_DEV_STAT_CORRUPTION_ERRS); | 938 | BTRFS_DEV_STAT_CORRUPTION_ERRS); |
| 939 | } | 939 | } |
| 940 | 940 | ||
| 941 | if (sctx->readonly && !sctx->is_dev_replace) | 941 | if (sctx->readonly) { |
| 942 | goto did_not_correct_error; | 942 | ASSERT(!sctx->is_dev_replace); |
| 943 | goto out; | ||
| 944 | } | ||
| 943 | 945 | ||
| 944 | if (!is_metadata && !have_csum) { | 946 | if (!is_metadata && !have_csum) { |
| 945 | struct scrub_fixup_nodatasum *fixup_nodatasum; | 947 | struct scrub_fixup_nodatasum *fixup_nodatasum; |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 57c16b46afbd..c6a872a8a468 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
| @@ -1480,7 +1480,7 @@ static void do_async_commit(struct work_struct *work) | |||
| 1480 | * We've got freeze protection passed with the transaction. | 1480 | * We've got freeze protection passed with the transaction. |
| 1481 | * Tell lockdep about it. | 1481 | * Tell lockdep about it. |
| 1482 | */ | 1482 | */ |
| 1483 | if (ac->newtrans->type < TRANS_JOIN_NOLOCK) | 1483 | if (ac->newtrans->type & __TRANS_FREEZABLE) |
| 1484 | rwsem_acquire_read( | 1484 | rwsem_acquire_read( |
| 1485 | &ac->root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1], | 1485 | &ac->root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1], |
| 1486 | 0, 1, _THIS_IP_); | 1486 | 0, 1, _THIS_IP_); |
| @@ -1521,7 +1521,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, | |||
| 1521 | * Tell lockdep we've released the freeze rwsem, since the | 1521 | * Tell lockdep we've released the freeze rwsem, since the |
| 1522 | * async commit thread will be the one to unlock it. | 1522 | * async commit thread will be the one to unlock it. |
| 1523 | */ | 1523 | */ |
| 1524 | if (trans->type < TRANS_JOIN_NOLOCK) | 1524 | if (ac->newtrans->type & __TRANS_FREEZABLE) |
| 1525 | rwsem_release( | 1525 | rwsem_release( |
| 1526 | &root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1], | 1526 | &root->fs_info->sb->s_writers.lock_map[SB_FREEZE_FS-1], |
| 1527 | 1, _THIS_IP_); | 1527 | 1, _THIS_IP_); |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 744553c83fe2..9f7fc51ca334 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
| @@ -3697,7 +3697,8 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, | |||
| 3697 | ret = btrfs_truncate_inode_items(trans, log, | 3697 | ret = btrfs_truncate_inode_items(trans, log, |
| 3698 | inode, 0, 0); | 3698 | inode, 0, 0); |
| 3699 | } else if (test_and_clear_bit(BTRFS_INODE_COPY_EVERYTHING, | 3699 | } else if (test_and_clear_bit(BTRFS_INODE_COPY_EVERYTHING, |
| 3700 | &BTRFS_I(inode)->runtime_flags)) { | 3700 | &BTRFS_I(inode)->runtime_flags) || |
| 3701 | inode_only == LOG_INODE_EXISTS) { | ||
| 3701 | if (inode_only == LOG_INODE_ALL) | 3702 | if (inode_only == LOG_INODE_ALL) |
| 3702 | fast_search = true; | 3703 | fast_search = true; |
| 3703 | max_key.type = BTRFS_XATTR_ITEM_KEY; | 3704 | max_key.type = BTRFS_XATTR_ITEM_KEY; |
| @@ -3801,7 +3802,7 @@ log_extents: | |||
| 3801 | err = ret; | 3802 | err = ret; |
| 3802 | goto out_unlock; | 3803 | goto out_unlock; |
| 3803 | } | 3804 | } |
| 3804 | } else { | 3805 | } else if (inode_only == LOG_INODE_ALL) { |
| 3805 | struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; | 3806 | struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; |
| 3806 | struct extent_map *em, *n; | 3807 | struct extent_map *em, *n; |
| 3807 | 3808 | ||
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 0db637097862..92303f42baaa 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
| @@ -5394,7 +5394,7 @@ static int bio_size_ok(struct block_device *bdev, struct bio *bio, | |||
| 5394 | { | 5394 | { |
| 5395 | struct bio_vec *prev; | 5395 | struct bio_vec *prev; |
| 5396 | struct request_queue *q = bdev_get_queue(bdev); | 5396 | struct request_queue *q = bdev_get_queue(bdev); |
| 5397 | unsigned short max_sectors = queue_max_sectors(q); | 5397 | unsigned int max_sectors = queue_max_sectors(q); |
| 5398 | struct bvec_merge_data bvm = { | 5398 | struct bvec_merge_data bvm = { |
| 5399 | .bi_bdev = bdev, | 5399 | .bi_bdev = bdev, |
| 5400 | .bi_sector = sector, | 5400 | .bi_sector = sector, |
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 277bd1be21fd..e081acbac2e7 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c | |||
| @@ -56,29 +56,28 @@ static void configfs_d_iput(struct dentry * dentry, | |||
| 56 | struct configfs_dirent *sd = dentry->d_fsdata; | 56 | struct configfs_dirent *sd = dentry->d_fsdata; |
| 57 | 57 | ||
| 58 | if (sd) { | 58 | if (sd) { |
| 59 | BUG_ON(sd->s_dentry != dentry); | ||
| 60 | /* Coordinate with configfs_readdir */ | 59 | /* Coordinate with configfs_readdir */ |
| 61 | spin_lock(&configfs_dirent_lock); | 60 | spin_lock(&configfs_dirent_lock); |
| 62 | sd->s_dentry = NULL; | 61 | /* Coordinate with configfs_attach_attr where will increase |
| 62 | * sd->s_count and update sd->s_dentry to new allocated one. | ||
| 63 | * Only set sd->dentry to null when this dentry is the only | ||
| 64 | * sd owner. | ||
| 65 | * If not do so, configfs_d_iput may run just after | ||
| 66 | * configfs_attach_attr and set sd->s_dentry to null | ||
| 67 | * even it's still in use. | ||
| 68 | */ | ||
| 69 | if (atomic_read(&sd->s_count) <= 2) | ||
| 70 | sd->s_dentry = NULL; | ||
| 71 | |||
| 63 | spin_unlock(&configfs_dirent_lock); | 72 | spin_unlock(&configfs_dirent_lock); |
| 64 | configfs_put(sd); | 73 | configfs_put(sd); |
| 65 | } | 74 | } |
| 66 | iput(inode); | 75 | iput(inode); |
| 67 | } | 76 | } |
| 68 | 77 | ||
| 69 | /* | ||
| 70 | * We _must_ delete our dentries on last dput, as the chain-to-parent | ||
| 71 | * behavior is required to clear the parents of default_groups. | ||
| 72 | */ | ||
| 73 | static int configfs_d_delete(const struct dentry *dentry) | ||
| 74 | { | ||
| 75 | return 1; | ||
| 76 | } | ||
| 77 | |||
| 78 | const struct dentry_operations configfs_dentry_ops = { | 78 | const struct dentry_operations configfs_dentry_ops = { |
| 79 | .d_iput = configfs_d_iput, | 79 | .d_iput = configfs_d_iput, |
| 80 | /* simple_delete_dentry() isn't exported */ | 80 | .d_delete = always_delete_dentry, |
| 81 | .d_delete = configfs_d_delete, | ||
| 82 | }; | 81 | }; |
| 83 | 82 | ||
| 84 | #ifdef CONFIG_LOCKDEP | 83 | #ifdef CONFIG_LOCKDEP |
| @@ -426,8 +425,11 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den | |||
| 426 | struct configfs_attribute * attr = sd->s_element; | 425 | struct configfs_attribute * attr = sd->s_element; |
| 427 | int error; | 426 | int error; |
| 428 | 427 | ||
| 428 | spin_lock(&configfs_dirent_lock); | ||
| 429 | dentry->d_fsdata = configfs_get(sd); | 429 | dentry->d_fsdata = configfs_get(sd); |
| 430 | sd->s_dentry = dentry; | 430 | sd->s_dentry = dentry; |
| 431 | spin_unlock(&configfs_dirent_lock); | ||
| 432 | |||
| 431 | error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, | 433 | error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, |
| 432 | configfs_init_file); | 434 | configfs_init_file); |
| 433 | if (error) { | 435 | if (error) { |
diff --git a/fs/coredump.c b/fs/coredump.c index 62406b6959b6..bc3fbcd32558 100644 --- a/fs/coredump.c +++ b/fs/coredump.c | |||
| @@ -695,7 +695,7 @@ int dump_emit(struct coredump_params *cprm, const void *addr, int nr) | |||
| 695 | while (nr) { | 695 | while (nr) { |
| 696 | if (dump_interrupted()) | 696 | if (dump_interrupted()) |
| 697 | return 0; | 697 | return 0; |
| 698 | n = vfs_write(file, addr, nr, &pos); | 698 | n = __kernel_write(file, addr, nr, &pos); |
| 699 | if (n <= 0) | 699 | if (n <= 0) |
| 700 | return 0; | 700 | return 0; |
| 701 | file->f_pos = pos; | 701 | file->f_pos = pos; |
| @@ -733,7 +733,7 @@ int dump_align(struct coredump_params *cprm, int align) | |||
| 733 | { | 733 | { |
| 734 | unsigned mod = cprm->written & (align - 1); | 734 | unsigned mod = cprm->written & (align - 1); |
| 735 | if (align & (align - 1)) | 735 | if (align & (align - 1)) |
| 736 | return -EINVAL; | 736 | return 0; |
| 737 | return mod ? dump_skip(cprm, align - mod) : 0; | 737 | return mod ? dump_skip(cprm, align - mod) : 1; |
| 738 | } | 738 | } |
| 739 | EXPORT_SYMBOL(dump_align); | 739 | EXPORT_SYMBOL(dump_align); |
diff --git a/fs/dcache.c b/fs/dcache.c index 0a38ef8d7f00..4bdb300b16e2 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -88,35 +88,6 @@ EXPORT_SYMBOL(rename_lock); | |||
| 88 | 88 | ||
| 89 | static struct kmem_cache *dentry_cache __read_mostly; | 89 | static struct kmem_cache *dentry_cache __read_mostly; |
| 90 | 90 | ||
| 91 | /** | ||
| 92 | * read_seqbegin_or_lock - begin a sequence number check or locking block | ||
| 93 | * @lock: sequence lock | ||
| 94 | * @seq : sequence number to be checked | ||
| 95 | * | ||
| 96 | * First try it once optimistically without taking the lock. If that fails, | ||
| 97 | * take the lock. The sequence number is also used as a marker for deciding | ||
| 98 | * whether to be a reader (even) or writer (odd). | ||
| 99 | * N.B. seq must be initialized to an even number to begin with. | ||
| 100 | */ | ||
| 101 | static inline void read_seqbegin_or_lock(seqlock_t *lock, int *seq) | ||
| 102 | { | ||
| 103 | if (!(*seq & 1)) /* Even */ | ||
| 104 | *seq = read_seqbegin(lock); | ||
| 105 | else /* Odd */ | ||
| 106 | read_seqlock_excl(lock); | ||
| 107 | } | ||
| 108 | |||
| 109 | static inline int need_seqretry(seqlock_t *lock, int seq) | ||
| 110 | { | ||
| 111 | return !(seq & 1) && read_seqretry(lock, seq); | ||
| 112 | } | ||
| 113 | |||
| 114 | static inline void done_seqretry(seqlock_t *lock, int seq) | ||
| 115 | { | ||
| 116 | if (seq & 1) | ||
| 117 | read_sequnlock_excl(lock); | ||
| 118 | } | ||
| 119 | |||
| 120 | /* | 91 | /* |
| 121 | * This is the single most critical data structure when it comes | 92 | * This is the single most critical data structure when it comes |
| 122 | * to the dcache: the hashtable for lookups. Somebody should try | 93 | * to the dcache: the hashtable for lookups. Somebody should try |
| @@ -125,8 +96,6 @@ static inline void done_seqretry(seqlock_t *lock, int seq) | |||
| 125 | * This hash-function tries to avoid losing too many bits of hash | 96 | * This hash-function tries to avoid losing too many bits of hash |
| 126 | * information, yet avoid using a prime hash-size or similar. | 97 | * information, yet avoid using a prime hash-size or similar. |
| 127 | */ | 98 | */ |
| 128 | #define D_HASHBITS d_hash_shift | ||
| 129 | #define D_HASHMASK d_hash_mask | ||
| 130 | 99 | ||
| 131 | static unsigned int d_hash_mask __read_mostly; | 100 | static unsigned int d_hash_mask __read_mostly; |
| 132 | static unsigned int d_hash_shift __read_mostly; | 101 | static unsigned int d_hash_shift __read_mostly; |
| @@ -137,8 +106,8 @@ static inline struct hlist_bl_head *d_hash(const struct dentry *parent, | |||
| 137 | unsigned int hash) | 106 | unsigned int hash) |
| 138 | { | 107 | { |
| 139 | hash += (unsigned long) parent / L1_CACHE_BYTES; | 108 | hash += (unsigned long) parent / L1_CACHE_BYTES; |
| 140 | hash = hash + (hash >> D_HASHBITS); | 109 | hash = hash + (hash >> d_hash_shift); |
| 141 | return dentry_hashtable + (hash & D_HASHMASK); | 110 | return dentry_hashtable + (hash & d_hash_mask); |
| 142 | } | 111 | } |
| 143 | 112 | ||
| 144 | /* Statistics gathering. */ | 113 | /* Statistics gathering. */ |
| @@ -469,7 +438,7 @@ static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) | |||
| 469 | { | 438 | { |
| 470 | list_del(&dentry->d_u.d_child); | 439 | list_del(&dentry->d_u.d_child); |
| 471 | /* | 440 | /* |
| 472 | * Inform try_to_ascend() that we are no longer attached to the | 441 | * Inform d_walk() that we are no longer attached to the |
| 473 | * dentry tree | 442 | * dentry tree |
| 474 | */ | 443 | */ |
| 475 | dentry->d_flags |= DCACHE_DENTRY_KILLED; | 444 | dentry->d_flags |= DCACHE_DENTRY_KILLED; |
| @@ -1069,34 +1038,6 @@ void shrink_dcache_sb(struct super_block *sb) | |||
| 1069 | } | 1038 | } |
| 1070 | EXPORT_SYMBOL(shrink_dcache_sb); | 1039 | EXPORT_SYMBOL(shrink_dcache_sb); |
| 1071 | 1040 | ||
| 1072 | /* | ||
| 1073 | * This tries to ascend one level of parenthood, but | ||
| 1074 | * we can race with renaming, so we need to re-check | ||
| 1075 | * the parenthood after dropping the lock and check | ||
| 1076 | * that the sequence number still matches. | ||
| 1077 | */ | ||
| 1078 | static struct dentry *try_to_ascend(struct dentry *old, unsigned seq) | ||
| 1079 | { | ||
| 1080 | struct dentry *new = old->d_parent; | ||
| 1081 | |||
| 1082 | rcu_read_lock(); | ||
| 1083 | spin_unlock(&old->d_lock); | ||
| 1084 | spin_lock(&new->d_lock); | ||
| 1085 | |||
| 1086 | /* | ||
| 1087 | * might go back up the wrong parent if we have had a rename | ||
| 1088 | * or deletion | ||
| 1089 | */ | ||
| 1090 | if (new != old->d_parent || | ||
| 1091 | (old->d_flags & DCACHE_DENTRY_KILLED) || | ||
| 1092 | need_seqretry(&rename_lock, seq)) { | ||
| 1093 | spin_unlock(&new->d_lock); | ||
| 1094 | new = NULL; | ||
| 1095 | } | ||
| 1096 | rcu_read_unlock(); | ||
| 1097 | return new; | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | /** | 1041 | /** |
| 1101 | * enum d_walk_ret - action to talke during tree walk | 1042 | * enum d_walk_ret - action to talke during tree walk |
| 1102 | * @D_WALK_CONTINUE: contrinue walk | 1043 | * @D_WALK_CONTINUE: contrinue walk |
| @@ -1185,9 +1126,24 @@ resume: | |||
| 1185 | */ | 1126 | */ |
| 1186 | if (this_parent != parent) { | 1127 | if (this_parent != parent) { |
| 1187 | struct dentry *child = this_parent; | 1128 | struct dentry *child = this_parent; |
| 1188 | this_parent = try_to_ascend(this_parent, seq); | 1129 | this_parent = child->d_parent; |
| 1189 | if (!this_parent) | 1130 | |
| 1131 | rcu_read_lock(); | ||
| 1132 | spin_unlock(&child->d_lock); | ||
| 1133 | spin_lock(&this_parent->d_lock); | ||
| 1134 | |||
| 1135 | /* | ||
| 1136 | * might go back up the wrong parent if we have had a rename | ||
| 1137 | * or deletion | ||
| 1138 | */ | ||
| 1139 | if (this_parent != child->d_parent || | ||
| 1140 | (child->d_flags & DCACHE_DENTRY_KILLED) || | ||
| 1141 | need_seqretry(&rename_lock, seq)) { | ||
| 1142 | spin_unlock(&this_parent->d_lock); | ||
| 1143 | rcu_read_unlock(); | ||
| 1190 | goto rename_retry; | 1144 | goto rename_retry; |
| 1145 | } | ||
| 1146 | rcu_read_unlock(); | ||
| 1191 | next = child->d_u.d_child.next; | 1147 | next = child->d_u.d_child.next; |
| 1192 | goto resume; | 1148 | goto resume; |
| 1193 | } | 1149 | } |
diff --git a/fs/dlm/netlink.c b/fs/dlm/netlink.c index 60a327863b11..e7cfbaf8d0e2 100644 --- a/fs/dlm/netlink.c +++ b/fs/dlm/netlink.c | |||
| @@ -74,14 +74,16 @@ static int user_cmd(struct sk_buff *skb, struct genl_info *info) | |||
| 74 | return 0; | 74 | return 0; |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | static struct genl_ops dlm_nl_ops = { | 77 | static struct genl_ops dlm_nl_ops[] = { |
| 78 | .cmd = DLM_CMD_HELLO, | 78 | { |
| 79 | .doit = user_cmd, | 79 | .cmd = DLM_CMD_HELLO, |
| 80 | .doit = user_cmd, | ||
| 81 | }, | ||
| 80 | }; | 82 | }; |
| 81 | 83 | ||
| 82 | int __init dlm_netlink_init(void) | 84 | int __init dlm_netlink_init(void) |
| 83 | { | 85 | { |
| 84 | return genl_register_family_with_ops(&family, &dlm_nl_ops, 1); | 86 | return genl_register_family_with_ops(&family, dlm_nl_ops); |
| 85 | } | 87 | } |
| 86 | 88 | ||
| 87 | void dlm_netlink_exit(void) | 89 | void dlm_netlink_exit(void) |
diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index a8766b880c07..becc725a1953 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c | |||
| @@ -83,19 +83,10 @@ static int efivarfs_d_hash(const struct dentry *dentry, struct qstr *qstr) | |||
| 83 | return 0; | 83 | return 0; |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | /* | ||
| 87 | * Retaining negative dentries for an in-memory filesystem just wastes | ||
| 88 | * memory and lookup time: arrange for them to be deleted immediately. | ||
| 89 | */ | ||
| 90 | static int efivarfs_delete_dentry(const struct dentry *dentry) | ||
| 91 | { | ||
| 92 | return 1; | ||
| 93 | } | ||
| 94 | |||
| 95 | static struct dentry_operations efivarfs_d_ops = { | 86 | static struct dentry_operations efivarfs_d_ops = { |
| 96 | .d_compare = efivarfs_d_compare, | 87 | .d_compare = efivarfs_d_compare, |
| 97 | .d_hash = efivarfs_d_hash, | 88 | .d_hash = efivarfs_d_hash, |
| 98 | .d_delete = efivarfs_delete_dentry, | 89 | .d_delete = always_delete_dentry, |
| 99 | }; | 90 | }; |
| 100 | 91 | ||
| 101 | static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name) | 92 | static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name) |
| @@ -1380,10 +1380,6 @@ int search_binary_handler(struct linux_binprm *bprm) | |||
| 1380 | if (retval) | 1380 | if (retval) |
| 1381 | return retval; | 1381 | return retval; |
| 1382 | 1382 | ||
| 1383 | retval = audit_bprm(bprm); | ||
| 1384 | if (retval) | ||
| 1385 | return retval; | ||
| 1386 | |||
| 1387 | retval = -ENOENT; | 1383 | retval = -ENOENT; |
| 1388 | retry: | 1384 | retry: |
| 1389 | read_lock(&binfmt_lock); | 1385 | read_lock(&binfmt_lock); |
| @@ -1431,6 +1427,7 @@ static int exec_binprm(struct linux_binprm *bprm) | |||
| 1431 | 1427 | ||
| 1432 | ret = search_binary_handler(bprm); | 1428 | ret = search_binary_handler(bprm); |
| 1433 | if (ret >= 0) { | 1429 | if (ret >= 0) { |
| 1430 | audit_bprm(bprm); | ||
| 1434 | trace_sched_process_exec(current, old_pid, bprm); | 1431 | trace_sched_process_exec(current, old_pid, bprm); |
| 1435 | ptrace_event(PTRACE_EVENT_EXEC, old_vpid); | 1432 | ptrace_event(PTRACE_EVENT_EXEC, old_vpid); |
| 1436 | current->did_exec = 1; | 1433 | current->did_exec = 1; |
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index e66a8009aff1..c8420f7e4db6 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c | |||
| @@ -1899,7 +1899,8 @@ static int gfs2_glock_iter_next(struct gfs2_glock_iter *gi) | |||
| 1899 | gi->nhash = 0; | 1899 | gi->nhash = 0; |
| 1900 | } | 1900 | } |
| 1901 | /* Skip entries for other sb and dead entries */ | 1901 | /* Skip entries for other sb and dead entries */ |
| 1902 | } while (gi->sdp != gi->gl->gl_sbd || __lockref_is_dead(&gl->gl_lockref)); | 1902 | } while (gi->sdp != gi->gl->gl_sbd || |
| 1903 | __lockref_is_dead(&gi->gl->gl_lockref)); | ||
| 1903 | 1904 | ||
| 1904 | return 0; | 1905 | return 0; |
| 1905 | } | 1906 | } |
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 1615df16cf4e..7119504159f1 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
| @@ -1171,8 +1171,11 @@ static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry, | |||
| 1171 | if (d != NULL) | 1171 | if (d != NULL) |
| 1172 | dentry = d; | 1172 | dentry = d; |
| 1173 | if (dentry->d_inode) { | 1173 | if (dentry->d_inode) { |
| 1174 | if (!(*opened & FILE_OPENED)) | 1174 | if (!(*opened & FILE_OPENED)) { |
| 1175 | if (d == NULL) | ||
| 1176 | dget(dentry); | ||
| 1175 | return finish_no_open(file, dentry); | 1177 | return finish_no_open(file, dentry); |
| 1178 | } | ||
| 1176 | dput(d); | 1179 | dput(d); |
| 1177 | return 0; | 1180 | return 0; |
| 1178 | } | 1181 | } |
diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c index c8423d6de6c3..2a6ba06bee6f 100644 --- a/fs/gfs2/lock_dlm.c +++ b/fs/gfs2/lock_dlm.c | |||
| @@ -466,19 +466,19 @@ static void gdlm_cancel(struct gfs2_glock *gl) | |||
| 466 | static void control_lvb_read(struct lm_lockstruct *ls, uint32_t *lvb_gen, | 466 | static void control_lvb_read(struct lm_lockstruct *ls, uint32_t *lvb_gen, |
| 467 | char *lvb_bits) | 467 | char *lvb_bits) |
| 468 | { | 468 | { |
| 469 | uint32_t gen; | 469 | __le32 gen; |
| 470 | memcpy(lvb_bits, ls->ls_control_lvb, GDLM_LVB_SIZE); | 470 | memcpy(lvb_bits, ls->ls_control_lvb, GDLM_LVB_SIZE); |
| 471 | memcpy(&gen, lvb_bits, sizeof(uint32_t)); | 471 | memcpy(&gen, lvb_bits, sizeof(__le32)); |
| 472 | *lvb_gen = le32_to_cpu(gen); | 472 | *lvb_gen = le32_to_cpu(gen); |
| 473 | } | 473 | } |
| 474 | 474 | ||
| 475 | static void control_lvb_write(struct lm_lockstruct *ls, uint32_t lvb_gen, | 475 | static void control_lvb_write(struct lm_lockstruct *ls, uint32_t lvb_gen, |
| 476 | char *lvb_bits) | 476 | char *lvb_bits) |
| 477 | { | 477 | { |
| 478 | uint32_t gen; | 478 | __le32 gen; |
| 479 | memcpy(ls->ls_control_lvb, lvb_bits, GDLM_LVB_SIZE); | 479 | memcpy(ls->ls_control_lvb, lvb_bits, GDLM_LVB_SIZE); |
| 480 | gen = cpu_to_le32(lvb_gen); | 480 | gen = cpu_to_le32(lvb_gen); |
| 481 | memcpy(ls->ls_control_lvb, &gen, sizeof(uint32_t)); | 481 | memcpy(ls->ls_control_lvb, &gen, sizeof(__le32)); |
| 482 | } | 482 | } |
| 483 | 483 | ||
| 484 | static int all_jid_bits_clear(char *lvb) | 484 | static int all_jid_bits_clear(char *lvb) |
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 453b50eaddec..98236d0df3ca 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c | |||
| @@ -667,7 +667,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, | |||
| 667 | struct buffer_head *bh; | 667 | struct buffer_head *bh; |
| 668 | struct page *page; | 668 | struct page *page; |
| 669 | void *kaddr, *ptr; | 669 | void *kaddr, *ptr; |
| 670 | struct gfs2_quota q, *qp; | 670 | struct gfs2_quota q; |
| 671 | int err, nbytes; | 671 | int err, nbytes; |
| 672 | u64 size; | 672 | u64 size; |
| 673 | 673 | ||
| @@ -683,28 +683,25 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, | |||
| 683 | return err; | 683 | return err; |
| 684 | 684 | ||
| 685 | err = -EIO; | 685 | err = -EIO; |
| 686 | qp = &q; | 686 | be64_add_cpu(&q.qu_value, change); |
| 687 | qp->qu_value = be64_to_cpu(qp->qu_value); | 687 | qd->qd_qb.qb_value = q.qu_value; |
| 688 | qp->qu_value += change; | ||
| 689 | qp->qu_value = cpu_to_be64(qp->qu_value); | ||
| 690 | qd->qd_qb.qb_value = qp->qu_value; | ||
| 691 | if (fdq) { | 688 | if (fdq) { |
| 692 | if (fdq->d_fieldmask & FS_DQ_BSOFT) { | 689 | if (fdq->d_fieldmask & FS_DQ_BSOFT) { |
| 693 | qp->qu_warn = cpu_to_be64(fdq->d_blk_softlimit >> sdp->sd_fsb2bb_shift); | 690 | q.qu_warn = cpu_to_be64(fdq->d_blk_softlimit >> sdp->sd_fsb2bb_shift); |
| 694 | qd->qd_qb.qb_warn = qp->qu_warn; | 691 | qd->qd_qb.qb_warn = q.qu_warn; |
| 695 | } | 692 | } |
| 696 | if (fdq->d_fieldmask & FS_DQ_BHARD) { | 693 | if (fdq->d_fieldmask & FS_DQ_BHARD) { |
| 697 | qp->qu_limit = cpu_to_be64(fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift); | 694 | q.qu_limit = cpu_to_be64(fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift); |
| 698 | qd->qd_qb.qb_limit = qp->qu_limit; | 695 | qd->qd_qb.qb_limit = q.qu_limit; |
| 699 | } | 696 | } |
| 700 | if (fdq->d_fieldmask & FS_DQ_BCOUNT) { | 697 | if (fdq->d_fieldmask & FS_DQ_BCOUNT) { |
| 701 | qp->qu_value = cpu_to_be64(fdq->d_bcount >> sdp->sd_fsb2bb_shift); | 698 | q.qu_value = cpu_to_be64(fdq->d_bcount >> sdp->sd_fsb2bb_shift); |
| 702 | qd->qd_qb.qb_value = qp->qu_value; | 699 | qd->qd_qb.qb_value = q.qu_value; |
| 703 | } | 700 | } |
| 704 | } | 701 | } |
| 705 | 702 | ||
| 706 | /* Write the quota into the quota file on disk */ | 703 | /* Write the quota into the quota file on disk */ |
| 707 | ptr = qp; | 704 | ptr = &q; |
| 708 | nbytes = sizeof(struct gfs2_quota); | 705 | nbytes = sizeof(struct gfs2_quota); |
| 709 | get_a_page: | 706 | get_a_page: |
| 710 | page = find_or_create_page(mapping, index, GFP_NOFS); | 707 | page = find_or_create_page(mapping, index, GFP_NOFS); |
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 4d83abdd5635..c8d6161bd682 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
| @@ -1127,7 +1127,7 @@ int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd) | |||
| 1127 | rgd->rd_flags |= (GFS2_RDF_UPTODATE | GFS2_RDF_CHECK); | 1127 | rgd->rd_flags |= (GFS2_RDF_UPTODATE | GFS2_RDF_CHECK); |
| 1128 | rgd->rd_free_clone = rgd->rd_free; | 1128 | rgd->rd_free_clone = rgd->rd_free; |
| 1129 | } | 1129 | } |
| 1130 | if (be32_to_cpu(GFS2_MAGIC) != rgd->rd_rgl->rl_magic) { | 1130 | if (cpu_to_be32(GFS2_MAGIC) != rgd->rd_rgl->rl_magic) { |
| 1131 | rgd->rd_rgl->rl_unlinked = cpu_to_be32(count_unlinked(rgd)); | 1131 | rgd->rd_rgl->rl_unlinked = cpu_to_be32(count_unlinked(rgd)); |
| 1132 | gfs2_rgrp_ondisk2lvb(rgd->rd_rgl, | 1132 | gfs2_rgrp_ondisk2lvb(rgd->rd_rgl, |
| 1133 | rgd->rd_bits[0].bi_bh->b_data); | 1133 | rgd->rd_bits[0].bi_bh->b_data); |
| @@ -1161,7 +1161,7 @@ int update_rgrp_lvb(struct gfs2_rgrpd *rgd) | |||
| 1161 | if (rgd->rd_flags & GFS2_RDF_UPTODATE) | 1161 | if (rgd->rd_flags & GFS2_RDF_UPTODATE) |
| 1162 | return 0; | 1162 | return 0; |
| 1163 | 1163 | ||
| 1164 | if (be32_to_cpu(GFS2_MAGIC) != rgd->rd_rgl->rl_magic) | 1164 | if (cpu_to_be32(GFS2_MAGIC) != rgd->rd_rgl->rl_magic) |
| 1165 | return gfs2_rgrp_bh_get(rgd); | 1165 | return gfs2_rgrp_bh_get(rgd); |
| 1166 | 1166 | ||
| 1167 | rl_flags = be32_to_cpu(rgd->rd_rgl->rl_flags); | 1167 | rl_flags = be32_to_cpu(rgd->rd_rgl->rl_flags); |
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 25437280a207..db23ce1bd903 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c | |||
| @@ -33,15 +33,6 @@ static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode) | |||
| 33 | 33 | ||
| 34 | #define FILE_HOSTFS_I(file) HOSTFS_I(file_inode(file)) | 34 | #define FILE_HOSTFS_I(file) HOSTFS_I(file_inode(file)) |
| 35 | 35 | ||
| 36 | static int hostfs_d_delete(const struct dentry *dentry) | ||
| 37 | { | ||
| 38 | return 1; | ||
| 39 | } | ||
| 40 | |||
| 41 | static const struct dentry_operations hostfs_dentry_ops = { | ||
| 42 | .d_delete = hostfs_d_delete, | ||
| 43 | }; | ||
| 44 | |||
| 45 | /* Changed in hostfs_args before the kernel starts running */ | 36 | /* Changed in hostfs_args before the kernel starts running */ |
| 46 | static char *root_ino = ""; | 37 | static char *root_ino = ""; |
| 47 | static int append = 0; | 38 | static int append = 0; |
| @@ -925,7 +916,7 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) | |||
| 925 | sb->s_blocksize_bits = 10; | 916 | sb->s_blocksize_bits = 10; |
| 926 | sb->s_magic = HOSTFS_SUPER_MAGIC; | 917 | sb->s_magic = HOSTFS_SUPER_MAGIC; |
| 927 | sb->s_op = &hostfs_sbops; | 918 | sb->s_op = &hostfs_sbops; |
| 928 | sb->s_d_op = &hostfs_dentry_ops; | 919 | sb->s_d_op = &simple_dentry_operations; |
| 929 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 920 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
| 930 | 921 | ||
| 931 | /* NULL is printed as <NULL> by sprintf: avoid that. */ | 922 | /* NULL is printed as <NULL> by sprintf: avoid that. */ |
diff --git a/fs/libfs.c b/fs/libfs.c index 5de06947ba5e..a1844244246f 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
| @@ -47,10 +47,16 @@ EXPORT_SYMBOL(simple_statfs); | |||
| 47 | * Retaining negative dentries for an in-memory filesystem just wastes | 47 | * Retaining negative dentries for an in-memory filesystem just wastes |
| 48 | * memory and lookup time: arrange for them to be deleted immediately. | 48 | * memory and lookup time: arrange for them to be deleted immediately. |
| 49 | */ | 49 | */ |
| 50 | static int simple_delete_dentry(const struct dentry *dentry) | 50 | int always_delete_dentry(const struct dentry *dentry) |
| 51 | { | 51 | { |
| 52 | return 1; | 52 | return 1; |
| 53 | } | 53 | } |
| 54 | EXPORT_SYMBOL(always_delete_dentry); | ||
| 55 | |||
| 56 | const struct dentry_operations simple_dentry_operations = { | ||
| 57 | .d_delete = always_delete_dentry, | ||
| 58 | }; | ||
| 59 | EXPORT_SYMBOL(simple_dentry_operations); | ||
| 54 | 60 | ||
| 55 | /* | 61 | /* |
| 56 | * Lookup the data. This is trivial - if the dentry didn't already | 62 | * Lookup the data. This is trivial - if the dentry didn't already |
| @@ -58,10 +64,6 @@ static int simple_delete_dentry(const struct dentry *dentry) | |||
| 58 | */ | 64 | */ |
| 59 | struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) | 65 | struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) |
| 60 | { | 66 | { |
| 61 | static const struct dentry_operations simple_dentry_operations = { | ||
| 62 | .d_delete = simple_delete_dentry, | ||
| 63 | }; | ||
| 64 | |||
| 65 | if (dentry->d_name.len > NAME_MAX) | 67 | if (dentry->d_name.len > NAME_MAX) |
| 66 | return ERR_PTR(-ENAMETOOLONG); | 68 | return ERR_PTR(-ENAMETOOLONG); |
| 67 | if (!dentry->d_sb->s_d_op) | 69 | if (!dentry->d_sb->s_d_op) |
diff --git a/fs/namei.c b/fs/namei.c index e029a4cbff7d..8f77a8cea289 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -2435,6 +2435,7 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) | |||
| 2435 | */ | 2435 | */ |
| 2436 | static inline int may_create(struct inode *dir, struct dentry *child) | 2436 | static inline int may_create(struct inode *dir, struct dentry *child) |
| 2437 | { | 2437 | { |
| 2438 | audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE); | ||
| 2438 | if (child->d_inode) | 2439 | if (child->d_inode) |
| 2439 | return -EEXIST; | 2440 | return -EEXIST; |
| 2440 | if (IS_DEADDIR(dir)) | 2441 | if (IS_DEADDIR(dir)) |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 1485e38daaa3..03c8d747be48 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -1151,10 +1151,16 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf, | |||
| 1151 | goto out_free_page; | 1151 | goto out_free_page; |
| 1152 | 1152 | ||
| 1153 | } | 1153 | } |
| 1154 | kloginuid = make_kuid(file->f_cred->user_ns, loginuid); | 1154 | |
| 1155 | if (!uid_valid(kloginuid)) { | 1155 | /* is userspace tring to explicitly UNSET the loginuid? */ |
| 1156 | length = -EINVAL; | 1156 | if (loginuid == AUDIT_UID_UNSET) { |
| 1157 | goto out_free_page; | 1157 | kloginuid = INVALID_UID; |
| 1158 | } else { | ||
| 1159 | kloginuid = make_kuid(file->f_cred->user_ns, loginuid); | ||
| 1160 | if (!uid_valid(kloginuid)) { | ||
| 1161 | length = -EINVAL; | ||
| 1162 | goto out_free_page; | ||
| 1163 | } | ||
| 1158 | } | 1164 | } |
| 1159 | 1165 | ||
| 1160 | length = audit_set_loginuid(kloginuid); | 1166 | length = audit_set_loginuid(kloginuid); |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 737e15615b04..cca93b6fb9a9 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
| @@ -175,22 +175,6 @@ static const struct inode_operations proc_link_inode_operations = { | |||
| 175 | }; | 175 | }; |
| 176 | 176 | ||
| 177 | /* | 177 | /* |
| 178 | * As some entries in /proc are volatile, we want to | ||
| 179 | * get rid of unused dentries. This could be made | ||
| 180 | * smarter: we could keep a "volatile" flag in the | ||
| 181 | * inode to indicate which ones to keep. | ||
| 182 | */ | ||
| 183 | static int proc_delete_dentry(const struct dentry * dentry) | ||
| 184 | { | ||
| 185 | return 1; | ||
| 186 | } | ||
| 187 | |||
| 188 | static const struct dentry_operations proc_dentry_operations = | ||
| 189 | { | ||
| 190 | .d_delete = proc_delete_dentry, | ||
| 191 | }; | ||
| 192 | |||
| 193 | /* | ||
| 194 | * Don't create negative dentries here, return -ENOENT by hand | 178 | * Don't create negative dentries here, return -ENOENT by hand |
| 195 | * instead. | 179 | * instead. |
| 196 | */ | 180 | */ |
| @@ -209,7 +193,7 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, | |||
| 209 | inode = proc_get_inode(dir->i_sb, de); | 193 | inode = proc_get_inode(dir->i_sb, de); |
| 210 | if (!inode) | 194 | if (!inode) |
| 211 | return ERR_PTR(-ENOMEM); | 195 | return ERR_PTR(-ENOMEM); |
| 212 | d_set_d_op(dentry, &proc_dentry_operations); | 196 | d_set_d_op(dentry, &simple_dentry_operations); |
| 213 | d_add(dentry, inode); | 197 | d_add(dentry, inode); |
| 214 | return NULL; | 198 | return NULL; |
| 215 | } | 199 | } |
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index 49a7fff2e83a..9ae46b87470d 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c | |||
| @@ -42,12 +42,6 @@ static const struct inode_operations ns_inode_operations = { | |||
| 42 | .setattr = proc_setattr, | 42 | .setattr = proc_setattr, |
| 43 | }; | 43 | }; |
| 44 | 44 | ||
| 45 | static int ns_delete_dentry(const struct dentry *dentry) | ||
| 46 | { | ||
| 47 | /* Don't cache namespace inodes when not in use */ | ||
| 48 | return 1; | ||
| 49 | } | ||
| 50 | |||
| 51 | static char *ns_dname(struct dentry *dentry, char *buffer, int buflen) | 45 | static char *ns_dname(struct dentry *dentry, char *buffer, int buflen) |
| 52 | { | 46 | { |
| 53 | struct inode *inode = dentry->d_inode; | 47 | struct inode *inode = dentry->d_inode; |
| @@ -59,7 +53,7 @@ static char *ns_dname(struct dentry *dentry, char *buffer, int buflen) | |||
| 59 | 53 | ||
| 60 | const struct dentry_operations ns_dentry_operations = | 54 | const struct dentry_operations ns_dentry_operations = |
| 61 | { | 55 | { |
| 62 | .d_delete = ns_delete_dentry, | 56 | .d_delete = always_delete_dentry, |
| 63 | .d_dname = ns_dname, | 57 | .d_dname = ns_dname, |
| 64 | }; | 58 | }; |
| 65 | 59 | ||
diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c index 16e8abb7709b..72d29177998e 100644 --- a/fs/quota/netlink.c +++ b/fs/quota/netlink.c | |||
| @@ -9,13 +9,25 @@ | |||
| 9 | #include <net/netlink.h> | 9 | #include <net/netlink.h> |
| 10 | #include <net/genetlink.h> | 10 | #include <net/genetlink.h> |
| 11 | 11 | ||
| 12 | static const struct genl_multicast_group quota_mcgrps[] = { | ||
| 13 | { .name = "events", }, | ||
| 14 | }; | ||
| 15 | |||
| 12 | /* Netlink family structure for quota */ | 16 | /* Netlink family structure for quota */ |
| 13 | static struct genl_family quota_genl_family = { | 17 | static struct genl_family quota_genl_family = { |
| 14 | .id = GENL_ID_GENERATE, | 18 | /* |
| 19 | * Needed due to multicast group ID abuse - old code assumed | ||
| 20 | * the family ID was also a valid multicast group ID (which | ||
| 21 | * isn't true) and userspace might thus rely on it. Assign a | ||
| 22 | * static ID for this group to make dealing with that easier. | ||
| 23 | */ | ||
| 24 | .id = GENL_ID_VFS_DQUOT, | ||
| 15 | .hdrsize = 0, | 25 | .hdrsize = 0, |
| 16 | .name = "VFS_DQUOT", | 26 | .name = "VFS_DQUOT", |
| 17 | .version = 1, | 27 | .version = 1, |
| 18 | .maxattr = QUOTA_NL_A_MAX, | 28 | .maxattr = QUOTA_NL_A_MAX, |
| 29 | .mcgrps = quota_mcgrps, | ||
| 30 | .n_mcgrps = ARRAY_SIZE(quota_mcgrps), | ||
| 19 | }; | 31 | }; |
| 20 | 32 | ||
| 21 | /** | 33 | /** |
| @@ -78,7 +90,7 @@ void quota_send_warning(struct kqid qid, dev_t dev, | |||
| 78 | goto attr_err_out; | 90 | goto attr_err_out; |
| 79 | genlmsg_end(skb, msg_head); | 91 | genlmsg_end(skb, msg_head); |
| 80 | 92 | ||
| 81 | genlmsg_multicast(skb, 0, quota_genl_family.id, GFP_NOFS); | 93 | genlmsg_multicast("a_genl_family, skb, 0, 0, GFP_NOFS); |
| 82 | return; | 94 | return; |
| 83 | attr_err_out: | 95 | attr_err_out: |
| 84 | printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); | 96 | printk(KERN_ERR "VFS: Not enough space to compose quota message!\n"); |
diff --git a/fs/seq_file.c b/fs/seq_file.c index 1cd2388ca5bd..1d641bb108d2 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c | |||
| @@ -136,6 +136,7 @@ static int traverse(struct seq_file *m, loff_t offset) | |||
| 136 | Eoverflow: | 136 | Eoverflow: |
| 137 | m->op->stop(m, p); | 137 | m->op->stop(m, p); |
| 138 | kfree(m->buf); | 138 | kfree(m->buf); |
| 139 | m->count = 0; | ||
| 139 | m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); | 140 | m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); |
| 140 | return !m->buf ? -ENOMEM : -EAGAIN; | 141 | return !m->buf ? -ENOMEM : -EAGAIN; |
| 141 | } | 142 | } |
| @@ -232,10 +233,10 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) | |||
| 232 | goto Fill; | 233 | goto Fill; |
| 233 | m->op->stop(m, p); | 234 | m->op->stop(m, p); |
| 234 | kfree(m->buf); | 235 | kfree(m->buf); |
| 236 | m->count = 0; | ||
| 235 | m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); | 237 | m->buf = kmalloc(m->size <<= 1, GFP_KERNEL); |
| 236 | if (!m->buf) | 238 | if (!m->buf) |
| 237 | goto Enomem; | 239 | goto Enomem; |
| 238 | m->count = 0; | ||
| 239 | m->version = 0; | 240 | m->version = 0; |
| 240 | pos = m->index; | 241 | pos = m->index; |
| 241 | p = m->op->start(m, &pos); | 242 | p = m->op->start(m, &pos); |
diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig index c70111ebefd4..b6fa8657dcbc 100644 --- a/fs/squashfs/Kconfig +++ b/fs/squashfs/Kconfig | |||
| @@ -25,6 +25,78 @@ config SQUASHFS | |||
| 25 | 25 | ||
| 26 | If unsure, say N. | 26 | If unsure, say N. |
| 27 | 27 | ||
| 28 | choice | ||
| 29 | prompt "File decompression options" | ||
| 30 | depends on SQUASHFS | ||
| 31 | help | ||
| 32 | Squashfs now supports two options for decompressing file | ||
| 33 | data. Traditionally Squashfs has decompressed into an | ||
| 34 | intermediate buffer and then memcopied it into the page cache. | ||
| 35 | Squashfs now supports the ability to decompress directly into | ||
| 36 | the page cache. | ||
| 37 | |||
| 38 | If unsure, select "Decompress file data into an intermediate buffer" | ||
| 39 | |||
| 40 | config SQUASHFS_FILE_CACHE | ||
| 41 | bool "Decompress file data into an intermediate buffer" | ||
| 42 | help | ||
| 43 | Decompress file data into an intermediate buffer and then | ||
| 44 | memcopy it into the page cache. | ||
| 45 | |||
| 46 | config SQUASHFS_FILE_DIRECT | ||
| 47 | bool "Decompress files directly into the page cache" | ||
| 48 | help | ||
| 49 | Directly decompress file data into the page cache. | ||
| 50 | Doing so can significantly improve performance because | ||
| 51 | it eliminates a memcpy and it also removes the lock contention | ||
| 52 | on the single buffer. | ||
| 53 | |||
| 54 | endchoice | ||
| 55 | |||
| 56 | choice | ||
| 57 | prompt "Decompressor parallelisation options" | ||
| 58 | depends on SQUASHFS | ||
| 59 | help | ||
| 60 | Squashfs now supports three parallelisation options for | ||
| 61 | decompression. Each one exhibits various trade-offs between | ||
| 62 | decompression performance and CPU and memory usage. | ||
| 63 | |||
| 64 | If in doubt, select "Single threaded compression" | ||
| 65 | |||
| 66 | config SQUASHFS_DECOMP_SINGLE | ||
| 67 | bool "Single threaded compression" | ||
| 68 | help | ||
| 69 | Traditionally Squashfs has used single-threaded decompression. | ||
| 70 | Only one block (data or metadata) can be decompressed at any | ||
| 71 | one time. This limits CPU and memory usage to a minimum. | ||
| 72 | |||
| 73 | config SQUASHFS_DECOMP_MULTI | ||
| 74 | bool "Use multiple decompressors for parallel I/O" | ||
| 75 | help | ||
| 76 | By default Squashfs uses a single decompressor but it gives | ||
| 77 | poor performance on parallel I/O workloads when using multiple CPU | ||
| 78 | machines due to waiting on decompressor availability. | ||
| 79 | |||
| 80 | If you have a parallel I/O workload and your system has enough memory, | ||
| 81 | using this option may improve overall I/O performance. | ||
| 82 | |||
| 83 | This decompressor implementation uses up to two parallel | ||
| 84 | decompressors per core. It dynamically allocates decompressors | ||
| 85 | on a demand basis. | ||
| 86 | |||
| 87 | config SQUASHFS_DECOMP_MULTI_PERCPU | ||
| 88 | bool "Use percpu multiple decompressors for parallel I/O" | ||
| 89 | help | ||
| 90 | By default Squashfs uses a single decompressor but it gives | ||
| 91 | poor performance on parallel I/O workloads when using multiple CPU | ||
| 92 | machines due to waiting on decompressor availability. | ||
| 93 | |||
| 94 | This decompressor implementation uses a maximum of one | ||
| 95 | decompressor per core. It uses percpu variables to ensure | ||
| 96 | decompression is load-balanced across the cores. | ||
| 97 | |||
| 98 | endchoice | ||
| 99 | |||
| 28 | config SQUASHFS_XATTR | 100 | config SQUASHFS_XATTR |
| 29 | bool "Squashfs XATTR support" | 101 | bool "Squashfs XATTR support" |
| 30 | depends on SQUASHFS | 102 | depends on SQUASHFS |
diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile index 110b0476f3b4..4132520b4ff2 100644 --- a/fs/squashfs/Makefile +++ b/fs/squashfs/Makefile | |||
| @@ -5,6 +5,11 @@ | |||
| 5 | obj-$(CONFIG_SQUASHFS) += squashfs.o | 5 | obj-$(CONFIG_SQUASHFS) += squashfs.o |
| 6 | squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o | 6 | squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o |
| 7 | squashfs-y += namei.o super.o symlink.o decompressor.o | 7 | squashfs-y += namei.o super.o symlink.o decompressor.o |
| 8 | squashfs-$(CONFIG_SQUASHFS_FILE_CACHE) += file_cache.o | ||
| 9 | squashfs-$(CONFIG_SQUASHFS_FILE_DIRECT) += file_direct.o page_actor.o | ||
| 10 | squashfs-$(CONFIG_SQUASHFS_DECOMP_SINGLE) += decompressor_single.o | ||
| 11 | squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI) += decompressor_multi.o | ||
| 12 | squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU) += decompressor_multi_percpu.o | ||
| 8 | squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o | 13 | squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o |
| 9 | squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o | 14 | squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o |
| 10 | squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o | 15 | squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o |
diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c index 41d108ecc9be..0cea9b9236d0 100644 --- a/fs/squashfs/block.c +++ b/fs/squashfs/block.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include "squashfs_fs_sb.h" | 36 | #include "squashfs_fs_sb.h" |
| 37 | #include "squashfs.h" | 37 | #include "squashfs.h" |
| 38 | #include "decompressor.h" | 38 | #include "decompressor.h" |
| 39 | #include "page_actor.h" | ||
| 39 | 40 | ||
| 40 | /* | 41 | /* |
| 41 | * Read the metadata block length, this is stored in the first two | 42 | * Read the metadata block length, this is stored in the first two |
| @@ -86,16 +87,16 @@ static struct buffer_head *get_block_length(struct super_block *sb, | |||
| 86 | * generated a larger block - this does occasionally happen with compression | 87 | * generated a larger block - this does occasionally happen with compression |
| 87 | * algorithms). | 88 | * algorithms). |
| 88 | */ | 89 | */ |
| 89 | int squashfs_read_data(struct super_block *sb, void **buffer, u64 index, | 90 | int squashfs_read_data(struct super_block *sb, u64 index, int length, |
| 90 | int length, u64 *next_index, int srclength, int pages) | 91 | u64 *next_index, struct squashfs_page_actor *output) |
| 91 | { | 92 | { |
| 92 | struct squashfs_sb_info *msblk = sb->s_fs_info; | 93 | struct squashfs_sb_info *msblk = sb->s_fs_info; |
| 93 | struct buffer_head **bh; | 94 | struct buffer_head **bh; |
| 94 | int offset = index & ((1 << msblk->devblksize_log2) - 1); | 95 | int offset = index & ((1 << msblk->devblksize_log2) - 1); |
| 95 | u64 cur_index = index >> msblk->devblksize_log2; | 96 | u64 cur_index = index >> msblk->devblksize_log2; |
| 96 | int bytes, compressed, b = 0, k = 0, page = 0, avail; | 97 | int bytes, compressed, b = 0, k = 0, avail, i; |
| 97 | 98 | ||
| 98 | bh = kcalloc(((srclength + msblk->devblksize - 1) | 99 | bh = kcalloc(((output->length + msblk->devblksize - 1) |
| 99 | >> msblk->devblksize_log2) + 1, sizeof(*bh), GFP_KERNEL); | 100 | >> msblk->devblksize_log2) + 1, sizeof(*bh), GFP_KERNEL); |
| 100 | if (bh == NULL) | 101 | if (bh == NULL) |
| 101 | return -ENOMEM; | 102 | return -ENOMEM; |
| @@ -111,9 +112,9 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index, | |||
| 111 | *next_index = index + length; | 112 | *next_index = index + length; |
| 112 | 113 | ||
| 113 | TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", | 114 | TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", |
| 114 | index, compressed ? "" : "un", length, srclength); | 115 | index, compressed ? "" : "un", length, output->length); |
| 115 | 116 | ||
| 116 | if (length < 0 || length > srclength || | 117 | if (length < 0 || length > output->length || |
| 117 | (index + length) > msblk->bytes_used) | 118 | (index + length) > msblk->bytes_used) |
| 118 | goto read_failure; | 119 | goto read_failure; |
| 119 | 120 | ||
| @@ -145,7 +146,7 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index, | |||
| 145 | TRACE("Block @ 0x%llx, %scompressed size %d\n", index, | 146 | TRACE("Block @ 0x%llx, %scompressed size %d\n", index, |
| 146 | compressed ? "" : "un", length); | 147 | compressed ? "" : "un", length); |
| 147 | 148 | ||
| 148 | if (length < 0 || length > srclength || | 149 | if (length < 0 || length > output->length || |
| 149 | (index + length) > msblk->bytes_used) | 150 | (index + length) > msblk->bytes_used) |
| 150 | goto block_release; | 151 | goto block_release; |
| 151 | 152 | ||
| @@ -158,9 +159,15 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index, | |||
| 158 | ll_rw_block(READ, b - 1, bh + 1); | 159 | ll_rw_block(READ, b - 1, bh + 1); |
| 159 | } | 160 | } |
| 160 | 161 | ||
| 162 | for (i = 0; i < b; i++) { | ||
| 163 | wait_on_buffer(bh[i]); | ||
| 164 | if (!buffer_uptodate(bh[i])) | ||
| 165 | goto block_release; | ||
| 166 | } | ||
| 167 | |||
| 161 | if (compressed) { | 168 | if (compressed) { |
| 162 | length = squashfs_decompress(msblk, buffer, bh, b, offset, | 169 | length = squashfs_decompress(msblk, bh, b, offset, length, |
| 163 | length, srclength, pages); | 170 | output); |
| 164 | if (length < 0) | 171 | if (length < 0) |
| 165 | goto read_failure; | 172 | goto read_failure; |
| 166 | } else { | 173 | } else { |
| @@ -168,22 +175,20 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index, | |||
| 168 | * Block is uncompressed. | 175 | * Block is uncompressed. |
| 169 | */ | 176 | */ |
| 170 | int in, pg_offset = 0; | 177 | int in, pg_offset = 0; |
| 178 | void *data = squashfs_first_page(output); | ||
| 171 | 179 | ||
| 172 | for (bytes = length; k < b; k++) { | 180 | for (bytes = length; k < b; k++) { |
| 173 | in = min(bytes, msblk->devblksize - offset); | 181 | in = min(bytes, msblk->devblksize - offset); |
| 174 | bytes -= in; | 182 | bytes -= in; |
| 175 | wait_on_buffer(bh[k]); | ||
| 176 | if (!buffer_uptodate(bh[k])) | ||
| 177 | goto block_release; | ||
| 178 | while (in) { | 183 | while (in) { |
| 179 | if (pg_offset == PAGE_CACHE_SIZE) { | 184 | if (pg_offset == PAGE_CACHE_SIZE) { |
| 180 | page++; | 185 | data = squashfs_next_page(output); |
| 181 | pg_offset = 0; | 186 | pg_offset = 0; |
| 182 | } | 187 | } |
| 183 | avail = min_t(int, in, PAGE_CACHE_SIZE - | 188 | avail = min_t(int, in, PAGE_CACHE_SIZE - |
| 184 | pg_offset); | 189 | pg_offset); |
| 185 | memcpy(buffer[page] + pg_offset, | 190 | memcpy(data + pg_offset, bh[k]->b_data + offset, |
| 186 | bh[k]->b_data + offset, avail); | 191 | avail); |
| 187 | in -= avail; | 192 | in -= avail; |
| 188 | pg_offset += avail; | 193 | pg_offset += avail; |
| 189 | offset += avail; | 194 | offset += avail; |
| @@ -191,6 +196,7 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index, | |||
| 191 | offset = 0; | 196 | offset = 0; |
| 192 | put_bh(bh[k]); | 197 | put_bh(bh[k]); |
| 193 | } | 198 | } |
| 199 | squashfs_finish_page(output); | ||
| 194 | } | 200 | } |
| 195 | 201 | ||
| 196 | kfree(bh); | 202 | kfree(bh); |
diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c index af0b73802592..1cb70a0b2168 100644 --- a/fs/squashfs/cache.c +++ b/fs/squashfs/cache.c | |||
| @@ -56,6 +56,7 @@ | |||
| 56 | #include "squashfs_fs.h" | 56 | #include "squashfs_fs.h" |
| 57 | #include "squashfs_fs_sb.h" | 57 | #include "squashfs_fs_sb.h" |
| 58 | #include "squashfs.h" | 58 | #include "squashfs.h" |
| 59 | #include "page_actor.h" | ||
| 59 | 60 | ||
| 60 | /* | 61 | /* |
| 61 | * Look-up block in cache, and increment usage count. If not in cache, read | 62 | * Look-up block in cache, and increment usage count. If not in cache, read |
| @@ -119,9 +120,8 @@ struct squashfs_cache_entry *squashfs_cache_get(struct super_block *sb, | |||
| 119 | entry->error = 0; | 120 | entry->error = 0; |
| 120 | spin_unlock(&cache->lock); | 121 | spin_unlock(&cache->lock); |
| 121 | 122 | ||
| 122 | entry->length = squashfs_read_data(sb, entry->data, | 123 | entry->length = squashfs_read_data(sb, block, length, |
| 123 | block, length, &entry->next_index, | 124 | &entry->next_index, entry->actor); |
| 124 | cache->block_size, cache->pages); | ||
| 125 | 125 | ||
| 126 | spin_lock(&cache->lock); | 126 | spin_lock(&cache->lock); |
| 127 | 127 | ||
| @@ -220,6 +220,7 @@ void squashfs_cache_delete(struct squashfs_cache *cache) | |||
| 220 | kfree(cache->entry[i].data[j]); | 220 | kfree(cache->entry[i].data[j]); |
| 221 | kfree(cache->entry[i].data); | 221 | kfree(cache->entry[i].data); |
| 222 | } | 222 | } |
| 223 | kfree(cache->entry[i].actor); | ||
| 223 | } | 224 | } |
| 224 | 225 | ||
| 225 | kfree(cache->entry); | 226 | kfree(cache->entry); |
| @@ -280,6 +281,13 @@ struct squashfs_cache *squashfs_cache_init(char *name, int entries, | |||
| 280 | goto cleanup; | 281 | goto cleanup; |
| 281 | } | 282 | } |
| 282 | } | 283 | } |
| 284 | |||
| 285 | entry->actor = squashfs_page_actor_init(entry->data, | ||
| 286 | cache->pages, 0); | ||
| 287 | if (entry->actor == NULL) { | ||
| 288 | ERROR("Failed to allocate %s cache entry\n", name); | ||
| 289 | goto cleanup; | ||
| 290 | } | ||
| 283 | } | 291 | } |
| 284 | 292 | ||
| 285 | return cache; | 293 | return cache; |
| @@ -410,6 +418,7 @@ void *squashfs_read_table(struct super_block *sb, u64 block, int length) | |||
| 410 | int pages = (length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 418 | int pages = (length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
| 411 | int i, res; | 419 | int i, res; |
| 412 | void *table, *buffer, **data; | 420 | void *table, *buffer, **data; |
| 421 | struct squashfs_page_actor *actor; | ||
| 413 | 422 | ||
| 414 | table = buffer = kmalloc(length, GFP_KERNEL); | 423 | table = buffer = kmalloc(length, GFP_KERNEL); |
| 415 | if (table == NULL) | 424 | if (table == NULL) |
| @@ -421,19 +430,28 @@ void *squashfs_read_table(struct super_block *sb, u64 block, int length) | |||
| 421 | goto failed; | 430 | goto failed; |
| 422 | } | 431 | } |
| 423 | 432 | ||
| 433 | actor = squashfs_page_actor_init(data, pages, length); | ||
| 434 | if (actor == NULL) { | ||
| 435 | res = -ENOMEM; | ||
| 436 | goto failed2; | ||
| 437 | } | ||
| 438 | |||
| 424 | for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE) | 439 | for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE) |
| 425 | data[i] = buffer; | 440 | data[i] = buffer; |
| 426 | 441 | ||
| 427 | res = squashfs_read_data(sb, data, block, length | | 442 | res = squashfs_read_data(sb, block, length | |
| 428 | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length, pages); | 443 | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, actor); |
| 429 | 444 | ||
| 430 | kfree(data); | 445 | kfree(data); |
| 446 | kfree(actor); | ||
| 431 | 447 | ||
| 432 | if (res < 0) | 448 | if (res < 0) |
| 433 | goto failed; | 449 | goto failed; |
| 434 | 450 | ||
| 435 | return table; | 451 | return table; |
| 436 | 452 | ||
| 453 | failed2: | ||
| 454 | kfree(data); | ||
| 437 | failed: | 455 | failed: |
| 438 | kfree(table); | 456 | kfree(table); |
| 439 | return ERR_PTR(res); | 457 | return ERR_PTR(res); |
diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c index 3f6271d86abc..ac22fe73b0ad 100644 --- a/fs/squashfs/decompressor.c +++ b/fs/squashfs/decompressor.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include "squashfs_fs_sb.h" | 30 | #include "squashfs_fs_sb.h" |
| 31 | #include "decompressor.h" | 31 | #include "decompressor.h" |
| 32 | #include "squashfs.h" | 32 | #include "squashfs.h" |
| 33 | #include "page_actor.h" | ||
| 33 | 34 | ||
| 34 | /* | 35 | /* |
| 35 | * This file (and decompressor.h) implements a decompressor framework for | 36 | * This file (and decompressor.h) implements a decompressor framework for |
| @@ -37,29 +38,29 @@ | |||
| 37 | */ | 38 | */ |
| 38 | 39 | ||
| 39 | static const struct squashfs_decompressor squashfs_lzma_unsupported_comp_ops = { | 40 | static const struct squashfs_decompressor squashfs_lzma_unsupported_comp_ops = { |
| 40 | NULL, NULL, NULL, LZMA_COMPRESSION, "lzma", 0 | 41 | NULL, NULL, NULL, NULL, LZMA_COMPRESSION, "lzma", 0 |
| 41 | }; | 42 | }; |
| 42 | 43 | ||
| 43 | #ifndef CONFIG_SQUASHFS_LZO | 44 | #ifndef CONFIG_SQUASHFS_LZO |
| 44 | static const struct squashfs_decompressor squashfs_lzo_comp_ops = { | 45 | static const struct squashfs_decompressor squashfs_lzo_comp_ops = { |
| 45 | NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0 | 46 | NULL, NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0 |
| 46 | }; | 47 | }; |
| 47 | #endif | 48 | #endif |
| 48 | 49 | ||
| 49 | #ifndef CONFIG_SQUASHFS_XZ | 50 | #ifndef CONFIG_SQUASHFS_XZ |
| 50 | static const struct squashfs_decompressor squashfs_xz_comp_ops = { | 51 | static const struct squashfs_decompressor squashfs_xz_comp_ops = { |
| 51 | NULL, NULL, NULL, XZ_COMPRESSION, "xz", 0 | 52 | NULL, NULL, NULL, NULL, XZ_COMPRESSION, "xz", 0 |
| 52 | }; | 53 | }; |
| 53 | #endif | 54 | #endif |
| 54 | 55 | ||
| 55 | #ifndef CONFIG_SQUASHFS_ZLIB | 56 | #ifndef CONFIG_SQUASHFS_ZLIB |
| 56 | static const struct squashfs_decompressor squashfs_zlib_comp_ops = { | 57 | static const struct squashfs_decompressor squashfs_zlib_comp_ops = { |
| 57 | NULL, NULL, NULL, ZLIB_COMPRESSION, "zlib", 0 | 58 | NULL, NULL, NULL, NULL, ZLIB_COMPRESSION, "zlib", 0 |
| 58 | }; | 59 | }; |
| 59 | #endif | 60 | #endif |
| 60 | 61 | ||
| 61 | static const struct squashfs_decompressor squashfs_unknown_comp_ops = { | 62 | static const struct squashfs_decompressor squashfs_unknown_comp_ops = { |
| 62 | NULL, NULL, NULL, 0, "unknown", 0 | 63 | NULL, NULL, NULL, NULL, 0, "unknown", 0 |
| 63 | }; | 64 | }; |
| 64 | 65 | ||
| 65 | static const struct squashfs_decompressor *decompressor[] = { | 66 | static const struct squashfs_decompressor *decompressor[] = { |
| @@ -83,10 +84,11 @@ const struct squashfs_decompressor *squashfs_lookup_decompressor(int id) | |||
| 83 | } | 84 | } |
| 84 | 85 | ||
| 85 | 86 | ||
| 86 | void *squashfs_decompressor_init(struct super_block *sb, unsigned short flags) | 87 | static void *get_comp_opts(struct super_block *sb, unsigned short flags) |
| 87 | { | 88 | { |
| 88 | struct squashfs_sb_info *msblk = sb->s_fs_info; | 89 | struct squashfs_sb_info *msblk = sb->s_fs_info; |
| 89 | void *strm, *buffer = NULL; | 90 | void *buffer = NULL, *comp_opts; |
| 91 | struct squashfs_page_actor *actor = NULL; | ||
| 90 | int length = 0; | 92 | int length = 0; |
| 91 | 93 | ||
| 92 | /* | 94 | /* |
| @@ -94,23 +96,46 @@ void *squashfs_decompressor_init(struct super_block *sb, unsigned short flags) | |||
| 94 | */ | 96 | */ |
| 95 | if (SQUASHFS_COMP_OPTS(flags)) { | 97 | if (SQUASHFS_COMP_OPTS(flags)) { |
| 96 | buffer = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); | 98 | buffer = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); |
| 97 | if (buffer == NULL) | 99 | if (buffer == NULL) { |
| 98 | return ERR_PTR(-ENOMEM); | 100 | comp_opts = ERR_PTR(-ENOMEM); |
| 101 | goto out; | ||
| 102 | } | ||
| 103 | |||
| 104 | actor = squashfs_page_actor_init(&buffer, 1, 0); | ||
| 105 | if (actor == NULL) { | ||
| 106 | comp_opts = ERR_PTR(-ENOMEM); | ||
| 107 | goto out; | ||
| 108 | } | ||
| 99 | 109 | ||
| 100 | length = squashfs_read_data(sb, &buffer, | 110 | length = squashfs_read_data(sb, |
| 101 | sizeof(struct squashfs_super_block), 0, NULL, | 111 | sizeof(struct squashfs_super_block), 0, NULL, actor); |
| 102 | PAGE_CACHE_SIZE, 1); | ||
| 103 | 112 | ||
| 104 | if (length < 0) { | 113 | if (length < 0) { |
| 105 | strm = ERR_PTR(length); | 114 | comp_opts = ERR_PTR(length); |
| 106 | goto finished; | 115 | goto out; |
| 107 | } | 116 | } |
| 108 | } | 117 | } |
| 109 | 118 | ||
| 110 | strm = msblk->decompressor->init(msblk, buffer, length); | 119 | comp_opts = squashfs_comp_opts(msblk, buffer, length); |
| 111 | 120 | ||
| 112 | finished: | 121 | out: |
| 122 | kfree(actor); | ||
| 113 | kfree(buffer); | 123 | kfree(buffer); |
| 124 | return comp_opts; | ||
| 125 | } | ||
| 126 | |||
| 127 | |||
| 128 | void *squashfs_decompressor_setup(struct super_block *sb, unsigned short flags) | ||
| 129 | { | ||
| 130 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
| 131 | void *stream, *comp_opts = get_comp_opts(sb, flags); | ||
| 132 | |||
| 133 | if (IS_ERR(comp_opts)) | ||
| 134 | return comp_opts; | ||
| 135 | |||
| 136 | stream = squashfs_decompressor_create(msblk, comp_opts); | ||
| 137 | if (IS_ERR(stream)) | ||
| 138 | kfree(comp_opts); | ||
| 114 | 139 | ||
| 115 | return strm; | 140 | return stream; |
| 116 | } | 141 | } |
diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h index 330073e29029..af0985321808 100644 --- a/fs/squashfs/decompressor.h +++ b/fs/squashfs/decompressor.h | |||
| @@ -24,28 +24,22 @@ | |||
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | struct squashfs_decompressor { | 26 | struct squashfs_decompressor { |
| 27 | void *(*init)(struct squashfs_sb_info *, void *, int); | 27 | void *(*init)(struct squashfs_sb_info *, void *); |
| 28 | void *(*comp_opts)(struct squashfs_sb_info *, void *, int); | ||
| 28 | void (*free)(void *); | 29 | void (*free)(void *); |
| 29 | int (*decompress)(struct squashfs_sb_info *, void **, | 30 | int (*decompress)(struct squashfs_sb_info *, void *, |
| 30 | struct buffer_head **, int, int, int, int, int); | 31 | struct buffer_head **, int, int, int, |
| 32 | struct squashfs_page_actor *); | ||
| 31 | int id; | 33 | int id; |
| 32 | char *name; | 34 | char *name; |
| 33 | int supported; | 35 | int supported; |
| 34 | }; | 36 | }; |
| 35 | 37 | ||
| 36 | static inline void squashfs_decompressor_free(struct squashfs_sb_info *msblk, | 38 | static inline void *squashfs_comp_opts(struct squashfs_sb_info *msblk, |
| 37 | void *s) | 39 | void *buff, int length) |
| 38 | { | 40 | { |
| 39 | if (msblk->decompressor) | 41 | return msblk->decompressor->comp_opts ? |
| 40 | msblk->decompressor->free(s); | 42 | msblk->decompressor->comp_opts(msblk, buff, length) : NULL; |
| 41 | } | ||
| 42 | |||
| 43 | static inline int squashfs_decompress(struct squashfs_sb_info *msblk, | ||
| 44 | void **buffer, struct buffer_head **bh, int b, int offset, int length, | ||
| 45 | int srclength, int pages) | ||
| 46 | { | ||
| 47 | return msblk->decompressor->decompress(msblk, buffer, bh, b, offset, | ||
| 48 | length, srclength, pages); | ||
| 49 | } | 43 | } |
| 50 | 44 | ||
| 51 | #ifdef CONFIG_SQUASHFS_XZ | 45 | #ifdef CONFIG_SQUASHFS_XZ |
diff --git a/fs/squashfs/decompressor_multi.c b/fs/squashfs/decompressor_multi.c new file mode 100644 index 000000000000..d6008a636479 --- /dev/null +++ b/fs/squashfs/decompressor_multi.c | |||
| @@ -0,0 +1,198 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2013 | ||
| 3 | * Minchan Kim <minchan@kernel.org> | ||
| 4 | * | ||
| 5 | * This work is licensed under the terms of the GNU GPL, version 2. See | ||
| 6 | * the COPYING file in the top-level directory. | ||
| 7 | */ | ||
| 8 | #include <linux/types.h> | ||
| 9 | #include <linux/mutex.h> | ||
| 10 | #include <linux/slab.h> | ||
| 11 | #include <linux/buffer_head.h> | ||
| 12 | #include <linux/sched.h> | ||
| 13 | #include <linux/wait.h> | ||
| 14 | #include <linux/cpumask.h> | ||
| 15 | |||
| 16 | #include "squashfs_fs.h" | ||
| 17 | #include "squashfs_fs_sb.h" | ||
| 18 | #include "decompressor.h" | ||
| 19 | #include "squashfs.h" | ||
| 20 | |||
| 21 | /* | ||
| 22 | * This file implements multi-threaded decompression in the | ||
| 23 | * decompressor framework | ||
| 24 | */ | ||
| 25 | |||
| 26 | |||
| 27 | /* | ||
| 28 | * The reason that multiply two is that a CPU can request new I/O | ||
| 29 | * while it is waiting previous request. | ||
| 30 | */ | ||
| 31 | #define MAX_DECOMPRESSOR (num_online_cpus() * 2) | ||
| 32 | |||
| 33 | |||
| 34 | int squashfs_max_decompressors(void) | ||
| 35 | { | ||
| 36 | return MAX_DECOMPRESSOR; | ||
| 37 | } | ||
| 38 | |||
| 39 | |||
| 40 | struct squashfs_stream { | ||
| 41 | void *comp_opts; | ||
| 42 | struct list_head strm_list; | ||
| 43 | struct mutex mutex; | ||
| 44 | int avail_decomp; | ||
| 45 | wait_queue_head_t wait; | ||
| 46 | }; | ||
| 47 | |||
| 48 | |||
| 49 | struct decomp_stream { | ||
| 50 | void *stream; | ||
| 51 | struct list_head list; | ||
| 52 | }; | ||
| 53 | |||
| 54 | |||
| 55 | static void put_decomp_stream(struct decomp_stream *decomp_strm, | ||
| 56 | struct squashfs_stream *stream) | ||
| 57 | { | ||
| 58 | mutex_lock(&stream->mutex); | ||
| 59 | list_add(&decomp_strm->list, &stream->strm_list); | ||
| 60 | mutex_unlock(&stream->mutex); | ||
| 61 | wake_up(&stream->wait); | ||
| 62 | } | ||
| 63 | |||
| 64 | void *squashfs_decompressor_create(struct squashfs_sb_info *msblk, | ||
| 65 | void *comp_opts) | ||
| 66 | { | ||
| 67 | struct squashfs_stream *stream; | ||
| 68 | struct decomp_stream *decomp_strm = NULL; | ||
| 69 | int err = -ENOMEM; | ||
| 70 | |||
| 71 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | ||
| 72 | if (!stream) | ||
| 73 | goto out; | ||
| 74 | |||
| 75 | stream->comp_opts = comp_opts; | ||
| 76 | mutex_init(&stream->mutex); | ||
| 77 | INIT_LIST_HEAD(&stream->strm_list); | ||
| 78 | init_waitqueue_head(&stream->wait); | ||
| 79 | |||
| 80 | /* | ||
| 81 | * We should have a decompressor at least as default | ||
| 82 | * so if we fail to allocate new decompressor dynamically, | ||
| 83 | * we could always fall back to default decompressor and | ||
| 84 | * file system works. | ||
| 85 | */ | ||
| 86 | decomp_strm = kmalloc(sizeof(*decomp_strm), GFP_KERNEL); | ||
| 87 | if (!decomp_strm) | ||
| 88 | goto out; | ||
| 89 | |||
| 90 | decomp_strm->stream = msblk->decompressor->init(msblk, | ||
| 91 | stream->comp_opts); | ||
| 92 | if (IS_ERR(decomp_strm->stream)) { | ||
| 93 | err = PTR_ERR(decomp_strm->stream); | ||
| 94 | goto out; | ||
| 95 | } | ||
| 96 | |||
| 97 | list_add(&decomp_strm->list, &stream->strm_list); | ||
| 98 | stream->avail_decomp = 1; | ||
| 99 | return stream; | ||
| 100 | |||
| 101 | out: | ||
| 102 | kfree(decomp_strm); | ||
| 103 | kfree(stream); | ||
| 104 | return ERR_PTR(err); | ||
| 105 | } | ||
| 106 | |||
| 107 | |||
| 108 | void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk) | ||
| 109 | { | ||
| 110 | struct squashfs_stream *stream = msblk->stream; | ||
| 111 | if (stream) { | ||
| 112 | struct decomp_stream *decomp_strm; | ||
| 113 | |||
| 114 | while (!list_empty(&stream->strm_list)) { | ||
| 115 | decomp_strm = list_entry(stream->strm_list.prev, | ||
| 116 | struct decomp_stream, list); | ||
| 117 | list_del(&decomp_strm->list); | ||
| 118 | msblk->decompressor->free(decomp_strm->stream); | ||
| 119 | kfree(decomp_strm); | ||
| 120 | stream->avail_decomp--; | ||
| 121 | } | ||
| 122 | WARN_ON(stream->avail_decomp); | ||
| 123 | kfree(stream->comp_opts); | ||
| 124 | kfree(stream); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | |||
| 129 | static struct decomp_stream *get_decomp_stream(struct squashfs_sb_info *msblk, | ||
| 130 | struct squashfs_stream *stream) | ||
| 131 | { | ||
| 132 | struct decomp_stream *decomp_strm; | ||
| 133 | |||
| 134 | while (1) { | ||
| 135 | mutex_lock(&stream->mutex); | ||
| 136 | |||
| 137 | /* There is available decomp_stream */ | ||
| 138 | if (!list_empty(&stream->strm_list)) { | ||
| 139 | decomp_strm = list_entry(stream->strm_list.prev, | ||
| 140 | struct decomp_stream, list); | ||
| 141 | list_del(&decomp_strm->list); | ||
| 142 | mutex_unlock(&stream->mutex); | ||
| 143 | break; | ||
| 144 | } | ||
| 145 | |||
| 146 | /* | ||
| 147 | * If there is no available decomp and already full, | ||
| 148 | * let's wait for releasing decomp from other users. | ||
| 149 | */ | ||
| 150 | if (stream->avail_decomp >= MAX_DECOMPRESSOR) | ||
| 151 | goto wait; | ||
| 152 | |||
| 153 | /* Let's allocate new decomp */ | ||
| 154 | decomp_strm = kmalloc(sizeof(*decomp_strm), GFP_KERNEL); | ||
| 155 | if (!decomp_strm) | ||
| 156 | goto wait; | ||
| 157 | |||
| 158 | decomp_strm->stream = msblk->decompressor->init(msblk, | ||
| 159 | stream->comp_opts); | ||
| 160 | if (IS_ERR(decomp_strm->stream)) { | ||
| 161 | kfree(decomp_strm); | ||
| 162 | goto wait; | ||
| 163 | } | ||
| 164 | |||
| 165 | stream->avail_decomp++; | ||
| 166 | WARN_ON(stream->avail_decomp > MAX_DECOMPRESSOR); | ||
| 167 | |||
| 168 | mutex_unlock(&stream->mutex); | ||
| 169 | break; | ||
| 170 | wait: | ||
| 171 | /* | ||
| 172 | * If system memory is tough, let's for other's | ||
| 173 | * releasing instead of hurting VM because it could | ||
| 174 | * make page cache thrashing. | ||
| 175 | */ | ||
| 176 | mutex_unlock(&stream->mutex); | ||
| 177 | wait_event(stream->wait, | ||
| 178 | !list_empty(&stream->strm_list)); | ||
| 179 | } | ||
| 180 | |||
| 181 | return decomp_strm; | ||
| 182 | } | ||
| 183 | |||
| 184 | |||
| 185 | int squashfs_decompress(struct squashfs_sb_info *msblk, struct buffer_head **bh, | ||
| 186 | int b, int offset, int length, struct squashfs_page_actor *output) | ||
| 187 | { | ||
| 188 | int res; | ||
| 189 | struct squashfs_stream *stream = msblk->stream; | ||
| 190 | struct decomp_stream *decomp_stream = get_decomp_stream(msblk, stream); | ||
| 191 | res = msblk->decompressor->decompress(msblk, decomp_stream->stream, | ||
| 192 | bh, b, offset, length, output); | ||
| 193 | put_decomp_stream(decomp_stream, stream); | ||
| 194 | if (res < 0) | ||
| 195 | ERROR("%s decompression failed, data probably corrupt\n", | ||
| 196 | msblk->decompressor->name); | ||
| 197 | return res; | ||
| 198 | } | ||
diff --git a/fs/squashfs/decompressor_multi_percpu.c b/fs/squashfs/decompressor_multi_percpu.c new file mode 100644 index 000000000000..23a9c28ad8ea --- /dev/null +++ b/fs/squashfs/decompressor_multi_percpu.c | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2013 | ||
| 3 | * Phillip Lougher <phillip@squashfs.org.uk> | ||
| 4 | * | ||
| 5 | * This work is licensed under the terms of the GNU GPL, version 2. See | ||
| 6 | * the COPYING file in the top-level directory. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/types.h> | ||
| 10 | #include <linux/slab.h> | ||
| 11 | #include <linux/percpu.h> | ||
| 12 | #include <linux/buffer_head.h> | ||
| 13 | |||
| 14 | #include "squashfs_fs.h" | ||
| 15 | #include "squashfs_fs_sb.h" | ||
| 16 | #include "decompressor.h" | ||
| 17 | #include "squashfs.h" | ||
| 18 | |||
| 19 | /* | ||
| 20 | * This file implements multi-threaded decompression using percpu | ||
| 21 | * variables, one thread per cpu core. | ||
| 22 | */ | ||
| 23 | |||
| 24 | struct squashfs_stream { | ||
| 25 | void *stream; | ||
| 26 | }; | ||
| 27 | |||
| 28 | void *squashfs_decompressor_create(struct squashfs_sb_info *msblk, | ||
| 29 | void *comp_opts) | ||
| 30 | { | ||
| 31 | struct squashfs_stream *stream; | ||
| 32 | struct squashfs_stream __percpu *percpu; | ||
| 33 | int err, cpu; | ||
| 34 | |||
| 35 | percpu = alloc_percpu(struct squashfs_stream); | ||
| 36 | if (percpu == NULL) | ||
| 37 | return ERR_PTR(-ENOMEM); | ||
| 38 | |||
| 39 | for_each_possible_cpu(cpu) { | ||
| 40 | stream = per_cpu_ptr(percpu, cpu); | ||
| 41 | stream->stream = msblk->decompressor->init(msblk, comp_opts); | ||
| 42 | if (IS_ERR(stream->stream)) { | ||
| 43 | err = PTR_ERR(stream->stream); | ||
| 44 | goto out; | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | kfree(comp_opts); | ||
| 49 | return (__force void *) percpu; | ||
| 50 | |||
| 51 | out: | ||
| 52 | for_each_possible_cpu(cpu) { | ||
| 53 | stream = per_cpu_ptr(percpu, cpu); | ||
| 54 | if (!IS_ERR_OR_NULL(stream->stream)) | ||
| 55 | msblk->decompressor->free(stream->stream); | ||
| 56 | } | ||
| 57 | free_percpu(percpu); | ||
| 58 | return ERR_PTR(err); | ||
| 59 | } | ||
| 60 | |||
| 61 | void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk) | ||
| 62 | { | ||
| 63 | struct squashfs_stream __percpu *percpu = | ||
| 64 | (struct squashfs_stream __percpu *) msblk->stream; | ||
| 65 | struct squashfs_stream *stream; | ||
| 66 | int cpu; | ||
| 67 | |||
| 68 | if (msblk->stream) { | ||
| 69 | for_each_possible_cpu(cpu) { | ||
| 70 | stream = per_cpu_ptr(percpu, cpu); | ||
| 71 | msblk->decompressor->free(stream->stream); | ||
| 72 | } | ||
| 73 | free_percpu(percpu); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | int squashfs_decompress(struct squashfs_sb_info *msblk, struct buffer_head **bh, | ||
| 78 | int b, int offset, int length, struct squashfs_page_actor *output) | ||
| 79 | { | ||
| 80 | struct squashfs_stream __percpu *percpu = | ||
| 81 | (struct squashfs_stream __percpu *) msblk->stream; | ||
| 82 | struct squashfs_stream *stream = get_cpu_ptr(percpu); | ||
| 83 | int res = msblk->decompressor->decompress(msblk, stream->stream, bh, b, | ||
| 84 | offset, length, output); | ||
| 85 | put_cpu_ptr(stream); | ||
| 86 | |||
| 87 | if (res < 0) | ||
| 88 | ERROR("%s decompression failed, data probably corrupt\n", | ||
| 89 | msblk->decompressor->name); | ||
| 90 | |||
| 91 | return res; | ||
| 92 | } | ||
| 93 | |||
| 94 | int squashfs_max_decompressors(void) | ||
| 95 | { | ||
| 96 | return num_possible_cpus(); | ||
| 97 | } | ||
diff --git a/fs/squashfs/decompressor_single.c b/fs/squashfs/decompressor_single.c new file mode 100644 index 000000000000..a6c75929a00e --- /dev/null +++ b/fs/squashfs/decompressor_single.c | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2013 | ||
| 3 | * Phillip Lougher <phillip@squashfs.org.uk> | ||
| 4 | * | ||
| 5 | * This work is licensed under the terms of the GNU GPL, version 2. See | ||
| 6 | * the COPYING file in the top-level directory. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/types.h> | ||
| 10 | #include <linux/mutex.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | #include <linux/buffer_head.h> | ||
| 13 | |||
| 14 | #include "squashfs_fs.h" | ||
| 15 | #include "squashfs_fs_sb.h" | ||
| 16 | #include "decompressor.h" | ||
| 17 | #include "squashfs.h" | ||
| 18 | |||
| 19 | /* | ||
| 20 | * This file implements single-threaded decompression in the | ||
| 21 | * decompressor framework | ||
| 22 | */ | ||
| 23 | |||
| 24 | struct squashfs_stream { | ||
| 25 | void *stream; | ||
| 26 | struct mutex mutex; | ||
| 27 | }; | ||
| 28 | |||
| 29 | void *squashfs_decompressor_create(struct squashfs_sb_info *msblk, | ||
| 30 | void *comp_opts) | ||
| 31 | { | ||
| 32 | struct squashfs_stream *stream; | ||
| 33 | int err = -ENOMEM; | ||
| 34 | |||
| 35 | stream = kmalloc(sizeof(*stream), GFP_KERNEL); | ||
| 36 | if (stream == NULL) | ||
| 37 | goto out; | ||
| 38 | |||
| 39 | stream->stream = msblk->decompressor->init(msblk, comp_opts); | ||
| 40 | if (IS_ERR(stream->stream)) { | ||
| 41 | err = PTR_ERR(stream->stream); | ||
| 42 | goto out; | ||
| 43 | } | ||
| 44 | |||
| 45 | kfree(comp_opts); | ||
| 46 | mutex_init(&stream->mutex); | ||
| 47 | return stream; | ||
| 48 | |||
| 49 | out: | ||
| 50 | kfree(stream); | ||
| 51 | return ERR_PTR(err); | ||
| 52 | } | ||
| 53 | |||
| 54 | void squashfs_decompressor_destroy(struct squashfs_sb_info *msblk) | ||
| 55 | { | ||
| 56 | struct squashfs_stream *stream = msblk->stream; | ||
| 57 | |||
| 58 | if (stream) { | ||
| 59 | msblk->decompressor->free(stream->stream); | ||
| 60 | kfree(stream); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | int squashfs_decompress(struct squashfs_sb_info *msblk, struct buffer_head **bh, | ||
| 65 | int b, int offset, int length, struct squashfs_page_actor *output) | ||
| 66 | { | ||
| 67 | int res; | ||
| 68 | struct squashfs_stream *stream = msblk->stream; | ||
| 69 | |||
| 70 | mutex_lock(&stream->mutex); | ||
| 71 | res = msblk->decompressor->decompress(msblk, stream->stream, bh, b, | ||
| 72 | offset, length, output); | ||
| 73 | mutex_unlock(&stream->mutex); | ||
| 74 | |||
| 75 | if (res < 0) | ||
| 76 | ERROR("%s decompression failed, data probably corrupt\n", | ||
| 77 | msblk->decompressor->name); | ||
| 78 | |||
| 79 | return res; | ||
| 80 | } | ||
| 81 | |||
| 82 | int squashfs_max_decompressors(void) | ||
| 83 | { | ||
| 84 | return 1; | ||
| 85 | } | ||
diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c index 8ca62c28fe12..e5c9689062ba 100644 --- a/fs/squashfs/file.c +++ b/fs/squashfs/file.c | |||
| @@ -370,77 +370,15 @@ static int read_blocklist(struct inode *inode, int index, u64 *block) | |||
| 370 | return le32_to_cpu(size); | 370 | return le32_to_cpu(size); |
| 371 | } | 371 | } |
| 372 | 372 | ||
| 373 | 373 | /* Copy data into page cache */ | |
| 374 | static int squashfs_readpage(struct file *file, struct page *page) | 374 | void squashfs_copy_cache(struct page *page, struct squashfs_cache_entry *buffer, |
| 375 | int bytes, int offset) | ||
| 375 | { | 376 | { |
| 376 | struct inode *inode = page->mapping->host; | 377 | struct inode *inode = page->mapping->host; |
| 377 | struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; | 378 | struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; |
| 378 | int bytes, i, offset = 0, sparse = 0; | ||
| 379 | struct squashfs_cache_entry *buffer = NULL; | ||
| 380 | void *pageaddr; | 379 | void *pageaddr; |
| 381 | 380 | int i, mask = (1 << (msblk->block_log - PAGE_CACHE_SHIFT)) - 1; | |
| 382 | int mask = (1 << (msblk->block_log - PAGE_CACHE_SHIFT)) - 1; | 381 | int start_index = page->index & ~mask, end_index = start_index | mask; |
| 383 | int index = page->index >> (msblk->block_log - PAGE_CACHE_SHIFT); | ||
| 384 | int start_index = page->index & ~mask; | ||
| 385 | int end_index = start_index | mask; | ||
| 386 | int file_end = i_size_read(inode) >> msblk->block_log; | ||
| 387 | |||
| 388 | TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", | ||
| 389 | page->index, squashfs_i(inode)->start); | ||
| 390 | |||
| 391 | if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> | ||
| 392 | PAGE_CACHE_SHIFT)) | ||
| 393 | goto out; | ||
| 394 | |||
| 395 | if (index < file_end || squashfs_i(inode)->fragment_block == | ||
| 396 | SQUASHFS_INVALID_BLK) { | ||
| 397 | /* | ||
| 398 | * Reading a datablock from disk. Need to read block list | ||
| 399 | * to get location and block size. | ||
| 400 | */ | ||
| 401 | u64 block = 0; | ||
| 402 | int bsize = read_blocklist(inode, index, &block); | ||
| 403 | if (bsize < 0) | ||
| 404 | goto error_out; | ||
| 405 | |||
| 406 | if (bsize == 0) { /* hole */ | ||
| 407 | bytes = index == file_end ? | ||
| 408 | (i_size_read(inode) & (msblk->block_size - 1)) : | ||
| 409 | msblk->block_size; | ||
| 410 | sparse = 1; | ||
| 411 | } else { | ||
| 412 | /* | ||
| 413 | * Read and decompress datablock. | ||
| 414 | */ | ||
| 415 | buffer = squashfs_get_datablock(inode->i_sb, | ||
| 416 | block, bsize); | ||
| 417 | if (buffer->error) { | ||
| 418 | ERROR("Unable to read page, block %llx, size %x" | ||
| 419 | "\n", block, bsize); | ||
| 420 | squashfs_cache_put(buffer); | ||
| 421 | goto error_out; | ||
| 422 | } | ||
| 423 | bytes = buffer->length; | ||
| 424 | } | ||
| 425 | } else { | ||
| 426 | /* | ||
| 427 | * Datablock is stored inside a fragment (tail-end packed | ||
| 428 | * block). | ||
| 429 | */ | ||
| 430 | buffer = squashfs_get_fragment(inode->i_sb, | ||
| 431 | squashfs_i(inode)->fragment_block, | ||
| 432 | squashfs_i(inode)->fragment_size); | ||
| 433 | |||
| 434 | if (buffer->error) { | ||
| 435 | ERROR("Unable to read page, block %llx, size %x\n", | ||
| 436 | squashfs_i(inode)->fragment_block, | ||
| 437 | squashfs_i(inode)->fragment_size); | ||
| 438 | squashfs_cache_put(buffer); | ||
| 439 | goto error_out; | ||
| 440 | } | ||
| 441 | bytes = i_size_read(inode) & (msblk->block_size - 1); | ||
| 442 | offset = squashfs_i(inode)->fragment_offset; | ||
| 443 | } | ||
| 444 | 382 | ||
| 445 | /* | 383 | /* |
| 446 | * Loop copying datablock into pages. As the datablock likely covers | 384 | * Loop copying datablock into pages. As the datablock likely covers |
| @@ -451,7 +389,7 @@ static int squashfs_readpage(struct file *file, struct page *page) | |||
| 451 | for (i = start_index; i <= end_index && bytes > 0; i++, | 389 | for (i = start_index; i <= end_index && bytes > 0; i++, |
| 452 | bytes -= PAGE_CACHE_SIZE, offset += PAGE_CACHE_SIZE) { | 390 | bytes -= PAGE_CACHE_SIZE, offset += PAGE_CACHE_SIZE) { |
| 453 | struct page *push_page; | 391 | struct page *push_page; |
| 454 | int avail = sparse ? 0 : min_t(int, bytes, PAGE_CACHE_SIZE); | 392 | int avail = buffer ? min_t(int, bytes, PAGE_CACHE_SIZE) : 0; |
| 455 | 393 | ||
| 456 | TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail); | 394 | TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail); |
| 457 | 395 | ||
| @@ -475,11 +413,75 @@ skip_page: | |||
| 475 | if (i != page->index) | 413 | if (i != page->index) |
| 476 | page_cache_release(push_page); | 414 | page_cache_release(push_page); |
| 477 | } | 415 | } |
| 416 | } | ||
| 417 | |||
| 418 | /* Read datablock stored packed inside a fragment (tail-end packed block) */ | ||
| 419 | static int squashfs_readpage_fragment(struct page *page) | ||
| 420 | { | ||
| 421 | struct inode *inode = page->mapping->host; | ||
| 422 | struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; | ||
| 423 | struct squashfs_cache_entry *buffer = squashfs_get_fragment(inode->i_sb, | ||
| 424 | squashfs_i(inode)->fragment_block, | ||
| 425 | squashfs_i(inode)->fragment_size); | ||
| 426 | int res = buffer->error; | ||
| 427 | |||
| 428 | if (res) | ||
| 429 | ERROR("Unable to read page, block %llx, size %x\n", | ||
| 430 | squashfs_i(inode)->fragment_block, | ||
| 431 | squashfs_i(inode)->fragment_size); | ||
| 432 | else | ||
| 433 | squashfs_copy_cache(page, buffer, i_size_read(inode) & | ||
| 434 | (msblk->block_size - 1), | ||
| 435 | squashfs_i(inode)->fragment_offset); | ||
| 436 | |||
| 437 | squashfs_cache_put(buffer); | ||
| 438 | return res; | ||
| 439 | } | ||
| 478 | 440 | ||
| 479 | if (!sparse) | 441 | static int squashfs_readpage_sparse(struct page *page, int index, int file_end) |
| 480 | squashfs_cache_put(buffer); | 442 | { |
| 443 | struct inode *inode = page->mapping->host; | ||
| 444 | struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; | ||
| 445 | int bytes = index == file_end ? | ||
| 446 | (i_size_read(inode) & (msblk->block_size - 1)) : | ||
| 447 | msblk->block_size; | ||
| 481 | 448 | ||
| 449 | squashfs_copy_cache(page, NULL, bytes, 0); | ||
| 482 | return 0; | 450 | return 0; |
| 451 | } | ||
| 452 | |||
| 453 | static int squashfs_readpage(struct file *file, struct page *page) | ||
| 454 | { | ||
| 455 | struct inode *inode = page->mapping->host; | ||
| 456 | struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; | ||
| 457 | int index = page->index >> (msblk->block_log - PAGE_CACHE_SHIFT); | ||
| 458 | int file_end = i_size_read(inode) >> msblk->block_log; | ||
| 459 | int res; | ||
| 460 | void *pageaddr; | ||
| 461 | |||
| 462 | TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", | ||
| 463 | page->index, squashfs_i(inode)->start); | ||
| 464 | |||
| 465 | if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> | ||
| 466 | PAGE_CACHE_SHIFT)) | ||
| 467 | goto out; | ||
| 468 | |||
| 469 | if (index < file_end || squashfs_i(inode)->fragment_block == | ||
| 470 | SQUASHFS_INVALID_BLK) { | ||
| 471 | u64 block = 0; | ||
| 472 | int bsize = read_blocklist(inode, index, &block); | ||
| 473 | if (bsize < 0) | ||
| 474 | goto error_out; | ||
| 475 | |||
| 476 | if (bsize == 0) | ||
| 477 | res = squashfs_readpage_sparse(page, index, file_end); | ||
| 478 | else | ||
| 479 | res = squashfs_readpage_block(page, block, bsize); | ||
| 480 | } else | ||
| 481 | res = squashfs_readpage_fragment(page); | ||
| 482 | |||
| 483 | if (!res) | ||
| 484 | return 0; | ||
| 483 | 485 | ||
| 484 | error_out: | 486 | error_out: |
| 485 | SetPageError(page); | 487 | SetPageError(page); |
diff --git a/fs/squashfs/file_cache.c b/fs/squashfs/file_cache.c new file mode 100644 index 000000000000..f2310d2a2019 --- /dev/null +++ b/fs/squashfs/file_cache.c | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2013 | ||
| 3 | * Phillip Lougher <phillip@squashfs.org.uk> | ||
| 4 | * | ||
| 5 | * This work is licensed under the terms of the GNU GPL, version 2. See | ||
| 6 | * the COPYING file in the top-level directory. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/fs.h> | ||
| 10 | #include <linux/vfs.h> | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/string.h> | ||
| 14 | #include <linux/pagemap.h> | ||
| 15 | #include <linux/mutex.h> | ||
| 16 | |||
| 17 | #include "squashfs_fs.h" | ||
| 18 | #include "squashfs_fs_sb.h" | ||
| 19 | #include "squashfs_fs_i.h" | ||
| 20 | #include "squashfs.h" | ||
| 21 | |||
| 22 | /* Read separately compressed datablock and memcopy into page cache */ | ||
| 23 | int squashfs_readpage_block(struct page *page, u64 block, int bsize) | ||
| 24 | { | ||
| 25 | struct inode *i = page->mapping->host; | ||
| 26 | struct squashfs_cache_entry *buffer = squashfs_get_datablock(i->i_sb, | ||
| 27 | block, bsize); | ||
| 28 | int res = buffer->error; | ||
| 29 | |||
| 30 | if (res) | ||
| 31 | ERROR("Unable to read page, block %llx, size %x\n", block, | ||
| 32 | bsize); | ||
| 33 | else | ||
| 34 | squashfs_copy_cache(page, buffer, buffer->length, 0); | ||
| 35 | |||
| 36 | squashfs_cache_put(buffer); | ||
| 37 | return res; | ||
| 38 | } | ||
diff --git a/fs/squashfs/file_direct.c b/fs/squashfs/file_direct.c new file mode 100644 index 000000000000..2943b2bfae48 --- /dev/null +++ b/fs/squashfs/file_direct.c | |||
| @@ -0,0 +1,173 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2013 | ||
| 3 | * Phillip Lougher <phillip@squashfs.org.uk> | ||
| 4 | * | ||
| 5 | * This work is licensed under the terms of the GNU GPL, version 2. See | ||
| 6 | * the COPYING file in the top-level directory. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/fs.h> | ||
| 10 | #include <linux/vfs.h> | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/string.h> | ||
| 14 | #include <linux/pagemap.h> | ||
| 15 | #include <linux/mutex.h> | ||
| 16 | |||
| 17 | #include "squashfs_fs.h" | ||
| 18 | #include "squashfs_fs_sb.h" | ||
| 19 | #include "squashfs_fs_i.h" | ||
| 20 | #include "squashfs.h" | ||
| 21 | #include "page_actor.h" | ||
| 22 | |||
| 23 | static int squashfs_read_cache(struct page *target_page, u64 block, int bsize, | ||
| 24 | int pages, struct page **page); | ||
| 25 | |||
| 26 | /* Read separately compressed datablock directly into page cache */ | ||
| 27 | int squashfs_readpage_block(struct page *target_page, u64 block, int bsize) | ||
| 28 | |||
| 29 | { | ||
| 30 | struct inode *inode = target_page->mapping->host; | ||
| 31 | struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; | ||
| 32 | |||
| 33 | int file_end = (i_size_read(inode) - 1) >> PAGE_CACHE_SHIFT; | ||
| 34 | int mask = (1 << (msblk->block_log - PAGE_CACHE_SHIFT)) - 1; | ||
| 35 | int start_index = target_page->index & ~mask; | ||
| 36 | int end_index = start_index | mask; | ||
| 37 | int i, n, pages, missing_pages, bytes, res = -ENOMEM; | ||
| 38 | struct page **page; | ||
| 39 | struct squashfs_page_actor *actor; | ||
| 40 | void *pageaddr; | ||
| 41 | |||
| 42 | if (end_index > file_end) | ||
| 43 | end_index = file_end; | ||
| 44 | |||
| 45 | pages = end_index - start_index + 1; | ||
| 46 | |||
| 47 | page = kmalloc(sizeof(void *) * pages, GFP_KERNEL); | ||
| 48 | if (page == NULL) | ||
| 49 | return res; | ||
| 50 | |||
| 51 | /* | ||
| 52 | * Create a "page actor" which will kmap and kunmap the | ||
| 53 | * page cache pages appropriately within the decompressor | ||
| 54 | */ | ||
| 55 | actor = squashfs_page_actor_init_special(page, pages, 0); | ||
| 56 | if (actor == NULL) | ||
| 57 | goto out; | ||
| 58 | |||
| 59 | /* Try to grab all the pages covered by the Squashfs block */ | ||
| 60 | for (missing_pages = 0, i = 0, n = start_index; i < pages; i++, n++) { | ||
| 61 | page[i] = (n == target_page->index) ? target_page : | ||
| 62 | grab_cache_page_nowait(target_page->mapping, n); | ||
| 63 | |||
| 64 | if (page[i] == NULL) { | ||
| 65 | missing_pages++; | ||
| 66 | continue; | ||
| 67 | } | ||
| 68 | |||
| 69 | if (PageUptodate(page[i])) { | ||
| 70 | unlock_page(page[i]); | ||
| 71 | page_cache_release(page[i]); | ||
| 72 | page[i] = NULL; | ||
| 73 | missing_pages++; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | if (missing_pages) { | ||
| 78 | /* | ||
| 79 | * Couldn't get one or more pages, this page has either | ||
| 80 | * been VM reclaimed, but others are still in the page cache | ||
| 81 | * and uptodate, or we're racing with another thread in | ||
| 82 | * squashfs_readpage also trying to grab them. Fall back to | ||
| 83 | * using an intermediate buffer. | ||
| 84 | */ | ||
| 85 | res = squashfs_read_cache(target_page, block, bsize, pages, | ||
| 86 | page); | ||
| 87 | goto out; | ||
| 88 | } | ||
| 89 | |||
| 90 | /* Decompress directly into the page cache buffers */ | ||
| 91 | res = squashfs_read_data(inode->i_sb, block, bsize, NULL, actor); | ||
| 92 | if (res < 0) | ||
| 93 | goto mark_errored; | ||
| 94 | |||
| 95 | /* Last page may have trailing bytes not filled */ | ||
| 96 | bytes = res % PAGE_CACHE_SIZE; | ||
| 97 | if (bytes) { | ||
| 98 | pageaddr = kmap_atomic(page[pages - 1]); | ||
| 99 | memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); | ||
| 100 | kunmap_atomic(pageaddr); | ||
| 101 | } | ||
| 102 | |||
| 103 | /* Mark pages as uptodate, unlock and release */ | ||
| 104 | for (i = 0; i < pages; i++) { | ||
| 105 | flush_dcache_page(page[i]); | ||
| 106 | SetPageUptodate(page[i]); | ||
| 107 | unlock_page(page[i]); | ||
| 108 | if (page[i] != target_page) | ||
| 109 | page_cache_release(page[i]); | ||
| 110 | } | ||
| 111 | |||
| 112 | kfree(actor); | ||
| 113 | kfree(page); | ||
| 114 | |||
| 115 | return 0; | ||
| 116 | |||
| 117 | mark_errored: | ||
| 118 | /* Decompression failed, mark pages as errored. Target_page is | ||
| 119 | * dealt with by the caller | ||
| 120 | */ | ||
| 121 | for (i = 0; i < pages; i++) { | ||
| 122 | if (page[i] == target_page) | ||
| 123 | continue; | ||
| 124 | flush_dcache_page(page[i]); | ||
| 125 | SetPageError(page[i]); | ||
| 126 | unlock_page(page[i]); | ||
| 127 | page_cache_release(page[i]); | ||
| 128 | } | ||
| 129 | |||
| 130 | out: | ||
| 131 | kfree(actor); | ||
| 132 | kfree(page); | ||
| 133 | return res; | ||
| 134 | } | ||
| 135 | |||
| 136 | |||
| 137 | static int squashfs_read_cache(struct page *target_page, u64 block, int bsize, | ||
| 138 | int pages, struct page **page) | ||
| 139 | { | ||
| 140 | struct inode *i = target_page->mapping->host; | ||
| 141 | struct squashfs_cache_entry *buffer = squashfs_get_datablock(i->i_sb, | ||
| 142 | block, bsize); | ||
| 143 | int bytes = buffer->length, res = buffer->error, n, offset = 0; | ||
| 144 | void *pageaddr; | ||
| 145 | |||
| 146 | if (res) { | ||
| 147 | ERROR("Unable to read page, block %llx, size %x\n", block, | ||
| 148 | bsize); | ||
| 149 | goto out; | ||
| 150 | } | ||
| 151 | |||
| 152 | for (n = 0; n < pages && bytes > 0; n++, | ||
| 153 | bytes -= PAGE_CACHE_SIZE, offset += PAGE_CACHE_SIZE) { | ||
| 154 | int avail = min_t(int, bytes, PAGE_CACHE_SIZE); | ||
| 155 | |||
| 156 | if (page[n] == NULL) | ||
| 157 | continue; | ||
| 158 | |||
| 159 | pageaddr = kmap_atomic(page[n]); | ||
| 160 | squashfs_copy_data(pageaddr, buffer, offset, avail); | ||
| 161 | memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail); | ||
| 162 | kunmap_atomic(pageaddr); | ||
| 163 | flush_dcache_page(page[n]); | ||
| 164 | SetPageUptodate(page[n]); | ||
| 165 | unlock_page(page[n]); | ||
| 166 | if (page[n] != target_page) | ||
| 167 | page_cache_release(page[n]); | ||
| 168 | } | ||
| 169 | |||
| 170 | out: | ||
| 171 | squashfs_cache_put(buffer); | ||
| 172 | return res; | ||
| 173 | } | ||
diff --git a/fs/squashfs/lzo_wrapper.c b/fs/squashfs/lzo_wrapper.c index 00f4dfc5f088..244b9fbfff7b 100644 --- a/fs/squashfs/lzo_wrapper.c +++ b/fs/squashfs/lzo_wrapper.c | |||
| @@ -31,13 +31,14 @@ | |||
| 31 | #include "squashfs_fs_sb.h" | 31 | #include "squashfs_fs_sb.h" |
| 32 | #include "squashfs.h" | 32 | #include "squashfs.h" |
| 33 | #include "decompressor.h" | 33 | #include "decompressor.h" |
| 34 | #include "page_actor.h" | ||
| 34 | 35 | ||
| 35 | struct squashfs_lzo { | 36 | struct squashfs_lzo { |
| 36 | void *input; | 37 | void *input; |
| 37 | void *output; | 38 | void *output; |
| 38 | }; | 39 | }; |
| 39 | 40 | ||
| 40 | static void *lzo_init(struct squashfs_sb_info *msblk, void *buff, int len) | 41 | static void *lzo_init(struct squashfs_sb_info *msblk, void *buff) |
| 41 | { | 42 | { |
| 42 | int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); | 43 | int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); |
| 43 | 44 | ||
| @@ -74,22 +75,16 @@ static void lzo_free(void *strm) | |||
| 74 | } | 75 | } |
| 75 | 76 | ||
| 76 | 77 | ||
| 77 | static int lzo_uncompress(struct squashfs_sb_info *msblk, void **buffer, | 78 | static int lzo_uncompress(struct squashfs_sb_info *msblk, void *strm, |
| 78 | struct buffer_head **bh, int b, int offset, int length, int srclength, | 79 | struct buffer_head **bh, int b, int offset, int length, |
| 79 | int pages) | 80 | struct squashfs_page_actor *output) |
| 80 | { | 81 | { |
| 81 | struct squashfs_lzo *stream = msblk->stream; | 82 | struct squashfs_lzo *stream = strm; |
| 82 | void *buff = stream->input; | 83 | void *buff = stream->input, *data; |
| 83 | int avail, i, bytes = length, res; | 84 | int avail, i, bytes = length, res; |
| 84 | size_t out_len = srclength; | 85 | size_t out_len = output->length; |
| 85 | |||
| 86 | mutex_lock(&msblk->read_data_mutex); | ||
| 87 | 86 | ||
| 88 | for (i = 0; i < b; i++) { | 87 | for (i = 0; i < b; i++) { |
| 89 | wait_on_buffer(bh[i]); | ||
| 90 | if (!buffer_uptodate(bh[i])) | ||
| 91 | goto block_release; | ||
| 92 | |||
| 93 | avail = min(bytes, msblk->devblksize - offset); | 88 | avail = min(bytes, msblk->devblksize - offset); |
| 94 | memcpy(buff, bh[i]->b_data + offset, avail); | 89 | memcpy(buff, bh[i]->b_data + offset, avail); |
| 95 | buff += avail; | 90 | buff += avail; |
| @@ -104,24 +99,24 @@ static int lzo_uncompress(struct squashfs_sb_info *msblk, void **buffer, | |||
| 104 | goto failed; | 99 | goto failed; |
| 105 | 100 | ||
| 106 | res = bytes = (int)out_len; | 101 | res = bytes = (int)out_len; |
| 107 | for (i = 0, buff = stream->output; bytes && i < pages; i++) { | 102 | data = squashfs_first_page(output); |
| 108 | avail = min_t(int, bytes, PAGE_CACHE_SIZE); | 103 | buff = stream->output; |
| 109 | memcpy(buffer[i], buff, avail); | 104 | while (data) { |
| 110 | buff += avail; | 105 | if (bytes <= PAGE_CACHE_SIZE) { |
| 111 | bytes -= avail; | 106 | memcpy(data, buff, bytes); |
| 107 | break; | ||
| 108 | } else { | ||
| 109 | memcpy(data, buff, PAGE_CACHE_SIZE); | ||
| 110 | buff += PAGE_CACHE_SIZE; | ||
| 111 | bytes -= PAGE_CACHE_SIZE; | ||
| 112 | data = squashfs_next_page(output); | ||
| 113 | } | ||
| 112 | } | 114 | } |
| 115 | squashfs_finish_page(output); | ||
| 113 | 116 | ||
| 114 | mutex_unlock(&msblk->read_data_mutex); | ||
| 115 | return res; | 117 | return res; |
| 116 | 118 | ||
| 117 | block_release: | ||
| 118 | for (; i < b; i++) | ||
| 119 | put_bh(bh[i]); | ||
| 120 | |||
| 121 | failed: | 119 | failed: |
| 122 | mutex_unlock(&msblk->read_data_mutex); | ||
| 123 | |||
| 124 | ERROR("lzo decompression failed, data probably corrupt\n"); | ||
| 125 | return -EIO; | 120 | return -EIO; |
| 126 | } | 121 | } |
| 127 | 122 | ||
diff --git a/fs/squashfs/page_actor.c b/fs/squashfs/page_actor.c new file mode 100644 index 000000000000..5a1c11f56441 --- /dev/null +++ b/fs/squashfs/page_actor.c | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2013 | ||
| 3 | * Phillip Lougher <phillip@squashfs.org.uk> | ||
| 4 | * | ||
| 5 | * This work is licensed under the terms of the GNU GPL, version 2. See | ||
| 6 | * the COPYING file in the top-level directory. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/kernel.h> | ||
| 10 | #include <linux/slab.h> | ||
| 11 | #include <linux/pagemap.h> | ||
| 12 | #include "page_actor.h" | ||
| 13 | |||
| 14 | /* | ||
| 15 | * This file contains implementations of page_actor for decompressing into | ||
| 16 | * an intermediate buffer, and for decompressing directly into the | ||
| 17 | * page cache. | ||
| 18 | * | ||
| 19 | * Calling code should avoid sleeping between calls to squashfs_first_page() | ||
| 20 | * and squashfs_finish_page(). | ||
| 21 | */ | ||
| 22 | |||
| 23 | /* Implementation of page_actor for decompressing into intermediate buffer */ | ||
| 24 | static void *cache_first_page(struct squashfs_page_actor *actor) | ||
| 25 | { | ||
| 26 | actor->next_page = 1; | ||
| 27 | return actor->buffer[0]; | ||
| 28 | } | ||
| 29 | |||
| 30 | static void *cache_next_page(struct squashfs_page_actor *actor) | ||
| 31 | { | ||
| 32 | if (actor->next_page == actor->pages) | ||
| 33 | return NULL; | ||
| 34 | |||
| 35 | return actor->buffer[actor->next_page++]; | ||
| 36 | } | ||
| 37 | |||
| 38 | static void cache_finish_page(struct squashfs_page_actor *actor) | ||
| 39 | { | ||
| 40 | /* empty */ | ||
| 41 | } | ||
| 42 | |||
| 43 | struct squashfs_page_actor *squashfs_page_actor_init(void **buffer, | ||
| 44 | int pages, int length) | ||
| 45 | { | ||
| 46 | struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL); | ||
| 47 | |||
| 48 | if (actor == NULL) | ||
| 49 | return NULL; | ||
| 50 | |||
| 51 | actor->length = length ? : pages * PAGE_CACHE_SIZE; | ||
| 52 | actor->buffer = buffer; | ||
| 53 | actor->pages = pages; | ||
| 54 | actor->next_page = 0; | ||
| 55 | actor->squashfs_first_page = cache_first_page; | ||
| 56 | actor->squashfs_next_page = cache_next_page; | ||
| 57 | actor->squashfs_finish_page = cache_finish_page; | ||
| 58 | return actor; | ||
| 59 | } | ||
| 60 | |||
| 61 | /* Implementation of page_actor for decompressing directly into page cache. */ | ||
| 62 | static void *direct_first_page(struct squashfs_page_actor *actor) | ||
| 63 | { | ||
| 64 | actor->next_page = 1; | ||
| 65 | return actor->pageaddr = kmap_atomic(actor->page[0]); | ||
| 66 | } | ||
| 67 | |||
| 68 | static void *direct_next_page(struct squashfs_page_actor *actor) | ||
| 69 | { | ||
| 70 | if (actor->pageaddr) | ||
| 71 | kunmap_atomic(actor->pageaddr); | ||
| 72 | |||
| 73 | return actor->pageaddr = actor->next_page == actor->pages ? NULL : | ||
| 74 | kmap_atomic(actor->page[actor->next_page++]); | ||
| 75 | } | ||
| 76 | |||
| 77 | static void direct_finish_page(struct squashfs_page_actor *actor) | ||
| 78 | { | ||
| 79 | if (actor->pageaddr) | ||
| 80 | kunmap_atomic(actor->pageaddr); | ||
| 81 | } | ||
| 82 | |||
| 83 | struct squashfs_page_actor *squashfs_page_actor_init_special(struct page **page, | ||
| 84 | int pages, int length) | ||
| 85 | { | ||
| 86 | struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL); | ||
| 87 | |||
| 88 | if (actor == NULL) | ||
| 89 | return NULL; | ||
| 90 | |||
| 91 | actor->length = length ? : pages * PAGE_CACHE_SIZE; | ||
| 92 | actor->page = page; | ||
| 93 | actor->pages = pages; | ||
| 94 | actor->next_page = 0; | ||
| 95 | actor->pageaddr = NULL; | ||
| 96 | actor->squashfs_first_page = direct_first_page; | ||
| 97 | actor->squashfs_next_page = direct_next_page; | ||
| 98 | actor->squashfs_finish_page = direct_finish_page; | ||
| 99 | return actor; | ||
| 100 | } | ||
diff --git a/fs/squashfs/page_actor.h b/fs/squashfs/page_actor.h new file mode 100644 index 000000000000..26dd82008b82 --- /dev/null +++ b/fs/squashfs/page_actor.h | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | #ifndef PAGE_ACTOR_H | ||
| 2 | #define PAGE_ACTOR_H | ||
| 3 | /* | ||
| 4 | * Copyright (c) 2013 | ||
| 5 | * Phillip Lougher <phillip@squashfs.org.uk> | ||
| 6 | * | ||
| 7 | * This work is licensed under the terms of the GNU GPL, version 2. See | ||
| 8 | * the COPYING file in the top-level directory. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef CONFIG_SQUASHFS_FILE_DIRECT | ||
| 12 | struct squashfs_page_actor { | ||
| 13 | void **page; | ||
| 14 | int pages; | ||
| 15 | int length; | ||
| 16 | int next_page; | ||
| 17 | }; | ||
| 18 | |||
| 19 | static inline struct squashfs_page_actor *squashfs_page_actor_init(void **page, | ||
| 20 | int pages, int length) | ||
| 21 | { | ||
| 22 | struct squashfs_page_actor *actor = kmalloc(sizeof(*actor), GFP_KERNEL); | ||
| 23 | |||
| 24 | if (actor == NULL) | ||
| 25 | return NULL; | ||
| 26 | |||
| 27 | actor->length = length ? : pages * PAGE_CACHE_SIZE; | ||
| 28 | actor->page = page; | ||
| 29 | actor->pages = pages; | ||
| 30 | actor->next_page = 0; | ||
| 31 | return actor; | ||
| 32 | } | ||
| 33 | |||
| 34 | static inline void *squashfs_first_page(struct squashfs_page_actor *actor) | ||
| 35 | { | ||
| 36 | actor->next_page = 1; | ||
| 37 | return actor->page[0]; | ||
| 38 | } | ||
| 39 | |||
| 40 | static inline void *squashfs_next_page(struct squashfs_page_actor *actor) | ||
| 41 | { | ||
| 42 | return actor->next_page == actor->pages ? NULL : | ||
| 43 | actor->page[actor->next_page++]; | ||
| 44 | } | ||
| 45 | |||
| 46 | static inline void squashfs_finish_page(struct squashfs_page_actor *actor) | ||
| 47 | { | ||
| 48 | /* empty */ | ||
| 49 | } | ||
| 50 | #else | ||
| 51 | struct squashfs_page_actor { | ||
| 52 | union { | ||
| 53 | void **buffer; | ||
| 54 | struct page **page; | ||
| 55 | }; | ||
| 56 | void *pageaddr; | ||
| 57 | void *(*squashfs_first_page)(struct squashfs_page_actor *); | ||
| 58 | void *(*squashfs_next_page)(struct squashfs_page_actor *); | ||
| 59 | void (*squashfs_finish_page)(struct squashfs_page_actor *); | ||
| 60 | int pages; | ||
| 61 | int length; | ||
| 62 | int next_page; | ||
| 63 | }; | ||
| 64 | |||
| 65 | extern struct squashfs_page_actor *squashfs_page_actor_init(void **, int, int); | ||
| 66 | extern struct squashfs_page_actor *squashfs_page_actor_init_special(struct page | ||
| 67 | **, int, int); | ||
| 68 | static inline void *squashfs_first_page(struct squashfs_page_actor *actor) | ||
| 69 | { | ||
| 70 | return actor->squashfs_first_page(actor); | ||
| 71 | } | ||
| 72 | static inline void *squashfs_next_page(struct squashfs_page_actor *actor) | ||
| 73 | { | ||
| 74 | return actor->squashfs_next_page(actor); | ||
| 75 | } | ||
| 76 | static inline void squashfs_finish_page(struct squashfs_page_actor *actor) | ||
| 77 | { | ||
| 78 | actor->squashfs_finish_page(actor); | ||
| 79 | } | ||
| 80 | #endif | ||
| 81 | #endif | ||
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index d1266516ed08..9e1bb79f7e6f 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h | |||
| @@ -28,8 +28,8 @@ | |||
| 28 | #define WARNING(s, args...) pr_warning("SQUASHFS: "s, ## args) | 28 | #define WARNING(s, args...) pr_warning("SQUASHFS: "s, ## args) |
| 29 | 29 | ||
| 30 | /* block.c */ | 30 | /* block.c */ |
| 31 | extern int squashfs_read_data(struct super_block *, void **, u64, int, u64 *, | 31 | extern int squashfs_read_data(struct super_block *, u64, int, u64 *, |
| 32 | int, int); | 32 | struct squashfs_page_actor *); |
| 33 | 33 | ||
| 34 | /* cache.c */ | 34 | /* cache.c */ |
| 35 | extern struct squashfs_cache *squashfs_cache_init(char *, int, int); | 35 | extern struct squashfs_cache *squashfs_cache_init(char *, int, int); |
| @@ -48,7 +48,14 @@ extern void *squashfs_read_table(struct super_block *, u64, int); | |||
| 48 | 48 | ||
| 49 | /* decompressor.c */ | 49 | /* decompressor.c */ |
| 50 | extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int); | 50 | extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int); |
| 51 | extern void *squashfs_decompressor_init(struct super_block *, unsigned short); | 51 | extern void *squashfs_decompressor_setup(struct super_block *, unsigned short); |
| 52 | |||
| 53 | /* decompressor_xxx.c */ | ||
| 54 | extern void *squashfs_decompressor_create(struct squashfs_sb_info *, void *); | ||
| 55 | extern void squashfs_decompressor_destroy(struct squashfs_sb_info *); | ||
| 56 | extern int squashfs_decompress(struct squashfs_sb_info *, struct buffer_head **, | ||
| 57 | int, int, int, struct squashfs_page_actor *); | ||
| 58 | extern int squashfs_max_decompressors(void); | ||
| 52 | 59 | ||
| 53 | /* export.c */ | 60 | /* export.c */ |
| 54 | extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, u64, | 61 | extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, u64, |
| @@ -59,6 +66,13 @@ extern int squashfs_frag_lookup(struct super_block *, unsigned int, u64 *); | |||
| 59 | extern __le64 *squashfs_read_fragment_index_table(struct super_block *, | 66 | extern __le64 *squashfs_read_fragment_index_table(struct super_block *, |
| 60 | u64, u64, unsigned int); | 67 | u64, u64, unsigned int); |
| 61 | 68 | ||
| 69 | /* file.c */ | ||
| 70 | void squashfs_copy_cache(struct page *, struct squashfs_cache_entry *, int, | ||
| 71 | int); | ||
| 72 | |||
| 73 | /* file_xxx.c */ | ||
| 74 | extern int squashfs_readpage_block(struct page *, u64, int); | ||
| 75 | |||
| 62 | /* id.c */ | 76 | /* id.c */ |
| 63 | extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); | 77 | extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); |
| 64 | extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, u64, | 78 | extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, u64, |
diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h index 52934a22f296..1da565cb50c3 100644 --- a/fs/squashfs/squashfs_fs_sb.h +++ b/fs/squashfs/squashfs_fs_sb.h | |||
| @@ -50,6 +50,7 @@ struct squashfs_cache_entry { | |||
| 50 | wait_queue_head_t wait_queue; | 50 | wait_queue_head_t wait_queue; |
| 51 | struct squashfs_cache *cache; | 51 | struct squashfs_cache *cache; |
| 52 | void **data; | 52 | void **data; |
| 53 | struct squashfs_page_actor *actor; | ||
| 53 | }; | 54 | }; |
| 54 | 55 | ||
| 55 | struct squashfs_sb_info { | 56 | struct squashfs_sb_info { |
| @@ -63,10 +64,9 @@ struct squashfs_sb_info { | |||
| 63 | __le64 *id_table; | 64 | __le64 *id_table; |
| 64 | __le64 *fragment_index; | 65 | __le64 *fragment_index; |
| 65 | __le64 *xattr_id_table; | 66 | __le64 *xattr_id_table; |
| 66 | struct mutex read_data_mutex; | ||
| 67 | struct mutex meta_index_mutex; | 67 | struct mutex meta_index_mutex; |
| 68 | struct meta_index *meta_index; | 68 | struct meta_index *meta_index; |
| 69 | void *stream; | 69 | struct squashfs_stream *stream; |
| 70 | __le64 *inode_lookup_table; | 70 | __le64 *inode_lookup_table; |
| 71 | u64 inode_table; | 71 | u64 inode_table; |
| 72 | u64 directory_table; | 72 | u64 directory_table; |
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 60553a9053ca..202df6312d4e 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c | |||
| @@ -98,7 +98,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 98 | msblk->devblksize = sb_min_blocksize(sb, SQUASHFS_DEVBLK_SIZE); | 98 | msblk->devblksize = sb_min_blocksize(sb, SQUASHFS_DEVBLK_SIZE); |
| 99 | msblk->devblksize_log2 = ffz(~msblk->devblksize); | 99 | msblk->devblksize_log2 = ffz(~msblk->devblksize); |
| 100 | 100 | ||
| 101 | mutex_init(&msblk->read_data_mutex); | ||
| 102 | mutex_init(&msblk->meta_index_mutex); | 101 | mutex_init(&msblk->meta_index_mutex); |
| 103 | 102 | ||
| 104 | /* | 103 | /* |
| @@ -206,13 +205,14 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 206 | goto failed_mount; | 205 | goto failed_mount; |
| 207 | 206 | ||
| 208 | /* Allocate read_page block */ | 207 | /* Allocate read_page block */ |
| 209 | msblk->read_page = squashfs_cache_init("data", 1, msblk->block_size); | 208 | msblk->read_page = squashfs_cache_init("data", |
| 209 | squashfs_max_decompressors(), msblk->block_size); | ||
| 210 | if (msblk->read_page == NULL) { | 210 | if (msblk->read_page == NULL) { |
| 211 | ERROR("Failed to allocate read_page block\n"); | 211 | ERROR("Failed to allocate read_page block\n"); |
| 212 | goto failed_mount; | 212 | goto failed_mount; |
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | msblk->stream = squashfs_decompressor_init(sb, flags); | 215 | msblk->stream = squashfs_decompressor_setup(sb, flags); |
| 216 | if (IS_ERR(msblk->stream)) { | 216 | if (IS_ERR(msblk->stream)) { |
| 217 | err = PTR_ERR(msblk->stream); | 217 | err = PTR_ERR(msblk->stream); |
| 218 | msblk->stream = NULL; | 218 | msblk->stream = NULL; |
| @@ -336,7 +336,7 @@ failed_mount: | |||
| 336 | squashfs_cache_delete(msblk->block_cache); | 336 | squashfs_cache_delete(msblk->block_cache); |
| 337 | squashfs_cache_delete(msblk->fragment_cache); | 337 | squashfs_cache_delete(msblk->fragment_cache); |
| 338 | squashfs_cache_delete(msblk->read_page); | 338 | squashfs_cache_delete(msblk->read_page); |
| 339 | squashfs_decompressor_free(msblk, msblk->stream); | 339 | squashfs_decompressor_destroy(msblk); |
| 340 | kfree(msblk->inode_lookup_table); | 340 | kfree(msblk->inode_lookup_table); |
| 341 | kfree(msblk->fragment_index); | 341 | kfree(msblk->fragment_index); |
| 342 | kfree(msblk->id_table); | 342 | kfree(msblk->id_table); |
| @@ -383,7 +383,7 @@ static void squashfs_put_super(struct super_block *sb) | |||
| 383 | squashfs_cache_delete(sbi->block_cache); | 383 | squashfs_cache_delete(sbi->block_cache); |
| 384 | squashfs_cache_delete(sbi->fragment_cache); | 384 | squashfs_cache_delete(sbi->fragment_cache); |
| 385 | squashfs_cache_delete(sbi->read_page); | 385 | squashfs_cache_delete(sbi->read_page); |
| 386 | squashfs_decompressor_free(sbi, sbi->stream); | 386 | squashfs_decompressor_destroy(sbi); |
| 387 | kfree(sbi->id_table); | 387 | kfree(sbi->id_table); |
| 388 | kfree(sbi->fragment_index); | 388 | kfree(sbi->fragment_index); |
| 389 | kfree(sbi->meta_index); | 389 | kfree(sbi->meta_index); |
diff --git a/fs/squashfs/xz_wrapper.c b/fs/squashfs/xz_wrapper.c index 1760b7d108f6..c609624e4b8a 100644 --- a/fs/squashfs/xz_wrapper.c +++ b/fs/squashfs/xz_wrapper.c | |||
| @@ -32,44 +32,70 @@ | |||
| 32 | #include "squashfs_fs_sb.h" | 32 | #include "squashfs_fs_sb.h" |
| 33 | #include "squashfs.h" | 33 | #include "squashfs.h" |
| 34 | #include "decompressor.h" | 34 | #include "decompressor.h" |
| 35 | #include "page_actor.h" | ||
| 35 | 36 | ||
| 36 | struct squashfs_xz { | 37 | struct squashfs_xz { |
| 37 | struct xz_dec *state; | 38 | struct xz_dec *state; |
| 38 | struct xz_buf buf; | 39 | struct xz_buf buf; |
| 39 | }; | 40 | }; |
| 40 | 41 | ||
| 41 | struct comp_opts { | 42 | struct disk_comp_opts { |
| 42 | __le32 dictionary_size; | 43 | __le32 dictionary_size; |
| 43 | __le32 flags; | 44 | __le32 flags; |
| 44 | }; | 45 | }; |
| 45 | 46 | ||
| 46 | static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff, | 47 | struct comp_opts { |
| 47 | int len) | 48 | int dict_size; |
| 49 | }; | ||
| 50 | |||
| 51 | static void *squashfs_xz_comp_opts(struct squashfs_sb_info *msblk, | ||
| 52 | void *buff, int len) | ||
| 48 | { | 53 | { |
| 49 | struct comp_opts *comp_opts = buff; | 54 | struct disk_comp_opts *comp_opts = buff; |
| 50 | struct squashfs_xz *stream; | 55 | struct comp_opts *opts; |
| 51 | int dict_size = msblk->block_size; | 56 | int err = 0, n; |
| 52 | int err, n; | 57 | |
| 58 | opts = kmalloc(sizeof(*opts), GFP_KERNEL); | ||
| 59 | if (opts == NULL) { | ||
| 60 | err = -ENOMEM; | ||
| 61 | goto out2; | ||
| 62 | } | ||
| 53 | 63 | ||
| 54 | if (comp_opts) { | 64 | if (comp_opts) { |
| 55 | /* check compressor options are the expected length */ | 65 | /* check compressor options are the expected length */ |
| 56 | if (len < sizeof(*comp_opts)) { | 66 | if (len < sizeof(*comp_opts)) { |
| 57 | err = -EIO; | 67 | err = -EIO; |
| 58 | goto failed; | 68 | goto out; |
| 59 | } | 69 | } |
| 60 | 70 | ||
| 61 | dict_size = le32_to_cpu(comp_opts->dictionary_size); | 71 | opts->dict_size = le32_to_cpu(comp_opts->dictionary_size); |
| 62 | 72 | ||
| 63 | /* the dictionary size should be 2^n or 2^n+2^(n+1) */ | 73 | /* the dictionary size should be 2^n or 2^n+2^(n+1) */ |
| 64 | n = ffs(dict_size) - 1; | 74 | n = ffs(opts->dict_size) - 1; |
| 65 | if (dict_size != (1 << n) && dict_size != (1 << n) + | 75 | if (opts->dict_size != (1 << n) && opts->dict_size != (1 << n) + |
| 66 | (1 << (n + 1))) { | 76 | (1 << (n + 1))) { |
| 67 | err = -EIO; | 77 | err = -EIO; |
| 68 | goto failed; | 78 | goto out; |
| 69 | } | 79 | } |
| 70 | } | 80 | } else |
| 81 | /* use defaults */ | ||
| 82 | opts->dict_size = max_t(int, msblk->block_size, | ||
| 83 | SQUASHFS_METADATA_SIZE); | ||
| 84 | |||
| 85 | return opts; | ||
| 86 | |||
| 87 | out: | ||
| 88 | kfree(opts); | ||
| 89 | out2: | ||
| 90 | return ERR_PTR(err); | ||
| 91 | } | ||
| 92 | |||
| 71 | 93 | ||
| 72 | dict_size = max_t(int, dict_size, SQUASHFS_METADATA_SIZE); | 94 | static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff) |
| 95 | { | ||
| 96 | struct comp_opts *comp_opts = buff; | ||
| 97 | struct squashfs_xz *stream; | ||
| 98 | int err; | ||
| 73 | 99 | ||
| 74 | stream = kmalloc(sizeof(*stream), GFP_KERNEL); | 100 | stream = kmalloc(sizeof(*stream), GFP_KERNEL); |
| 75 | if (stream == NULL) { | 101 | if (stream == NULL) { |
| @@ -77,7 +103,7 @@ static void *squashfs_xz_init(struct squashfs_sb_info *msblk, void *buff, | |||
| 77 | goto failed; | 103 | goto failed; |
| 78 | } | 104 | } |
| 79 | 105 | ||
| 80 | stream->state = xz_dec_init(XZ_PREALLOC, dict_size); | 106 | stream->state = xz_dec_init(XZ_PREALLOC, comp_opts->dict_size); |
| 81 | if (stream->state == NULL) { | 107 | if (stream->state == NULL) { |
| 82 | kfree(stream); | 108 | kfree(stream); |
| 83 | err = -ENOMEM; | 109 | err = -ENOMEM; |
| @@ -103,42 +129,37 @@ static void squashfs_xz_free(void *strm) | |||
| 103 | } | 129 | } |
| 104 | 130 | ||
| 105 | 131 | ||
| 106 | static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void **buffer, | 132 | static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void *strm, |
| 107 | struct buffer_head **bh, int b, int offset, int length, int srclength, | 133 | struct buffer_head **bh, int b, int offset, int length, |
| 108 | int pages) | 134 | struct squashfs_page_actor *output) |
| 109 | { | 135 | { |
| 110 | enum xz_ret xz_err; | 136 | enum xz_ret xz_err; |
| 111 | int avail, total = 0, k = 0, page = 0; | 137 | int avail, total = 0, k = 0; |
| 112 | struct squashfs_xz *stream = msblk->stream; | 138 | struct squashfs_xz *stream = strm; |
| 113 | |||
| 114 | mutex_lock(&msblk->read_data_mutex); | ||
| 115 | 139 | ||
| 116 | xz_dec_reset(stream->state); | 140 | xz_dec_reset(stream->state); |
| 117 | stream->buf.in_pos = 0; | 141 | stream->buf.in_pos = 0; |
| 118 | stream->buf.in_size = 0; | 142 | stream->buf.in_size = 0; |
| 119 | stream->buf.out_pos = 0; | 143 | stream->buf.out_pos = 0; |
| 120 | stream->buf.out_size = PAGE_CACHE_SIZE; | 144 | stream->buf.out_size = PAGE_CACHE_SIZE; |
| 121 | stream->buf.out = buffer[page++]; | 145 | stream->buf.out = squashfs_first_page(output); |
| 122 | 146 | ||
| 123 | do { | 147 | do { |
| 124 | if (stream->buf.in_pos == stream->buf.in_size && k < b) { | 148 | if (stream->buf.in_pos == stream->buf.in_size && k < b) { |
| 125 | avail = min(length, msblk->devblksize - offset); | 149 | avail = min(length, msblk->devblksize - offset); |
| 126 | length -= avail; | 150 | length -= avail; |
| 127 | wait_on_buffer(bh[k]); | ||
| 128 | if (!buffer_uptodate(bh[k])) | ||
| 129 | goto release_mutex; | ||
| 130 | |||
| 131 | stream->buf.in = bh[k]->b_data + offset; | 151 | stream->buf.in = bh[k]->b_data + offset; |
| 132 | stream->buf.in_size = avail; | 152 | stream->buf.in_size = avail; |
| 133 | stream->buf.in_pos = 0; | 153 | stream->buf.in_pos = 0; |
| 134 | offset = 0; | 154 | offset = 0; |
| 135 | } | 155 | } |
| 136 | 156 | ||
| 137 | if (stream->buf.out_pos == stream->buf.out_size | 157 | if (stream->buf.out_pos == stream->buf.out_size) { |
| 138 | && page < pages) { | 158 | stream->buf.out = squashfs_next_page(output); |
| 139 | stream->buf.out = buffer[page++]; | 159 | if (stream->buf.out != NULL) { |
| 140 | stream->buf.out_pos = 0; | 160 | stream->buf.out_pos = 0; |
| 141 | total += PAGE_CACHE_SIZE; | 161 | total += PAGE_CACHE_SIZE; |
| 162 | } | ||
| 142 | } | 163 | } |
| 143 | 164 | ||
| 144 | xz_err = xz_dec_run(stream->state, &stream->buf); | 165 | xz_err = xz_dec_run(stream->state, &stream->buf); |
| @@ -147,23 +168,14 @@ static int squashfs_xz_uncompress(struct squashfs_sb_info *msblk, void **buffer, | |||
| 147 | put_bh(bh[k++]); | 168 | put_bh(bh[k++]); |
| 148 | } while (xz_err == XZ_OK); | 169 | } while (xz_err == XZ_OK); |
| 149 | 170 | ||
| 150 | if (xz_err != XZ_STREAM_END) { | 171 | squashfs_finish_page(output); |
| 151 | ERROR("xz_dec_run error, data probably corrupt\n"); | ||
| 152 | goto release_mutex; | ||
| 153 | } | ||
| 154 | |||
| 155 | if (k < b) { | ||
| 156 | ERROR("xz_uncompress error, input remaining\n"); | ||
| 157 | goto release_mutex; | ||
| 158 | } | ||
| 159 | 172 | ||
| 160 | total += stream->buf.out_pos; | 173 | if (xz_err != XZ_STREAM_END || k < b) |
| 161 | mutex_unlock(&msblk->read_data_mutex); | 174 | goto out; |
| 162 | return total; | ||
| 163 | 175 | ||
| 164 | release_mutex: | 176 | return total + stream->buf.out_pos; |
| 165 | mutex_unlock(&msblk->read_data_mutex); | ||
| 166 | 177 | ||
| 178 | out: | ||
| 167 | for (; k < b; k++) | 179 | for (; k < b; k++) |
| 168 | put_bh(bh[k]); | 180 | put_bh(bh[k]); |
| 169 | 181 | ||
| @@ -172,6 +184,7 @@ release_mutex: | |||
| 172 | 184 | ||
| 173 | const struct squashfs_decompressor squashfs_xz_comp_ops = { | 185 | const struct squashfs_decompressor squashfs_xz_comp_ops = { |
| 174 | .init = squashfs_xz_init, | 186 | .init = squashfs_xz_init, |
| 187 | .comp_opts = squashfs_xz_comp_opts, | ||
| 175 | .free = squashfs_xz_free, | 188 | .free = squashfs_xz_free, |
| 176 | .decompress = squashfs_xz_uncompress, | 189 | .decompress = squashfs_xz_uncompress, |
| 177 | .id = XZ_COMPRESSION, | 190 | .id = XZ_COMPRESSION, |
diff --git a/fs/squashfs/zlib_wrapper.c b/fs/squashfs/zlib_wrapper.c index 55d918fd2d86..8727caba6882 100644 --- a/fs/squashfs/zlib_wrapper.c +++ b/fs/squashfs/zlib_wrapper.c | |||
| @@ -32,8 +32,9 @@ | |||
| 32 | #include "squashfs_fs_sb.h" | 32 | #include "squashfs_fs_sb.h" |
| 33 | #include "squashfs.h" | 33 | #include "squashfs.h" |
| 34 | #include "decompressor.h" | 34 | #include "decompressor.h" |
| 35 | #include "page_actor.h" | ||
| 35 | 36 | ||
| 36 | static void *zlib_init(struct squashfs_sb_info *dummy, void *buff, int len) | 37 | static void *zlib_init(struct squashfs_sb_info *dummy, void *buff) |
| 37 | { | 38 | { |
| 38 | z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL); | 39 | z_stream *stream = kmalloc(sizeof(z_stream), GFP_KERNEL); |
| 39 | if (stream == NULL) | 40 | if (stream == NULL) |
| @@ -61,44 +62,37 @@ static void zlib_free(void *strm) | |||
| 61 | } | 62 | } |
| 62 | 63 | ||
| 63 | 64 | ||
| 64 | static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer, | 65 | static int zlib_uncompress(struct squashfs_sb_info *msblk, void *strm, |
| 65 | struct buffer_head **bh, int b, int offset, int length, int srclength, | 66 | struct buffer_head **bh, int b, int offset, int length, |
| 66 | int pages) | 67 | struct squashfs_page_actor *output) |
| 67 | { | 68 | { |
| 68 | int zlib_err, zlib_init = 0; | 69 | int zlib_err, zlib_init = 0, k = 0; |
| 69 | int k = 0, page = 0; | 70 | z_stream *stream = strm; |
| 70 | z_stream *stream = msblk->stream; | ||
| 71 | |||
| 72 | mutex_lock(&msblk->read_data_mutex); | ||
| 73 | 71 | ||
| 74 | stream->avail_out = 0; | 72 | stream->avail_out = PAGE_CACHE_SIZE; |
| 73 | stream->next_out = squashfs_first_page(output); | ||
| 75 | stream->avail_in = 0; | 74 | stream->avail_in = 0; |
| 76 | 75 | ||
| 77 | do { | 76 | do { |
| 78 | if (stream->avail_in == 0 && k < b) { | 77 | if (stream->avail_in == 0 && k < b) { |
| 79 | int avail = min(length, msblk->devblksize - offset); | 78 | int avail = min(length, msblk->devblksize - offset); |
| 80 | length -= avail; | 79 | length -= avail; |
| 81 | wait_on_buffer(bh[k]); | ||
| 82 | if (!buffer_uptodate(bh[k])) | ||
| 83 | goto release_mutex; | ||
| 84 | |||
| 85 | stream->next_in = bh[k]->b_data + offset; | 80 | stream->next_in = bh[k]->b_data + offset; |
| 86 | stream->avail_in = avail; | 81 | stream->avail_in = avail; |
| 87 | offset = 0; | 82 | offset = 0; |
| 88 | } | 83 | } |
| 89 | 84 | ||
| 90 | if (stream->avail_out == 0 && page < pages) { | 85 | if (stream->avail_out == 0) { |
| 91 | stream->next_out = buffer[page++]; | 86 | stream->next_out = squashfs_next_page(output); |
| 92 | stream->avail_out = PAGE_CACHE_SIZE; | 87 | if (stream->next_out != NULL) |
| 88 | stream->avail_out = PAGE_CACHE_SIZE; | ||
| 93 | } | 89 | } |
| 94 | 90 | ||
| 95 | if (!zlib_init) { | 91 | if (!zlib_init) { |
| 96 | zlib_err = zlib_inflateInit(stream); | 92 | zlib_err = zlib_inflateInit(stream); |
| 97 | if (zlib_err != Z_OK) { | 93 | if (zlib_err != Z_OK) { |
| 98 | ERROR("zlib_inflateInit returned unexpected " | 94 | squashfs_finish_page(output); |
| 99 | "result 0x%x, srclength %d\n", | 95 | goto out; |
| 100 | zlib_err, srclength); | ||
| 101 | goto release_mutex; | ||
| 102 | } | 96 | } |
| 103 | zlib_init = 1; | 97 | zlib_init = 1; |
| 104 | } | 98 | } |
| @@ -109,29 +103,21 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer, | |||
| 109 | put_bh(bh[k++]); | 103 | put_bh(bh[k++]); |
| 110 | } while (zlib_err == Z_OK); | 104 | } while (zlib_err == Z_OK); |
| 111 | 105 | ||
| 112 | if (zlib_err != Z_STREAM_END) { | 106 | squashfs_finish_page(output); |
| 113 | ERROR("zlib_inflate error, data probably corrupt\n"); | ||
| 114 | goto release_mutex; | ||
| 115 | } | ||
| 116 | 107 | ||
| 117 | zlib_err = zlib_inflateEnd(stream); | 108 | if (zlib_err != Z_STREAM_END) |
| 118 | if (zlib_err != Z_OK) { | 109 | goto out; |
| 119 | ERROR("zlib_inflate error, data probably corrupt\n"); | ||
| 120 | goto release_mutex; | ||
| 121 | } | ||
| 122 | 110 | ||
| 123 | if (k < b) { | 111 | zlib_err = zlib_inflateEnd(stream); |
| 124 | ERROR("zlib_uncompress error, data remaining\n"); | 112 | if (zlib_err != Z_OK) |
| 125 | goto release_mutex; | 113 | goto out; |
| 126 | } | ||
| 127 | 114 | ||
| 128 | length = stream->total_out; | 115 | if (k < b) |
| 129 | mutex_unlock(&msblk->read_data_mutex); | 116 | goto out; |
| 130 | return length; | ||
| 131 | 117 | ||
| 132 | release_mutex: | 118 | return stream->total_out; |
| 133 | mutex_unlock(&msblk->read_data_mutex); | ||
| 134 | 119 | ||
| 120 | out: | ||
| 135 | for (; k < b; k++) | 121 | for (; k < b; k++) |
| 136 | put_bh(bh[k]); | 122 | put_bh(bh[k]); |
| 137 | 123 | ||
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 1c02da8bb7df..3ef11b22e750 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
| @@ -1137,6 +1137,7 @@ xfs_bmap_add_attrfork( | |||
| 1137 | int committed; /* xaction was committed */ | 1137 | int committed; /* xaction was committed */ |
| 1138 | int logflags; /* logging flags */ | 1138 | int logflags; /* logging flags */ |
| 1139 | int error; /* error return value */ | 1139 | int error; /* error return value */ |
| 1140 | int cancel_flags = 0; | ||
| 1140 | 1141 | ||
| 1141 | ASSERT(XFS_IFORK_Q(ip) == 0); | 1142 | ASSERT(XFS_IFORK_Q(ip) == 0); |
| 1142 | 1143 | ||
| @@ -1147,19 +1148,20 @@ xfs_bmap_add_attrfork( | |||
| 1147 | if (rsvd) | 1148 | if (rsvd) |
| 1148 | tp->t_flags |= XFS_TRANS_RESERVE; | 1149 | tp->t_flags |= XFS_TRANS_RESERVE; |
| 1149 | error = xfs_trans_reserve(tp, &M_RES(mp)->tr_addafork, blks, 0); | 1150 | error = xfs_trans_reserve(tp, &M_RES(mp)->tr_addafork, blks, 0); |
| 1150 | if (error) | 1151 | if (error) { |
| 1151 | goto error0; | 1152 | xfs_trans_cancel(tp, 0); |
| 1153 | return error; | ||
| 1154 | } | ||
| 1155 | cancel_flags = XFS_TRANS_RELEASE_LOG_RES; | ||
| 1152 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 1156 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
| 1153 | error = xfs_trans_reserve_quota_nblks(tp, ip, blks, 0, rsvd ? | 1157 | error = xfs_trans_reserve_quota_nblks(tp, ip, blks, 0, rsvd ? |
| 1154 | XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : | 1158 | XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : |
| 1155 | XFS_QMOPT_RES_REGBLKS); | 1159 | XFS_QMOPT_RES_REGBLKS); |
| 1156 | if (error) { | 1160 | if (error) |
| 1157 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 1161 | goto trans_cancel; |
| 1158 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES); | 1162 | cancel_flags |= XFS_TRANS_ABORT; |
| 1159 | return error; | ||
| 1160 | } | ||
| 1161 | if (XFS_IFORK_Q(ip)) | 1163 | if (XFS_IFORK_Q(ip)) |
| 1162 | goto error1; | 1164 | goto trans_cancel; |
| 1163 | if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS) { | 1165 | if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS) { |
| 1164 | /* | 1166 | /* |
| 1165 | * For inodes coming from pre-6.2 filesystems. | 1167 | * For inodes coming from pre-6.2 filesystems. |
| @@ -1169,7 +1171,7 @@ xfs_bmap_add_attrfork( | |||
| 1169 | } | 1171 | } |
| 1170 | ASSERT(ip->i_d.di_anextents == 0); | 1172 | ASSERT(ip->i_d.di_anextents == 0); |
| 1171 | 1173 | ||
| 1172 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | 1174 | xfs_trans_ijoin(tp, ip, 0); |
| 1173 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 1175 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
| 1174 | 1176 | ||
| 1175 | switch (ip->i_d.di_format) { | 1177 | switch (ip->i_d.di_format) { |
| @@ -1191,7 +1193,7 @@ xfs_bmap_add_attrfork( | |||
| 1191 | default: | 1193 | default: |
| 1192 | ASSERT(0); | 1194 | ASSERT(0); |
| 1193 | error = XFS_ERROR(EINVAL); | 1195 | error = XFS_ERROR(EINVAL); |
| 1194 | goto error1; | 1196 | goto trans_cancel; |
| 1195 | } | 1197 | } |
| 1196 | 1198 | ||
| 1197 | ASSERT(ip->i_afp == NULL); | 1199 | ASSERT(ip->i_afp == NULL); |
| @@ -1219,7 +1221,7 @@ xfs_bmap_add_attrfork( | |||
| 1219 | if (logflags) | 1221 | if (logflags) |
| 1220 | xfs_trans_log_inode(tp, ip, logflags); | 1222 | xfs_trans_log_inode(tp, ip, logflags); |
| 1221 | if (error) | 1223 | if (error) |
| 1222 | goto error2; | 1224 | goto bmap_cancel; |
| 1223 | if (!xfs_sb_version_hasattr(&mp->m_sb) || | 1225 | if (!xfs_sb_version_hasattr(&mp->m_sb) || |
| 1224 | (!xfs_sb_version_hasattr2(&mp->m_sb) && version == 2)) { | 1226 | (!xfs_sb_version_hasattr2(&mp->m_sb) && version == 2)) { |
| 1225 | __int64_t sbfields = 0; | 1227 | __int64_t sbfields = 0; |
| @@ -1242,14 +1244,16 @@ xfs_bmap_add_attrfork( | |||
| 1242 | 1244 | ||
| 1243 | error = xfs_bmap_finish(&tp, &flist, &committed); | 1245 | error = xfs_bmap_finish(&tp, &flist, &committed); |
| 1244 | if (error) | 1246 | if (error) |
| 1245 | goto error2; | 1247 | goto bmap_cancel; |
| 1246 | return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); | 1248 | error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES); |
| 1247 | error2: | 1249 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
| 1250 | return error; | ||
| 1251 | |||
| 1252 | bmap_cancel: | ||
| 1248 | xfs_bmap_cancel(&flist); | 1253 | xfs_bmap_cancel(&flist); |
| 1249 | error1: | 1254 | trans_cancel: |
| 1255 | xfs_trans_cancel(tp, cancel_flags); | ||
| 1250 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 1256 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
| 1251 | error0: | ||
| 1252 | xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); | ||
| 1253 | return error; | 1257 | return error; |
| 1254 | } | 1258 | } |
| 1255 | 1259 | ||
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index da88f167af78..02df7b408a26 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
| @@ -41,6 +41,7 @@ | |||
| 41 | #include "xfs_fsops.h" | 41 | #include "xfs_fsops.h" |
| 42 | #include "xfs_trace.h" | 42 | #include "xfs_trace.h" |
| 43 | #include "xfs_icache.h" | 43 | #include "xfs_icache.h" |
| 44 | #include "xfs_dinode.h" | ||
| 44 | 45 | ||
| 45 | 46 | ||
| 46 | #ifdef HAVE_PERCPU_SB | 47 | #ifdef HAVE_PERCPU_SB |
| @@ -718,8 +719,22 @@ xfs_mountfs( | |||
| 718 | * Set the inode cluster size. | 719 | * Set the inode cluster size. |
| 719 | * This may still be overridden by the file system | 720 | * This may still be overridden by the file system |
| 720 | * block size if it is larger than the chosen cluster size. | 721 | * block size if it is larger than the chosen cluster size. |
| 722 | * | ||
| 723 | * For v5 filesystems, scale the cluster size with the inode size to | ||
| 724 | * keep a constant ratio of inode per cluster buffer, but only if mkfs | ||
| 725 | * has set the inode alignment value appropriately for larger cluster | ||
| 726 | * sizes. | ||
| 721 | */ | 727 | */ |
| 722 | mp->m_inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE; | 728 | mp->m_inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE; |
| 729 | if (xfs_sb_version_hascrc(&mp->m_sb)) { | ||
| 730 | int new_size = mp->m_inode_cluster_size; | ||
| 731 | |||
| 732 | new_size *= mp->m_sb.sb_inodesize / XFS_DINODE_MIN_SIZE; | ||
| 733 | if (mp->m_sb.sb_inoalignmt >= XFS_B_TO_FSBT(mp, new_size)) | ||
| 734 | mp->m_inode_cluster_size = new_size; | ||
| 735 | xfs_info(mp, "Using inode cluster size of %d bytes", | ||
| 736 | mp->m_inode_cluster_size); | ||
| 737 | } | ||
| 723 | 738 | ||
| 724 | /* | 739 | /* |
| 725 | * Set inode alignment fields | 740 | * Set inode alignment fields |
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 1d8101a10d8e..a466c5e5826e 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h | |||
| @@ -112,7 +112,7 @@ typedef struct xfs_mount { | |||
| 112 | __uint8_t m_blkbb_log; /* blocklog - BBSHIFT */ | 112 | __uint8_t m_blkbb_log; /* blocklog - BBSHIFT */ |
| 113 | __uint8_t m_agno_log; /* log #ag's */ | 113 | __uint8_t m_agno_log; /* log #ag's */ |
| 114 | __uint8_t m_agino_log; /* #bits for agino in inum */ | 114 | __uint8_t m_agino_log; /* #bits for agino in inum */ |
| 115 | __uint16_t m_inode_cluster_size;/* min inode buf size */ | 115 | uint m_inode_cluster_size;/* min inode buf size */ |
| 116 | uint m_blockmask; /* sb_blocksize-1 */ | 116 | uint m_blockmask; /* sb_blocksize-1 */ |
| 117 | uint m_blockwsize; /* sb_blocksize in words */ | 117 | uint m_blockwsize; /* sb_blocksize in words */ |
| 118 | uint m_blockwmask; /* blockwsize-1 */ | 118 | uint m_blockwmask; /* blockwsize-1 */ |
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c index 1bba7f60d94c..50c3f5614288 100644 --- a/fs/xfs/xfs_trans_inode.c +++ b/fs/xfs/xfs_trans_inode.c | |||
| @@ -111,12 +111,14 @@ xfs_trans_log_inode( | |||
| 111 | 111 | ||
| 112 | /* | 112 | /* |
| 113 | * First time we log the inode in a transaction, bump the inode change | 113 | * First time we log the inode in a transaction, bump the inode change |
| 114 | * counter if it is configured for this to occur. | 114 | * counter if it is configured for this to occur. We don't use |
| 115 | * inode_inc_version() because there is no need for extra locking around | ||
| 116 | * i_version as we already hold the inode locked exclusively for | ||
| 117 | * metadata modification. | ||
| 115 | */ | 118 | */ |
| 116 | if (!(ip->i_itemp->ili_item.li_desc->lid_flags & XFS_LID_DIRTY) && | 119 | if (!(ip->i_itemp->ili_item.li_desc->lid_flags & XFS_LID_DIRTY) && |
| 117 | IS_I_VERSION(VFS_I(ip))) { | 120 | IS_I_VERSION(VFS_I(ip))) { |
| 118 | inode_inc_iversion(VFS_I(ip)); | 121 | ip->i_d.di_changecount = ++VFS_I(ip)->i_version; |
| 119 | ip->i_d.di_changecount = VFS_I(ip)->i_version; | ||
| 120 | flags |= XFS_ILOG_CORE; | 122 | flags |= XFS_ILOG_CORE; |
| 121 | } | 123 | } |
| 122 | 124 | ||
diff --git a/fs/xfs/xfs_trans_resv.c b/fs/xfs/xfs_trans_resv.c index d53d9f0627a7..2fd59c0dae66 100644 --- a/fs/xfs/xfs_trans_resv.c +++ b/fs/xfs/xfs_trans_resv.c | |||
| @@ -385,8 +385,7 @@ xfs_calc_ifree_reservation( | |||
| 385 | xfs_calc_inode_res(mp, 1) + | 385 | xfs_calc_inode_res(mp, 1) + |
| 386 | xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) + | 386 | xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) + |
| 387 | xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, 1)) + | 387 | xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, 1)) + |
| 388 | MAX((__uint16_t)XFS_FSB_TO_B(mp, 1), | 388 | max_t(uint, XFS_FSB_TO_B(mp, 1), XFS_INODE_CLUSTER_SIZE(mp)) + |
| 389 | XFS_INODE_CLUSTER_SIZE(mp)) + | ||
| 390 | xfs_calc_buf_res(1, 0) + | 389 | xfs_calc_buf_res(1, 0) + |
| 391 | xfs_calc_buf_res(2 + XFS_IALLOC_BLOCKS(mp) + | 390 | xfs_calc_buf_res(2 + XFS_IALLOC_BLOCKS(mp) + |
| 392 | mp->m_in_maxlevels, 0) + | 391 | mp->m_in_maxlevels, 0) + |
