super.c revision bff5ece68d8d8e60b95c16c60db5eae46b230433
1/* 2 * Squashfs - a compressed read only filesystem for Linux 3 * 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 5 * Phillip Lougher <phillip@lougher.demon.co.uk> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2, 10 * or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20 * 21 * super.c 22 */ 23 24#include <linux/fs.h> 25#include <linux/vfs.h> 26#include <linux/slab.h> 27#include <linux/vmalloc.h> 28#include <linux/mutex.h> 29#include <linux/pagemap.h> 30#include <linux/init.h> 31#include <linux/module.h> 32#include <linux/zlib.h> 33#include <linux/squashfs_fs.h> 34#include <linux/squashfs_fs_sb.h> 35#include <linux/squashfs_fs_i.h> 36 37#include "squashfs.h" 38 39static struct file_system_type squashfs_fs_type; 40static struct super_operations squashfs_super_ops; 41 42static int supported_squashfs_filesystem(short major, short minor, int silent) 43{ 44 if (major < SQUASHFS_MAJOR) { 45 SERROR("Major/Minor mismatch, older Squashfs %d.%d filesystems " 46 "are unsupported\n", major, minor); 47 return 0; 48 } else if (major > SQUASHFS_MAJOR || minor > SQUASHFS_MINOR) { 49 SERROR("Major/Minor mismatch, trying to mount newer %d.%d " 50 "filesystem\n", major, minor); 51 SERROR("Please update your kernel\n"); 52 return 0; 53 } 54 55 return 1; 56} 57 58 59static int squashfs_fill_super(struct super_block *s, void *data, int silent) 60{ 61 struct squashfs_sb_info *msblk; 62 struct squashfs_super_block *sblk = NULL; 63 char b[BDEVNAME_SIZE]; 64 struct inode *root; 65 long long root_inode; 66 unsigned short flags; 67 unsigned int fragments; 68 long long lookup_table_start; 69 70 71 TRACE("Entered squashfs_fill_superblock\n"); 72 73 s->s_fs_info = kzalloc(sizeof(struct squashfs_sb_info), GFP_KERNEL); 74 if (s->s_fs_info == NULL) { 75 ERROR("Failed to allocate squashfs_sb_info\n"); 76 goto failure2; 77 } 78 msblk = s->s_fs_info; 79 80 msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize()); 81 if (msblk->stream.workspace == NULL) { 82 ERROR("Failed to allocate zlib workspace\n"); 83 goto failure; 84 } 85 86 sblk = kzalloc(sizeof(struct squashfs_super_block), GFP_KERNEL); 87 if (sblk == NULL) { 88 ERROR("Failed to allocate squashfs_super_block\n"); 89 goto failure; 90 } 91 92 msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE); 93 msblk->devblksize_log2 = ffz(~msblk->devblksize); 94 95 mutex_init(&msblk->read_data_mutex); 96 mutex_init(&msblk->read_page_mutex); 97 mutex_init(&msblk->meta_index_mutex); 98 99 /* msblk->bytes_used is checked in squashfs_read_data to ensure reads 100 * are not beyond filesystem end. As we're using squashfs_read_data to 101 * read sblk here, first set sblk->bytes_used to a useful value 102 */ 103 msblk->bytes_used = sizeof(struct squashfs_super_block); 104 if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START, 105 sizeof(struct squashfs_super_block) | 106 SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, 107 sizeof(struct squashfs_super_block))) { 108 SERROR("unable to read squashfs_super_block\n"); 109 goto failed_mount; 110 } 111 112 /* Check it is a SQUASHFS superblock */ 113 s->s_magic = le32_to_cpu(sblk->s_magic); 114 if (s->s_magic != SQUASHFS_MAGIC) { 115 SERROR("Can't find a SQUASHFS superblock on %s\n", 116 bdevname(s->s_bdev, b)); 117 goto failed_mount; 118 } 119 120 /* Check the MAJOR & MINOR versions */ 121 if (!supported_squashfs_filesystem(le16_to_cpu(sblk->s_major), 122 le16_to_cpu(sblk->s_minor), silent)) 123 goto failed_mount; 124 125 /* Check the filesystem does not extend beyond the end of the 126 block device */ 127 msblk->bytes_used = le64_to_cpu(sblk->bytes_used); 128 if (msblk->bytes_used < 0 || msblk->bytes_used > 129 i_size_read(s->s_bdev->bd_inode)) 130 goto failed_mount; 131 132 /* Check block size for sanity */ 133 msblk->block_size = le32_to_cpu(sblk->block_size); 134 if (msblk->block_size > SQUASHFS_FILE_SIZE) 135 goto failed_mount; 136 137 msblk->block_log = le16_to_cpu(sblk->block_log); 138 if (msblk->block_log > SQUASHFS_FILE_LOG) 139 goto failed_mount; 140 141 /* Check the root inode for sanity */ 142 root_inode = le64_to_cpu(sblk->root_inode); 143 if (SQUASHFS_INODE_OFFSET(root_inode) > SQUASHFS_METADATA_SIZE) 144 goto failed_mount; 145 146 msblk->inode_table_start = le64_to_cpu(sblk->inode_table_start); 147 msblk->directory_table_start = le64_to_cpu(sblk->directory_table_start); 148 msblk->inodes = le32_to_cpu(sblk->inodes); 149 flags = le16_to_cpu(sblk->flags); 150 151 TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b)); 152 TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(flags) 153 ? "un" : ""); 154 TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(flags) 155 ? "un" : ""); 156 TRACE("Check data is %spresent in the filesystem\n", 157 SQUASHFS_CHECK_DATA(flags) ? "" : "not "); 158 TRACE("Filesystem size %lld bytes\n", msblk->bytes_used); 159 TRACE("Block size %d\n", msblk->block_size); 160 TRACE("Number of inodes %d\n", inodes); 161 TRACE("Number of fragments %d\n", le32_to_cpu(sblk->fragments)); 162 TRACE("Number of ids %d\n", le16_to_cpu(sblk->no_ids)); 163 TRACE("sblk->inode_table_start %llx\n", msblk->inode_table_start); 164 TRACE("sblk->directory_table_start %llx\n", 165 msblk->directory_table_start); 166 TRACE("sblk->fragment_table_start %llx\n", 167 le32_to_cpu(sblk->fragment_table_start)); 168 TRACE("sblk->id_table_start %llx\n", le64_to_cpu(sblk->id_table_start)); 169 170 s->s_maxbytes = MAX_LFS_FILESIZE; 171 s->s_flags |= MS_RDONLY; 172 s->s_op = &squashfs_super_ops; 173 174 msblk->block_cache = squashfs_cache_init("metadata", 175 SQUASHFS_CACHED_BLKS, 176 SQUASHFS_METADATA_SIZE, 0); 177 if (msblk->block_cache == NULL) 178 goto failed_mount; 179 180 /* Allocate read_page block */ 181 msblk->read_page = vmalloc(msblk->block_size); 182 if (msblk->read_page == NULL) { 183 ERROR("Failed to allocate read_page block\n"); 184 goto failed_mount; 185 } 186 187 /* Allocate and read id index table */ 188 msblk->id_table = read_id_index_table(s, 189 le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids)); 190 if (msblk->id_table == NULL) 191 goto failed_mount; 192 193 fragments = le32_to_cpu(sblk->fragments); 194 if (fragments == 0) 195 goto allocate_lookup_table; 196 197 msblk->fragment_cache = squashfs_cache_init("fragment", 198 SQUASHFS_CACHED_FRAGMENTS, msblk->block_size, 1); 199 if (msblk->fragment_cache == NULL) 200 goto failed_mount; 201 202 /* Allocate and read fragment index table */ 203 read_fragment_index_table(s, le64_to_cpu(sblk->fragment_table_start), 204 fragments); 205 if (msblk->fragment_index == NULL) 206 goto failed_mount; 207 208allocate_lookup_table: 209 lookup_table_start = le64_to_cpu(sblk->lookup_table_start); 210 if (lookup_table_start == SQUASHFS_INVALID_BLK) 211 goto allocate_root; 212 213 /* Allocate and read inode lookup table */ 214 msblk->inode_lookup_table = read_inode_lookup_table(s, 215 lookup_table_start, msblk->inodes); 216 if (msblk->inode_lookup_table == NULL) 217 goto failed_mount; 218 219 s->s_export_op = &squashfs_export_ops; 220 221allocate_root: 222 root = new_inode(s); 223 if (squashfs_read_inode(root, root_inode) == 0) 224 goto failed_mount; 225 insert_inode_hash(root); 226 227 s->s_root = d_alloc_root(root); 228 if (s->s_root == NULL) { 229 ERROR("Root inode create failed\n"); 230 iput(root); 231 goto failed_mount; 232 } 233 234 TRACE("Leaving squashfs_fill_super\n"); 235 kfree(sblk); 236 return 0; 237 238failed_mount: 239 kfree(msblk->inode_lookup_table); 240 kfree(msblk->fragment_index); 241 squashfs_cache_delete(msblk->fragment_cache); 242 kfree(msblk->id_table); 243 vfree(msblk->read_page); 244 squashfs_cache_delete(msblk->block_cache); 245 kfree(sblk); 246 vfree(msblk->stream.workspace); 247 kfree(s->s_fs_info); 248 s->s_fs_info = NULL; 249 return -EINVAL; 250 251failure: 252 vfree(msblk->stream.workspace); 253 kfree(s->s_fs_info); 254failure2: 255 return -ENOMEM; 256} 257 258 259static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) 260{ 261 struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info; 262 263 TRACE("Entered squashfs_statfs\n"); 264 265 buf->f_type = SQUASHFS_MAGIC; 266 buf->f_bsize = msblk->block_size; 267 buf->f_blocks = ((msblk->bytes_used - 1) >> msblk->block_log) + 1; 268 buf->f_bfree = buf->f_bavail = 0; 269 buf->f_files = msblk->inodes; 270 buf->f_ffree = 0; 271 buf->f_namelen = SQUASHFS_NAME_LEN; 272 273 return 0; 274} 275 276 277static int squashfs_remount(struct super_block *s, int *flags, char *data) 278{ 279 *flags |= MS_RDONLY; 280 return 0; 281} 282 283 284static void squashfs_put_super(struct super_block *s) 285{ 286 if (s->s_fs_info) { 287 struct squashfs_sb_info *sbi = s->s_fs_info; 288 squashfs_cache_delete(sbi->block_cache); 289 squashfs_cache_delete(sbi->fragment_cache); 290 vfree(sbi->read_page); 291 kfree(sbi->id_table); 292 kfree(sbi->fragment_index); 293 kfree(sbi->meta_index); 294 vfree(sbi->stream.workspace); 295 kfree(s->s_fs_info); 296 s->s_fs_info = NULL; 297 } 298} 299 300 301static int squashfs_get_sb(struct file_system_type *fs_type, int flags, 302 const char *dev_name, void *data, 303 struct vfsmount *mnt) 304{ 305 return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, 306 mnt); 307} 308 309 310static struct kmem_cache *squashfs_inode_cachep; 311 312 313static void init_once(void *foo) 314{ 315 struct squashfs_inode_info *ei = foo; 316 317 inode_init_once(&ei->vfs_inode); 318} 319 320 321static int __init init_inodecache(void) 322{ 323 squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache", 324 sizeof(struct squashfs_inode_info), 0, 325 SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, init_once); 326 if (squashfs_inode_cachep == NULL) 327 return -ENOMEM; 328 return 0; 329} 330 331 332static void destroy_inodecache(void) 333{ 334 kmem_cache_destroy(squashfs_inode_cachep); 335} 336 337 338static int __init init_squashfs_fs(void) 339{ 340 int err = init_inodecache(); 341 if (err) 342 goto out; 343 344 printk(KERN_INFO "squashfs: version 4.0-CVS (2008/10/04) " 345 "Phillip Lougher\n"); 346 347 err = register_filesystem(&squashfs_fs_type); 348 if (err) 349 destroy_inodecache(); 350 351out: 352 return err; 353} 354 355 356static void __exit exit_squashfs_fs(void) 357{ 358 unregister_filesystem(&squashfs_fs_type); 359 destroy_inodecache(); 360} 361 362 363static struct inode *squashfs_alloc_inode(struct super_block *sb) 364{ 365 struct squashfs_inode_info *ei; 366 ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL); 367 return ei ? &ei->vfs_inode : NULL; 368} 369 370 371static void squashfs_destroy_inode(struct inode *inode) 372{ 373 kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode)); 374} 375 376 377static struct file_system_type squashfs_fs_type = { 378 .owner = THIS_MODULE, 379 .name = "squashfs", 380 .get_sb = squashfs_get_sb, 381 .kill_sb = kill_block_super, 382 .fs_flags = FS_REQUIRES_DEV 383}; 384 385static struct super_operations squashfs_super_ops = { 386 .alloc_inode = squashfs_alloc_inode, 387 .destroy_inode = squashfs_destroy_inode, 388 .statfs = squashfs_statfs, 389 .put_super = squashfs_put_super, 390 .remount_fs = squashfs_remount 391}; 392 393module_init(init_squashfs_fs); 394module_exit(exit_squashfs_fs); 395MODULE_DESCRIPTION("squashfs 4.0-CVS, a compressed read-only filesystem"); 396MODULE_AUTHOR("Phillip Lougher <phillip@lougher.demon.co.uk>"); 397MODULE_LICENSE("GPL"); 398