super.c revision f38a2e88af0e3af3446422780625132615d9c8b4
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 /* 100 * msblk->bytes_used is checked in squashfs_read_data to ensure reads 101 * are not beyond filesystem end. But as we're using squashfs_read_data 102 * here to read the superblock (including the value of 103 * bytes_used) we need to set it to an initial sensible dummy value 104 */ 105 msblk->bytes_used = sizeof(struct squashfs_super_block); 106 if (!squashfs_read_data(s, sblk, SQUASHFS_START, 107 sizeof(struct squashfs_super_block) | 108 SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, 109 sizeof(struct squashfs_super_block))) { 110 SERROR("unable to read squashfs_super_block\n"); 111 goto failed_mount; 112 } 113 114 /* Check it is a SQUASHFS superblock */ 115 s->s_magic = le32_to_cpu(sblk->s_magic); 116 if (s->s_magic != SQUASHFS_MAGIC) { 117 SERROR("Can't find a SQUASHFS superblock on %s\n", 118 bdevname(s->s_bdev, b)); 119 goto failed_mount; 120 } 121 122 /* Check the MAJOR & MINOR versions */ 123 if (!supported_squashfs_filesystem(le16_to_cpu(sblk->s_major), 124 le16_to_cpu(sblk->s_minor), silent)) 125 goto failed_mount; 126 127 /* Check the filesystem does not extend beyond the end of the 128 block device */ 129 msblk->bytes_used = le64_to_cpu(sblk->bytes_used); 130 if (msblk->bytes_used < 0 || msblk->bytes_used > 131 i_size_read(s->s_bdev->bd_inode)) 132 goto failed_mount; 133 134 /* Check block size for sanity */ 135 msblk->block_size = le32_to_cpu(sblk->block_size); 136 if (msblk->block_size > SQUASHFS_FILE_SIZE) 137 goto failed_mount; 138 139 msblk->block_log = le16_to_cpu(sblk->block_log); 140 if (msblk->block_log > SQUASHFS_FILE_LOG) 141 goto failed_mount; 142 143 /* Check the root inode for sanity */ 144 root_inode = le64_to_cpu(sblk->root_inode); 145 if (SQUASHFS_INODE_OFFSET(root_inode) > SQUASHFS_METADATA_SIZE) 146 goto failed_mount; 147 148 msblk->inode_table_start = le64_to_cpu(sblk->inode_table_start); 149 msblk->directory_table_start = le64_to_cpu(sblk->directory_table_start); 150 msblk->inodes = le32_to_cpu(sblk->inodes); 151 flags = le16_to_cpu(sblk->flags); 152 153 TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b)); 154 TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(flags) 155 ? "un" : ""); 156 TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(flags) 157 ? "un" : ""); 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", msblk->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 le64_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, SQUASHFS_METADATA_SIZE, 0); 176 if (msblk->block_cache == NULL) 177 goto failed_mount; 178 179 /* Allocate read_page block */ 180 msblk->read_page = vmalloc(msblk->block_size); 181 if (msblk->read_page == NULL) { 182 ERROR("Failed to allocate read_page block\n"); 183 goto failed_mount; 184 } 185 186 /* Allocate and read id index table */ 187 msblk->id_table = read_id_index_table(s, 188 le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids)); 189 if (msblk->id_table == NULL) 190 goto failed_mount; 191 192 fragments = le32_to_cpu(sblk->fragments); 193 if (fragments == 0) 194 goto allocate_lookup_table; 195 196 msblk->fragment_cache = squashfs_cache_init("fragment", 197 SQUASHFS_CACHED_FRAGMENTS, msblk->block_size, 1); 198 if (msblk->fragment_cache == NULL) 199 goto failed_mount; 200 201 /* Allocate and read fragment index table */ 202 msblk->fragment_index = read_fragment_index_table(s, 203 le64_to_cpu(sblk->fragment_table_start), fragments); 204 if (msblk->fragment_index == NULL) 205 goto failed_mount; 206 207allocate_lookup_table: 208 lookup_table_start = le64_to_cpu(sblk->lookup_table_start); 209 if (lookup_table_start == SQUASHFS_INVALID_BLK) 210 goto allocate_root; 211 212 /* Allocate and read inode lookup table */ 213 msblk->inode_lookup_table = read_inode_lookup_table(s, 214 lookup_table_start, msblk->inodes); 215 if (msblk->inode_lookup_table == NULL) 216 goto failed_mount; 217 218 s->s_export_op = &squashfs_export_ops; 219 220allocate_root: 221 root = new_inode(s); 222 if (squashfs_read_inode(root, root_inode) == 0) 223 goto failed_mount; 224 insert_inode_hash(root); 225 226 s->s_root = d_alloc_root(root); 227 if (s->s_root == NULL) { 228 ERROR("Root inode create failed\n"); 229 iput(root); 230 goto failed_mount; 231 } 232 233 TRACE("Leaving squashfs_fill_super\n"); 234 kfree(sblk); 235 return 0; 236 237failed_mount: 238 squashfs_cache_delete(msblk->block_cache); 239 squashfs_cache_delete(msblk->fragment_cache); 240 kfree(msblk->inode_lookup_table); 241 kfree(msblk->fragment_index); 242 kfree(msblk->id_table); 243 vfree(msblk->read_page); 244 vfree(msblk->stream.workspace); 245 kfree(s->s_fs_info); 246 s->s_fs_info = NULL; 247 kfree(sblk); 248 return -EINVAL; 249 250failure: 251 vfree(msblk->stream.workspace); 252 kfree(s->s_fs_info); 253 s->s_fs_info = NULL; 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 327 return squashfs_inode_cachep ? 0 : -ENOMEM; 328} 329 330 331static void destroy_inodecache(void) 332{ 333 kmem_cache_destroy(squashfs_inode_cachep); 334} 335 336 337static int __init init_squashfs_fs(void) 338{ 339 int err = init_inodecache(); 340 341 if (err) 342 goto out; 343 344 err = register_filesystem(&squashfs_fs_type); 345 if (err) { 346 destroy_inodecache(); 347 goto out; 348 } 349 350 printk(KERN_INFO "squashfs: version 4.0-CVS (2008/10/14) " 351 "Phillip Lougher\n"); 352 353out: 354 return err; 355} 356 357 358static void __exit exit_squashfs_fs(void) 359{ 360 unregister_filesystem(&squashfs_fs_type); 361 destroy_inodecache(); 362} 363 364 365static struct inode *squashfs_alloc_inode(struct super_block *sb) 366{ 367 struct squashfs_inode_info *ei = 368 kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL); 369 370 return ei ? &ei->vfs_inode : NULL; 371} 372 373 374static void squashfs_destroy_inode(struct inode *inode) 375{ 376 kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode)); 377} 378 379 380static struct file_system_type squashfs_fs_type = { 381 .owner = THIS_MODULE, 382 .name = "squashfs", 383 .get_sb = squashfs_get_sb, 384 .kill_sb = kill_block_super, 385 .fs_flags = FS_REQUIRES_DEV 386}; 387 388static struct super_operations squashfs_super_ops = { 389 .alloc_inode = squashfs_alloc_inode, 390 .destroy_inode = squashfs_destroy_inode, 391 .statfs = squashfs_statfs, 392 .put_super = squashfs_put_super, 393 .remount_fs = squashfs_remount 394}; 395 396module_init(init_squashfs_fs); 397module_exit(exit_squashfs_fs); 398MODULE_DESCRIPTION("squashfs 4.0-CVS, a compressed read-only filesystem"); 399MODULE_AUTHOR("Phillip Lougher <phillip@lougher.demon.co.uk>"); 400MODULE_LICENSE("GPL"); 401