1 From 59bc81578d57166e3a4c4626a679f3333739b4bb Mon Sep 17 00:00:00 2001
2 From: David-John Willis <John.Willis@Distant-earth.com>
3 Date: Mon, 21 Dec 2009 19:44:51 +0000
4 Subject: [PATCH 6/6] SquashFS: Backport SquashFS4 to our 2.6.27 tree.
9 fs/squashfs/Kconfig | 51 +++++
10 fs/squashfs/Makefile | 7 +
11 fs/squashfs/block.c | 270 +++++++++++++++++++++++
12 fs/squashfs/cache.c | 413 ++++++++++++++++++++++++++++++++++
13 fs/squashfs/dir.c | 235 ++++++++++++++++++++
14 fs/squashfs/export.c | 172 ++++++++++++++
15 fs/squashfs/file.c | 502 ++++++++++++++++++++++++++++++++++++++++++
16 fs/squashfs/fragment.c | 98 ++++++++
17 fs/squashfs/id.c | 94 ++++++++
18 fs/squashfs/inode.c | 348 +++++++++++++++++++++++++++++
19 fs/squashfs/namei.c | 242 ++++++++++++++++++++
20 fs/squashfs/squashfs.h | 90 ++++++++
21 fs/squashfs/squashfs_fs.h | 382 ++++++++++++++++++++++++++++++++
22 fs/squashfs/squashfs_fs_i.h | 45 ++++
23 fs/squashfs/squashfs_fs_sb.h | 76 +++++++
24 fs/squashfs/super.c | 454 ++++++++++++++++++++++++++++++++++++++
25 fs/squashfs/symlink.c | 118 ++++++++++
26 init/do_mounts_rd.c | 14 ++
27 20 files changed, 3614 insertions(+), 0 deletions(-)
28 create mode 100644 fs/squashfs/Kconfig
29 create mode 100644 fs/squashfs/Makefile
30 create mode 100644 fs/squashfs/block.c
31 create mode 100644 fs/squashfs/cache.c
32 create mode 100644 fs/squashfs/dir.c
33 create mode 100644 fs/squashfs/export.c
34 create mode 100644 fs/squashfs/file.c
35 create mode 100644 fs/squashfs/fragment.c
36 create mode 100644 fs/squashfs/id.c
37 create mode 100644 fs/squashfs/inode.c
38 create mode 100644 fs/squashfs/namei.c
39 create mode 100644 fs/squashfs/squashfs.h
40 create mode 100644 fs/squashfs/squashfs_fs.h
41 create mode 100644 fs/squashfs/squashfs_fs_i.h
42 create mode 100644 fs/squashfs/squashfs_fs_sb.h
43 create mode 100644 fs/squashfs/super.c
44 create mode 100644 fs/squashfs/symlink.c
46 diff --git a/fs/Kconfig b/fs/Kconfig
47 index abccb5d..bd989c0 100644
50 @@ -1348,6 +1348,8 @@ config CRAMFS
54 +source "fs/squashfs/Kconfig"
57 tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"
59 diff --git a/fs/Makefile b/fs/Makefile
60 index a1482a5..0871ab5 100644
63 @@ -74,6 +74,7 @@ obj-$(CONFIG_JBD) += jbd/
64 obj-$(CONFIG_JBD2) += jbd2/
65 obj-$(CONFIG_EXT2_FS) += ext2/
66 obj-$(CONFIG_CRAMFS) += cramfs/
67 +obj-$(CONFIG_SQUASHFS) += squashfs/
69 obj-$(CONFIG_HUGETLBFS) += hugetlbfs/
70 obj-$(CONFIG_CODA_FS) += coda/
71 diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig
73 index 0000000..25a00d1
75 +++ b/fs/squashfs/Kconfig
78 + tristate "SquashFS 4.0 - Squashed file system support"
82 + Saying Y here includes support for SquashFS 4.0 (a Compressed
83 + Read-Only File System). Squashfs is a highly compressed read-only
84 + filesystem for Linux. It uses zlib compression to compress both
85 + files, inodes and directories. Inodes in the system are very small
86 + and all blocks are packed to minimise data overhead. Block sizes
87 + greater than 4K are supported up to a maximum of 1 Mbytes (default
88 + block size 128K). SquashFS 4.0 supports 64 bit filesystems and files
89 + (larger than 4GB), full uid/gid information, hard links and
92 + Squashfs is intended for general read-only filesystem use, for
93 + archival use (i.e. in cases where a .tar.gz file may be used), and in
94 + embedded systems where low overhead is needed. Further information
95 + and tools are available from http://squashfs.sourceforge.net.
97 + If you want to compile this as a module ( = code which can be
98 + inserted in and removed from the running kernel whenever you want),
99 + say M here and read <file:Documentation/modules.txt>. The module
100 + will be called squashfs. Note that the root file system (the one
101 + containing the directory /) cannot be compiled as a module.
105 +config SQUASHFS_EMBEDDED
107 + bool "Additional option for memory-constrained systems"
108 + depends on SQUASHFS
111 + Saying Y here allows you to specify cache size.
115 +config SQUASHFS_FRAGMENT_CACHE_SIZE
116 + int "Number of fragments cached" if SQUASHFS_EMBEDDED
117 + depends on SQUASHFS
120 + By default SquashFS caches the last 3 fragments read from
121 + the filesystem. Increasing this amount may mean SquashFS
122 + has to re-read fragments less often from disk, at the expense
123 + of extra system memory. Decreasing this amount will mean
124 + SquashFS uses less memory at the expense of extra reads from disk.
126 + Note there must be at least one cached fragment. Anything
127 + much more than three will probably not make much difference.
128 diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile
130 index 0000000..70e3244
132 +++ b/fs/squashfs/Makefile
135 +# Makefile for the linux squashfs routines.
138 +obj-$(CONFIG_SQUASHFS) += squashfs.o
139 +squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
140 +squashfs-y += namei.o super.o symlink.o
141 diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c
143 index 0000000..2a79603
145 +++ b/fs/squashfs/block.c
148 + * Squashfs - a compressed read only filesystem for Linux
150 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
151 + * Phillip Lougher <phillip@lougher.demon.co.uk>
153 + * This program is free software; you can redistribute it and/or
154 + * modify it under the terms of the GNU General Public License
155 + * as published by the Free Software Foundation; either version 2,
156 + * or (at your option) any later version.
158 + * This program is distributed in the hope that it will be useful,
159 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
160 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
161 + * GNU General Public License for more details.
163 + * You should have received a copy of the GNU General Public License
164 + * along with this program; if not, write to the Free Software
165 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
171 + * This file implements the low-level routines to read and decompress
172 + * datablocks and metadata blocks.
175 +#include <linux/fs.h>
176 +#include <linux/vfs.h>
177 +#include <linux/slab.h>
178 +#include <linux/mutex.h>
179 +#include <linux/string.h>
180 +#include <linux/buffer_head.h>
181 +#include <linux/zlib.h>
183 +#include "squashfs_fs.h"
184 +#include "squashfs_fs_sb.h"
185 +#include "squashfs_fs_i.h"
186 +#include "squashfs.h"
189 + * Read the metadata block length, this is stored in the first two
190 + * bytes of the metadata block.
192 +static struct buffer_head *get_block_length(struct super_block *sb,
193 + u64 *cur_index, int *offset, int *length)
195 + struct squashfs_sb_info *msblk = sb->s_fs_info;
196 + struct buffer_head *bh;
198 + bh = sb_bread(sb, *cur_index);
202 + if (msblk->devblksize - *offset == 1) {
203 + *length = (unsigned char) bh->b_data[*offset];
205 + bh = sb_bread(sb, ++(*cur_index));
208 + *length |= (unsigned char) bh->b_data[0] << 8;
211 + *length = (unsigned char) bh->b_data[*offset] |
212 + (unsigned char) bh->b_data[*offset + 1] << 8;
221 + * Read and decompress a metadata block or datablock. Length is non-zero
222 + * if a datablock is being read (the size is stored elsewhere in the
223 + * filesystem), otherwise the length is obtained from the first two bytes of
224 + * the metadata block. A bit in the length field indicates if the block
225 + * is stored uncompressed in the filesystem (usually because compression
226 + * generated a larger block - this does occasionally happen with zlib).
228 +int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
229 + int length, u64 *next_index, int srclength, int pages)
231 + struct squashfs_sb_info *msblk = sb->s_fs_info;
232 + struct buffer_head **bh;
233 + int offset = index & ((1 << msblk->devblksize_log2) - 1);
234 + u64 cur_index = index >> msblk->devblksize_log2;
235 + int bytes, compressed, b = 0, k = 0, page = 0, avail;
238 + bh = kcalloc((msblk->block_size >> msblk->devblksize_log2) + 1,
239 + sizeof(*bh), GFP_KERNEL);
248 + compressed = SQUASHFS_COMPRESSED_BLOCK(length);
249 + length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length);
251 + *next_index = index + length;
253 + TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n",
254 + index, compressed ? "" : "un", length, srclength);
256 + if (length < 0 || length > srclength ||
257 + (index + length) > msblk->bytes_used)
260 + for (b = 0; bytes < length; b++, cur_index++) {
261 + bh[b] = sb_getblk(sb, cur_index);
263 + goto block_release;
264 + bytes += msblk->devblksize;
266 + ll_rw_block(READ, b, bh);
271 + if ((index + 2) > msblk->bytes_used)
274 + bh[0] = get_block_length(sb, &cur_index, &offset, &length);
279 + bytes = msblk->devblksize - offset;
280 + compressed = SQUASHFS_COMPRESSED(length);
281 + length = SQUASHFS_COMPRESSED_SIZE(length);
283 + *next_index = index + length + 2;
285 + TRACE("Block @ 0x%llx, %scompressed size %d\n", index,
286 + compressed ? "" : "un", length);
288 + if (length < 0 || length > srclength ||
289 + (index + length) > msblk->bytes_used)
290 + goto block_release;
292 + for (; bytes < length; b++) {
293 + bh[b] = sb_getblk(sb, ++cur_index);
295 + goto block_release;
296 + bytes += msblk->devblksize;
298 + ll_rw_block(READ, b - 1, bh + 1);
302 + int zlib_err = 0, zlib_init = 0;
305 + * Uncompress block.
308 + mutex_lock(&msblk->read_data_mutex);
310 + msblk->stream.avail_out = 0;
311 + msblk->stream.avail_in = 0;
315 + if (msblk->stream.avail_in == 0 && k < b) {
316 + avail = min(bytes, msblk->devblksize - offset);
318 + wait_on_buffer(bh[k]);
319 + if (!buffer_uptodate(bh[k]))
320 + goto release_mutex;
328 + msblk->stream.next_in = bh[k]->b_data + offset;
329 + msblk->stream.avail_in = avail;
333 + if (msblk->stream.avail_out == 0 && page < pages) {
334 + msblk->stream.next_out = buffer[page++];
335 + msblk->stream.avail_out = PAGE_CACHE_SIZE;
339 + zlib_err = zlib_inflateInit(&msblk->stream);
340 + if (zlib_err != Z_OK) {
341 + ERROR("zlib_inflateInit returned"
342 + " unexpected result 0x%x,"
343 + " srclength %d\n", zlib_err,
345 + goto release_mutex;
350 + zlib_err = zlib_inflate(&msblk->stream, Z_SYNC_FLUSH);
352 + if (msblk->stream.avail_in == 0 && k < b)
354 + } while (zlib_err == Z_OK);
356 + if (zlib_err != Z_STREAM_END) {
357 + ERROR("zlib_inflate error, data probably corrupt\n");
358 + goto release_mutex;
361 + zlib_err = zlib_inflateEnd(&msblk->stream);
362 + if (zlib_err != Z_OK) {
363 + ERROR("zlib_inflate error, data probably corrupt\n");
364 + goto release_mutex;
366 + length = msblk->stream.total_out;
367 + mutex_unlock(&msblk->read_data_mutex);
370 + * Block is uncompressed.
372 + int i, in, pg_offset = 0;
374 + for (i = 0; i < b; i++) {
375 + wait_on_buffer(bh[i]);
376 + if (!buffer_uptodate(bh[i]))
377 + goto block_release;
380 + for (bytes = length; k < b; k++) {
381 + in = min(bytes, msblk->devblksize - offset);
384 + if (pg_offset == PAGE_CACHE_SIZE) {
388 + avail = min_t(int, in, PAGE_CACHE_SIZE -
390 + memcpy(buffer[page] + pg_offset,
391 + bh[k]->b_data + offset, avail);
393 + pg_offset += avail;
405 + mutex_unlock(&msblk->read_data_mutex);
412 + ERROR("squashfs_read_data failed to read block 0x%llx\n",
413 + (unsigned long long) index);
417 diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c
419 index 0000000..40c98fa
421 +++ b/fs/squashfs/cache.c
424 + * Squashfs - a compressed read only filesystem for Linux
426 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
427 + * Phillip Lougher <phillip@lougher.demon.co.uk>
429 + * This program is free software; you can redistribute it and/or
430 + * modify it under the terms of the GNU General Public License
431 + * as published by the Free Software Foundation; either version 2,
432 + * or (at your option) any later version.
434 + * This program is distributed in the hope that it will be useful,
435 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
436 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
437 + * GNU General Public License for more details.
439 + * You should have received a copy of the GNU General Public License
440 + * along with this program; if not, write to the Free Software
441 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
447 + * Blocks in Squashfs are compressed. To avoid repeatedly decompressing
448 + * recently accessed data Squashfs uses two small metadata and fragment caches.
450 + * This file implements a generic cache implementation used for both caches,
451 + * plus functions layered ontop of the generic cache implementation to
452 + * access the metadata and fragment caches.
454 + * To avoid out of memory and fragmentation isssues with vmalloc the cache
455 + * uses sequences of kmalloced PAGE_CACHE_SIZE buffers.
457 + * It should be noted that the cache is not used for file datablocks, these
458 + * are decompressed and cached in the page-cache in the normal way. The
459 + * cache is only used to temporarily cache fragment and metadata blocks
460 + * which have been read as as a result of a metadata (i.e. inode or
461 + * directory) or fragment access. Because metadata and fragments are packed
462 + * together into blocks (to gain greater compression) the read of a particular
463 + * piece of metadata or fragment will retrieve other metadata/fragments which
464 + * have been packed with it, these because of locality-of-reference may be read
465 + * in the near future. Temporarily caching them ensures they are available for
466 + * near future access without requiring an additional read and decompress.
469 +#include <linux/fs.h>
470 +#include <linux/vfs.h>
471 +#include <linux/slab.h>
472 +#include <linux/vmalloc.h>
473 +#include <linux/sched.h>
474 +#include <linux/spinlock.h>
475 +#include <linux/wait.h>
476 +#include <linux/zlib.h>
477 +#include <linux/pagemap.h>
479 +#include "squashfs_fs.h"
480 +#include "squashfs_fs_sb.h"
481 +#include "squashfs_fs_i.h"
482 +#include "squashfs.h"
485 + * Look-up block in cache, and increment usage count. If not in cache, read
486 + * and decompress it from disk.
488 +struct squashfs_cache_entry *squashfs_cache_get(struct super_block *sb,
489 + struct squashfs_cache *cache, u64 block, int length)
492 + struct squashfs_cache_entry *entry;
494 + spin_lock(&cache->lock);
497 + for (i = 0; i < cache->entries; i++)
498 + if (cache->entry[i].block == block)
501 + if (i == cache->entries) {
503 + * Block not in cache, if all cache entries are used
504 + * go to sleep waiting for one to become available.
506 + if (cache->unused == 0) {
507 + cache->num_waiters++;
508 + spin_unlock(&cache->lock);
509 + wait_event(cache->wait_queue, cache->unused);
510 + spin_lock(&cache->lock);
511 + cache->num_waiters--;
516 + * At least one unused cache entry. A simple
517 + * round-robin strategy is used to choose the entry to
518 + * be evicted from the cache.
520 + i = cache->next_blk;
521 + for (n = 0; n < cache->entries; n++) {
522 + if (cache->entry[i].refcount == 0)
524 + i = (i + 1) % cache->entries;
527 + cache->next_blk = (i + 1) % cache->entries;
528 + entry = &cache->entry[i];
531 + * Initialise choosen cache entry, and fill it in from
535 + entry->block = block;
536 + entry->refcount = 1;
537 + entry->pending = 1;
538 + entry->num_waiters = 0;
540 + spin_unlock(&cache->lock);
542 + entry->length = squashfs_read_data(sb, entry->data,
543 + block, length, &entry->next_index,
544 + cache->block_size, cache->pages);
546 + spin_lock(&cache->lock);
548 + if (entry->length < 0)
549 + entry->error = entry->length;
551 + entry->pending = 0;
554 + * While filling this entry one or more other processes
555 + * have looked it up in the cache, and have slept
556 + * waiting for it to become available.
558 + if (entry->num_waiters) {
559 + spin_unlock(&cache->lock);
560 + wake_up_all(&entry->wait_queue);
562 + spin_unlock(&cache->lock);
568 + * Block already in cache. Increment refcount so it doesn't
569 + * get reused until we're finished with it, if it was
570 + * previously unused there's one less cache entry available
573 + entry = &cache->entry[i];
574 + if (entry->refcount == 0)
579 + * If the entry is currently being filled in by another process
580 + * go to sleep waiting for it to become available.
582 + if (entry->pending) {
583 + entry->num_waiters++;
584 + spin_unlock(&cache->lock);
585 + wait_event(entry->wait_queue, !entry->pending);
587 + spin_unlock(&cache->lock);
593 + TRACE("Got %s %d, start block %lld, refcount %d, error %d\n",
594 + cache->name, i, entry->block, entry->refcount, entry->error);
597 + ERROR("Unable to read %s cache entry [%llx]\n", cache->name,
604 + * Release cache entry, once usage count is zero it can be reused.
606 +void squashfs_cache_put(struct squashfs_cache_entry *entry)
608 + struct squashfs_cache *cache = entry->cache;
610 + spin_lock(&cache->lock);
612 + if (entry->refcount == 0) {
615 + * If there's any processes waiting for a block to become
616 + * available, wake one up.
618 + if (cache->num_waiters) {
619 + spin_unlock(&cache->lock);
620 + wake_up(&cache->wait_queue);
624 + spin_unlock(&cache->lock);
628 + * Delete cache reclaiming all kmalloced buffers.
630 +void squashfs_cache_delete(struct squashfs_cache *cache)
637 + for (i = 0; i < cache->entries; i++) {
638 + if (cache->entry[i].data) {
639 + for (j = 0; j < cache->pages; j++)
640 + kfree(cache->entry[i].data[j]);
641 + kfree(cache->entry[i].data);
645 + kfree(cache->entry);
651 + * Initialise cache allocating the specified number of entries, each of
652 + * size block_size. To avoid vmalloc fragmentation issues each entry
653 + * is allocated as a sequence of kmalloced PAGE_CACHE_SIZE buffers.
655 +struct squashfs_cache *squashfs_cache_init(char *name, int entries,
659 + struct squashfs_cache *cache = kzalloc(sizeof(*cache), GFP_KERNEL);
661 + if (cache == NULL) {
662 + ERROR("Failed to allocate %s cache\n", name);
666 + cache->entry = kcalloc(entries, sizeof(*(cache->entry)), GFP_KERNEL);
667 + if (cache->entry == NULL) {
668 + ERROR("Failed to allocate %s cache\n", name);
672 + cache->next_blk = 0;
673 + cache->unused = entries;
674 + cache->entries = entries;
675 + cache->block_size = block_size;
676 + cache->pages = block_size >> PAGE_CACHE_SHIFT;
677 + cache->pages = cache->pages ? cache->pages : 1;
678 + cache->name = name;
679 + cache->num_waiters = 0;
680 + spin_lock_init(&cache->lock);
681 + init_waitqueue_head(&cache->wait_queue);
683 + for (i = 0; i < entries; i++) {
684 + struct squashfs_cache_entry *entry = &cache->entry[i];
686 + init_waitqueue_head(&cache->entry[i].wait_queue);
687 + entry->cache = cache;
688 + entry->block = SQUASHFS_INVALID_BLK;
689 + entry->data = kcalloc(cache->pages, sizeof(void *), GFP_KERNEL);
690 + if (entry->data == NULL) {
691 + ERROR("Failed to allocate %s cache entry\n", name);
695 + for (j = 0; j < cache->pages; j++) {
696 + entry->data[j] = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
697 + if (entry->data[j] == NULL) {
698 + ERROR("Failed to allocate %s buffer\n", name);
707 + squashfs_cache_delete(cache);
713 + * Copy upto length bytes from cache entry to buffer starting at offset bytes
714 + * into the cache entry. If there's not length bytes then copy the number of
715 + * bytes available. In all cases return the number of bytes copied.
717 +int squashfs_copy_data(void *buffer, struct squashfs_cache_entry *entry,
718 + int offset, int length)
720 + int remaining = length;
724 + else if (buffer == NULL)
725 + return min(length, entry->length - offset);
727 + while (offset < entry->length) {
728 + void *buff = entry->data[offset / PAGE_CACHE_SIZE]
729 + + (offset % PAGE_CACHE_SIZE);
730 + int bytes = min_t(int, entry->length - offset,
731 + PAGE_CACHE_SIZE - (offset % PAGE_CACHE_SIZE));
733 + if (bytes >= remaining) {
734 + memcpy(buffer, buff, remaining);
739 + memcpy(buffer, buff, bytes);
741 + remaining -= bytes;
745 + return length - remaining;
750 + * Read length bytes from metadata position <block, offset> (block is the
751 + * start of the compressed block on disk, and offset is the offset into
752 + * the block once decompressed). Data is packed into consecutive blocks,
753 + * and length bytes may require reading more than one block.
755 +int squashfs_read_metadata(struct super_block *sb, void *buffer,
756 + u64 *block, int *offset, int length)
758 + struct squashfs_sb_info *msblk = sb->s_fs_info;
759 + int bytes, copied = length;
760 + struct squashfs_cache_entry *entry;
762 + TRACE("Entered squashfs_read_metadata [%llx:%x]\n", *block, *offset);
765 + entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0);
767 + return entry->error;
768 + else if (*offset >= entry->length)
771 + bytes = squashfs_copy_data(buffer, entry, *offset, length);
777 + if (*offset == entry->length) {
778 + *block = entry->next_index;
782 + squashfs_cache_put(entry);
790 + * Look-up in the fragmment cache the fragment located at <start_block> in the
791 + * filesystem. If necessary read and decompress it from disk.
793 +struct squashfs_cache_entry *squashfs_get_fragment(struct super_block *sb,
794 + u64 start_block, int length)
796 + struct squashfs_sb_info *msblk = sb->s_fs_info;
798 + return squashfs_cache_get(sb, msblk->fragment_cache, start_block,
804 + * Read and decompress the datablock located at <start_block> in the
805 + * filesystem. The cache is used here to avoid duplicating locking and
806 + * read/decompress code.
808 +struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *sb,
809 + u64 start_block, int length)
811 + struct squashfs_sb_info *msblk = sb->s_fs_info;
813 + return squashfs_cache_get(sb, msblk->read_page, start_block, length);
818 + * Read a filesystem table (uncompressed sequence of bytes) from disk
820 +int squashfs_read_table(struct super_block *sb, void *buffer, u64 block,
823 + int pages = (length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
825 + void **data = kcalloc(pages, sizeof(void *), GFP_KERNEL);
829 + for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE)
831 + res = squashfs_read_data(sb, data, block, length |
832 + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length, pages);
836 diff --git a/fs/squashfs/dir.c b/fs/squashfs/dir.c
838 index 0000000..566b0ea
840 +++ b/fs/squashfs/dir.c
843 + * Squashfs - a compressed read only filesystem for Linux
845 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
846 + * Phillip Lougher <phillip@lougher.demon.co.uk>
848 + * This program is free software; you can redistribute it and/or
849 + * modify it under the terms of the GNU General Public License
850 + * as published by the Free Software Foundation; either version 2,
851 + * or (at your option) any later version.
853 + * This program is distributed in the hope that it will be useful,
854 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
855 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
856 + * GNU General Public License for more details.
858 + * You should have received a copy of the GNU General Public License
859 + * along with this program; if not, write to the Free Software
860 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
866 + * This file implements code to read directories from disk.
868 + * See namei.c for a description of directory organisation on disk.
871 +#include <linux/fs.h>
872 +#include <linux/vfs.h>
873 +#include <linux/slab.h>
874 +#include <linux/zlib.h>
876 +#include "squashfs_fs.h"
877 +#include "squashfs_fs_sb.h"
878 +#include "squashfs_fs_i.h"
879 +#include "squashfs.h"
881 +static const unsigned char squashfs_filetype_table[] = {
882 + DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
886 + * Lookup offset (f_pos) in the directory index, returning the
887 + * metadata block containing it.
889 + * If we get an error reading the index then return the part of the index
890 + * (if any) we have managed to read - the index isn't essential, just
893 +static int get_dir_index_using_offset(struct super_block *sb,
894 + u64 *next_block, int *next_offset, u64 index_start, int index_offset,
895 + int i_count, u64 f_pos)
897 + struct squashfs_sb_info *msblk = sb->s_fs_info;
898 + int err, i, index, length = 0;
899 + struct squashfs_dir_index dir_index;
901 + TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %lld\n",
905 + * Translate from external f_pos to the internal f_pos. This
906 + * is offset by 3 because we invent "." and ".." entries which are
907 + * not actually stored in the directory.
913 + for (i = 0; i < i_count; i++) {
914 + err = squashfs_read_metadata(sb, &dir_index, &index_start,
915 + &index_offset, sizeof(dir_index));
919 + index = le32_to_cpu(dir_index.index);
922 + * Found the index we're looking for.
926 + err = squashfs_read_metadata(sb, NULL, &index_start,
927 + &index_offset, le32_to_cpu(dir_index.size) + 1);
932 + *next_block = le32_to_cpu(dir_index.start_block) +
933 + msblk->directory_table;
936 + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
939 + * Translate back from internal f_pos to external f_pos.
945 +static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
947 + struct inode *inode = file->f_dentry->d_inode;
948 + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
949 + u64 block = squashfs_i(inode)->start + msblk->directory_table;
950 + int offset = squashfs_i(inode)->offset, length = 0, dir_count, size,
952 + unsigned int inode_number;
953 + struct squashfs_dir_header dirh;
954 + struct squashfs_dir_entry *dire;
956 + TRACE("Entered squashfs_readdir [%llx:%x]\n", block, offset);
958 + dire = kmalloc(sizeof(*dire) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
959 + if (dire == NULL) {
960 + ERROR("Failed to allocate squashfs_dir_entry\n");
965 + * Return "." and ".." entries as the first two filenames in the
966 + * directory. To maximise compression these two entries are not
967 + * stored in the directory, and so we invent them here.
969 + * It also means that the external f_pos is offset by 3 from the
970 + * on-disk directory f_pos.
972 + while (file->f_pos < 3) {
976 + if (file->f_pos == 0) {
979 + i_ino = inode->i_ino;
983 + i_ino = squashfs_i(inode)->parent;
986 + TRACE("Calling filldir(%p, %s, %d, %lld, %d, %d)\n",
987 + dirent, name, size, file->f_pos, i_ino,
988 + squashfs_filetype_table[1]);
990 + if (filldir(dirent, name, size, file->f_pos, i_ino,
991 + squashfs_filetype_table[1]) < 0) {
992 + TRACE("Filldir returned less than 0\n");
996 + file->f_pos += size;
999 + length = get_dir_index_using_offset(inode->i_sb, &block, &offset,
1000 + squashfs_i(inode)->dir_idx_start,
1001 + squashfs_i(inode)->dir_idx_offset,
1002 + squashfs_i(inode)->dir_idx_cnt,
1005 + while (length < i_size_read(inode)) {
1007 + * Read directory header
1009 + err = squashfs_read_metadata(inode->i_sb, &dirh, &block,
1010 + &offset, sizeof(dirh));
1014 + length += sizeof(dirh);
1016 + dir_count = le32_to_cpu(dirh.count) + 1;
1017 + while (dir_count--) {
1019 + * Read directory entry.
1021 + err = squashfs_read_metadata(inode->i_sb, dire, &block,
1022 + &offset, sizeof(*dire));
1026 + size = le16_to_cpu(dire->size) + 1;
1028 + err = squashfs_read_metadata(inode->i_sb, dire->name,
1029 + &block, &offset, size);
1033 + length += sizeof(*dire) + size;
1035 + if (file->f_pos >= length)
1038 + dire->name[size] = '\0';
1039 + inode_number = le32_to_cpu(dirh.inode_number) +
1040 + ((short) le16_to_cpu(dire->inode_number));
1041 + type = le16_to_cpu(dire->type);
1043 + TRACE("Calling filldir(%p, %s, %d, %lld, %x:%x, %d, %d)"
1044 + "\n", dirent, dire->name, size,
1046 + le32_to_cpu(dirh.start_block),
1047 + le16_to_cpu(dire->offset),
1049 + squashfs_filetype_table[type]);
1051 + if (filldir(dirent, dire->name, size, file->f_pos,
1053 + squashfs_filetype_table[type]) < 0) {
1054 + TRACE("Filldir returned less than 0\n");
1058 + file->f_pos = length;
1067 + ERROR("Unable to read directory block [%llx:%x]\n", block, offset);
1073 +const struct file_operations squashfs_dir_ops = {
1074 + .read = generic_read_dir,
1075 + .readdir = squashfs_readdir
1077 diff --git a/fs/squashfs/export.c b/fs/squashfs/export.c
1078 new file mode 100644
1079 index 0000000..a1ded6f
1081 +++ b/fs/squashfs/export.c
1084 + * Squashfs - a compressed read only filesystem for Linux
1086 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
1087 + * Phillip Lougher <phillip@lougher.demon.co.uk>
1089 + * This program is free software; you can redistribute it and/or
1090 + * modify it under the terms of the GNU General Public License
1091 + * as published by the Free Software Foundation; either version 2,
1092 + * or (at your option) any later version.
1094 + * This program is distributed in the hope that it will be useful,
1095 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1096 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1097 + * GNU General Public License for more details.
1099 + * You should have received a copy of the GNU General Public License
1100 + * along with this program; if not, write to the Free Software
1101 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1107 + * This file implements code to make Squashfs filesystems exportable (NFS etc.)
1109 + * The export code uses an inode lookup table to map inode numbers passed in
1110 + * filehandles to an inode location on disk. This table is stored compressed
1111 + * into metadata blocks. A second index table is used to locate these. This
1112 + * second index table for speed of access (and because it is small) is read at
1113 + * mount time and cached in memory.
1115 + * The inode lookup table is used only by the export code, inode disk
1116 + * locations are directly encoded in directories, enabling direct access
1117 + * without an intermediate lookup for all operations except the export ops.
1120 +#include <linux/fs.h>
1121 +#include <linux/vfs.h>
1122 +#include <linux/dcache.h>
1123 +#include <linux/exportfs.h>
1124 +#include <linux/zlib.h>
1125 +#include <linux/slab.h>
1127 +#include "squashfs_fs.h"
1128 +#include "squashfs_fs_sb.h"
1129 +#include "squashfs_fs_i.h"
1130 +#include "squashfs.h"
1133 + * Look-up inode number (ino) in table, returning the inode location.
1135 +static long long squashfs_inode_lookup(struct super_block *sb, int ino_num)
1137 + struct squashfs_sb_info *msblk = sb->s_fs_info;
1138 + int blk = SQUASHFS_LOOKUP_BLOCK(ino_num - 1);
1139 + int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino_num - 1);
1140 + u64 start = le64_to_cpu(msblk->inode_lookup_table[blk]);
1144 + TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino_num);
1146 + err = squashfs_read_metadata(sb, &ino, &start, &offset, sizeof(ino));
1150 + TRACE("squashfs_inode_lookup, inode = 0x%llx\n",
1151 + (u64) le64_to_cpu(ino));
1153 + return le64_to_cpu(ino);
1157 +static struct dentry *squashfs_export_iget(struct super_block *sb,
1158 + unsigned int ino_num)
1161 + struct dentry *dentry;
1164 + TRACE("Entered squashfs_export_iget\n");
1166 + ino = squashfs_inode_lookup(sb, ino_num);
1168 + dentry = ERR_PTR(-ENOENT);
1172 + i = squashfs_iget(sb, ino, ino_num);
1174 + dentry = ERR_PTR(-EACCES);
1178 + dentry = d_alloc_anon(i);
1179 + if (dentry == NULL) {
1181 + dentry = ERR_PTR(-ENOMEM);
1189 +static struct dentry *squashfs_fh_to_dentry(struct super_block *sb,
1190 + struct fid *fid, int fh_len, int fh_type)
1192 + if ((fh_type != FILEID_INO32_GEN && fh_type != FILEID_INO32_GEN_PARENT)
1196 + return squashfs_export_iget(sb, fid->i32.ino);
1200 +static struct dentry *squashfs_fh_to_parent(struct super_block *sb,
1201 + struct fid *fid, int fh_len, int fh_type)
1203 + if (fh_type != FILEID_INO32_GEN_PARENT || fh_len < 4)
1206 + return squashfs_export_iget(sb, fid->i32.parent_ino);
1210 +static struct dentry *squashfs_get_parent(struct dentry *child)
1212 + struct inode *inode = child->d_inode;
1213 + unsigned int parent_ino = squashfs_i(inode)->parent;
1215 + return squashfs_export_iget(inode->i_sb, parent_ino);
1220 + * Read uncompressed inode lookup table indexes off disk into memory
1222 +__le64 *squashfs_read_inode_lookup_table(struct super_block *sb,
1223 + u64 lookup_table_start, unsigned int inodes)
1225 + unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(inodes);
1226 + __le64 *inode_lookup_table;
1229 + TRACE("In read_inode_lookup_table, length %d\n", length);
1231 + /* Allocate inode lookup table indexes */
1232 + inode_lookup_table = kmalloc(length, GFP_KERNEL);
1233 + if (inode_lookup_table == NULL) {
1234 + ERROR("Failed to allocate inode lookup table\n");
1235 + return ERR_PTR(-ENOMEM);
1238 + err = squashfs_read_table(sb, inode_lookup_table, lookup_table_start,
1241 + ERROR("unable to read inode lookup table\n");
1242 + kfree(inode_lookup_table);
1243 + return ERR_PTR(err);
1246 + return inode_lookup_table;
1250 +const struct export_operations squashfs_export_ops = {
1251 + .fh_to_dentry = squashfs_fh_to_dentry,
1252 + .fh_to_parent = squashfs_fh_to_parent,
1253 + .get_parent = squashfs_get_parent
1255 diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c
1256 new file mode 100644
1257 index 0000000..717767d
1259 +++ b/fs/squashfs/file.c
1262 + * Squashfs - a compressed read only filesystem for Linux
1264 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
1265 + * Phillip Lougher <phillip@lougher.demon.co.uk>
1267 + * This program is free software; you can redistribute it and/or
1268 + * modify it under the terms of the GNU General Public License
1269 + * as published by the Free Software Foundation; either version 2,
1270 + * or (at your option) any later version.
1272 + * This program is distributed in the hope that it will be useful,
1273 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1274 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1275 + * GNU General Public License for more details.
1277 + * You should have received a copy of the GNU General Public License
1278 + * along with this program; if not, write to the Free Software
1279 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1285 + * This file contains code for handling regular files. A regular file
1286 + * consists of a sequence of contiguous compressed blocks, and/or a
1287 + * compressed fragment block (tail-end packed block). The compressed size
1288 + * of each datablock is stored in a block list contained within the
1289 + * file inode (itself stored in one or more compressed metadata blocks).
1291 + * To speed up access to datablocks when reading 'large' files (256 Mbytes or
1292 + * larger), the code implements an index cache that caches the mapping from
1293 + * block index to datablock location on disk.
1295 + * The index cache allows Squashfs to handle large files (up to 1.75 TiB) while
1296 + * retaining a simple and space-efficient block list on disk. The cache
1297 + * is split into slots, caching up to eight 224 GiB files (128 KiB blocks).
1298 + * Larger files use multiple slots, with 1.75 TiB files using all 8 slots.
1299 + * The index cache is designed to be memory efficient, and by default uses
1303 +#include <linux/fs.h>
1304 +#include <linux/vfs.h>
1305 +#include <linux/kernel.h>
1306 +#include <linux/slab.h>
1307 +#include <linux/string.h>
1308 +#include <linux/pagemap.h>
1309 +#include <linux/mutex.h>
1310 +#include <linux/zlib.h>
1312 +#include "squashfs_fs.h"
1313 +#include "squashfs_fs_sb.h"
1314 +#include "squashfs_fs_i.h"
1315 +#include "squashfs.h"
1318 + * Locate cache slot in range [offset, index] for specified inode. If
1319 + * there's more than one return the slot closest to index.
1321 +static struct meta_index *locate_meta_index(struct inode *inode, int offset,
1324 + struct meta_index *meta = NULL;
1325 + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1328 + mutex_lock(&msblk->meta_index_mutex);
1330 + TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
1332 + if (msblk->meta_index == NULL)
1333 + goto not_allocated;
1335 + for (i = 0; i < SQUASHFS_META_SLOTS; i++) {
1336 + if (msblk->meta_index[i].inode_number == inode->i_ino &&
1337 + msblk->meta_index[i].offset >= offset &&
1338 + msblk->meta_index[i].offset <= index &&
1339 + msblk->meta_index[i].locked == 0) {
1340 + TRACE("locate_meta_index: entry %d, offset %d\n", i,
1341 + msblk->meta_index[i].offset);
1342 + meta = &msblk->meta_index[i];
1343 + offset = meta->offset;
1351 + mutex_unlock(&msblk->meta_index_mutex);
1358 + * Find and initialise an empty cache slot for index offset.
1360 +static struct meta_index *empty_meta_index(struct inode *inode, int offset,
1363 + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1364 + struct meta_index *meta = NULL;
1367 + mutex_lock(&msblk->meta_index_mutex);
1369 + TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
1371 + if (msblk->meta_index == NULL) {
1373 + * First time cache index has been used, allocate and
1374 + * initialise. The cache index could be allocated at
1375 + * mount time but doing it here means it is allocated only
1376 + * if a 'large' file is read.
1378 + msblk->meta_index = kcalloc(SQUASHFS_META_SLOTS,
1379 + sizeof(*(msblk->meta_index)), GFP_KERNEL);
1380 + if (msblk->meta_index == NULL) {
1381 + ERROR("Failed to allocate meta_index\n");
1384 + for (i = 0; i < SQUASHFS_META_SLOTS; i++) {
1385 + msblk->meta_index[i].inode_number = 0;
1386 + msblk->meta_index[i].locked = 0;
1388 + msblk->next_meta_index = 0;
1391 + for (i = SQUASHFS_META_SLOTS; i &&
1392 + msblk->meta_index[msblk->next_meta_index].locked; i--)
1393 + msblk->next_meta_index = (msblk->next_meta_index + 1) %
1394 + SQUASHFS_META_SLOTS;
1397 + TRACE("empty_meta_index: failed!\n");
1401 + TRACE("empty_meta_index: returned meta entry %d, %p\n",
1402 + msblk->next_meta_index,
1403 + &msblk->meta_index[msblk->next_meta_index]);
1405 + meta = &msblk->meta_index[msblk->next_meta_index];
1406 + msblk->next_meta_index = (msblk->next_meta_index + 1) %
1407 + SQUASHFS_META_SLOTS;
1409 + meta->inode_number = inode->i_ino;
1410 + meta->offset = offset;
1411 + meta->skip = skip;
1412 + meta->entries = 0;
1416 + mutex_unlock(&msblk->meta_index_mutex);
1421 +static void release_meta_index(struct inode *inode, struct meta_index *meta)
1423 + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1424 + mutex_lock(&msblk->meta_index_mutex);
1426 + mutex_unlock(&msblk->meta_index_mutex);
1431 + * Read the next n blocks from the block list, starting from
1432 + * metadata block <start_block, offset>.
1434 +static long long read_indexes(struct super_block *sb, int n,
1435 + u64 *start_block, int *offset)
1438 + long long block = 0;
1439 + __le32 *blist = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
1441 + if (blist == NULL) {
1442 + ERROR("read_indexes: Failed to allocate block_list\n");
1447 + int blocks = min_t(int, n, PAGE_CACHE_SIZE >> 2);
1449 + err = squashfs_read_metadata(sb, blist, start_block,
1450 + offset, blocks << 2);
1452 + ERROR("read_indexes: reading block [%llx:%x]\n",
1453 + *start_block, *offset);
1457 + for (i = 0; i < blocks; i++) {
1458 + int size = le32_to_cpu(blist[i]);
1459 + block += SQUASHFS_COMPRESSED_SIZE_BLOCK(size);
1474 + * Each cache index slot has SQUASHFS_META_ENTRIES, each of which
1475 + * can cache one index -> datablock/blocklist-block mapping. We wish
1476 + * to distribute these over the length of the file, entry[0] maps index x,
1477 + * entry[1] maps index x + skip, entry[2] maps index x + 2 * skip, and so on.
1478 + * The larger the file, the greater the skip factor. The skip factor is
1479 + * limited to the size of the metadata cache (SQUASHFS_CACHED_BLKS) to ensure
1480 + * the number of metadata blocks that need to be read fits into the cache.
1481 + * If the skip factor is limited in this way then the file will use multiple
1484 +static inline int calculate_skip(int blocks)
1486 + int skip = blocks / ((SQUASHFS_META_ENTRIES + 1)
1487 + * SQUASHFS_META_INDEXES);
1488 + return min(SQUASHFS_CACHED_BLKS - 1, skip + 1);
1493 + * Search and grow the index cache for the specified inode, returning the
1494 + * on-disk locations of the datablock and block list metadata block
1495 + * <index_block, index_offset> for index (scaled to nearest cache index).
1497 +static int fill_meta_index(struct inode *inode, int index,
1498 + u64 *index_block, int *index_offset, u64 *data_block)
1500 + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1501 + int skip = calculate_skip(i_size_read(inode) >> msblk->block_log);
1503 + struct meta_index *meta;
1504 + struct meta_entry *meta_entry;
1505 + u64 cur_index_block = squashfs_i(inode)->block_list_start;
1506 + int cur_offset = squashfs_i(inode)->offset;
1507 + u64 cur_data_block = squashfs_i(inode)->start;
1511 + * Scale index to cache index (cache slot entry)
1513 + index /= SQUASHFS_META_INDEXES * skip;
1515 + while (offset < index) {
1516 + meta = locate_meta_index(inode, offset + 1, index);
1518 + if (meta == NULL) {
1519 + meta = empty_meta_index(inode, offset + 1, skip);
1523 + offset = index < meta->offset + meta->entries ? index :
1524 + meta->offset + meta->entries - 1;
1525 + meta_entry = &meta->meta_entry[offset - meta->offset];
1526 + cur_index_block = meta_entry->index_block +
1527 + msblk->inode_table;
1528 + cur_offset = meta_entry->offset;
1529 + cur_data_block = meta_entry->data_block;
1530 + TRACE("get_meta_index: offset %d, meta->offset %d, "
1531 + "meta->entries %d\n", offset, meta->offset,
1533 + TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
1534 + " data_block 0x%llx\n", cur_index_block,
1535 + cur_offset, cur_data_block);
1539 + * If necessary grow cache slot by reading block list. Cache
1540 + * slot is extended up to index or to the end of the slot, in
1541 + * which case further slots will be used.
1543 + for (i = meta->offset + meta->entries; i <= index &&
1544 + i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
1545 + int blocks = skip * SQUASHFS_META_INDEXES;
1546 + long long res = read_indexes(inode->i_sb, blocks,
1547 + &cur_index_block, &cur_offset);
1550 + if (meta->entries == 0)
1552 + * Don't leave an empty slot on read
1553 + * error allocated to this inode...
1555 + meta->inode_number = 0;
1560 + cur_data_block += res;
1561 + meta_entry = &meta->meta_entry[i - meta->offset];
1562 + meta_entry->index_block = cur_index_block -
1563 + msblk->inode_table;
1564 + meta_entry->offset = cur_offset;
1565 + meta_entry->data_block = cur_data_block;
1570 + TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
1571 + meta->offset, meta->entries);
1573 + release_meta_index(inode, meta);
1577 + *index_block = cur_index_block;
1578 + *index_offset = cur_offset;
1579 + *data_block = cur_data_block;
1582 + * Scale cache index (cache slot entry) to index
1584 + return offset * SQUASHFS_META_INDEXES * skip;
1587 + release_meta_index(inode, meta);
1593 + * Get the on-disk location and compressed size of the datablock
1594 + * specified by index. Fill_meta_index() does most of the work.
1596 +static int read_blocklist(struct inode *inode, int index, u64 *block)
1602 + int res = fill_meta_index(inode, index, &start, &offset, block);
1604 + TRACE("read_blocklist: res %d, index %d, start 0x%llx, offset"
1605 + " 0x%x, block 0x%llx\n", res, index, start, offset,
1612 + * res contains the index of the mapping returned by fill_meta_index(),
1613 + * this will likely be less than the desired index (because the
1614 + * meta_index cache works at a higher granularity). Read any
1615 + * extra block indexes needed.
1617 + if (res < index) {
1618 + blks = read_indexes(inode->i_sb, index - res, &start, &offset);
1620 + return (int) blks;
1625 + * Read length of block specified by index.
1627 + res = squashfs_read_metadata(inode->i_sb, &size, &start, &offset,
1631 + return le32_to_cpu(size);
1635 +static int squashfs_readpage(struct file *file, struct page *page)
1637 + struct inode *inode = page->mapping->host;
1638 + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1639 + int bytes, i, offset = 0, sparse = 0;
1640 + struct squashfs_cache_entry *buffer = NULL;
1643 + int mask = (1 << (msblk->block_log - PAGE_CACHE_SHIFT)) - 1;
1644 + int index = page->index >> (msblk->block_log - PAGE_CACHE_SHIFT);
1645 + int start_index = page->index & ~mask;
1646 + int end_index = start_index | mask;
1647 + int file_end = i_size_read(inode) >> msblk->block_log;
1649 + TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
1650 + page->index, squashfs_i(inode)->start);
1652 + if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
1653 + PAGE_CACHE_SHIFT))
1656 + if (index < file_end || squashfs_i(inode)->fragment_block ==
1657 + SQUASHFS_INVALID_BLK) {
1659 + * Reading a datablock from disk. Need to read block list
1660 + * to get location and block size.
1663 + int bsize = read_blocklist(inode, index, &block);
1667 + if (bsize == 0) { /* hole */
1668 + bytes = index == file_end ?
1669 + (i_size_read(inode) & (msblk->block_size - 1)) :
1670 + msblk->block_size;
1674 + * Read and decompress datablock.
1676 + buffer = squashfs_get_datablock(inode->i_sb,
1678 + if (buffer->error) {
1679 + ERROR("Unable to read page, block %llx, size %x"
1680 + "\n", block, bsize);
1681 + squashfs_cache_put(buffer);
1684 + bytes = buffer->length;
1688 + * Datablock is stored inside a fragment (tail-end packed
1691 + buffer = squashfs_get_fragment(inode->i_sb,
1692 + squashfs_i(inode)->fragment_block,
1693 + squashfs_i(inode)->fragment_size);
1695 + if (buffer->error) {
1696 + ERROR("Unable to read page, block %llx, size %x\n",
1697 + squashfs_i(inode)->fragment_block,
1698 + squashfs_i(inode)->fragment_size);
1699 + squashfs_cache_put(buffer);
1702 + bytes = i_size_read(inode) & (msblk->block_size - 1);
1703 + offset = squashfs_i(inode)->fragment_offset;
1707 + * Loop copying datablock into pages. As the datablock likely covers
1708 + * many PAGE_CACHE_SIZE pages (default block size is 128 KiB) explicitly
1709 + * grab the pages from the page cache, except for the page that we've
1710 + * been called to fill.
1712 + for (i = start_index; i <= end_index && bytes > 0; i++,
1713 + bytes -= PAGE_CACHE_SIZE, offset += PAGE_CACHE_SIZE) {
1714 + struct page *push_page;
1715 + int avail = sparse ? 0 : min_t(int, bytes, PAGE_CACHE_SIZE);
1717 + TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail);
1719 + push_page = (i == page->index) ? page :
1720 + grab_cache_page_nowait(page->mapping, i);
1725 + if (PageUptodate(push_page))
1728 + pageaddr = kmap_atomic(push_page, KM_USER0);
1729 + squashfs_copy_data(pageaddr, buffer, offset, avail);
1730 + memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail);
1731 + kunmap_atomic(pageaddr, KM_USER0);
1732 + flush_dcache_page(push_page);
1733 + SetPageUptodate(push_page);
1735 + unlock_page(push_page);
1736 + if (i != page->index)
1737 + page_cache_release(push_page);
1741 + squashfs_cache_put(buffer);
1746 + SetPageError(page);
1748 + pageaddr = kmap_atomic(page, KM_USER0);
1749 + memset(pageaddr, 0, PAGE_CACHE_SIZE);
1750 + kunmap_atomic(pageaddr, KM_USER0);
1751 + flush_dcache_page(page);
1752 + if (!PageError(page))
1753 + SetPageUptodate(page);
1754 + unlock_page(page);
1760 +const struct address_space_operations squashfs_aops = {
1761 + .readpage = squashfs_readpage
1763 diff --git a/fs/squashfs/fragment.c b/fs/squashfs/fragment.c
1764 new file mode 100644
1765 index 0000000..b5a2c15
1767 +++ b/fs/squashfs/fragment.c
1770 + * Squashfs - a compressed read only filesystem for Linux
1772 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
1773 + * Phillip Lougher <phillip@lougher.demon.co.uk>
1775 + * This program is free software; you can redistribute it and/or
1776 + * modify it under the terms of the GNU General Public License
1777 + * as published by the Free Software Foundation; either version 2,
1778 + * or (at your option) any later version.
1780 + * This program is distributed in the hope that it will be useful,
1781 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1782 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1783 + * GNU General Public License for more details.
1785 + * You should have received a copy of the GNU General Public License
1786 + * along with this program; if not, write to the Free Software
1787 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1793 + * This file implements code to handle compressed fragments (tail-end packed
1796 + * Regular files contain a fragment index which is mapped to a fragment
1797 + * location on disk and compressed size using a fragment lookup table.
1798 + * Like everything in Squashfs this fragment lookup table is itself stored
1799 + * compressed into metadata blocks. A second index table is used to locate
1800 + * these. This second index table for speed of access (and because it
1801 + * is small) is read at mount time and cached in memory.
1804 +#include <linux/fs.h>
1805 +#include <linux/vfs.h>
1806 +#include <linux/slab.h>
1807 +#include <linux/zlib.h>
1809 +#include "squashfs_fs.h"
1810 +#include "squashfs_fs_sb.h"
1811 +#include "squashfs_fs_i.h"
1812 +#include "squashfs.h"
1815 + * Look-up fragment using the fragment index table. Return the on disk
1816 + * location of the fragment and its compressed size
1818 +int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment,
1819 + u64 *fragment_block)
1821 + struct squashfs_sb_info *msblk = sb->s_fs_info;
1822 + int block = SQUASHFS_FRAGMENT_INDEX(fragment);
1823 + int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
1824 + u64 start_block = le64_to_cpu(msblk->fragment_index[block]);
1825 + struct squashfs_fragment_entry fragment_entry;
1828 + size = squashfs_read_metadata(sb, &fragment_entry, &start_block,
1829 + &offset, sizeof(fragment_entry));
1833 + *fragment_block = le64_to_cpu(fragment_entry.start_block);
1834 + size = le32_to_cpu(fragment_entry.size);
1841 + * Read the uncompressed fragment lookup table indexes off disk into memory
1843 +__le64 *squashfs_read_fragment_index_table(struct super_block *sb,
1844 + u64 fragment_table_start, unsigned int fragments)
1846 + unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(fragments);
1847 + __le64 *fragment_index;
1850 + /* Allocate fragment lookup table indexes */
1851 + fragment_index = kmalloc(length, GFP_KERNEL);
1852 + if (fragment_index == NULL) {
1853 + ERROR("Failed to allocate fragment index table\n");
1854 + return ERR_PTR(-ENOMEM);
1857 + err = squashfs_read_table(sb, fragment_index, fragment_table_start,
1860 + ERROR("unable to read fragment index table\n");
1861 + kfree(fragment_index);
1862 + return ERR_PTR(err);
1865 + return fragment_index;
1867 diff --git a/fs/squashfs/id.c b/fs/squashfs/id.c
1868 new file mode 100644
1869 index 0000000..3795b83
1871 +++ b/fs/squashfs/id.c
1874 + * Squashfs - a compressed read only filesystem for Linux
1876 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
1877 + * Phillip Lougher <phillip@lougher.demon.co.uk>
1879 + * This program is free software; you can redistribute it and/or
1880 + * modify it under the terms of the GNU General Public License
1881 + * as published by the Free Software Foundation; either version 2,
1882 + * or (at your option) any later version.
1884 + * This program is distributed in the hope that it will be useful,
1885 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1886 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1887 + * GNU General Public License for more details.
1889 + * You should have received a copy of the GNU General Public License
1890 + * along with this program; if not, write to the Free Software
1891 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1897 + * This file implements code to handle uids and gids.
1899 + * For space efficiency regular files store uid and gid indexes, which are
1900 + * converted to 32-bit uids/gids using an id look up table. This table is
1901 + * stored compressed into metadata blocks. A second index table is used to
1902 + * locate these. This second index table for speed of access (and because it
1903 + * is small) is read at mount time and cached in memory.
1906 +#include <linux/fs.h>
1907 +#include <linux/vfs.h>
1908 +#include <linux/slab.h>
1909 +#include <linux/zlib.h>
1911 +#include "squashfs_fs.h"
1912 +#include "squashfs_fs_sb.h"
1913 +#include "squashfs_fs_i.h"
1914 +#include "squashfs.h"
1917 + * Map uid/gid index into real 32-bit uid/gid using the id look up table
1919 +int squashfs_get_id(struct super_block *sb, unsigned int index,
1922 + struct squashfs_sb_info *msblk = sb->s_fs_info;
1923 + int block = SQUASHFS_ID_BLOCK(index);
1924 + int offset = SQUASHFS_ID_BLOCK_OFFSET(index);
1925 + u64 start_block = le64_to_cpu(msblk->id_table[block]);
1929 + err = squashfs_read_metadata(sb, &disk_id, &start_block, &offset,
1934 + *id = le32_to_cpu(disk_id);
1940 + * Read uncompressed id lookup table indexes from disk into memory
1942 +__le64 *squashfs_read_id_index_table(struct super_block *sb,
1943 + u64 id_table_start, unsigned short no_ids)
1945 + unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids);
1949 + TRACE("In read_id_index_table, length %d\n", length);
1951 + /* Allocate id lookup table indexes */
1952 + id_table = kmalloc(length, GFP_KERNEL);
1953 + if (id_table == NULL) {
1954 + ERROR("Failed to allocate id index table\n");
1955 + return ERR_PTR(-ENOMEM);
1958 + err = squashfs_read_table(sb, id_table, id_table_start, length);
1960 + ERROR("unable to read id index table\n");
1962 + return ERR_PTR(err);
1967 diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c
1968 new file mode 100644
1969 index 0000000..9101dbd
1971 +++ b/fs/squashfs/inode.c
1974 + * Squashfs - a compressed read only filesystem for Linux
1976 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
1977 + * Phillip Lougher <phillip@lougher.demon.co.uk>
1979 + * This program is free software; you can redistribute it and/or
1980 + * modify it under the terms of the GNU General Public License
1981 + * as published by the Free Software Foundation; either version 2,
1982 + * or (at your option) any later version.
1984 + * This program is distributed in the hope that it will be useful,
1985 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1986 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1987 + * GNU General Public License for more details.
1989 + * You should have received a copy of the GNU General Public License
1990 + * along with this program; if not, write to the Free Software
1991 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1997 + * This file implements code to create and read inodes from disk.
1999 + * Inodes in Squashfs are identified by a 48-bit inode which encodes the
2000 + * location of the compressed metadata block containing the inode, and the byte
2001 + * offset into that block where the inode is placed (<block, offset>).
2003 + * To maximise compression there are different inodes for each file type
2004 + * (regular file, directory, device, etc.), the inode contents and length
2005 + * varying with the type.
2007 + * To further maximise compression, two types of regular file inode and
2008 + * directory inode are defined: inodes optimised for frequently occurring
2009 + * regular files and directories, and extended types where extra
2010 + * information has to be stored.
2013 +#include <linux/fs.h>
2014 +#include <linux/vfs.h>
2015 +#include <linux/zlib.h>
2017 +#include "squashfs_fs.h"
2018 +#include "squashfs_fs_sb.h"
2019 +#include "squashfs_fs_i.h"
2020 +#include "squashfs.h"
2023 + * Initialise VFS inode with the base inode information common to all
2024 + * Squashfs inode types. Sqsh_ino contains the unswapped base inode
2027 +static int squashfs_new_inode(struct super_block *sb, struct inode *inode,
2028 + struct squashfs_base_inode *sqsh_ino)
2032 + err = squashfs_get_id(sb, le16_to_cpu(sqsh_ino->uid), &inode->i_uid);
2036 + err = squashfs_get_id(sb, le16_to_cpu(sqsh_ino->guid), &inode->i_gid);
2040 + inode->i_ino = le32_to_cpu(sqsh_ino->inode_number);
2041 + inode->i_mtime.tv_sec = le32_to_cpu(sqsh_ino->mtime);
2042 + inode->i_atime.tv_sec = inode->i_mtime.tv_sec;
2043 + inode->i_ctime.tv_sec = inode->i_mtime.tv_sec;
2044 + inode->i_mode = le16_to_cpu(sqsh_ino->mode);
2045 + inode->i_size = 0;
2051 +struct inode *squashfs_iget(struct super_block *sb, long long ino,
2052 + unsigned int ino_number)
2054 + struct inode *inode = iget_locked(sb, ino_number);
2057 + TRACE("Entered squashfs_iget\n");
2060 + return ERR_PTR(-ENOMEM);
2061 + if (!(inode->i_state & I_NEW))
2064 + err = squashfs_read_inode(inode, ino);
2066 + iget_failed(inode);
2067 + return ERR_PTR(err);
2070 + unlock_new_inode(inode);
2076 + * Initialise VFS inode by reading inode from inode table (compressed
2077 + * metadata). The format and amount of data read depends on type.
2079 +int squashfs_read_inode(struct inode *inode, long long ino)
2081 + struct super_block *sb = inode->i_sb;
2082 + struct squashfs_sb_info *msblk = sb->s_fs_info;
2083 + u64 block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table;
2084 + int err, type, offset = SQUASHFS_INODE_OFFSET(ino);
2085 + union squashfs_inode squashfs_ino;
2086 + struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base;
2088 + TRACE("Entered squashfs_read_inode\n");
2091 + * Read inode base common to all inode types.
2093 + err = squashfs_read_metadata(sb, sqshb_ino, &block,
2094 + &offset, sizeof(*sqshb_ino));
2098 + err = squashfs_new_inode(sb, inode, sqshb_ino);
2102 + block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table;
2103 + offset = SQUASHFS_INODE_OFFSET(ino);
2105 + type = le16_to_cpu(sqshb_ino->inode_type);
2107 + case SQUASHFS_REG_TYPE: {
2108 + unsigned int frag_offset, frag;
2111 + struct squashfs_reg_inode *sqsh_ino = &squashfs_ino.reg;
2113 + err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
2114 + sizeof(*sqsh_ino));
2118 + frag = le32_to_cpu(sqsh_ino->fragment);
2119 + if (frag != SQUASHFS_INVALID_FRAG) {
2120 + frag_offset = le32_to_cpu(sqsh_ino->offset);
2121 + frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
2122 + if (frag_size < 0) {
2127 + frag_blk = SQUASHFS_INVALID_BLK;
2132 + inode->i_nlink = 1;
2133 + inode->i_size = le32_to_cpu(sqsh_ino->file_size);
2134 + inode->i_fop = &generic_ro_fops;
2135 + inode->i_mode |= S_IFREG;
2136 + inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;
2137 + squashfs_i(inode)->fragment_block = frag_blk;
2138 + squashfs_i(inode)->fragment_size = frag_size;
2139 + squashfs_i(inode)->fragment_offset = frag_offset;
2140 + squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
2141 + squashfs_i(inode)->block_list_start = block;
2142 + squashfs_i(inode)->offset = offset;
2143 + inode->i_data.a_ops = &squashfs_aops;
2145 + TRACE("File inode %x:%x, start_block %llx, block_list_start "
2146 + "%llx, offset %x\n", SQUASHFS_INODE_BLK(ino),
2147 + offset, squashfs_i(inode)->start, block, offset);
2150 + case SQUASHFS_LREG_TYPE: {
2151 + unsigned int frag_offset, frag;
2154 + struct squashfs_lreg_inode *sqsh_ino = &squashfs_ino.lreg;
2156 + err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
2157 + sizeof(*sqsh_ino));
2161 + frag = le32_to_cpu(sqsh_ino->fragment);
2162 + if (frag != SQUASHFS_INVALID_FRAG) {
2163 + frag_offset = le32_to_cpu(sqsh_ino->offset);
2164 + frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
2165 + if (frag_size < 0) {
2170 + frag_blk = SQUASHFS_INVALID_BLK;
2175 + inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
2176 + inode->i_size = le64_to_cpu(sqsh_ino->file_size);
2177 + inode->i_fop = &generic_ro_fops;
2178 + inode->i_mode |= S_IFREG;
2179 + inode->i_blocks = ((inode->i_size -
2180 + le64_to_cpu(sqsh_ino->sparse) - 1) >> 9) + 1;
2182 + squashfs_i(inode)->fragment_block = frag_blk;
2183 + squashfs_i(inode)->fragment_size = frag_size;
2184 + squashfs_i(inode)->fragment_offset = frag_offset;
2185 + squashfs_i(inode)->start = le64_to_cpu(sqsh_ino->start_block);
2186 + squashfs_i(inode)->block_list_start = block;
2187 + squashfs_i(inode)->offset = offset;
2188 + inode->i_data.a_ops = &squashfs_aops;
2190 + TRACE("File inode %x:%x, start_block %llx, block_list_start "
2191 + "%llx, offset %x\n", SQUASHFS_INODE_BLK(ino),
2192 + offset, squashfs_i(inode)->start, block, offset);
2195 + case SQUASHFS_DIR_TYPE: {
2196 + struct squashfs_dir_inode *sqsh_ino = &squashfs_ino.dir;
2198 + err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
2199 + sizeof(*sqsh_ino));
2203 + inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
2204 + inode->i_size = le16_to_cpu(sqsh_ino->file_size);
2205 + inode->i_op = &squashfs_dir_inode_ops;
2206 + inode->i_fop = &squashfs_dir_ops;
2207 + inode->i_mode |= S_IFDIR;
2208 + squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
2209 + squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset);
2210 + squashfs_i(inode)->dir_idx_cnt = 0;
2211 + squashfs_i(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode);
2213 + TRACE("Directory inode %x:%x, start_block %llx, offset %x\n",
2214 + SQUASHFS_INODE_BLK(ino), offset,
2215 + squashfs_i(inode)->start,
2216 + le16_to_cpu(sqsh_ino->offset));
2219 + case SQUASHFS_LDIR_TYPE: {
2220 + struct squashfs_ldir_inode *sqsh_ino = &squashfs_ino.ldir;
2222 + err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
2223 + sizeof(*sqsh_ino));
2227 + inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
2228 + inode->i_size = le32_to_cpu(sqsh_ino->file_size);
2229 + inode->i_op = &squashfs_dir_inode_ops;
2230 + inode->i_fop = &squashfs_dir_ops;
2231 + inode->i_mode |= S_IFDIR;
2232 + squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
2233 + squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset);
2234 + squashfs_i(inode)->dir_idx_start = block;
2235 + squashfs_i(inode)->dir_idx_offset = offset;
2236 + squashfs_i(inode)->dir_idx_cnt = le16_to_cpu(sqsh_ino->i_count);
2237 + squashfs_i(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode);
2239 + TRACE("Long directory inode %x:%x, start_block %llx, offset "
2240 + "%x\n", SQUASHFS_INODE_BLK(ino), offset,
2241 + squashfs_i(inode)->start,
2242 + le16_to_cpu(sqsh_ino->offset));
2245 + case SQUASHFS_SYMLINK_TYPE:
2246 + case SQUASHFS_LSYMLINK_TYPE: {
2247 + struct squashfs_symlink_inode *sqsh_ino = &squashfs_ino.symlink;
2249 + err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
2250 + sizeof(*sqsh_ino));
2254 + inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
2255 + inode->i_size = le32_to_cpu(sqsh_ino->symlink_size);
2256 + inode->i_op = &page_symlink_inode_operations;
2257 + inode->i_data.a_ops = &squashfs_symlink_aops;
2258 + inode->i_mode |= S_IFLNK;
2259 + squashfs_i(inode)->start = block;
2260 + squashfs_i(inode)->offset = offset;
2262 + TRACE("Symbolic link inode %x:%x, start_block %llx, offset "
2263 + "%x\n", SQUASHFS_INODE_BLK(ino), offset,
2267 + case SQUASHFS_BLKDEV_TYPE:
2268 + case SQUASHFS_CHRDEV_TYPE:
2269 + case SQUASHFS_LBLKDEV_TYPE:
2270 + case SQUASHFS_LCHRDEV_TYPE: {
2271 + struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev;
2272 + unsigned int rdev;
2274 + err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
2275 + sizeof(*sqsh_ino));
2279 + if (type == SQUASHFS_CHRDEV_TYPE)
2280 + inode->i_mode |= S_IFCHR;
2282 + inode->i_mode |= S_IFBLK;
2283 + inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
2284 + rdev = le32_to_cpu(sqsh_ino->rdev);
2285 + init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
2287 + TRACE("Device inode %x:%x, rdev %x\n",
2288 + SQUASHFS_INODE_BLK(ino), offset, rdev);
2291 + case SQUASHFS_FIFO_TYPE:
2292 + case SQUASHFS_SOCKET_TYPE:
2293 + case SQUASHFS_LFIFO_TYPE:
2294 + case SQUASHFS_LSOCKET_TYPE: {
2295 + struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc;
2297 + err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
2298 + sizeof(*sqsh_ino));
2302 + if (type == SQUASHFS_FIFO_TYPE)
2303 + inode->i_mode |= S_IFIFO;
2305 + inode->i_mode |= S_IFSOCK;
2306 + inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
2307 + init_special_inode(inode, inode->i_mode, 0);
2311 + ERROR("Unknown inode type %d in squashfs_iget!\n", type);
2318 + ERROR("Unable to read inode 0x%llx\n", ino);
2321 diff --git a/fs/squashfs/namei.c b/fs/squashfs/namei.c
2322 new file mode 100644
2323 index 0000000..9e39865
2325 +++ b/fs/squashfs/namei.c
2328 + * Squashfs - a compressed read only filesystem for Linux
2330 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
2331 + * Phillip Lougher <phillip@lougher.demon.co.uk>
2333 + * This program is free software; you can redistribute it and/or
2334 + * modify it under the terms of the GNU General Public License
2335 + * as published by the Free Software Foundation; either version 2,
2336 + * or (at your option) any later version.
2338 + * This program is distributed in the hope that it will be useful,
2339 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2340 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2341 + * GNU General Public License for more details.
2343 + * You should have received a copy of the GNU General Public License
2344 + * along with this program; if not, write to the Free Software
2345 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2351 + * This file implements code to do filename lookup in directories.
2353 + * Like inodes, directories are packed into compressed metadata blocks, stored
2354 + * in a directory table. Directories are accessed using the start address of
2355 + * the metablock containing the directory and the offset into the
2356 + * decompressed block (<block, offset>).
2358 + * Directories are organised in a slightly complex way, and are not simply
2359 + * a list of file names. The organisation takes advantage of the
2360 + * fact that (in most cases) the inodes of the files will be in the same
2361 + * compressed metadata block, and therefore, can share the start block.
2362 + * Directories are therefore organised in a two level list, a directory
2363 + * header containing the shared start block value, and a sequence of directory
2364 + * entries, each of which share the shared start block. A new directory header
2365 + * is written once/if the inode start block changes. The directory
2366 + * header/directory entry list is repeated as many times as necessary.
2368 + * Directories are sorted, and can contain a directory index to speed up
2369 + * file lookup. Directory indexes store one entry per metablock, each entry
2370 + * storing the index/filename mapping to the first directory header
2371 + * in each metadata block. Directories are sorted in alphabetical order,
2372 + * and at lookup the index is scanned linearly looking for the first filename
2373 + * alphabetically larger than the filename being looked up. At this point the
2374 + * location of the metadata block the filename is in has been found.
2375 + * The general idea of the index is ensure only one metadata block needs to be
2376 + * decompressed to do a lookup irrespective of the length of the directory.
2377 + * This scheme has the advantage that it doesn't require extra memory overhead
2378 + * and doesn't require much extra storage on disk.
2381 +#include <linux/fs.h>
2382 +#include <linux/vfs.h>
2383 +#include <linux/slab.h>
2384 +#include <linux/string.h>
2385 +#include <linux/dcache.h>
2386 +#include <linux/zlib.h>
2388 +#include "squashfs_fs.h"
2389 +#include "squashfs_fs_sb.h"
2390 +#include "squashfs_fs_i.h"
2391 +#include "squashfs.h"
2394 + * Lookup name in the directory index, returning the location of the metadata
2395 + * block containing it, and the directory index this represents.
2397 + * If we get an error reading the index then return the part of the index
2398 + * (if any) we have managed to read - the index isn't essential, just
2401 +static int get_dir_index_using_name(struct super_block *sb,
2402 + u64 *next_block, int *next_offset, u64 index_start,
2403 + int index_offset, int i_count, const char *name,
2406 + struct squashfs_sb_info *msblk = sb->s_fs_info;
2407 + int i, size, length = 0, err;
2408 + struct squashfs_dir_index *index;
2411 + TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
2413 + index = kmalloc(sizeof(*index) + SQUASHFS_NAME_LEN * 2 + 2, GFP_KERNEL);
2414 + if (index == NULL) {
2415 + ERROR("Failed to allocate squashfs_dir_index\n");
2419 + str = &index->name[SQUASHFS_NAME_LEN + 1];
2420 + strncpy(str, name, len);
2423 + for (i = 0; i < i_count; i++) {
2424 + err = squashfs_read_metadata(sb, index, &index_start,
2425 + &index_offset, sizeof(*index));
2430 + size = le32_to_cpu(index->size) + 1;
2432 + err = squashfs_read_metadata(sb, index->name, &index_start,
2433 + &index_offset, size);
2437 + index->name[size] = '\0';
2439 + if (strcmp(index->name, str) > 0)
2442 + length = le32_to_cpu(index->index);
2443 + *next_block = le32_to_cpu(index->start_block) +
2444 + msblk->directory_table;
2447 + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
2452 + * Return index (f_pos) of the looked up metadata block. Translate
2453 + * from internal f_pos to external f_pos which is offset by 3 because
2454 + * we invent "." and ".." entries which are not actually stored in the
2457 + return length + 3;
2461 +static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,
2462 + struct nameidata *nd)
2464 + const unsigned char *name = dentry->d_name.name;
2465 + int len = dentry->d_name.len;
2466 + struct inode *inode = NULL;
2467 + struct squashfs_sb_info *msblk = dir->i_sb->s_fs_info;
2468 + struct squashfs_dir_header dirh;
2469 + struct squashfs_dir_entry *dire;
2470 + u64 block = squashfs_i(dir)->start + msblk->directory_table;
2471 + int offset = squashfs_i(dir)->offset;
2472 + int err, length = 0, dir_count, size;
2474 + TRACE("Entered squashfs_lookup [%llx:%x]\n", block, offset);
2476 + dire = kmalloc(sizeof(*dire) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
2477 + if (dire == NULL) {
2478 + ERROR("Failed to allocate squashfs_dir_entry\n");
2479 + return ERR_PTR(-ENOMEM);
2482 + if (len > SQUASHFS_NAME_LEN) {
2483 + err = -ENAMETOOLONG;
2487 + length = get_dir_index_using_name(dir->i_sb, &block, &offset,
2488 + squashfs_i(dir)->dir_idx_start,
2489 + squashfs_i(dir)->dir_idx_offset,
2490 + squashfs_i(dir)->dir_idx_cnt, name, len);
2492 + while (length < i_size_read(dir)) {
2494 + * Read directory header.
2496 + err = squashfs_read_metadata(dir->i_sb, &dirh, &block,
2497 + &offset, sizeof(dirh));
2499 + goto read_failure;
2501 + length += sizeof(dirh);
2503 + dir_count = le32_to_cpu(dirh.count) + 1;
2504 + while (dir_count--) {
2506 + * Read directory entry.
2508 + err = squashfs_read_metadata(dir->i_sb, dire, &block,
2509 + &offset, sizeof(*dire));
2511 + goto read_failure;
2513 + size = le16_to_cpu(dire->size) + 1;
2515 + err = squashfs_read_metadata(dir->i_sb, dire->name,
2516 + &block, &offset, size);
2518 + goto read_failure;
2520 + length += sizeof(*dire) + size;
2522 + if (name[0] < dire->name[0])
2525 + if (len == size && !strncmp(name, dire->name, len)) {
2526 + unsigned int blk, off, ino_num;
2528 + blk = le32_to_cpu(dirh.start_block);
2529 + off = le16_to_cpu(dire->offset);
2530 + ino_num = le32_to_cpu(dirh.inode_number) +
2531 + (short) le16_to_cpu(dire->inode_number);
2532 + ino = SQUASHFS_MKINODE(blk, off);
2534 + TRACE("calling squashfs_iget for directory "
2535 + "entry %s, inode %x:%x, %d\n", name,
2536 + blk, off, ino_num);
2538 + inode = squashfs_iget(dir->i_sb, ino, ino_num);
2539 + if (IS_ERR(inode)) {
2540 + err = PTR_ERR(inode);
2552 + return d_splice_alias(inode, dentry);
2553 + d_add(dentry, inode);
2554 + return ERR_PTR(0);
2557 + ERROR("Unable to read directory block [%llx:%x]\n",
2558 + squashfs_i(dir)->start + msblk->directory_table,
2559 + squashfs_i(dir)->offset);
2562 + return ERR_PTR(err);
2566 +const struct inode_operations squashfs_dir_inode_ops = {
2567 + .lookup = squashfs_lookup
2569 diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h
2570 new file mode 100644
2571 index 0000000..0e9feb6
2573 +++ b/fs/squashfs/squashfs.h
2576 + * Squashfs - a compressed read only filesystem for Linux
2578 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
2579 + * Phillip Lougher <phillip@lougher.demon.co.uk>
2581 + * This program is free software; you can redistribute it and/or
2582 + * modify it under the terms of the GNU General Public License
2583 + * as published by the Free Software Foundation; either version 2,
2584 + * or (at your option) any later version.
2586 + * This program is distributed in the hope that it will be useful,
2587 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2588 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2589 + * GNU General Public License for more details.
2591 + * You should have received a copy of the GNU General Public License
2592 + * along with this program; if not, write to the Free Software
2593 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2598 +#define TRACE(s, args...) pr_debug("SQUASHFS: "s, ## args)
2600 +#define ERROR(s, args...) pr_err("SQUASHFS error: "s, ## args)
2602 +#define WARNING(s, args...) pr_warning("SQUASHFS: "s, ## args)
2604 +static inline struct squashfs_inode_info *squashfs_i(struct inode *inode)
2606 + return list_entry(inode, struct squashfs_inode_info, vfs_inode);
2610 +extern int squashfs_read_data(struct super_block *, void **, u64, int, u64 *,
2614 +extern struct squashfs_cache *squashfs_cache_init(char *, int, int);
2615 +extern void squashfs_cache_delete(struct squashfs_cache *);
2616 +extern struct squashfs_cache_entry *squashfs_cache_get(struct super_block *,
2617 + struct squashfs_cache *, u64, int);
2618 +extern void squashfs_cache_put(struct squashfs_cache_entry *);
2619 +extern int squashfs_copy_data(void *, struct squashfs_cache_entry *, int, int);
2620 +extern int squashfs_read_metadata(struct super_block *, void *, u64 *,
2622 +extern struct squashfs_cache_entry *squashfs_get_fragment(struct super_block *,
2624 +extern struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *,
2626 +extern int squashfs_read_table(struct super_block *, void *, u64, int);
2629 +extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64,
2633 +extern int squashfs_frag_lookup(struct super_block *, unsigned int, u64 *);
2634 +extern __le64 *squashfs_read_fragment_index_table(struct super_block *,
2635 + u64, unsigned int);
2638 +extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *);
2639 +extern __le64 *squashfs_read_id_index_table(struct super_block *, u64,
2643 +extern struct inode *squashfs_iget(struct super_block *, long long,
2645 +extern int squashfs_read_inode(struct inode *, long long);
2648 + * Inodes and files operations
2652 +extern const struct file_operations squashfs_dir_ops;
2655 +extern const struct export_operations squashfs_export_ops;
2658 +extern const struct address_space_operations squashfs_aops;
2661 +extern const struct inode_operations squashfs_dir_inode_ops;
2664 +extern const struct address_space_operations squashfs_symlink_aops;
2665 diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h
2666 new file mode 100644
2667 index 0000000..70c3f39
2669 +++ b/fs/squashfs/squashfs_fs.h
2671 +#ifndef SQUASHFS_FS
2672 +#define SQUASHFS_FS
2676 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
2677 + * Phillip Lougher <phillip@lougher.demon.co.uk>
2679 + * This program is free software; you can redistribute it and/or
2680 + * modify it under the terms of the GNU General Public License
2681 + * as published by the Free Software Foundation; either version 2,
2682 + * or (at your option) any later version.
2684 + * This program is distributed in the hope that it will be useful,
2685 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2686 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2687 + * GNU General Public License for more details.
2689 + * You should have received a copy of the GNU General Public License
2690 + * along with this program; if not, write to the Free Software
2691 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2696 +#define SQUASHFS_MAGIC 0x73717368
2698 +#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
2699 +#define SQUASHFS_MAJOR 4
2700 +#define SQUASHFS_MINOR 0
2701 +#define SQUASHFS_START 0
2703 +/* size of metadata (inode and directory) blocks */
2704 +#define SQUASHFS_METADATA_SIZE 8192
2705 +#define SQUASHFS_METADATA_LOG 13
2707 +/* default size of data blocks */
2708 +#define SQUASHFS_FILE_SIZE 131072
2709 +#define SQUASHFS_FILE_LOG 17
2711 +#define SQUASHFS_FILE_MAX_SIZE 1048576
2712 +#define SQUASHFS_FILE_MAX_LOG 20
2714 +/* Max number of uids and gids */
2715 +#define SQUASHFS_IDS 65536
2717 +/* Max length of filename (not 255) */
2718 +#define SQUASHFS_NAME_LEN 256
2720 +#define SQUASHFS_INVALID_FRAG (0xffffffffU)
2721 +#define SQUASHFS_INVALID_BLK (-1LL)
2723 +/* Filesystem flags */
2724 +#define SQUASHFS_NOI 0
2725 +#define SQUASHFS_NOD 1
2726 +#define SQUASHFS_NOF 3
2727 +#define SQUASHFS_NO_FRAG 4
2728 +#define SQUASHFS_ALWAYS_FRAG 5
2729 +#define SQUASHFS_DUPLICATE 6
2730 +#define SQUASHFS_EXPORT 7
2732 +#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1)
2734 +#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \
2737 +#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \
2740 +#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
2743 +#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
2746 +#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
2747 + SQUASHFS_ALWAYS_FRAG)
2749 +#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \
2750 + SQUASHFS_DUPLICATE)
2752 +#define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \
2755 +/* Max number of types and file types */
2756 +#define SQUASHFS_DIR_TYPE 1
2757 +#define SQUASHFS_REG_TYPE 2
2758 +#define SQUASHFS_SYMLINK_TYPE 3
2759 +#define SQUASHFS_BLKDEV_TYPE 4
2760 +#define SQUASHFS_CHRDEV_TYPE 5
2761 +#define SQUASHFS_FIFO_TYPE 6
2762 +#define SQUASHFS_SOCKET_TYPE 7
2763 +#define SQUASHFS_LDIR_TYPE 8
2764 +#define SQUASHFS_LREG_TYPE 9
2765 +#define SQUASHFS_LSYMLINK_TYPE 10
2766 +#define SQUASHFS_LBLKDEV_TYPE 11
2767 +#define SQUASHFS_LCHRDEV_TYPE 12
2768 +#define SQUASHFS_LFIFO_TYPE 13
2769 +#define SQUASHFS_LSOCKET_TYPE 14
2771 +/* Flag whether block is compressed or uncompressed, bit is set if block is
2773 +#define SQUASHFS_COMPRESSED_BIT (1 << 15)
2775 +#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
2776 + (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT)
2778 +#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT))
2780 +#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24)
2782 +#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) ((B) & \
2783 + ~SQUASHFS_COMPRESSED_BIT_BLOCK)
2785 +#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
2788 + * Inode number ops. Inodes consist of a compressed block number, and an
2789 + * uncompressed offset within that block
2791 +#define SQUASHFS_INODE_BLK(A) ((unsigned int) ((A) >> 16))
2793 +#define SQUASHFS_INODE_OFFSET(A) ((unsigned int) ((A) & 0xffff))
2795 +#define SQUASHFS_MKINODE(A, B) ((long long)(((long long) (A)\
2798 +/* Translate between VFS mode and squashfs mode */
2799 +#define SQUASHFS_MODE(A) ((A) & 0xfff)
2801 +/* fragment and fragment table defines */
2802 +#define SQUASHFS_FRAGMENT_BYTES(A) \
2803 + ((A) * sizeof(struct squashfs_fragment_entry))
2805 +#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \
2806 + SQUASHFS_METADATA_SIZE)
2808 +#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \
2809 + SQUASHFS_METADATA_SIZE)
2811 +#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \
2812 + SQUASHFS_METADATA_SIZE - 1) / \
2813 + SQUASHFS_METADATA_SIZE)
2815 +#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\
2818 +/* inode lookup table defines */
2819 +#define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(u64))
2821 +#define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \
2822 + SQUASHFS_METADATA_SIZE)
2824 +#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \
2825 + SQUASHFS_METADATA_SIZE)
2827 +#define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \
2828 + SQUASHFS_METADATA_SIZE - 1) / \
2829 + SQUASHFS_METADATA_SIZE)
2831 +#define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\
2834 +/* uid/gid lookup table defines */
2835 +#define SQUASHFS_ID_BYTES(A) ((A) * sizeof(unsigned int))
2837 +#define SQUASHFS_ID_BLOCK(A) (SQUASHFS_ID_BYTES(A) / \
2838 + SQUASHFS_METADATA_SIZE)
2840 +#define SQUASHFS_ID_BLOCK_OFFSET(A) (SQUASHFS_ID_BYTES(A) % \
2841 + SQUASHFS_METADATA_SIZE)
2843 +#define SQUASHFS_ID_BLOCKS(A) ((SQUASHFS_ID_BYTES(A) + \
2844 + SQUASHFS_METADATA_SIZE - 1) / \
2845 + SQUASHFS_METADATA_SIZE)
2847 +#define SQUASHFS_ID_BLOCK_BYTES(A) (SQUASHFS_ID_BLOCKS(A) *\
2850 +/* cached data constants for filesystem */
2851 +#define SQUASHFS_CACHED_BLKS 8
2853 +#define SQUASHFS_MAX_FILE_SIZE_LOG 64
2855 +#define SQUASHFS_MAX_FILE_SIZE (1LL << \
2856 + (SQUASHFS_MAX_FILE_SIZE_LOG - 2))
2858 +#define SQUASHFS_MARKER_BYTE 0xff
2860 +/* meta index cache */
2861 +#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
2862 +#define SQUASHFS_META_ENTRIES 127
2863 +#define SQUASHFS_META_SLOTS 8
2865 +struct meta_entry {
2867 + unsigned int index_block;
2868 + unsigned short offset;
2869 + unsigned short pad;
2872 +struct meta_index {
2873 + unsigned int inode_number;
2874 + unsigned int offset;
2875 + unsigned short entries;
2876 + unsigned short skip;
2877 + unsigned short locked;
2878 + unsigned short pad;
2879 + struct meta_entry meta_entry[SQUASHFS_META_ENTRIES];
2884 + * definitions for structures on disk
2886 +#define ZLIB_COMPRESSION 1
2888 +struct squashfs_super_block {
2892 + __le32 block_size;
2894 + __le16 compression;
2900 + __le64 root_inode;
2901 + __le64 bytes_used;
2902 + __le64 id_table_start;
2903 + __le64 xattr_table_start;
2904 + __le64 inode_table_start;
2905 + __le64 directory_table_start;
2906 + __le64 fragment_table_start;
2907 + __le64 lookup_table_start;
2910 +struct squashfs_dir_index {
2912 + __le32 start_block;
2914 + unsigned char name[0];
2917 +struct squashfs_base_inode {
2918 + __le16 inode_type;
2923 + __le32 inode_number;
2926 +struct squashfs_ipc_inode {
2927 + __le16 inode_type;
2932 + __le32 inode_number;
2936 +struct squashfs_dev_inode {
2937 + __le16 inode_type;
2942 + __le32 inode_number;
2947 +struct squashfs_symlink_inode {
2948 + __le16 inode_type;
2953 + __le32 inode_number;
2955 + __le32 symlink_size;
2959 +struct squashfs_reg_inode {
2960 + __le16 inode_type;
2965 + __le32 inode_number;
2966 + __le32 start_block;
2970 + __le16 block_list[0];
2973 +struct squashfs_lreg_inode {
2974 + __le16 inode_type;
2979 + __le32 inode_number;
2980 + __le64 start_block;
2987 + __le16 block_list[0];
2990 +struct squashfs_dir_inode {
2991 + __le16 inode_type;
2996 + __le32 inode_number;
2997 + __le32 start_block;
3001 + __le32 parent_inode;
3004 +struct squashfs_ldir_inode {
3005 + __le16 inode_type;
3010 + __le32 inode_number;
3013 + __le32 start_block;
3014 + __le32 parent_inode;
3018 + struct squashfs_dir_index index[0];
3021 +union squashfs_inode {
3022 + struct squashfs_base_inode base;
3023 + struct squashfs_dev_inode dev;
3024 + struct squashfs_symlink_inode symlink;
3025 + struct squashfs_reg_inode reg;
3026 + struct squashfs_lreg_inode lreg;
3027 + struct squashfs_dir_inode dir;
3028 + struct squashfs_ldir_inode ldir;
3029 + struct squashfs_ipc_inode ipc;
3032 +struct squashfs_dir_entry {
3034 + __le16 inode_number;
3040 +struct squashfs_dir_header {
3042 + __le32 start_block;
3043 + __le32 inode_number;
3046 +struct squashfs_fragment_entry {
3047 + __le64 start_block;
3049 + unsigned int unused;
3053 diff --git a/fs/squashfs/squashfs_fs_i.h b/fs/squashfs/squashfs_fs_i.h
3054 new file mode 100644
3055 index 0000000..fbfca30
3057 +++ b/fs/squashfs/squashfs_fs_i.h
3059 +#ifndef SQUASHFS_FS_I
3060 +#define SQUASHFS_FS_I
3064 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
3065 + * Phillip Lougher <phillip@lougher.demon.co.uk>
3067 + * This program is free software; you can redistribute it and/or
3068 + * modify it under the terms of the GNU General Public License
3069 + * as published by the Free Software Foundation; either version 2,
3070 + * or (at your option) any later version.
3072 + * This program is distributed in the hope that it will be useful,
3073 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3074 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3075 + * GNU General Public License for more details.
3077 + * You should have received a copy of the GNU General Public License
3078 + * along with this program; if not, write to the Free Software
3079 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
3084 +struct squashfs_inode_info {
3089 + u64 fragment_block;
3090 + int fragment_size;
3091 + int fragment_offset;
3092 + u64 block_list_start;
3095 + u64 dir_idx_start;
3096 + int dir_idx_offset;
3101 + struct inode vfs_inode;
3104 diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h
3105 new file mode 100644
3106 index 0000000..c8c6561
3108 +++ b/fs/squashfs/squashfs_fs_sb.h
3110 +#ifndef SQUASHFS_FS_SB
3111 +#define SQUASHFS_FS_SB
3115 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
3116 + * Phillip Lougher <phillip@lougher.demon.co.uk>
3118 + * This program is free software; you can redistribute it and/or
3119 + * modify it under the terms of the GNU General Public License
3120 + * as published by the Free Software Foundation; either version 2,
3121 + * or (at your option) any later version.
3123 + * This program is distributed in the hope that it will be useful,
3124 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3125 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3126 + * GNU General Public License for more details.
3128 + * You should have received a copy of the GNU General Public License
3129 + * along with this program; if not, write to the Free Software
3130 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
3132 + * squashfs_fs_sb.h
3135 +#include "squashfs_fs.h"
3137 +struct squashfs_cache {
3146 + wait_queue_head_t wait_queue;
3147 + struct squashfs_cache_entry *entry;
3150 +struct squashfs_cache_entry {
3158 + wait_queue_head_t wait_queue;
3159 + struct squashfs_cache *cache;
3163 +struct squashfs_sb_info {
3165 + int devblksize_log2;
3166 + struct squashfs_cache *block_cache;
3167 + struct squashfs_cache *fragment_cache;
3168 + struct squashfs_cache *read_page;
3169 + int next_meta_index;
3171 + __le64 *fragment_index;
3172 + unsigned int *fragment_index_2;
3173 + struct mutex read_data_mutex;
3174 + struct mutex meta_index_mutex;
3175 + struct meta_index *meta_index;
3177 + __le64 *inode_lookup_table;
3179 + u64 directory_table;
3180 + unsigned int block_size;
3181 + unsigned short block_log;
3182 + long long bytes_used;
3183 + unsigned int inodes;
3186 diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c
3187 new file mode 100644
3188 index 0000000..0adc624
3190 +++ b/fs/squashfs/super.c
3193 + * Squashfs - a compressed read only filesystem for Linux
3195 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
3196 + * Phillip Lougher <phillip@lougher.demon.co.uk>
3198 + * This program is free software; you can redistribute it and/or
3199 + * modify it under the terms of the GNU General Public License
3200 + * as published by the Free Software Foundation; either version 2,
3201 + * or (at your option) any later version.
3203 + * This program is distributed in the hope that it will be useful,
3204 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3205 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3206 + * GNU General Public License for more details.
3208 + * You should have received a copy of the GNU General Public License
3209 + * along with this program; if not, write to the Free Software
3210 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
3216 + * This file implements code to read the superblock, read and initialise
3217 + * in-memory structures at mount time, and all the VFS glue code to register
3221 +#include <linux/fs.h>
3222 +#include <linux/vfs.h>
3223 +#include <linux/slab.h>
3224 +#include <linux/mutex.h>
3225 +#include <linux/pagemap.h>
3226 +#include <linux/init.h>
3227 +#include <linux/module.h>
3228 +#include <linux/zlib.h>
3229 +#include <linux/magic.h>
3231 +#include "squashfs_fs.h"
3232 +#include "squashfs_fs_sb.h"
3233 +#include "squashfs_fs_i.h"
3234 +#include "squashfs.h"
3236 +static struct file_system_type squashfs_fs_type;
3237 +static struct super_operations squashfs_super_ops;
3239 +static int supported_squashfs_filesystem(short major, short minor, short comp)
3241 + if (major < SQUASHFS_MAJOR) {
3242 + ERROR("Major/Minor mismatch, older Squashfs %d.%d "
3243 + "filesystems are unsupported\n", major, minor);
3245 + } else if (major > SQUASHFS_MAJOR || minor > SQUASHFS_MINOR) {
3246 + ERROR("Major/Minor mismatch, trying to mount newer "
3247 + "%d.%d filesystem\n", major, minor);
3248 + ERROR("Please update your kernel\n");
3252 + if (comp != ZLIB_COMPRESSION)
3259 +static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
3261 + struct squashfs_sb_info *msblk;
3262 + struct squashfs_super_block *sblk = NULL;
3263 + char b[BDEVNAME_SIZE];
3264 + struct inode *root;
3265 + long long root_inode;
3266 + unsigned short flags;
3267 + unsigned int fragments;
3268 + u64 lookup_table_start;
3271 + TRACE("Entered squashfs_fill_superblock\n");
3273 + sb->s_fs_info = kzalloc(sizeof(*msblk), GFP_KERNEL);
3274 + if (sb->s_fs_info == NULL) {
3275 + ERROR("Failed to allocate squashfs_sb_info\n");
3278 + msblk = sb->s_fs_info;
3280 + msblk->stream.workspace = kmalloc(zlib_inflate_workspacesize(),
3282 + if (msblk->stream.workspace == NULL) {
3283 + ERROR("Failed to allocate zlib workspace\n");
3287 + sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
3288 + if (sblk == NULL) {
3289 + ERROR("Failed to allocate squashfs_super_block\n");
3293 + msblk->devblksize = sb_min_blocksize(sb, BLOCK_SIZE);
3294 + msblk->devblksize_log2 = ffz(~msblk->devblksize);
3296 + mutex_init(&msblk->read_data_mutex);
3297 + mutex_init(&msblk->meta_index_mutex);
3300 + * msblk->bytes_used is checked in squashfs_read_table to ensure reads
3301 + * are not beyond filesystem end. But as we're using
3302 + * squashfs_read_table here to read the superblock (including the value
3303 + * of bytes_used) we need to set it to an initial sensible dummy value
3305 + msblk->bytes_used = sizeof(*sblk);
3306 + err = squashfs_read_table(sb, sblk, SQUASHFS_START, sizeof(*sblk));
3309 + ERROR("unable to read squashfs_super_block\n");
3310 + goto failed_mount;
3313 + /* Check it is a SQUASHFS superblock */
3314 + sb->s_magic = le32_to_cpu(sblk->s_magic);
3315 + if (sb->s_magic != SQUASHFS_MAGIC) {
3317 + ERROR("Can't find a SQUASHFS superblock on %s\n",
3318 + bdevname(sb->s_bdev, b));
3320 + goto failed_mount;
3323 + /* Check the MAJOR & MINOR versions and compression type */
3324 + err = supported_squashfs_filesystem(le16_to_cpu(sblk->s_major),
3325 + le16_to_cpu(sblk->s_minor),
3326 + le16_to_cpu(sblk->compression));
3328 + goto failed_mount;
3333 + * Check if there's xattrs in the filesystem. These are not
3334 + * supported in this version, so warn that they will be ignored.
3336 + if (le64_to_cpu(sblk->xattr_table_start) != SQUASHFS_INVALID_BLK)
3337 + ERROR("Xattrs in filesystem, these will be ignored\n");
3339 + /* Check the filesystem does not extend beyond the end of the
3341 + msblk->bytes_used = le64_to_cpu(sblk->bytes_used);
3342 + if (msblk->bytes_used < 0 || msblk->bytes_used >
3343 + i_size_read(sb->s_bdev->bd_inode))
3344 + goto failed_mount;
3346 + /* Check block size for sanity */
3347 + msblk->block_size = le32_to_cpu(sblk->block_size);
3348 + if (msblk->block_size > SQUASHFS_FILE_MAX_SIZE)
3349 + goto failed_mount;
3352 + * Check the system page size is not larger than the filesystem
3353 + * block size (by default 128K). This is currently not supported.
3355 + if (PAGE_CACHE_SIZE > msblk->block_size) {
3356 + ERROR("Page size > filesystem block size (%d). This is "
3357 + "currently not supported!\n", msblk->block_size);
3358 + goto failed_mount;
3361 + msblk->block_log = le16_to_cpu(sblk->block_log);
3362 + if (msblk->block_log > SQUASHFS_FILE_MAX_LOG)
3363 + goto failed_mount;
3365 + /* Check the root inode for sanity */
3366 + root_inode = le64_to_cpu(sblk->root_inode);
3367 + if (SQUASHFS_INODE_OFFSET(root_inode) > SQUASHFS_METADATA_SIZE)
3368 + goto failed_mount;
3370 + msblk->inode_table = le64_to_cpu(sblk->inode_table_start);
3371 + msblk->directory_table = le64_to_cpu(sblk->directory_table_start);
3372 + msblk->inodes = le32_to_cpu(sblk->inodes);
3373 + flags = le16_to_cpu(sblk->flags);
3375 + TRACE("Found valid superblock on %s\n", bdevname(sb->s_bdev, b));
3376 + TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(flags)
3378 + TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(flags)
3380 + TRACE("Filesystem size %lld bytes\n", msblk->bytes_used);
3381 + TRACE("Block size %d\n", msblk->block_size);
3382 + TRACE("Number of inodes %d\n", msblk->inodes);
3383 + TRACE("Number of fragments %d\n", le32_to_cpu(sblk->fragments));
3384 + TRACE("Number of ids %d\n", le16_to_cpu(sblk->no_ids));
3385 + TRACE("sblk->inode_table_start %llx\n", msblk->inode_table);
3386 + TRACE("sblk->directory_table_start %llx\n", msblk->directory_table);
3387 + TRACE("sblk->fragment_table_start %llx\n",
3388 + (u64) le64_to_cpu(sblk->fragment_table_start));
3389 + TRACE("sblk->id_table_start %llx\n",
3390 + (u64) le64_to_cpu(sblk->id_table_start));
3392 + sb->s_maxbytes = MAX_LFS_FILESIZE;
3393 + sb->s_flags |= MS_RDONLY;
3394 + sb->s_op = &squashfs_super_ops;
3398 + msblk->block_cache = squashfs_cache_init("metadata",
3399 + SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE);
3400 + if (msblk->block_cache == NULL)
3401 + goto failed_mount;
3403 + /* Allocate read_page block */
3404 + msblk->read_page = squashfs_cache_init("data", 1, msblk->block_size);
3405 + if (msblk->read_page == NULL) {
3406 + ERROR("Failed to allocate read_page block\n");
3407 + goto failed_mount;
3410 + /* Allocate and read id index table */
3411 + msblk->id_table = squashfs_read_id_index_table(sb,
3412 + le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids));
3413 + if (IS_ERR(msblk->id_table)) {
3414 + err = PTR_ERR(msblk->id_table);
3415 + msblk->id_table = NULL;
3416 + goto failed_mount;
3419 + fragments = le32_to_cpu(sblk->fragments);
3420 + if (fragments == 0)
3421 + goto allocate_lookup_table;
3423 + msblk->fragment_cache = squashfs_cache_init("fragment",
3424 + SQUASHFS_CACHED_FRAGMENTS, msblk->block_size);
3425 + if (msblk->fragment_cache == NULL) {
3427 + goto failed_mount;
3430 + /* Allocate and read fragment index table */
3431 + msblk->fragment_index = squashfs_read_fragment_index_table(sb,
3432 + le64_to_cpu(sblk->fragment_table_start), fragments);
3433 + if (IS_ERR(msblk->fragment_index)) {
3434 + err = PTR_ERR(msblk->fragment_index);
3435 + msblk->fragment_index = NULL;
3436 + goto failed_mount;
3439 +allocate_lookup_table:
3440 + lookup_table_start = le64_to_cpu(sblk->lookup_table_start);
3441 + if (lookup_table_start == SQUASHFS_INVALID_BLK)
3442 + goto allocate_root;
3444 + /* Allocate and read inode lookup table */
3445 + msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb,
3446 + lookup_table_start, msblk->inodes);
3447 + if (IS_ERR(msblk->inode_lookup_table)) {
3448 + err = PTR_ERR(msblk->inode_lookup_table);
3449 + msblk->inode_lookup_table = NULL;
3450 + goto failed_mount;
3453 + sb->s_export_op = &squashfs_export_ops;
3456 + root = new_inode(sb);
3459 + goto failed_mount;
3462 + err = squashfs_read_inode(root, root_inode);
3464 + iget_failed(root);
3465 + goto failed_mount;
3467 + insert_inode_hash(root);
3469 + sb->s_root = d_alloc_root(root);
3470 + if (sb->s_root == NULL) {
3471 + ERROR("Root inode create failed\n");
3474 + goto failed_mount;
3477 + TRACE("Leaving squashfs_fill_super\n");
3482 + squashfs_cache_delete(msblk->block_cache);
3483 + squashfs_cache_delete(msblk->fragment_cache);
3484 + squashfs_cache_delete(msblk->read_page);
3485 + kfree(msblk->inode_lookup_table);
3486 + kfree(msblk->fragment_index);
3487 + kfree(msblk->id_table);
3488 + kfree(msblk->stream.workspace);
3489 + kfree(sb->s_fs_info);
3490 + sb->s_fs_info = NULL;
3495 + kfree(msblk->stream.workspace);
3496 + kfree(sb->s_fs_info);
3497 + sb->s_fs_info = NULL;
3502 +static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
3504 + struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info;
3505 + u64 id = huge_encode_dev(dentry->d_sb->s_bdev->bd_dev);
3507 + TRACE("Entered squashfs_statfs\n");
3509 + buf->f_type = SQUASHFS_MAGIC;
3510 + buf->f_bsize = msblk->block_size;
3511 + buf->f_blocks = ((msblk->bytes_used - 1) >> msblk->block_log) + 1;
3512 + buf->f_bfree = buf->f_bavail = 0;
3513 + buf->f_files = msblk->inodes;
3515 + buf->f_namelen = SQUASHFS_NAME_LEN;
3516 + buf->f_fsid.val[0] = (u32)id;
3517 + buf->f_fsid.val[1] = (u32)(id >> 32);
3523 +static int squashfs_remount(struct super_block *sb, int *flags, char *data)
3525 + *flags |= MS_RDONLY;
3530 +static void squashfs_put_super(struct super_block *sb)
3532 + if (sb->s_fs_info) {
3533 + struct squashfs_sb_info *sbi = sb->s_fs_info;
3534 + squashfs_cache_delete(sbi->block_cache);
3535 + squashfs_cache_delete(sbi->fragment_cache);
3536 + squashfs_cache_delete(sbi->read_page);
3537 + kfree(sbi->id_table);
3538 + kfree(sbi->fragment_index);
3539 + kfree(sbi->meta_index);
3540 + kfree(sbi->stream.workspace);
3541 + kfree(sb->s_fs_info);
3542 + sb->s_fs_info = NULL;
3547 +static int squashfs_get_sb(struct file_system_type *fs_type, int flags,
3548 + const char *dev_name, void *data,
3549 + struct vfsmount *mnt)
3551 + return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super,
3556 +static struct kmem_cache *squashfs_inode_cachep;
3559 +static void init_once(void *foo)
3561 + struct squashfs_inode_info *ei = foo;
3563 + inode_init_once(&ei->vfs_inode);
3567 +static int __init init_inodecache(void)
3569 + squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache",
3570 + sizeof(struct squashfs_inode_info), 0,
3571 + SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, init_once);
3573 + return squashfs_inode_cachep ? 0 : -ENOMEM;
3577 +static void destroy_inodecache(void)
3579 + kmem_cache_destroy(squashfs_inode_cachep);
3583 +static int __init init_squashfs_fs(void)
3585 + int err = init_inodecache();
3590 + err = register_filesystem(&squashfs_fs_type);
3592 + destroy_inodecache();
3596 + printk(KERN_INFO "squashfs: version 4.0 (2009/01/31) "
3597 + "Phillip Lougher\n");
3603 +static void __exit exit_squashfs_fs(void)
3605 + unregister_filesystem(&squashfs_fs_type);
3606 + destroy_inodecache();
3610 +static struct inode *squashfs_alloc_inode(struct super_block *sb)
3612 + struct squashfs_inode_info *ei =
3613 + kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL);
3615 + return ei ? &ei->vfs_inode : NULL;
3619 +static void squashfs_destroy_inode(struct inode *inode)
3621 + kmem_cache_free(squashfs_inode_cachep, squashfs_i(inode));
3625 +static struct file_system_type squashfs_fs_type = {
3626 + .owner = THIS_MODULE,
3627 + .name = "squashfs",
3628 + .get_sb = squashfs_get_sb,
3629 + .kill_sb = kill_block_super,
3630 + .fs_flags = FS_REQUIRES_DEV
3633 +static struct super_operations squashfs_super_ops = {
3634 + .alloc_inode = squashfs_alloc_inode,
3635 + .destroy_inode = squashfs_destroy_inode,
3636 + .statfs = squashfs_statfs,
3637 + .put_super = squashfs_put_super,
3638 + .remount_fs = squashfs_remount
3641 +module_init(init_squashfs_fs);
3642 +module_exit(exit_squashfs_fs);
3643 +MODULE_DESCRIPTION("squashfs 4.0, a compressed read-only filesystem");
3644 +MODULE_AUTHOR("Phillip Lougher <phillip@lougher.demon.co.uk>");
3645 +MODULE_LICENSE("GPL");
3646 diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c
3647 new file mode 100644
3648 index 0000000..83d8788
3650 +++ b/fs/squashfs/symlink.c
3653 + * Squashfs - a compressed read only filesystem for Linux
3655 + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
3656 + * Phillip Lougher <phillip@lougher.demon.co.uk>
3658 + * This program is free software; you can redistribute it and/or
3659 + * modify it under the terms of the GNU General Public License
3660 + * as published by the Free Software Foundation; either version 2,
3661 + * or (at your option) any later version.
3663 + * This program is distributed in the hope that it will be useful,
3664 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3665 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3666 + * GNU General Public License for more details.
3668 + * You should have received a copy of the GNU General Public License
3669 + * along with this program; if not, write to the Free Software
3670 + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
3676 + * This file implements code to handle symbolic links.
3678 + * The data contents of symbolic links are stored inside the symbolic
3679 + * link inode within the inode table. This allows the normally small symbolic
3680 + * link to be compressed as part of the inode table, achieving much greater
3681 + * compression than if the symbolic link was compressed individually.
3684 +#include <linux/fs.h>
3685 +#include <linux/vfs.h>
3686 +#include <linux/kernel.h>
3687 +#include <linux/slab.h>
3688 +#include <linux/string.h>
3689 +#include <linux/pagemap.h>
3690 +#include <linux/zlib.h>
3692 +#include "squashfs_fs.h"
3693 +#include "squashfs_fs_sb.h"
3694 +#include "squashfs_fs_i.h"
3695 +#include "squashfs.h"
3697 +static int squashfs_symlink_readpage(struct file *file, struct page *page)
3699 + struct inode *inode = page->mapping->host;
3700 + struct super_block *sb = inode->i_sb;
3701 + struct squashfs_sb_info *msblk = sb->s_fs_info;
3702 + int index = page->index << PAGE_CACHE_SHIFT;
3703 + u64 block = squashfs_i(inode)->start;
3704 + int offset = squashfs_i(inode)->offset;
3705 + int length = min_t(int, i_size_read(inode) - index, PAGE_CACHE_SIZE);
3706 + int bytes, copied;
3708 + struct squashfs_cache_entry *entry;
3710 + TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
3711 + "%llx, offset %x\n", page->index, block, offset);
3714 + * Skip index bytes into symlink metadata.
3717 + bytes = squashfs_read_metadata(sb, NULL, &block, &offset,
3720 + ERROR("Unable to read symlink [%llx:%x]\n",
3721 + squashfs_i(inode)->start,
3722 + squashfs_i(inode)->offset);
3728 + * Read length bytes from symlink metadata. Squashfs_read_metadata
3729 + * is not used here because it can sleep and we want to use
3730 + * kmap_atomic to map the page. Instead call the underlying
3731 + * squashfs_cache_get routine. As length bytes may overlap metadata
3732 + * blocks, we may need to call squashfs_cache_get multiple times.
3734 + for (bytes = 0; bytes < length; offset = 0, bytes += copied) {
3735 + entry = squashfs_cache_get(sb, msblk->block_cache, block, 0);
3736 + if (entry->error) {
3737 + ERROR("Unable to read symlink [%llx:%x]\n",
3738 + squashfs_i(inode)->start,
3739 + squashfs_i(inode)->offset);
3740 + squashfs_cache_put(entry);
3744 + pageaddr = kmap_atomic(page, KM_USER0);
3745 + copied = squashfs_copy_data(pageaddr + bytes, entry, offset,
3747 + if (copied == length - bytes)
3748 + memset(pageaddr + length, 0, PAGE_CACHE_SIZE - length);
3750 + block = entry->next_index;
3751 + kunmap_atomic(pageaddr, KM_USER0);
3752 + squashfs_cache_put(entry);
3755 + flush_dcache_page(page);
3756 + SetPageUptodate(page);
3757 + unlock_page(page);
3761 + SetPageError(page);
3762 + unlock_page(page);
3767 +const struct address_space_operations squashfs_symlink_aops = {
3768 + .readpage = squashfs_symlink_readpage
3770 diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c
3771 index fedef93..7931b35 100644
3772 --- a/init/do_mounts_rd.c
3773 +++ b/init/do_mounts_rd.c
3775 #include <linux/string.h>
3777 #include "do_mounts.h"
3778 +#include "../fs/squashfs/squashfs_fs.h"
3780 int __initdata rd_prompt = 1;/* 1 = prompt for RAM disk, 0 = don't prompt */
3782 @@ -41,6 +42,7 @@ static int __init crd_load(int in_fd, int out_fd);
3790 @@ -51,6 +53,7 @@ identify_ramdisk_image(int fd, int start_block)
3791 struct ext2_super_block *ext2sb;
3792 struct romfs_super_block *romfsb;
3793 struct cramfs_super *cramfsb;
3794 + struct squashfs_super_block *squashfsb;
3798 @@ -62,6 +65,7 @@ identify_ramdisk_image(int fd, int start_block)
3799 ext2sb = (struct ext2_super_block *) buf;
3800 romfsb = (struct romfs_super_block *) buf;
3801 cramfsb = (struct cramfs_super *) buf;
3802 + squashfsb = (struct squashfs_super_block *) buf;
3803 memset(buf, 0xe5, size);
3806 @@ -99,6 +103,16 @@ identify_ramdisk_image(int fd, int start_block)
3810 + /* squashfs is at block zero too */
3811 + if (le32_to_cpu(squashfsb->s_magic) == SQUASHFS_MAGIC) {
3812 + printk(KERN_NOTICE
3813 + "RAMDISK: squashfs filesystem found at block %d\n",
3815 + nblocks = (le64_to_cpu(squashfsb->bytes_used) + BLOCK_SIZE - 1)
3816 + >> BLOCK_SIZE_BITS;
3821 * Read block 1 to test for minix and ext2 superblock