699 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Squashfs - a compressed read only filesystem for Linux4 *5 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 20086 * Phillip Lougher <phillip@squashfs.org.uk>7 *8 * super.c9 */10 11/*12 * This file implements code to read the superblock, read and initialise13 * in-memory structures at mount time, and all the VFS glue code to register14 * the filesystem.15 */16 17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt18 19#include <linux/blkdev.h>20#include <linux/fs.h>21#include <linux/fs_context.h>22#include <linux/fs_parser.h>23#include <linux/vfs.h>24#include <linux/slab.h>25#include <linux/mutex.h>26#include <linux/seq_file.h>27#include <linux/pagemap.h>28#include <linux/init.h>29#include <linux/module.h>30#include <linux/magic.h>31#include <linux/xattr.h>32 33#include "squashfs_fs.h"34#include "squashfs_fs_sb.h"35#include "squashfs_fs_i.h"36#include "squashfs.h"37#include "decompressor.h"38#include "xattr.h"39 40static struct file_system_type squashfs_fs_type;41static const struct super_operations squashfs_super_ops;42 43enum Opt_errors {44 Opt_errors_continue,45 Opt_errors_panic,46};47 48enum squashfs_param {49 Opt_errors,50 Opt_threads,51};52 53struct squashfs_mount_opts {54 enum Opt_errors errors;55 const struct squashfs_decompressor_thread_ops *thread_ops;56 int thread_num;57};58 59static const struct constant_table squashfs_param_errors[] = {60 {"continue", Opt_errors_continue },61 {"panic", Opt_errors_panic },62 {}63};64 65static const struct fs_parameter_spec squashfs_fs_parameters[] = {66 fsparam_enum("errors", Opt_errors, squashfs_param_errors),67 fsparam_string("threads", Opt_threads),68 {}69};70 71 72static int squashfs_parse_param_threads_str(const char *str, struct squashfs_mount_opts *opts)73{74#ifdef CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT75 if (strcmp(str, "single") == 0) {76 opts->thread_ops = &squashfs_decompressor_single;77 return 0;78 }79 if (strcmp(str, "multi") == 0) {80 opts->thread_ops = &squashfs_decompressor_multi;81 return 0;82 }83 if (strcmp(str, "percpu") == 0) {84 opts->thread_ops = &squashfs_decompressor_percpu;85 return 0;86 }87#endif88 return -EINVAL;89}90 91static int squashfs_parse_param_threads_num(const char *str, struct squashfs_mount_opts *opts)92{93#ifdef CONFIG_SQUASHFS_MOUNT_DECOMP_THREADS94 int ret;95 unsigned long num;96 97 ret = kstrtoul(str, 0, &num);98 if (ret != 0)99 return -EINVAL;100 if (num > 1) {101 opts->thread_ops = &squashfs_decompressor_multi;102 if (num > opts->thread_ops->max_decompressors())103 return -EINVAL;104 opts->thread_num = (int)num;105 return 0;106 }107#ifdef CONFIG_SQUASHFS_DECOMP_SINGLE108 if (num == 1) {109 opts->thread_ops = &squashfs_decompressor_single;110 opts->thread_num = 1;111 return 0;112 }113#endif114#endif /* !CONFIG_SQUASHFS_MOUNT_DECOMP_THREADS */115 return -EINVAL;116}117 118static int squashfs_parse_param_threads(const char *str, struct squashfs_mount_opts *opts)119{120 int ret = squashfs_parse_param_threads_str(str, opts);121 122 if (ret == 0)123 return ret;124 return squashfs_parse_param_threads_num(str, opts);125}126 127static int squashfs_parse_param(struct fs_context *fc, struct fs_parameter *param)128{129 struct squashfs_mount_opts *opts = fc->fs_private;130 struct fs_parse_result result;131 int opt;132 133 opt = fs_parse(fc, squashfs_fs_parameters, param, &result);134 if (opt < 0)135 return opt;136 137 switch (opt) {138 case Opt_errors:139 opts->errors = result.uint_32;140 break;141 case Opt_threads:142 if (squashfs_parse_param_threads(param->string, opts) != 0)143 return -EINVAL;144 break;145 default:146 return -EINVAL;147 }148 149 return 0;150}151 152static const struct squashfs_decompressor *supported_squashfs_filesystem(153 struct fs_context *fc,154 short major, short minor, short id)155{156 const struct squashfs_decompressor *decompressor;157 158 if (major < SQUASHFS_MAJOR) {159 errorf(fc, "Major/Minor mismatch, older Squashfs %d.%d "160 "filesystems are unsupported", major, minor);161 return NULL;162 } else if (major > SQUASHFS_MAJOR || minor > SQUASHFS_MINOR) {163 errorf(fc, "Major/Minor mismatch, trying to mount newer "164 "%d.%d filesystem", major, minor);165 errorf(fc, "Please update your kernel");166 return NULL;167 }168 169 decompressor = squashfs_lookup_decompressor(id);170 if (!decompressor->supported) {171 errorf(fc, "Filesystem uses \"%s\" compression. This is not supported",172 decompressor->name);173 return NULL;174 }175 176 return decompressor;177}178 179 180static int squashfs_fill_super(struct super_block *sb, struct fs_context *fc)181{182 struct squashfs_mount_opts *opts = fc->fs_private;183 struct squashfs_sb_info *msblk;184 struct squashfs_super_block *sblk = NULL;185 struct inode *root;186 long long root_inode;187 unsigned short flags;188 unsigned int fragments;189 u64 lookup_table_start, xattr_id_table_start, next_table;190 int err;191 192 TRACE("Entered squashfs_fill_superblock\n");193 194 sb->s_fs_info = kzalloc(sizeof(*msblk), GFP_KERNEL);195 if (sb->s_fs_info == NULL) {196 ERROR("Failed to allocate squashfs_sb_info\n");197 return -ENOMEM;198 }199 msblk = sb->s_fs_info;200 msblk->thread_ops = opts->thread_ops;201 202 msblk->panic_on_errors = (opts->errors == Opt_errors_panic);203 204 msblk->devblksize = sb_min_blocksize(sb, SQUASHFS_DEVBLK_SIZE);205 msblk->devblksize_log2 = ffz(~msblk->devblksize);206 207 mutex_init(&msblk->meta_index_mutex);208 209 /*210 * msblk->bytes_used is checked in squashfs_read_table to ensure reads211 * are not beyond filesystem end. But as we're using212 * squashfs_read_table here to read the superblock (including the value213 * of bytes_used) we need to set it to an initial sensible dummy value214 */215 msblk->bytes_used = sizeof(*sblk);216 sblk = squashfs_read_table(sb, SQUASHFS_START, sizeof(*sblk));217 218 if (IS_ERR(sblk)) {219 errorf(fc, "unable to read squashfs_super_block");220 err = PTR_ERR(sblk);221 sblk = NULL;222 goto failed_mount;223 }224 225 err = -EINVAL;226 227 /* Check it is a SQUASHFS superblock */228 sb->s_magic = le32_to_cpu(sblk->s_magic);229 if (sb->s_magic != SQUASHFS_MAGIC) {230 if (!(fc->sb_flags & SB_SILENT))231 errorf(fc, "Can't find a SQUASHFS superblock on %pg",232 sb->s_bdev);233 goto failed_mount;234 }235 236 if (opts->thread_num == 0) {237 msblk->max_thread_num = msblk->thread_ops->max_decompressors();238 } else {239 msblk->max_thread_num = opts->thread_num;240 }241 242 /* Check the MAJOR & MINOR versions and lookup compression type */243 msblk->decompressor = supported_squashfs_filesystem(244 fc,245 le16_to_cpu(sblk->s_major),246 le16_to_cpu(sblk->s_minor),247 le16_to_cpu(sblk->compression));248 if (msblk->decompressor == NULL)249 goto failed_mount;250 251 /* Check the filesystem does not extend beyond the end of the252 block device */253 msblk->bytes_used = le64_to_cpu(sblk->bytes_used);254 if (msblk->bytes_used < 0 ||255 msblk->bytes_used > bdev_nr_bytes(sb->s_bdev))256 goto failed_mount;257 258 /* Check block size for sanity */259 msblk->block_size = le32_to_cpu(sblk->block_size);260 if (msblk->block_size > SQUASHFS_FILE_MAX_SIZE)261 goto insanity;262 263 /*264 * Check the system page size is not larger than the filesystem265 * block size (by default 128K). This is currently not supported.266 */267 if (PAGE_SIZE > msblk->block_size) {268 errorf(fc, "Page size > filesystem block size (%d). This is "269 "currently not supported!", msblk->block_size);270 goto failed_mount;271 }272 273 /* Check block log for sanity */274 msblk->block_log = le16_to_cpu(sblk->block_log);275 if (msblk->block_log > SQUASHFS_FILE_MAX_LOG)276 goto failed_mount;277 278 /* Check that block_size and block_log match */279 if (msblk->block_size != (1 << msblk->block_log))280 goto insanity;281 282 /* Check the root inode for sanity */283 root_inode = le64_to_cpu(sblk->root_inode);284 if (SQUASHFS_INODE_OFFSET(root_inode) > SQUASHFS_METADATA_SIZE)285 goto insanity;286 287 msblk->inode_table = le64_to_cpu(sblk->inode_table_start);288 msblk->directory_table = le64_to_cpu(sblk->directory_table_start);289 msblk->inodes = le32_to_cpu(sblk->inodes);290 msblk->fragments = le32_to_cpu(sblk->fragments);291 msblk->ids = le16_to_cpu(sblk->no_ids);292 flags = le16_to_cpu(sblk->flags);293 294 TRACE("Found valid superblock on %pg\n", sb->s_bdev);295 TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(flags)296 ? "un" : "");297 TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(flags)298 ? "un" : "");299 TRACE("Filesystem size %lld bytes\n", msblk->bytes_used);300 TRACE("Block size %d\n", msblk->block_size);301 TRACE("Number of inodes %d\n", msblk->inodes);302 TRACE("Number of fragments %d\n", msblk->fragments);303 TRACE("Number of ids %d\n", msblk->ids);304 TRACE("sblk->inode_table_start %llx\n", msblk->inode_table);305 TRACE("sblk->directory_table_start %llx\n", msblk->directory_table);306 TRACE("sblk->fragment_table_start %llx\n",307 (u64) le64_to_cpu(sblk->fragment_table_start));308 TRACE("sblk->id_table_start %llx\n",309 (u64) le64_to_cpu(sblk->id_table_start));310 311 sb->s_maxbytes = MAX_LFS_FILESIZE;312 sb->s_time_min = 0;313 sb->s_time_max = U32_MAX;314 sb->s_flags |= SB_RDONLY;315 sb->s_op = &squashfs_super_ops;316 317 err = -ENOMEM;318 319 msblk->block_cache = squashfs_cache_init("metadata",320 SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE);321 if (msblk->block_cache == NULL)322 goto failed_mount;323 324 /* Allocate read_page block */325 msblk->read_page = squashfs_cache_init("data",326 msblk->max_thread_num, msblk->block_size);327 if (msblk->read_page == NULL) {328 errorf(fc, "Failed to allocate read_page block");329 goto failed_mount;330 }331 332 if (msblk->devblksize == PAGE_SIZE) {333 struct inode *cache = new_inode(sb);334 335 if (cache == NULL)336 goto failed_mount;337 338 set_nlink(cache, 1);339 cache->i_size = OFFSET_MAX;340 mapping_set_gfp_mask(cache->i_mapping, GFP_NOFS);341 342 msblk->cache_mapping = cache->i_mapping;343 }344 345 msblk->stream = squashfs_decompressor_setup(sb, flags);346 if (IS_ERR(msblk->stream)) {347 err = PTR_ERR(msblk->stream);348 msblk->stream = NULL;349 goto insanity;350 }351 352 /* Handle xattrs */353 sb->s_xattr = squashfs_xattr_handlers;354 xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start);355 if (xattr_id_table_start == SQUASHFS_INVALID_BLK) {356 next_table = msblk->bytes_used;357 goto allocate_id_index_table;358 }359 360 /* Allocate and read xattr id lookup table */361 msblk->xattr_id_table = squashfs_read_xattr_id_table(sb,362 xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids);363 if (IS_ERR(msblk->xattr_id_table)) {364 errorf(fc, "unable to read xattr id index table");365 err = PTR_ERR(msblk->xattr_id_table);366 msblk->xattr_id_table = NULL;367 if (err != -ENOTSUPP)368 goto failed_mount;369 }370 next_table = msblk->xattr_table;371 372allocate_id_index_table:373 /* Allocate and read id index table */374 msblk->id_table = squashfs_read_id_index_table(sb,375 le64_to_cpu(sblk->id_table_start), next_table, msblk->ids);376 if (IS_ERR(msblk->id_table)) {377 errorf(fc, "unable to read id index table");378 err = PTR_ERR(msblk->id_table);379 msblk->id_table = NULL;380 goto failed_mount;381 }382 next_table = le64_to_cpu(msblk->id_table[0]);383 384 /* Handle inode lookup table */385 lookup_table_start = le64_to_cpu(sblk->lookup_table_start);386 if (lookup_table_start == SQUASHFS_INVALID_BLK)387 goto handle_fragments;388 389 /* Allocate and read inode lookup table */390 msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb,391 lookup_table_start, next_table, msblk->inodes);392 if (IS_ERR(msblk->inode_lookup_table)) {393 errorf(fc, "unable to read inode lookup table");394 err = PTR_ERR(msblk->inode_lookup_table);395 msblk->inode_lookup_table = NULL;396 goto failed_mount;397 }398 next_table = le64_to_cpu(msblk->inode_lookup_table[0]);399 400 sb->s_export_op = &squashfs_export_ops;401 402handle_fragments:403 fragments = msblk->fragments;404 if (fragments == 0)405 goto check_directory_table;406 407 msblk->fragment_cache = squashfs_cache_init("fragment",408 SQUASHFS_CACHED_FRAGMENTS, msblk->block_size);409 if (msblk->fragment_cache == NULL) {410 err = -ENOMEM;411 goto failed_mount;412 }413 414 /* Allocate and read fragment index table */415 msblk->fragment_index = squashfs_read_fragment_index_table(sb,416 le64_to_cpu(sblk->fragment_table_start), next_table, fragments);417 if (IS_ERR(msblk->fragment_index)) {418 errorf(fc, "unable to read fragment index table");419 err = PTR_ERR(msblk->fragment_index);420 msblk->fragment_index = NULL;421 goto failed_mount;422 }423 next_table = le64_to_cpu(msblk->fragment_index[0]);424 425check_directory_table:426 /* Sanity check directory_table */427 if (msblk->directory_table > next_table) {428 err = -EINVAL;429 goto insanity;430 }431 432 /* Sanity check inode_table */433 if (msblk->inode_table >= msblk->directory_table) {434 err = -EINVAL;435 goto insanity;436 }437 438 /* allocate root */439 root = new_inode(sb);440 if (!root) {441 err = -ENOMEM;442 goto failed_mount;443 }444 445 err = squashfs_read_inode(root, root_inode);446 if (err) {447 make_bad_inode(root);448 iput(root);449 goto failed_mount;450 }451 insert_inode_hash(root);452 453 sb->s_root = d_make_root(root);454 if (sb->s_root == NULL) {455 ERROR("Root inode create failed\n");456 err = -ENOMEM;457 goto failed_mount;458 }459 460 TRACE("Leaving squashfs_fill_super\n");461 kfree(sblk);462 return 0;463 464insanity:465 errorf(fc, "squashfs image failed sanity check");466failed_mount:467 squashfs_cache_delete(msblk->block_cache);468 squashfs_cache_delete(msblk->fragment_cache);469 squashfs_cache_delete(msblk->read_page);470 if (msblk->cache_mapping)471 iput(msblk->cache_mapping->host);472 msblk->thread_ops->destroy(msblk);473 kfree(msblk->inode_lookup_table);474 kfree(msblk->fragment_index);475 kfree(msblk->id_table);476 kfree(msblk->xattr_id_table);477 kfree(sb->s_fs_info);478 sb->s_fs_info = NULL;479 kfree(sblk);480 return err;481}482 483static int squashfs_get_tree(struct fs_context *fc)484{485 return get_tree_bdev(fc, squashfs_fill_super);486}487 488static int squashfs_reconfigure(struct fs_context *fc)489{490 struct super_block *sb = fc->root->d_sb;491 struct squashfs_sb_info *msblk = sb->s_fs_info;492 struct squashfs_mount_opts *opts = fc->fs_private;493 494 sync_filesystem(fc->root->d_sb);495 fc->sb_flags |= SB_RDONLY;496 497 msblk->panic_on_errors = (opts->errors == Opt_errors_panic);498 499 return 0;500}501 502static void squashfs_free_fs_context(struct fs_context *fc)503{504 kfree(fc->fs_private);505}506 507static const struct fs_context_operations squashfs_context_ops = {508 .get_tree = squashfs_get_tree,509 .free = squashfs_free_fs_context,510 .parse_param = squashfs_parse_param,511 .reconfigure = squashfs_reconfigure,512};513 514static int squashfs_show_options(struct seq_file *s, struct dentry *root)515{516 struct super_block *sb = root->d_sb;517 struct squashfs_sb_info *msblk = sb->s_fs_info;518 519 if (msblk->panic_on_errors)520 seq_puts(s, ",errors=panic");521 else522 seq_puts(s, ",errors=continue");523 524#ifdef CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT525 if (msblk->thread_ops == &squashfs_decompressor_single) {526 seq_puts(s, ",threads=single");527 return 0;528 }529 if (msblk->thread_ops == &squashfs_decompressor_percpu) {530 seq_puts(s, ",threads=percpu");531 return 0;532 }533#endif534#ifdef CONFIG_SQUASHFS_MOUNT_DECOMP_THREADS535 seq_printf(s, ",threads=%d", msblk->max_thread_num);536#endif537 return 0;538}539 540static int squashfs_init_fs_context(struct fs_context *fc)541{542 struct squashfs_mount_opts *opts;543 544 opts = kzalloc(sizeof(*opts), GFP_KERNEL);545 if (!opts)546 return -ENOMEM;547 548#ifdef CONFIG_SQUASHFS_DECOMP_SINGLE549 opts->thread_ops = &squashfs_decompressor_single;550#elif defined(CONFIG_SQUASHFS_DECOMP_MULTI)551 opts->thread_ops = &squashfs_decompressor_multi;552#elif defined(CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU)553 opts->thread_ops = &squashfs_decompressor_percpu;554#else555#error "fail: unknown squashfs decompression thread mode?"556#endif557 opts->thread_num = 0;558 fc->fs_private = opts;559 fc->ops = &squashfs_context_ops;560 return 0;561}562 563static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)564{565 struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info;566 u64 id = huge_encode_dev(dentry->d_sb->s_bdev->bd_dev);567 568 TRACE("Entered squashfs_statfs\n");569 570 buf->f_type = SQUASHFS_MAGIC;571 buf->f_bsize = msblk->block_size;572 buf->f_blocks = ((msblk->bytes_used - 1) >> msblk->block_log) + 1;573 buf->f_bfree = buf->f_bavail = 0;574 buf->f_files = msblk->inodes;575 buf->f_ffree = 0;576 buf->f_namelen = SQUASHFS_NAME_LEN;577 buf->f_fsid = u64_to_fsid(id);578 579 return 0;580}581 582 583static void squashfs_put_super(struct super_block *sb)584{585 if (sb->s_fs_info) {586 struct squashfs_sb_info *sbi = sb->s_fs_info;587 squashfs_cache_delete(sbi->block_cache);588 squashfs_cache_delete(sbi->fragment_cache);589 squashfs_cache_delete(sbi->read_page);590 if (sbi->cache_mapping)591 iput(sbi->cache_mapping->host);592 sbi->thread_ops->destroy(sbi);593 kfree(sbi->id_table);594 kfree(sbi->fragment_index);595 kfree(sbi->meta_index);596 kfree(sbi->inode_lookup_table);597 kfree(sbi->xattr_id_table);598 kfree(sb->s_fs_info);599 sb->s_fs_info = NULL;600 }601}602 603static struct kmem_cache *squashfs_inode_cachep;604 605 606static void init_once(void *foo)607{608 struct squashfs_inode_info *ei = foo;609 610 inode_init_once(&ei->vfs_inode);611}612 613 614static int __init init_inodecache(void)615{616 squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache",617 sizeof(struct squashfs_inode_info), 0,618 SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_ACCOUNT,619 init_once);620 621 return squashfs_inode_cachep ? 0 : -ENOMEM;622}623 624 625static void destroy_inodecache(void)626{627 /*628 * Make sure all delayed rcu free inodes are flushed before we629 * destroy cache.630 */631 rcu_barrier();632 kmem_cache_destroy(squashfs_inode_cachep);633}634 635 636static int __init init_squashfs_fs(void)637{638 int err = init_inodecache();639 640 if (err)641 return err;642 643 err = register_filesystem(&squashfs_fs_type);644 if (err) {645 destroy_inodecache();646 return err;647 }648 649 pr_info("version 4.0 (2009/01/31) Phillip Lougher\n");650 651 return 0;652}653 654 655static void __exit exit_squashfs_fs(void)656{657 unregister_filesystem(&squashfs_fs_type);658 destroy_inodecache();659}660 661 662static struct inode *squashfs_alloc_inode(struct super_block *sb)663{664 struct squashfs_inode_info *ei =665 alloc_inode_sb(sb, squashfs_inode_cachep, GFP_KERNEL);666 667 return ei ? &ei->vfs_inode : NULL;668}669 670 671static void squashfs_free_inode(struct inode *inode)672{673 kmem_cache_free(squashfs_inode_cachep, squashfs_i(inode));674}675 676static struct file_system_type squashfs_fs_type = {677 .owner = THIS_MODULE,678 .name = "squashfs",679 .init_fs_context = squashfs_init_fs_context,680 .parameters = squashfs_fs_parameters,681 .kill_sb = kill_block_super,682 .fs_flags = FS_REQUIRES_DEV | FS_ALLOW_IDMAP,683};684MODULE_ALIAS_FS("squashfs");685 686static const struct super_operations squashfs_super_ops = {687 .alloc_inode = squashfs_alloc_inode,688 .free_inode = squashfs_free_inode,689 .statfs = squashfs_statfs,690 .put_super = squashfs_put_super,691 .show_options = squashfs_show_options,692};693 694module_init(init_squashfs_fs);695module_exit(exit_squashfs_fs);696MODULE_DESCRIPTION("squashfs 4.0, a compressed read-only filesystem");697MODULE_AUTHOR("Phillip Lougher <phillip@squashfs.org.uk>");698MODULE_LICENSE("GPL");699