Magellan Linux

Annotation of /trunk/kernel26-magellan-server/patches-2.6.24-r5/0152-2.6.21-squashfs-3.3.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 574 - (hide annotations) (download)
Mon Apr 21 17:56:37 2008 UTC (16 years ago) by niro
File size: 128850 byte(s)
- 2.6.24-magellan-r5: updated to linux-2.6.24.5

1 niro 574 diff -x .gitignore -Nurp linux-2.6.24/fs/Kconfig linux-2.6.24-squashfs3.3/fs/Kconfig
2     --- linux-2.6.24/fs/Kconfig 2007-10-25 17:41:45.000000000 +0100
3     +++ linux-2.6.24-squashfs3.3/fs/Kconfig 2007-11-01 05:06:25.000000000 +0000
4     @@ -1396,6 +1396,56 @@ config CRAMFS
5    
6     If unsure, say N.
7    
8     +config SQUASHFS
9     + tristate "SquashFS 3.3 - Squashed file system support"
10     + select ZLIB_INFLATE
11     + help
12     + Saying Y here includes support for SquashFS 3.3 (a Compressed
13     + Read-Only File System). Squashfs is a highly compressed read-only
14     + filesystem for Linux. It uses zlib compression to compress both
15     + files, inodes and directories. Inodes in the system are very small
16     + and all blocks are packed to minimise data overhead. Block sizes
17     + greater than 4K are supported up to a maximum of 1 Mbytes (default
18     + block size 128K). SquashFS 3.3 supports 64 bit filesystems and files
19     + (larger than 4GB), full uid/gid information, hard links and timestamps.
20     +
21     + Squashfs is intended for general read-only filesystem use, for
22     + archival use (i.e. in cases where a .tar.gz file may be used), and in
23     + embedded systems where low overhead is needed. Further information
24     + and filesystem tools are available from http://squashfs.sourceforge.net.
25     +
26     + If you want to compile this as a module ( = code which can be
27     + inserted in and removed from the running kernel whenever you want),
28     + say M here and read <file:Documentation/modules.txt>. The module
29     + will be called squashfs. Note that the root file system (the one
30     + containing the directory /) cannot be compiled as a module.
31     +
32     + If unsure, say N.
33     +
34     +config SQUASHFS_EMBEDDED
35     +
36     + bool "Additional option for memory-constrained systems"
37     + depends on SQUASHFS
38     + default n
39     + help
40     + Saying Y here allows you to specify cache size.
41     +
42     + If unsure, say N.
43     +
44     +config SQUASHFS_FRAGMENT_CACHE_SIZE
45     + int "Number of fragments cached" if SQUASHFS_EMBEDDED
46     + depends on SQUASHFS
47     + default "3"
48     + help
49     + By default SquashFS caches the last 3 fragments read from
50     + the filesystem. Increasing this amount may mean SquashFS
51     + has to re-read fragments less often from disk, at the expense
52     + of extra system memory. Decreasing this amount will mean
53     + SquashFS uses less memory at the expense of extra reads from disk.
54     +
55     + Note there must be at least one cached fragment. Anything
56     + much more than three will probably not make much difference.
57     +
58     config VXFS_FS
59     tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"
60     depends on BLOCK
61     diff -x .gitignore -Nurp linux-2.6.24/fs/Makefile linux-2.6.24-squashfs3.3/fs/Makefile
62     --- linux-2.6.24/fs/Makefile 2007-10-25 17:41:45.000000000 +0100
63     +++ linux-2.6.24-squashfs3.3/fs/Makefile 2007-11-01 05:08:09.000000000 +0000
64     @@ -72,6 +72,7 @@ obj-$(CONFIG_JBD) += jbd/
65     obj-$(CONFIG_JBD2) += jbd2/
66     obj-$(CONFIG_EXT2_FS) += ext2/
67     obj-$(CONFIG_CRAMFS) += cramfs/
68     +obj-$(CONFIG_SQUASHFS) += squashfs/
69     obj-y += ramfs/
70     obj-$(CONFIG_HUGETLBFS) += hugetlbfs/
71     obj-$(CONFIG_CODA_FS) += coda/
72     diff -x .gitignore -Nurp linux-2.6.24/fs/squashfs/inode.c linux-2.6.24-squashfs3.3/fs/squashfs/inode.c
73     --- linux-2.6.24/fs/squashfs/inode.c 1970-01-01 01:00:00.000000000 +0100
74     +++ linux-2.6.24-squashfs3.3/fs/squashfs/inode.c 2007-11-01 05:05:00.000000000 +0000
75     @@ -0,0 +1,2192 @@
76     +/*
77     + * Squashfs - a compressed read only filesystem for Linux
78     + *
79     + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
80     + * Phillip Lougher <phillip@lougher.demon.co.uk>
81     + *
82     + * This program is free software; you can redistribute it and/or
83     + * modify it under the terms of the GNU General Public License
84     + * as published by the Free Software Foundation; either version 2,
85     + * or (at your option) any later version.
86     + *
87     + * This program is distributed in the hope that it will be useful,
88     + * but WITHOUT ANY WARRANTY; without even the implied warranty of
89     + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
90     + * GNU General Public License for more details.
91     + *
92     + * You should have received a copy of the GNU General Public License
93     + * along with this program; if not, write to the Free Software
94     + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
95     + *
96     + * inode.c
97     + */
98     +
99     +#include <linux/squashfs_fs.h>
100     +#include <linux/module.h>
101     +#include <linux/zlib.h>
102     +#include <linux/fs.h>
103     +#include <linux/squashfs_fs_sb.h>
104     +#include <linux/squashfs_fs_i.h>
105     +#include <linux/buffer_head.h>
106     +#include <linux/vfs.h>
107     +#include <linux/vmalloc.h>
108     +#include <linux/smp_lock.h>
109     +#include <linux/exportfs.h>
110     +
111     +#include "squashfs.h"
112     +
113     +int squashfs_cached_blks;
114     +
115     +static void vfs_read_inode(struct inode *i);
116     +static struct dentry *squashfs_get_parent(struct dentry *child);
117     +static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode);
118     +static int squashfs_statfs(struct dentry *, struct kstatfs *);
119     +static int squashfs_symlink_readpage(struct file *file, struct page *page);
120     +static long long read_blocklist(struct inode *inode, int index,
121     + int readahead_blks, char *block_list,
122     + unsigned short **block_p, unsigned int *bsize);
123     +static int squashfs_readpage(struct file *file, struct page *page);
124     +static int squashfs_readdir(struct file *, void *, filldir_t);
125     +static struct dentry *squashfs_lookup(struct inode *, struct dentry *,
126     + struct nameidata *);
127     +static int squashfs_remount(struct super_block *s, int *flags, char *data);
128     +static void squashfs_put_super(struct super_block *);
129     +static int squashfs_get_sb(struct file_system_type *,int, const char *, void *,
130     + struct vfsmount *);
131     +static struct inode *squashfs_alloc_inode(struct super_block *sb);
132     +static void squashfs_destroy_inode(struct inode *inode);
133     +static int init_inodecache(void);
134     +static void destroy_inodecache(void);
135     +
136     +static struct file_system_type squashfs_fs_type = {
137     + .owner = THIS_MODULE,
138     + .name = "squashfs",
139     + .get_sb = squashfs_get_sb,
140     + .kill_sb = kill_block_super,
141     + .fs_flags = FS_REQUIRES_DEV
142     +};
143     +
144     +static const unsigned char squashfs_filetype_table[] = {
145     + DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
146     +};
147     +
148     +static struct super_operations squashfs_super_ops = {
149     + .alloc_inode = squashfs_alloc_inode,
150     + .destroy_inode = squashfs_destroy_inode,
151     + .statfs = squashfs_statfs,
152     + .put_super = squashfs_put_super,
153     + .remount_fs = squashfs_remount
154     +};
155     +
156     +static struct super_operations squashfs_export_super_ops = {
157     + .alloc_inode = squashfs_alloc_inode,
158     + .destroy_inode = squashfs_destroy_inode,
159     + .statfs = squashfs_statfs,
160     + .put_super = squashfs_put_super,
161     + .read_inode = vfs_read_inode
162     +};
163     +
164     +static struct export_operations squashfs_export_ops = {
165     + .get_parent = squashfs_get_parent
166     +};
167     +
168     +SQSH_EXTERN const struct address_space_operations squashfs_symlink_aops = {
169     + .readpage = squashfs_symlink_readpage
170     +};
171     +
172     +SQSH_EXTERN const struct address_space_operations squashfs_aops = {
173     + .readpage = squashfs_readpage
174     +};
175     +
176     +static const struct file_operations squashfs_dir_ops = {
177     + .read = generic_read_dir,
178     + .readdir = squashfs_readdir
179     +};
180     +
181     +SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = {
182     + .lookup = squashfs_lookup
183     +};
184     +
185     +
186     +static struct buffer_head *get_block_length(struct super_block *s,
187     + int *cur_index, int *offset, int *c_byte)
188     +{
189     + struct squashfs_sb_info *msblk = s->s_fs_info;
190     + unsigned short temp;
191     + struct buffer_head *bh;
192     +
193     + if (!(bh = sb_bread(s, *cur_index)))
194     + goto out;
195     +
196     + if (msblk->devblksize - *offset == 1) {
197     + if (msblk->swap)
198     + ((unsigned char *) &temp)[1] = *((unsigned char *)
199     + (bh->b_data + *offset));
200     + else
201     + ((unsigned char *) &temp)[0] = *((unsigned char *)
202     + (bh->b_data + *offset));
203     + brelse(bh);
204     + if (!(bh = sb_bread(s, ++(*cur_index))))
205     + goto out;
206     + if (msblk->swap)
207     + ((unsigned char *) &temp)[0] = *((unsigned char *)
208     + bh->b_data);
209     + else
210     + ((unsigned char *) &temp)[1] = *((unsigned char *)
211     + bh->b_data);
212     + *c_byte = temp;
213     + *offset = 1;
214     + } else {
215     + if (msblk->swap) {
216     + ((unsigned char *) &temp)[1] = *((unsigned char *)
217     + (bh->b_data + *offset));
218     + ((unsigned char *) &temp)[0] = *((unsigned char *)
219     + (bh->b_data + *offset + 1));
220     + } else {
221     + ((unsigned char *) &temp)[0] = *((unsigned char *)
222     + (bh->b_data + *offset));
223     + ((unsigned char *) &temp)[1] = *((unsigned char *)
224     + (bh->b_data + *offset + 1));
225     + }
226     + *c_byte = temp;
227     + *offset += 2;
228     + }
229     +
230     + if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) {
231     + if (*offset == msblk->devblksize) {
232     + brelse(bh);
233     + if (!(bh = sb_bread(s, ++(*cur_index))))
234     + goto out;
235     + *offset = 0;
236     + }
237     + if (*((unsigned char *) (bh->b_data + *offset)) !=
238     + SQUASHFS_MARKER_BYTE) {
239     + ERROR("Metadata block marker corrupt @ %x\n",
240     + *cur_index);
241     + brelse(bh);
242     + goto out;
243     + }
244     + (*offset)++;
245     + }
246     + return bh;
247     +
248     +out:
249     + return NULL;
250     +}
251     +
252     +
253     +SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
254     + long long index, unsigned int length,
255     + long long *next_index, int srclength)
256     +{
257     + struct squashfs_sb_info *msblk = s->s_fs_info;
258     + struct squashfs_super_block *sblk = &msblk->sblk;
259     + struct buffer_head **bh;
260     + unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
261     + unsigned int cur_index = index >> msblk->devblksize_log2;
262     + int bytes, avail_bytes, b = 0, k = 0;
263     + unsigned int compressed;
264     + unsigned int c_byte = length;
265     +
266     + bh = kmalloc(((sblk->block_size >> msblk->devblksize_log2) + 1) *
267     + sizeof(struct buffer_head *), GFP_KERNEL);
268     + if (bh == NULL)
269     + goto read_failure;
270     +
271     + if (c_byte) {
272     + bytes = msblk->devblksize - offset;
273     + compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
274     + c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
275     +
276     + TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index,
277     + compressed ? "" : "un", (unsigned int) c_byte, srclength);
278     +
279     + if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used)
280     + goto read_failure;
281     +
282     + bh[0] = sb_getblk(s, cur_index);
283     + if (bh[0] == NULL)
284     + goto block_release;
285     +
286     + for (b = 1; bytes < c_byte; b++) {
287     + bh[b] = sb_getblk(s, ++cur_index);
288     + if (bh[b] == NULL)
289     + goto block_release;
290     + bytes += msblk->devblksize;
291     + }
292     + ll_rw_block(READ, b, bh);
293     + } else {
294     + if (index < 0 || (index + 2) > sblk->bytes_used)
295     + goto read_failure;
296     +
297     + bh[0] = get_block_length(s, &cur_index, &offset, &c_byte);
298     + if (bh[0] == NULL)
299     + goto read_failure;
300     +
301     + bytes = msblk->devblksize - offset;
302     + compressed = SQUASHFS_COMPRESSED(c_byte);
303     + c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
304     +
305     + TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
306     + ? "" : "un", (unsigned int) c_byte);
307     +
308     + if (c_byte > srclength || (index + c_byte) > sblk->bytes_used)
309     + goto read_failure;
310     +
311     + for (b = 1; bytes < c_byte; b++) {
312     + bh[b] = sb_getblk(s, ++cur_index);
313     + if (bh[b] == NULL)
314     + goto block_release;
315     + bytes += msblk->devblksize;
316     + }
317     + ll_rw_block(READ, b - 1, bh + 1);
318     + }
319     +
320     + if (compressed) {
321     + int zlib_err = 0;
322     +
323     + /*
324     + * uncompress block
325     + */
326     +
327     + mutex_lock(&msblk->read_data_mutex);
328     +
329     + msblk->stream.next_out = buffer;
330     + msblk->stream.avail_out = srclength;
331     +
332     + for (bytes = 0; k < b; k++) {
333     + avail_bytes = min(c_byte - bytes, msblk->devblksize - offset);
334     +
335     + wait_on_buffer(bh[k]);
336     + if (!buffer_uptodate(bh[k]))
337     + goto release_mutex;
338     +
339     + msblk->stream.next_in = bh[k]->b_data + offset;
340     + msblk->stream.avail_in = avail_bytes;
341     +
342     + if (k == 0) {
343     + zlib_err = zlib_inflateInit(&msblk->stream);
344     + if (zlib_err != Z_OK) {
345     + ERROR("zlib_inflateInit returned unexpected result 0x%x,"
346     + " srclength %d\n", zlib_err, srclength);
347     + goto release_mutex;
348     + }
349     +
350     + if (avail_bytes == 0) {
351     + offset = 0;
352     + brelse(bh[k]);
353     + continue;
354     + }
355     + }
356     +
357     + zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH);
358     + if (zlib_err != Z_OK && zlib_err != Z_STREAM_END) {
359     + ERROR("zlib_inflate returned unexpected result 0x%x,"
360     + " srclength %d, avail_in %d, avail_out %d\n", zlib_err,
361     + srclength, msblk->stream.avail_in, msblk->stream.avail_out);
362     + goto release_mutex;
363     + }
364     +
365     + bytes += avail_bytes;
366     + offset = 0;
367     + brelse(bh[k]);
368     + }
369     +
370     + if (zlib_err != Z_STREAM_END)
371     + goto release_mutex;
372     +
373     + zlib_err = zlib_inflateEnd(&msblk->stream);
374     + if (zlib_err != Z_OK) {
375     + ERROR("zlib_inflateEnd returned unexpected result 0x%x,"
376     + " srclength %d\n", zlib_err, srclength);
377     + goto release_mutex;
378     + }
379     + bytes = msblk->stream.total_out;
380     + mutex_unlock(&msblk->read_data_mutex);
381     + } else {
382     + int i;
383     +
384     + for(i = 0; i < b; i++) {
385     + wait_on_buffer(bh[i]);
386     + if (!buffer_uptodate(bh[i]))
387     + goto block_release;
388     + }
389     +
390     + for (bytes = 0; k < b; k++) {
391     + avail_bytes = min(c_byte - bytes, msblk->devblksize - offset);
392     +
393     + memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes);
394     + bytes += avail_bytes;
395     + offset = 0;
396     + brelse(bh[k]);
397     + }
398     + }
399     +
400     + if (next_index)
401     + *next_index = index + c_byte + (length ? 0 :
402     + (SQUASHFS_CHECK_DATA(msblk->sblk.flags) ? 3 : 2));
403     +
404     + kfree(bh);
405     + return bytes;
406     +
407     +release_mutex:
408     + mutex_unlock(&msblk->read_data_mutex);
409     +
410     +block_release:
411     + for (; k < b; k++)
412     + brelse(bh[k]);
413     +
414     +read_failure:
415     + ERROR("sb_bread failed reading block 0x%x\n", cur_index);
416     + kfree(bh);
417     + return 0;
418     +}
419     +
420     +
421     +SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, void *buffer,
422     + long long block, unsigned int offset,
423     + int length, long long *next_block,
424     + unsigned int *next_offset)
425     +{
426     + struct squashfs_sb_info *msblk = s->s_fs_info;
427     + int n, i, bytes, return_length = length;
428     + long long next_index;
429     +
430     + TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
431     +
432     + while (1) {
433     + for (i = 0; i < squashfs_cached_blks; i++)
434     + if (msblk->block_cache[i].block == block)
435     + break;
436     +
437     + mutex_lock(&msblk->block_cache_mutex);
438     +
439     + if (i == squashfs_cached_blks) {
440     + /* read inode header block */
441     + if (msblk->unused_cache_blks == 0) {
442     + mutex_unlock(&msblk->block_cache_mutex);
443     + wait_event(msblk->waitq, msblk->unused_cache_blks);
444     + continue;
445     + }
446     +
447     + i = msblk->next_cache;
448     + for (n = 0; n < squashfs_cached_blks; n++) {
449     + if (msblk->block_cache[i].block != SQUASHFS_USED_BLK)
450     + break;
451     + i = (i + 1) % squashfs_cached_blks;
452     + }
453     +
454     + msblk->next_cache = (i + 1) % squashfs_cached_blks;
455     +
456     + if (msblk->block_cache[i].block == SQUASHFS_INVALID_BLK) {
457     + msblk->block_cache[i].data = vmalloc(SQUASHFS_METADATA_SIZE);
458     + if (msblk->block_cache[i].data == NULL) {
459     + ERROR("Failed to allocate cache block\n");
460     + mutex_unlock(&msblk->block_cache_mutex);
461     + goto out;
462     + }
463     + }
464     +
465     + msblk->block_cache[i].block = SQUASHFS_USED_BLK;
466     + msblk->unused_cache_blks --;
467     + mutex_unlock(&msblk->block_cache_mutex);
468     +
469     + msblk->block_cache[i].length = squashfs_read_data(s,
470     + msblk->block_cache[i].data, block, 0, &next_index,
471     + SQUASHFS_METADATA_SIZE);
472     +
473     + if (msblk->block_cache[i].length == 0) {
474     + ERROR("Unable to read cache block [%llx:%x]\n", block, offset);
475     + mutex_lock(&msblk->block_cache_mutex);
476     + msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
477     + msblk->unused_cache_blks ++;
478     + smp_mb();
479     + vfree(msblk->block_cache[i].data);
480     + wake_up(&msblk->waitq);
481     + mutex_unlock(&msblk->block_cache_mutex);
482     + goto out;
483     + }
484     +
485     + mutex_lock(&msblk->block_cache_mutex);
486     + msblk->block_cache[i].block = block;
487     + msblk->block_cache[i].next_index = next_index;
488     + msblk->unused_cache_blks ++;
489     + smp_mb();
490     + wake_up(&msblk->waitq);
491     + TRACE("Read cache block [%llx:%x]\n", block, offset);
492     + }
493     +
494     + if (msblk->block_cache[i].block != block) {
495     + mutex_unlock(&msblk->block_cache_mutex);
496     + continue;
497     + }
498     +
499     + bytes = msblk->block_cache[i].length - offset;
500     +
501     + if (bytes < 1) {
502     + mutex_unlock(&msblk->block_cache_mutex);
503     + goto out;
504     + } else if (bytes >= length) {
505     + if (buffer)
506     + memcpy(buffer, msblk->block_cache[i].data + offset, length);
507     + if (msblk->block_cache[i].length - offset == length) {
508     + *next_block = msblk->block_cache[i].next_index;
509     + *next_offset = 0;
510     + } else {
511     + *next_block = block;
512     + *next_offset = offset + length;
513     + }
514     + mutex_unlock(&msblk->block_cache_mutex);
515     + goto finish;
516     + } else {
517     + if (buffer) {
518     + memcpy(buffer, msblk->block_cache[i].data + offset, bytes);
519     + buffer = (char *) buffer + bytes;
520     + }
521     + block = msblk->block_cache[i].next_index;
522     + mutex_unlock(&msblk->block_cache_mutex);
523     + length -= bytes;
524     + offset = 0;
525     + }
526     + }
527     +
528     +finish:
529     + return return_length;
530     +out:
531     + return 0;
532     +}
533     +
534     +
535     +static int get_fragment_location(struct super_block *s, unsigned int fragment,
536     + long long *fragment_start_block,
537     + unsigned int *fragment_size)
538     +{
539     + struct squashfs_sb_info *msblk = s->s_fs_info;
540     + long long start_block =
541     + msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];
542     + int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
543     + struct squashfs_fragment_entry fragment_entry;
544     +
545     + if (msblk->swap) {
546     + struct squashfs_fragment_entry sfragment_entry;
547     +
548     + if (!squashfs_get_cached_block(s, &sfragment_entry, start_block, offset,
549     + sizeof(sfragment_entry), &start_block, &offset))
550     + goto out;
551     + SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);
552     + } else
553     + if (!squashfs_get_cached_block(s, &fragment_entry, start_block, offset,
554     + sizeof(fragment_entry), &start_block, &offset))
555     + goto out;
556     +
557     + *fragment_start_block = fragment_entry.start_block;
558     + *fragment_size = fragment_entry.size;
559     +
560     + return 1;
561     +
562     +out:
563     + return 0;
564     +}
565     +
566     +
567     +SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk,
568     + struct squashfs_fragment_cache *fragment)
569     +{
570     + mutex_lock(&msblk->fragment_mutex);
571     + fragment->locked --;
572     + if (fragment->locked == 0) {
573     + msblk->unused_frag_blks ++;
574     + smp_mb();
575     + wake_up(&msblk->fragment_wait_queue);
576     + }
577     + mutex_unlock(&msblk->fragment_mutex);
578     +}
579     +
580     +
581     +SQSH_EXTERN
582     +struct squashfs_fragment_cache *get_cached_fragment(struct super_block *s,
583     + long long start_block, int length)
584     +{
585     + int i, n;
586     + struct squashfs_sb_info *msblk = s->s_fs_info;
587     + struct squashfs_super_block *sblk = &msblk->sblk;
588     +
589     + while (1) {
590     + mutex_lock(&msblk->fragment_mutex);
591     +
592     + for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&
593     + msblk->fragment[i].block != start_block; i++);
594     +
595     + if (i == SQUASHFS_CACHED_FRAGMENTS) {
596     + if (msblk->unused_frag_blks == 0) {
597     + mutex_unlock(&msblk->fragment_mutex);
598     + wait_event(msblk->fragment_wait_queue, msblk->unused_frag_blks);
599     + continue;
600     + }
601     +
602     + i = msblk->next_fragment;
603     + for (n = 0; n < SQUASHFS_CACHED_FRAGMENTS; n++) {
604     + if (msblk->fragment[i].locked == 0)
605     + break;
606     + i = (i + 1) % SQUASHFS_CACHED_FRAGMENTS;
607     + }
608     +
609     + msblk->next_fragment = (msblk->next_fragment + 1) %
610     + SQUASHFS_CACHED_FRAGMENTS;
611     +
612     + if (msblk->fragment[i].data == NULL) {
613     + msblk->fragment[i].data = vmalloc(sblk->block_size);
614     + if (msblk->fragment[i].data == NULL) {
615     + ERROR("Failed to allocate fragment cache block\n");
616     + mutex_unlock(&msblk->fragment_mutex);
617     + goto out;
618     + }
619     + }
620     +
621     + msblk->unused_frag_blks --;
622     + msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
623     + msblk->fragment[i].locked = 1;
624     + mutex_unlock(&msblk->fragment_mutex);
625     +
626     + msblk->fragment[i].length = squashfs_read_data(s,
627     + msblk->fragment[i].data, start_block, length, NULL,
628     + sblk->block_size);
629     +
630     + if (msblk->fragment[i].length == 0) {
631     + ERROR("Unable to read fragment cache block [%llx]\n", start_block);
632     + msblk->fragment[i].locked = 0;
633     + msblk->unused_frag_blks ++;
634     + smp_mb();
635     + wake_up(&msblk->fragment_wait_queue);
636     + goto out;
637     + }
638     +
639     + mutex_lock(&msblk->fragment_mutex);
640     + msblk->fragment[i].block = start_block;
641     + TRACE("New fragment %d, start block %lld, locked %d\n",
642     + i, msblk->fragment[i].block, msblk->fragment[i].locked);
643     + mutex_unlock(&msblk->fragment_mutex);
644     + break;
645     + }
646     +
647     + if (msblk->fragment[i].locked == 0)
648     + msblk->unused_frag_blks --;
649     + msblk->fragment[i].locked++;
650     + mutex_unlock(&msblk->fragment_mutex);
651     + TRACE("Got fragment %d, start block %lld, locked %d\n", i,
652     + msblk->fragment[i].block, msblk->fragment[i].locked);
653     + break;
654     + }
655     +
656     + return &msblk->fragment[i];
657     +
658     +out:
659     + return NULL;
660     +}
661     +
662     +
663     +static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i,
664     + struct squashfs_base_inode_header *inodeb)
665     +{
666     + i->i_ino = inodeb->inode_number;
667     + i->i_mtime.tv_sec = inodeb->mtime;
668     + i->i_atime.tv_sec = inodeb->mtime;
669     + i->i_ctime.tv_sec = inodeb->mtime;
670     + i->i_uid = msblk->uid[inodeb->uid];
671     + i->i_mode = inodeb->mode;
672     + i->i_size = 0;
673     +
674     + if (inodeb->guid == SQUASHFS_GUIDS)
675     + i->i_gid = i->i_uid;
676     + else
677     + i->i_gid = msblk->guid[inodeb->guid];
678     +}
679     +
680     +
681     +static squashfs_inode_t squashfs_inode_lookup(struct super_block *s, int ino)
682     +{
683     + struct squashfs_sb_info *msblk = s->s_fs_info;
684     + long long start = msblk->inode_lookup_table[SQUASHFS_LOOKUP_BLOCK(ino - 1)];
685     + int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino - 1);
686     + squashfs_inode_t inode;
687     +
688     + TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino);
689     +
690     + if (msblk->swap) {
691     + squashfs_inode_t sinode;
692     +
693     + if (!squashfs_get_cached_block(s, &sinode, start, offset,
694     + sizeof(sinode), &start, &offset))
695     + goto out;
696     + SQUASHFS_SWAP_INODE_T((&inode), &sinode);
697     + } else if (!squashfs_get_cached_block(s, &inode, start, offset,
698     + sizeof(inode), &start, &offset))
699     + goto out;
700     +
701     + TRACE("squashfs_inode_lookup, inode = 0x%llx\n", inode);
702     +
703     + return inode;
704     +
705     +out:
706     + return SQUASHFS_INVALID_BLK;
707     +}
708     +
709     +
710     +static void vfs_read_inode(struct inode *i)
711     +{
712     + struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
713     + squashfs_inode_t inode = squashfs_inode_lookup(i->i_sb, i->i_ino);
714     +
715     + TRACE("Entered vfs_read_inode\n");
716     +
717     + if(inode != SQUASHFS_INVALID_BLK)
718     + (msblk->read_inode)(i, inode);
719     +}
720     +
721     +
722     +static struct dentry *squashfs_get_parent(struct dentry *child)
723     +{
724     + struct inode *i = child->d_inode;
725     + struct inode *parent = iget(i->i_sb, SQUASHFS_I(i)->u.s2.parent_inode);
726     + struct dentry *rv;
727     +
728     + TRACE("Entered squashfs_get_parent\n");
729     +
730     + if(parent == NULL) {
731     + rv = ERR_PTR(-EACCES);
732     + goto out;
733     + }
734     +
735     + rv = d_alloc_anon(parent);
736     + if(rv == NULL)
737     + rv = ERR_PTR(-ENOMEM);
738     +
739     +out:
740     + return rv;
741     +}
742     +
743     +
744     +SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s,
745     + squashfs_inode_t inode, unsigned int inode_number)
746     +{
747     + struct squashfs_sb_info *msblk = s->s_fs_info;
748     + struct inode *i = iget_locked(s, inode_number);
749     +
750     + TRACE("Entered squashfs_iget\n");
751     +
752     + if(i && (i->i_state & I_NEW)) {
753     + (msblk->read_inode)(i, inode);
754     + unlock_new_inode(i);
755     + }
756     +
757     + return i;
758     +}
759     +
760     +
761     +static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode)
762     +{
763     + struct super_block *s = i->i_sb;
764     + struct squashfs_sb_info *msblk = s->s_fs_info;
765     + struct squashfs_super_block *sblk = &msblk->sblk;
766     + long long block = SQUASHFS_INODE_BLK(inode) + sblk->inode_table_start;
767     + unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
768     + long long next_block;
769     + unsigned int next_offset;
770     + union squashfs_inode_header id, sid;
771     + struct squashfs_base_inode_header *inodeb = &id.base, *sinodeb = &sid.base;
772     +
773     + TRACE("Entered squashfs_read_inode\n");
774     +
775     + if (msblk->swap) {
776     + if (!squashfs_get_cached_block(s, sinodeb, block, offset,
777     + sizeof(*sinodeb), &next_block, &next_offset))
778     + goto failed_read;
779     + SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb, sizeof(*sinodeb));
780     + } else
781     + if (!squashfs_get_cached_block(s, inodeb, block, offset,
782     + sizeof(*inodeb), &next_block, &next_offset))
783     + goto failed_read;
784     +
785     + squashfs_new_inode(msblk, i, inodeb);
786     +
787     + switch(inodeb->inode_type) {
788     + case SQUASHFS_FILE_TYPE: {
789     + unsigned int frag_size;
790     + long long frag_blk;
791     + struct squashfs_reg_inode_header *inodep = &id.reg;
792     + struct squashfs_reg_inode_header *sinodep = &sid.reg;
793     +
794     + if (msblk->swap) {
795     + if (!squashfs_get_cached_block(s, sinodep, block, offset,
796     + sizeof(*sinodep), &next_block, &next_offset))
797     + goto failed_read;
798     + SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);
799     + } else
800     + if (!squashfs_get_cached_block(s, inodep, block, offset,
801     + sizeof(*inodep), &next_block, &next_offset))
802     + goto failed_read;
803     +
804     + frag_blk = SQUASHFS_INVALID_BLK;
805     +
806     + if (inodep->fragment != SQUASHFS_INVALID_FRAG)
807     + if(!get_fragment_location(s, inodep->fragment, &frag_blk,
808     + &frag_size))
809     + goto failed_read;
810     +
811     + i->i_nlink = 1;
812     + i->i_size = inodep->file_size;
813     + i->i_fop = &generic_ro_fops;
814     + i->i_mode |= S_IFREG;
815     + i->i_blocks = ((i->i_size - 1) >> 9) + 1;
816     + SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
817     + SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
818     + SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
819     + SQUASHFS_I(i)->start_block = inodep->start_block;
820     + SQUASHFS_I(i)->u.s1.block_list_start = next_block;
821     + SQUASHFS_I(i)->offset = next_offset;
822     + i->i_data.a_ops = &squashfs_aops;
823     +
824     + TRACE("File inode %x:%x, start_block %llx, "
825     + "block_list_start %llx, offset %x\n",
826     + SQUASHFS_INODE_BLK(inode), offset,
827     + inodep->start_block, next_block,
828     + next_offset);
829     + break;
830     + }
831     + case SQUASHFS_LREG_TYPE: {
832     + unsigned int frag_size;
833     + long long frag_blk;
834     + struct squashfs_lreg_inode_header *inodep = &id.lreg;
835     + struct squashfs_lreg_inode_header *sinodep = &sid.lreg;
836     +
837     + if (msblk->swap) {
838     + if (!squashfs_get_cached_block(s, sinodep, block, offset,
839     + sizeof(*sinodep), &next_block, &next_offset))
840     + goto failed_read;
841     + SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);
842     + } else
843     + if (!squashfs_get_cached_block(s, inodep, block, offset,
844     + sizeof(*inodep), &next_block, &next_offset))
845     + goto failed_read;
846     +
847     + frag_blk = SQUASHFS_INVALID_BLK;
848     +
849     + if (inodep->fragment != SQUASHFS_INVALID_FRAG)
850     + if (!get_fragment_location(s, inodep->fragment, &frag_blk,
851     + &frag_size))
852     + goto failed_read;
853     +
854     + i->i_nlink = inodep->nlink;
855     + i->i_size = inodep->file_size;
856     + i->i_fop = &generic_ro_fops;
857     + i->i_mode |= S_IFREG;
858     + i->i_blocks = ((i->i_size - 1) >> 9) + 1;
859     + SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
860     + SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
861     + SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
862     + SQUASHFS_I(i)->start_block = inodep->start_block;
863     + SQUASHFS_I(i)->u.s1.block_list_start = next_block;
864     + SQUASHFS_I(i)->offset = next_offset;
865     + i->i_data.a_ops = &squashfs_aops;
866     +
867     + TRACE("File inode %x:%x, start_block %llx, "
868     + "block_list_start %llx, offset %x\n",
869     + SQUASHFS_INODE_BLK(inode), offset,
870     + inodep->start_block, next_block,
871     + next_offset);
872     + break;
873     + }
874     + case SQUASHFS_DIR_TYPE: {
875     + struct squashfs_dir_inode_header *inodep = &id.dir;
876     + struct squashfs_dir_inode_header *sinodep = &sid.dir;
877     +
878     + if (msblk->swap) {
879     + if (!squashfs_get_cached_block(s, sinodep, block, offset,
880     + sizeof(*sinodep), &next_block, &next_offset))
881     + goto failed_read;
882     + SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);
883     + } else
884     + if (!squashfs_get_cached_block(s, inodep, block, offset,
885     + sizeof(*inodep), &next_block, &next_offset))
886     + goto failed_read;
887     +
888     + i->i_nlink = inodep->nlink;
889     + i->i_size = inodep->file_size;
890     + i->i_op = &squashfs_dir_inode_ops;
891     + i->i_fop = &squashfs_dir_ops;
892     + i->i_mode |= S_IFDIR;
893     + SQUASHFS_I(i)->start_block = inodep->start_block;
894     + SQUASHFS_I(i)->offset = inodep->offset;
895     + SQUASHFS_I(i)->u.s2.directory_index_count = 0;
896     + SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
897     +
898     + TRACE("Directory inode %x:%x, start_block %x, offset "
899     + "%x\n", SQUASHFS_INODE_BLK(inode),
900     + offset, inodep->start_block,
901     + inodep->offset);
902     + break;
903     + }
904     + case SQUASHFS_LDIR_TYPE: {
905     + struct squashfs_ldir_inode_header *inodep = &id.ldir;
906     + struct squashfs_ldir_inode_header *sinodep = &sid.ldir;
907     +
908     + if (msblk->swap) {
909     + if (!squashfs_get_cached_block(s, sinodep, block, offset,
910     + sizeof(*sinodep), &next_block, &next_offset))
911     + goto failed_read;
912     + SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep, sinodep);
913     + } else
914     + if (!squashfs_get_cached_block(s, inodep, block, offset,
915     + sizeof(*inodep), &next_block, &next_offset))
916     + goto failed_read;
917     +
918     + i->i_nlink = inodep->nlink;
919     + i->i_size = inodep->file_size;
920     + i->i_op = &squashfs_dir_inode_ops;
921     + i->i_fop = &squashfs_dir_ops;
922     + i->i_mode |= S_IFDIR;
923     + SQUASHFS_I(i)->start_block = inodep->start_block;
924     + SQUASHFS_I(i)->offset = inodep->offset;
925     + SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
926     + SQUASHFS_I(i)->u.s2.directory_index_offset = next_offset;
927     + SQUASHFS_I(i)->u.s2.directory_index_count = inodep->i_count;
928     + SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
929     +
930     + TRACE("Long directory inode %x:%x, start_block %x, offset %x\n",
931     + SQUASHFS_INODE_BLK(inode), offset,
932     + inodep->start_block, inodep->offset);
933     + break;
934     + }
935     + case SQUASHFS_SYMLINK_TYPE: {
936     + struct squashfs_symlink_inode_header *inodep = &id.symlink;
937     + struct squashfs_symlink_inode_header *sinodep = &sid.symlink;
938     +
939     + if (msblk->swap) {
940     + if (!squashfs_get_cached_block(s, sinodep, block, offset,
941     + sizeof(*sinodep), &next_block, &next_offset))
942     + goto failed_read;
943     + SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, sinodep);
944     + } else
945     + if (!squashfs_get_cached_block(s, inodep, block, offset,
946     + sizeof(*inodep), &next_block, &next_offset))
947     + goto failed_read;
948     +
949     + i->i_nlink = inodep->nlink;
950     + i->i_size = inodep->symlink_size;
951     + i->i_op = &page_symlink_inode_operations;
952     + i->i_data.a_ops = &squashfs_symlink_aops;
953     + i->i_mode |= S_IFLNK;
954     + SQUASHFS_I(i)->start_block = next_block;
955     + SQUASHFS_I(i)->offset = next_offset;
956     +
957     + TRACE("Symbolic link inode %x:%x, start_block %llx, offset %x\n",
958     + SQUASHFS_INODE_BLK(inode), offset,
959     + next_block, next_offset);
960     + break;
961     + }
962     + case SQUASHFS_BLKDEV_TYPE:
963     + case SQUASHFS_CHRDEV_TYPE: {
964     + struct squashfs_dev_inode_header *inodep = &id.dev;
965     + struct squashfs_dev_inode_header *sinodep = &sid.dev;
966     +
967     + if (msblk->swap) {
968     + if (!squashfs_get_cached_block(s, sinodep, block, offset,
969     + sizeof(*sinodep), &next_block, &next_offset))
970     + goto failed_read;
971     + SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);
972     + } else
973     + if (!squashfs_get_cached_block(s, inodep, block, offset,
974     + sizeof(*inodep), &next_block, &next_offset))
975     + goto failed_read;
976     +
977     + i->i_nlink = inodep->nlink;
978     + i->i_mode |= (inodeb->inode_type == SQUASHFS_CHRDEV_TYPE) ?
979     + S_IFCHR : S_IFBLK;
980     + init_special_inode(i, i->i_mode, old_decode_dev(inodep->rdev));
981     +
982     + TRACE("Device inode %x:%x, rdev %x\n",
983     + SQUASHFS_INODE_BLK(inode), offset, inodep->rdev);
984     + break;
985     + }
986     + case SQUASHFS_FIFO_TYPE:
987     + case SQUASHFS_SOCKET_TYPE: {
988     + struct squashfs_ipc_inode_header *inodep = &id.ipc;
989     + struct squashfs_ipc_inode_header *sinodep = &sid.ipc;
990     +
991     + if (msblk->swap) {
992     + if (!squashfs_get_cached_block(s, sinodep, block, offset,
993     + sizeof(*sinodep), &next_block, &next_offset))
994     + goto failed_read;
995     + SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);
996     + } else
997     + if (!squashfs_get_cached_block(s, inodep, block, offset,
998     + sizeof(*inodep), &next_block, &next_offset))
999     + goto failed_read;
1000     +
1001     + i->i_nlink = inodep->nlink;
1002     + i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
1003     + ? S_IFIFO : S_IFSOCK;
1004     + init_special_inode(i, i->i_mode, 0);
1005     + break;
1006     + }
1007     + default:
1008     + ERROR("Unknown inode type %d in squashfs_iget!\n",
1009     + inodeb->inode_type);
1010     + goto failed_read1;
1011     + }
1012     +
1013     + return 1;
1014     +
1015     +failed_read:
1016     + ERROR("Unable to read inode [%llx:%x]\n", block, offset);
1017     +
1018     +failed_read1:
1019     + make_bad_inode(i);
1020     + return 0;
1021     +}
1022     +
1023     +
1024     +static int read_inode_lookup_table(struct super_block *s)
1025     +{
1026     + struct squashfs_sb_info *msblk = s->s_fs_info;
1027     + struct squashfs_super_block *sblk = &msblk->sblk;
1028     + unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(sblk->inodes);
1029     +
1030     + TRACE("In read_inode_lookup_table, length %d\n", length);
1031     +
1032     + /* Allocate inode lookup table */
1033     + msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL);
1034     + if (msblk->inode_lookup_table == NULL) {
1035     + ERROR("Failed to allocate inode lookup table\n");
1036     + return 0;
1037     + }
1038     +
1039     + if (!squashfs_read_data(s, (char *) msblk->inode_lookup_table,
1040     + sblk->lookup_table_start, length |
1041     + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) {
1042     + ERROR("unable to read inode lookup table\n");
1043     + return 0;
1044     + }
1045     +
1046     + if (msblk->swap) {
1047     + int i;
1048     + long long block;
1049     +
1050     + for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) {
1051     + /* XXX */
1052     + SQUASHFS_SWAP_LOOKUP_BLOCKS((&block),
1053     + &msblk->inode_lookup_table[i], 1);
1054     + msblk->inode_lookup_table[i] = block;
1055     + }
1056     + }
1057     +
1058     + return 1;
1059     +}
1060     +
1061     +
1062     +static int read_fragment_index_table(struct super_block *s)
1063     +{
1064     + struct squashfs_sb_info *msblk = s->s_fs_info;
1065     + struct squashfs_super_block *sblk = &msblk->sblk;
1066     + unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments);
1067     +
1068     + if(length == 0)
1069     + return 1;
1070     +
1071     + /* Allocate fragment index table */
1072     + msblk->fragment_index = kmalloc(length, GFP_KERNEL);
1073     + if (msblk->fragment_index == NULL) {
1074     + ERROR("Failed to allocate fragment index table\n");
1075     + return 0;
1076     + }
1077     +
1078     + if (!squashfs_read_data(s, (char *) msblk->fragment_index,
1079     + sblk->fragment_table_start, length |
1080     + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) {
1081     + ERROR("unable to read fragment index table\n");
1082     + return 0;
1083     + }
1084     +
1085     + if (msblk->swap) {
1086     + int i;
1087     + long long fragment;
1088     +
1089     + for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) {
1090     + /* XXX */
1091     + SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
1092     + &msblk->fragment_index[i], 1);
1093     + msblk->fragment_index[i] = fragment;
1094     + }
1095     + }
1096     +
1097     + return 1;
1098     +}
1099     +
1100     +
1101     +static int readahead_metadata(struct super_block *s)
1102     +{
1103     + struct squashfs_sb_info *msblk = s->s_fs_info;
1104     + int i;
1105     +
1106     + squashfs_cached_blks = SQUASHFS_CACHED_BLKS;
1107     +
1108     + /* Init inode_table block pointer array */
1109     + msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
1110     + squashfs_cached_blks, GFP_KERNEL);
1111     + if (msblk->block_cache == NULL) {
1112     + ERROR("Failed to allocate block cache\n");
1113     + goto failed;
1114     + }
1115     +
1116     + for (i = 0; i < squashfs_cached_blks; i++)
1117     + msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
1118     +
1119     + msblk->next_cache = 0;
1120     + msblk->unused_cache_blks = squashfs_cached_blks;
1121     +
1122     + return 1;
1123     +
1124     +failed:
1125     + return 0;
1126     +}
1127     +
1128     +
1129     +static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
1130     +{
1131     + struct squashfs_super_block *sblk = &msblk->sblk;
1132     +
1133     + msblk->read_inode = squashfs_read_inode;
1134     + msblk->read_blocklist = read_blocklist;
1135     + msblk->read_fragment_index_table = read_fragment_index_table;
1136     +
1137     + if (sblk->s_major == 1) {
1138     + if (!squashfs_1_0_supported(msblk)) {
1139     + SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "
1140     + "are unsupported\n");
1141     + SERROR("Please recompile with Squashfs 1.0 support enabled\n");
1142     + return 0;
1143     + }
1144     + } else if (sblk->s_major == 2) {
1145     + if (!squashfs_2_0_supported(msblk)) {
1146     + SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "
1147     + "are unsupported\n");
1148     + SERROR("Please recompile with Squashfs 2.0 support enabled\n");
1149     + return 0;
1150     + }
1151     + } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
1152     + SQUASHFS_MINOR) {
1153     + SERROR("Major/Minor mismatch, trying to mount newer %d.%d "
1154     + "filesystem\n", sblk->s_major, sblk->s_minor);
1155     + SERROR("Please update your kernel\n");
1156     + return 0;
1157     + }
1158     +
1159     + return 1;
1160     +}
1161     +
1162     +
1163     +static int squashfs_fill_super(struct super_block *s, void *data, int silent)
1164     +{
1165     + struct squashfs_sb_info *msblk;
1166     + struct squashfs_super_block *sblk;
1167     + int i;
1168     + char b[BDEVNAME_SIZE];
1169     + struct inode *root;
1170     +
1171     + TRACE("Entered squashfs_fill_superblock\n");
1172     +
1173     + s->s_fs_info = kzalloc(sizeof(struct squashfs_sb_info), GFP_KERNEL);
1174     + if (s->s_fs_info == NULL) {
1175     + ERROR("Failed to allocate superblock\n");
1176     + goto failure;
1177     + }
1178     + msblk = s->s_fs_info;
1179     +
1180     + msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize());
1181     + if (msblk->stream.workspace == NULL) {
1182     + ERROR("Failed to allocate zlib workspace\n");
1183     + goto failure;
1184     + }
1185     + sblk = &msblk->sblk;
1186     +
1187     + msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE);
1188     + msblk->devblksize_log2 = ffz(~msblk->devblksize);
1189     +
1190     + mutex_init(&msblk->read_data_mutex);
1191     + mutex_init(&msblk->read_page_mutex);
1192     + mutex_init(&msblk->block_cache_mutex);
1193     + mutex_init(&msblk->fragment_mutex);
1194     + mutex_init(&msblk->meta_index_mutex);
1195     +
1196     + init_waitqueue_head(&msblk->waitq);
1197     + init_waitqueue_head(&msblk->fragment_wait_queue);
1198     +
1199     + /* sblk->bytes_used is checked in squashfs_read_data to ensure reads are not
1200     + * beyond filesystem end. As we're using squashfs_read_data to read sblk here,
1201     + * first set sblk->bytes_used to a useful value */
1202     + sblk->bytes_used = sizeof(struct squashfs_super_block);
1203     + if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
1204     + sizeof(struct squashfs_super_block) |
1205     + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, sizeof(struct squashfs_super_block))) {
1206     + SERROR("unable to read superblock\n");
1207     + goto failed_mount;
1208     + }
1209     +
1210     + /* Check it is a SQUASHFS superblock */
1211     + if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) {
1212     + if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) {
1213     + struct squashfs_super_block ssblk;
1214     +
1215     + WARNING("Mounting a different endian SQUASHFS filesystem on %s\n",
1216     + bdevname(s->s_bdev, b));
1217     +
1218     + SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);
1219     + memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));
1220     + msblk->swap = 1;
1221     + } else {
1222     + SERROR("Can't find a SQUASHFS superblock on %s\n",
1223     + bdevname(s->s_bdev, b));
1224     + goto failed_mount;
1225     + }
1226     + }
1227     +
1228     + /* Check the MAJOR & MINOR versions */
1229     + if(!supported_squashfs_filesystem(msblk, silent))
1230     + goto failed_mount;
1231     +
1232     + /* Check the filesystem does not extend beyond the end of the
1233     + block device */
1234     + if(sblk->bytes_used < 0 || sblk->bytes_used > i_size_read(s->s_bdev->bd_inode))
1235     + goto failed_mount;
1236     +
1237     + /* Check the root inode for sanity */
1238     + if (SQUASHFS_INODE_OFFSET(sblk->root_inode) > SQUASHFS_METADATA_SIZE)
1239     + goto failed_mount;
1240     +
1241     + TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b));
1242     + TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sblk->flags)
1243     + ? "un" : "");
1244     + TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
1245     + ? "un" : "");
1246     + TRACE("Check data is %spresent in the filesystem\n",
1247     + SQUASHFS_CHECK_DATA(sblk->flags) ? "" : "not ");
1248     + TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);
1249     + TRACE("Block size %d\n", sblk->block_size);
1250     + TRACE("Number of inodes %d\n", sblk->inodes);
1251     + if (sblk->s_major > 1)
1252     + TRACE("Number of fragments %d\n", sblk->fragments);
1253     + TRACE("Number of uids %d\n", sblk->no_uids);
1254     + TRACE("Number of gids %d\n", sblk->no_guids);
1255     + TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);
1256     + TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);
1257     + if (sblk->s_major > 1)
1258     + TRACE("sblk->fragment_table_start %llx\n", sblk->fragment_table_start);
1259     + TRACE("sblk->uid_start %llx\n", sblk->uid_start);
1260     +
1261     + s->s_maxbytes = MAX_LFS_FILESIZE;
1262     + s->s_flags |= MS_RDONLY;
1263     + s->s_op = &squashfs_super_ops;
1264     +
1265     + if (readahead_metadata(s) == 0)
1266     + goto failed_mount;
1267     +
1268     + /* Allocate read_page block */
1269     + msblk->read_page = vmalloc(sblk->block_size);
1270     + if (msblk->read_page == NULL) {
1271     + ERROR("Failed to allocate read_page block\n");
1272     + goto failed_mount;
1273     + }
1274     +
1275     + /* Allocate uid and gid tables */
1276     + msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
1277     + sizeof(unsigned int), GFP_KERNEL);
1278     + if (msblk->uid == NULL) {
1279     + ERROR("Failed to allocate uid/gid table\n");
1280     + goto failed_mount;
1281     + }
1282     + msblk->guid = msblk->uid + sblk->no_uids;
1283     +
1284     + if (msblk->swap) {
1285     + unsigned int suid[sblk->no_uids + sblk->no_guids];
1286     +
1287     + if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,
1288     + ((sblk->no_uids + sblk->no_guids) *
1289     + sizeof(unsigned int)) |
1290     + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) {
1291     + ERROR("unable to read uid/gid table\n");
1292     + goto failed_mount;
1293     + }
1294     +
1295     + SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids +
1296     + sblk->no_guids), (sizeof(unsigned int) * 8));
1297     + } else
1298     + if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,
1299     + ((sblk->no_uids + sblk->no_guids) *
1300     + sizeof(unsigned int)) |
1301     + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) {
1302     + ERROR("unable to read uid/gid table\n");
1303     + goto failed_mount;
1304     + }
1305     +
1306     +
1307     + if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))
1308     + goto allocate_root;
1309     +
1310     + msblk->fragment = kzalloc(sizeof(struct squashfs_fragment_cache) *
1311     + SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL);
1312     + if (msblk->fragment == NULL) {
1313     + ERROR("Failed to allocate fragment block cache\n");
1314     + goto failed_mount;
1315     + }
1316     +
1317     + for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {
1318     + msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
1319     + }
1320     +
1321     + msblk->next_fragment = 0;
1322     + msblk->unused_frag_blks = SQUASHFS_CACHED_FRAGMENTS;
1323     +
1324     + /* Allocate and read fragment index table */
1325     + if (msblk->read_fragment_index_table(s) == 0)
1326     + goto failed_mount;
1327     +
1328     + if(sblk->s_major < 3 || sblk->lookup_table_start == SQUASHFS_INVALID_BLK)
1329     + goto allocate_root;
1330     +
1331     + /* Allocate and read inode lookup table */
1332     + if (read_inode_lookup_table(s) == 0)
1333     + goto failed_mount;
1334     +
1335     + s->s_op = &squashfs_export_super_ops;
1336     + s->s_export_op = &squashfs_export_ops;
1337     +
1338     +allocate_root:
1339     + root = new_inode(s);
1340     + if ((msblk->read_inode)(root, sblk->root_inode) == 0)
1341     + goto failed_mount;
1342     + insert_inode_hash(root);
1343     +
1344     + s->s_root = d_alloc_root(root);
1345     + if (s->s_root == NULL) {
1346     + ERROR("Root inode create failed\n");
1347     + iput(root);
1348     + goto failed_mount;
1349     + }
1350     +
1351     + TRACE("Leaving squashfs_fill_super\n");
1352     + return 0;
1353     +
1354     +failed_mount:
1355     + kfree(msblk->inode_lookup_table);
1356     + kfree(msblk->fragment_index);
1357     + kfree(msblk->fragment);
1358     + kfree(msblk->uid);
1359     + vfree(msblk->read_page);
1360     + kfree(msblk->block_cache);
1361     + kfree(msblk->fragment_index_2);
1362     + vfree(msblk->stream.workspace);
1363     + kfree(s->s_fs_info);
1364     + s->s_fs_info = NULL;
1365     + return -EINVAL;
1366     +
1367     +failure:
1368     + return -ENOMEM;
1369     +}
1370     +
1371     +
1372     +static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
1373     +{
1374     + struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info;
1375     + struct squashfs_super_block *sblk = &msblk->sblk;
1376     +
1377     + TRACE("Entered squashfs_statfs\n");
1378     +
1379     + buf->f_type = SQUASHFS_MAGIC;
1380     + buf->f_bsize = sblk->block_size;
1381     + buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1;
1382     + buf->f_bfree = buf->f_bavail = 0;
1383     + buf->f_files = sblk->inodes;
1384     + buf->f_ffree = 0;
1385     + buf->f_namelen = SQUASHFS_NAME_LEN;
1386     +
1387     + return 0;
1388     +}
1389     +
1390     +
1391     +static int squashfs_symlink_readpage(struct file *file, struct page *page)
1392     +{
1393     + struct inode *inode = page->mapping->host;
1394     + int index = page->index << PAGE_CACHE_SHIFT, length, bytes, avail_bytes;
1395     + long long block = SQUASHFS_I(inode)->start_block;
1396     + int offset = SQUASHFS_I(inode)->offset;
1397     + void *pageaddr = kmap(page);
1398     +
1399     + TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
1400     + "%llx, offset %x\n", page->index,
1401     + SQUASHFS_I(inode)->start_block,
1402     + SQUASHFS_I(inode)->offset);
1403     +
1404     + for (length = 0; length < index; length += bytes) {
1405     + bytes = squashfs_get_cached_block(inode->i_sb, NULL, block,
1406     + offset, PAGE_CACHE_SIZE, &block, &offset);
1407     + if (bytes == 0) {
1408     + ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
1409     + goto skip_read;
1410     + }
1411     + }
1412     +
1413     + if (length != index) {
1414     + ERROR("(squashfs_symlink_readpage) length != index\n");
1415     + bytes = 0;
1416     + goto skip_read;
1417     + }
1418     +
1419     + avail_bytes = min_t(int, i_size_read(inode) - length, PAGE_CACHE_SIZE);
1420     +
1421     + bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset,
1422     + avail_bytes, &block, &offset);
1423     + if (bytes == 0)
1424     + ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
1425     +
1426     +skip_read:
1427     + memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
1428     + kunmap(page);
1429     + flush_dcache_page(page);
1430     + SetPageUptodate(page);
1431     + unlock_page(page);
1432     +
1433     + return 0;
1434     +}
1435     +
1436     +
1437     +struct meta_index *locate_meta_index(struct inode *inode, int index, int offset)
1438     +{
1439     + struct meta_index *meta = NULL;
1440     + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1441     + int i;
1442     +
1443     + mutex_lock(&msblk->meta_index_mutex);
1444     +
1445     + TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
1446     +
1447     + if (msblk->meta_index == NULL)
1448     + goto not_allocated;
1449     +
1450     + for (i = 0; i < SQUASHFS_META_NUMBER; i ++) {
1451     + if (msblk->meta_index[i].inode_number == inode->i_ino &&
1452     + msblk->meta_index[i].offset >= offset &&
1453     + msblk->meta_index[i].offset <= index &&
1454     + msblk->meta_index[i].locked == 0) {
1455     + TRACE("locate_meta_index: entry %d, offset %d\n", i,
1456     + msblk->meta_index[i].offset);
1457     + meta = &msblk->meta_index[i];
1458     + offset = meta->offset;
1459     + }
1460     + }
1461     +
1462     + if (meta)
1463     + meta->locked = 1;
1464     +
1465     +not_allocated:
1466     + mutex_unlock(&msblk->meta_index_mutex);
1467     +
1468     + return meta;
1469     +}
1470     +
1471     +
1472     +struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip)
1473     +{
1474     + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1475     + struct meta_index *meta = NULL;
1476     + int i;
1477     +
1478     + mutex_lock(&msblk->meta_index_mutex);
1479     +
1480     + TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
1481     +
1482     + if (msblk->meta_index == NULL) {
1483     + msblk->meta_index = kmalloc(sizeof(struct meta_index) *
1484     + SQUASHFS_META_NUMBER, GFP_KERNEL);
1485     + if (msblk->meta_index == NULL) {
1486     + ERROR("Failed to allocate meta_index\n");
1487     + goto failed;
1488     + }
1489     + for (i = 0; i < SQUASHFS_META_NUMBER; i++) {
1490     + msblk->meta_index[i].inode_number = 0;
1491     + msblk->meta_index[i].locked = 0;
1492     + }
1493     + msblk->next_meta_index = 0;
1494     + }
1495     +
1496     + for (i = SQUASHFS_META_NUMBER; i &&
1497     + msblk->meta_index[msblk->next_meta_index].locked; i --)
1498     + msblk->next_meta_index = (msblk->next_meta_index + 1) %
1499     + SQUASHFS_META_NUMBER;
1500     +
1501     + if (i == 0) {
1502     + TRACE("empty_meta_index: failed!\n");
1503     + goto failed;
1504     + }
1505     +
1506     + TRACE("empty_meta_index: returned meta entry %d, %p\n",
1507     + msblk->next_meta_index,
1508     + &msblk->meta_index[msblk->next_meta_index]);
1509     +
1510     + meta = &msblk->meta_index[msblk->next_meta_index];
1511     + msblk->next_meta_index = (msblk->next_meta_index + 1) %
1512     + SQUASHFS_META_NUMBER;
1513     +
1514     + meta->inode_number = inode->i_ino;
1515     + meta->offset = offset;
1516     + meta->skip = skip;
1517     + meta->entries = 0;
1518     + meta->locked = 1;
1519     +
1520     +failed:
1521     + mutex_unlock(&msblk->meta_index_mutex);
1522     + return meta;
1523     +}
1524     +
1525     +
1526     +void release_meta_index(struct inode *inode, struct meta_index *meta)
1527     +{
1528     + meta->locked = 0;
1529     + smp_mb();
1530     +}
1531     +
1532     +
1533     +static int read_block_index(struct super_block *s, int blocks, char *block_list,
1534     + long long *start_block, int *offset)
1535     +{
1536     + struct squashfs_sb_info *msblk = s->s_fs_info;
1537     + unsigned int *block_listp;
1538     + int block = 0;
1539     +
1540     + if (msblk->swap) {
1541     + char sblock_list[blocks << 2];
1542     +
1543     + if (!squashfs_get_cached_block(s, sblock_list, *start_block,
1544     + *offset, blocks << 2, start_block, offset)) {
1545     + ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset);
1546     + goto failure;
1547     + }
1548     + SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
1549     + ((unsigned int *)sblock_list), blocks);
1550     + } else {
1551     + if (!squashfs_get_cached_block(s, block_list, *start_block,
1552     + *offset, blocks << 2, start_block, offset)) {
1553     + ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset);
1554     + goto failure;
1555     + }
1556     + }
1557     +
1558     + for (block_listp = (unsigned int *) block_list; blocks;
1559     + block_listp++, blocks --)
1560     + block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);
1561     +
1562     + return block;
1563     +
1564     +failure:
1565     + return -1;
1566     +}
1567     +
1568     +
1569     +#define SIZE 256
1570     +
1571     +static inline int calculate_skip(int blocks) {
1572     + int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES);
1573     + return skip >= 7 ? 7 : skip + 1;
1574     +}
1575     +
1576     +
1577     +static int get_meta_index(struct inode *inode, int index,
1578     + long long *index_block, int *index_offset,
1579     + long long *data_block, char *block_list)
1580     +{
1581     + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1582     + struct squashfs_super_block *sblk = &msblk->sblk;
1583     + int skip = calculate_skip(i_size_read(inode) >> sblk->block_log);
1584     + int offset = 0;
1585     + struct meta_index *meta;
1586     + struct meta_entry *meta_entry;
1587     + long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start;
1588     + int cur_offset = SQUASHFS_I(inode)->offset;
1589     + long long cur_data_block = SQUASHFS_I(inode)->start_block;
1590     + int i;
1591     +
1592     + index /= SQUASHFS_META_INDEXES * skip;
1593     +
1594     + while (offset < index) {
1595     + meta = locate_meta_index(inode, index, offset + 1);
1596     +
1597     + if (meta == NULL) {
1598     + meta = empty_meta_index(inode, offset + 1, skip);
1599     + if (meta == NULL)
1600     + goto all_done;
1601     + } else {
1602     + if(meta->entries == 0)
1603     + goto failed;
1604     + /* XXX */
1605     + offset = index < meta->offset + meta->entries ? index :
1606     + meta->offset + meta->entries - 1;
1607     + /* XXX */
1608     + meta_entry = &meta->meta_entry[offset - meta->offset];
1609     + cur_index_block = meta_entry->index_block + sblk->inode_table_start;
1610     + cur_offset = meta_entry->offset;
1611     + cur_data_block = meta_entry->data_block;
1612     + TRACE("get_meta_index: offset %d, meta->offset %d, "
1613     + "meta->entries %d\n", offset, meta->offset, meta->entries);
1614     + TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
1615     + " data_block 0x%llx\n", cur_index_block,
1616     + cur_offset, cur_data_block);
1617     + }
1618     +
1619     + for (i = meta->offset + meta->entries; i <= index &&
1620     + i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
1621     + int blocks = skip * SQUASHFS_META_INDEXES;
1622     +
1623     + while (blocks) {
1624     + int block = blocks > (SIZE >> 2) ? (SIZE >> 2) : blocks;
1625     + int res = read_block_index(inode->i_sb, block, block_list,
1626     + &cur_index_block, &cur_offset);
1627     +
1628     + if (res == -1)
1629     + goto failed;
1630     +
1631     + cur_data_block += res;
1632     + blocks -= block;
1633     + }
1634     +
1635     + meta_entry = &meta->meta_entry[i - meta->offset];
1636     + meta_entry->index_block = cur_index_block - sblk->inode_table_start;
1637     + meta_entry->offset = cur_offset;
1638     + meta_entry->data_block = cur_data_block;
1639     + meta->entries ++;
1640     + offset ++;
1641     + }
1642     +
1643     + TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
1644     + meta->offset, meta->entries);
1645     +
1646     + release_meta_index(inode, meta);
1647     + }
1648     +
1649     +all_done:
1650     + *index_block = cur_index_block;
1651     + *index_offset = cur_offset;
1652     + *data_block = cur_data_block;
1653     +
1654     + return offset * SQUASHFS_META_INDEXES * skip;
1655     +
1656     +failed:
1657     + release_meta_index(inode, meta);
1658     + return -1;
1659     +}
1660     +
1661     +
1662     +static long long read_blocklist(struct inode *inode, int index,
1663     + int readahead_blks, char *block_list,
1664     + unsigned short **block_p, unsigned int *bsize)
1665     +{
1666     + long long block_ptr;
1667     + int offset;
1668     + long long block;
1669     + int res = get_meta_index(inode, index, &block_ptr, &offset, &block,
1670     + block_list);
1671     +
1672     + TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"
1673     + " 0x%x, block 0x%llx\n", res, index, block_ptr, offset, block);
1674     +
1675     + if(res == -1)
1676     + goto failure;
1677     +
1678     + index -= res;
1679     +
1680     + while (index) {
1681     + int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
1682     + int res = read_block_index(inode->i_sb, blocks, block_list,
1683     + &block_ptr, &offset);
1684     + if (res == -1)
1685     + goto failure;
1686     + block += res;
1687     + index -= blocks;
1688     + }
1689     +
1690     + if (read_block_index(inode->i_sb, 1, block_list, &block_ptr, &offset) == -1)
1691     + goto failure;
1692     + *bsize = *((unsigned int *) block_list);
1693     +
1694     + return block;
1695     +
1696     +failure:
1697     + return 0;
1698     +}
1699     +
1700     +
1701     +static int squashfs_readpage(struct file *file, struct page *page)
1702     +{
1703     + struct inode *inode = page->mapping->host;
1704     + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
1705     + struct squashfs_super_block *sblk = &msblk->sblk;
1706     + unsigned char *block_list = NULL;
1707     + long long block;
1708     + unsigned int bsize, i;
1709     + int bytes;
1710     + int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
1711     + void *pageaddr;
1712     + struct squashfs_fragment_cache *fragment = NULL;
1713     + char *data_ptr = msblk->read_page;
1714     +
1715     + int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
1716     + int start_index = page->index & ~mask;
1717     + int end_index = start_index | mask;
1718     + int file_end = i_size_read(inode) >> sblk->block_log;
1719     + int sparse = 0;
1720     +
1721     + TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
1722     + page->index, SQUASHFS_I(inode)->start_block);
1723     +
1724     + if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
1725     + PAGE_CACHE_SHIFT))
1726     + goto out;
1727     +
1728     + if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
1729     + || index < file_end) {
1730     + block_list = kmalloc(SIZE, GFP_KERNEL);
1731     + if (block_list == NULL) {
1732     + ERROR("Failed to allocate block_list\n");
1733     + goto error_out;
1734     + }
1735     +
1736     + block = (msblk->read_blocklist)(inode, index, 1, block_list, NULL, &bsize);
1737     + if (block == 0)
1738     + goto error_out;
1739     +
1740     + if (bsize == 0) { /* hole */
1741     + bytes = index == file_end ?
1742     + (i_size_read(inode) & (sblk->block_size - 1)) : sblk->block_size;
1743     + sparse = 1;
1744     + } else {
1745     + mutex_lock(&msblk->read_page_mutex);
1746     +
1747     + bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
1748     + bsize, NULL, sblk->block_size);
1749     +
1750     + if (bytes == 0) {
1751     + ERROR("Unable to read page, block %llx, size %x\n", block, bsize);
1752     + mutex_unlock(&msblk->read_page_mutex);
1753     + goto error_out;
1754     + }
1755     + }
1756     + } else {
1757     + fragment = get_cached_fragment(inode->i_sb,
1758     + SQUASHFS_I(inode)-> u.s1.fragment_start_block,
1759     + SQUASHFS_I(inode)->u.s1.fragment_size);
1760     +
1761     + if (fragment == NULL) {
1762     + ERROR("Unable to read page, block %llx, size %x\n",
1763     + SQUASHFS_I(inode)->u.s1.fragment_start_block,
1764     + (int) SQUASHFS_I(inode)->u.s1.fragment_size);
1765     + goto error_out;
1766     + }
1767     + bytes = i_size_read(inode) & (sblk->block_size - 1);
1768     + data_ptr = fragment->data + SQUASHFS_I(inode)->u.s1.fragment_offset;
1769     + }
1770     +
1771     + for (i = start_index; i <= end_index && bytes > 0; i++,
1772     + bytes -= PAGE_CACHE_SIZE, data_ptr += PAGE_CACHE_SIZE) {
1773     + struct page *push_page;
1774     + int avail = sparse ? 0 : min_t(unsigned int, bytes, PAGE_CACHE_SIZE);
1775     +
1776     + TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail);
1777     +
1778     + push_page = (i == page->index) ? page :
1779     + grab_cache_page_nowait(page->mapping, i);
1780     +
1781     + if (!push_page)
1782     + continue;
1783     +
1784     + if (PageUptodate(push_page))
1785     + goto skip_page;
1786     +
1787     + pageaddr = kmap_atomic(push_page, KM_USER0);
1788     + memcpy(pageaddr, data_ptr, avail);
1789     + memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail);
1790     + kunmap_atomic(pageaddr, KM_USER0);
1791     + flush_dcache_page(push_page);
1792     + SetPageUptodate(push_page);
1793     +skip_page:
1794     + unlock_page(push_page);
1795     + if(i != page->index)
1796     + page_cache_release(push_page);
1797     + }
1798     +
1799     + if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
1800     + || index < file_end) {
1801     + if (!sparse)
1802     + mutex_unlock(&msblk->read_page_mutex);
1803     + kfree(block_list);
1804     + } else
1805     + release_cached_fragment(msblk, fragment);
1806     +
1807     + return 0;
1808     +
1809     +error_out:
1810     + SetPageError(page);
1811     +out:
1812     + pageaddr = kmap_atomic(page, KM_USER0);
1813     + memset(pageaddr, 0, PAGE_CACHE_SIZE);
1814     + kunmap_atomic(pageaddr, KM_USER0);
1815     + flush_dcache_page(page);
1816     + if (!PageError(page))
1817     + SetPageUptodate(page);
1818     + unlock_page(page);
1819     +
1820     + kfree(block_list);
1821     + return 0;
1822     +}
1823     +
1824     +
1825     +static int get_dir_index_using_offset(struct super_block *s,
1826     + long long *next_block, unsigned int *next_offset,
1827     + long long index_start, unsigned int index_offset, int i_count,
1828     + long long f_pos)
1829     +{
1830     + struct squashfs_sb_info *msblk = s->s_fs_info;
1831     + struct squashfs_super_block *sblk = &msblk->sblk;
1832     + int i, length = 0;
1833     + struct squashfs_dir_index index;
1834     +
1835     + TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
1836     + i_count, (unsigned int) f_pos);
1837     +
1838     + f_pos =- 3;
1839     + if (f_pos == 0)
1840     + goto finish;
1841     +
1842     + for (i = 0; i < i_count; i++) {
1843     + if (msblk->swap) {
1844     + struct squashfs_dir_index sindex;
1845     + squashfs_get_cached_block(s, &sindex, index_start, index_offset,
1846     + sizeof(sindex), &index_start, &index_offset);
1847     + SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
1848     + } else
1849     + squashfs_get_cached_block(s, &index, index_start, index_offset,
1850     + sizeof(index), &index_start, &index_offset);
1851     +
1852     + if (index.index > f_pos)
1853     + break;
1854     +
1855     + squashfs_get_cached_block(s, NULL, index_start, index_offset,
1856     + index.size + 1, &index_start, &index_offset);
1857     +
1858     + length = index.index;
1859     + *next_block = index.start_block + sblk->directory_table_start;
1860     + }
1861     +
1862     + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
1863     +
1864     +finish:
1865     + return length + 3;
1866     +}
1867     +
1868     +
1869     +static int get_dir_index_using_name(struct super_block *s,
1870     + long long *next_block, unsigned int *next_offset,
1871     + long long index_start, unsigned int index_offset, int i_count,
1872     + const char *name, int size)
1873     +{
1874     + struct squashfs_sb_info *msblk = s->s_fs_info;
1875     + struct squashfs_super_block *sblk = &msblk->sblk;
1876     + int i, length = 0;
1877     + struct squashfs_dir_index *index;
1878     + char *str;
1879     +
1880     + TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
1881     +
1882     + str = kmalloc(sizeof(struct squashfs_dir_index) +
1883     + (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL);
1884     + if (str == NULL) {
1885     + ERROR("Failed to allocate squashfs_dir_index\n");
1886     + goto failure;
1887     + }
1888     +
1889     + index = (struct squashfs_dir_index *) (str + SQUASHFS_NAME_LEN + 1);
1890     + strncpy(str, name, size);
1891     + str[size] = '\0';
1892     +
1893     + for (i = 0; i < i_count; i++) {
1894     + if (msblk->swap) {
1895     + struct squashfs_dir_index sindex;
1896     + squashfs_get_cached_block(s, &sindex, index_start, index_offset,
1897     + sizeof(sindex), &index_start, &index_offset);
1898     + SQUASHFS_SWAP_DIR_INDEX(index, &sindex);
1899     + } else
1900     + squashfs_get_cached_block(s, index, index_start, index_offset,
1901     + sizeof(struct squashfs_dir_index), &index_start, &index_offset);
1902     +
1903     + squashfs_get_cached_block(s, index->name, index_start, index_offset,
1904     + index->size + 1, &index_start, &index_offset);
1905     +
1906     + index->name[index->size + 1] = '\0';
1907     +
1908     + if (strcmp(index->name, str) > 0)
1909     + break;
1910     +
1911     + length = index->index;
1912     + *next_block = index->start_block + sblk->directory_table_start;
1913     + }
1914     +
1915     + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
1916     + kfree(str);
1917     +
1918     +failure:
1919     + return length + 3;
1920     +}
1921     +
1922     +
1923     +static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
1924     +{
1925     + struct inode *i = file->f_dentry->d_inode;
1926     + struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
1927     + struct squashfs_super_block *sblk = &msblk->sblk;
1928     + long long next_block = SQUASHFS_I(i)->start_block +
1929     + sblk->directory_table_start;
1930     + int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count;
1931     + struct squashfs_dir_header dirh;
1932     + struct squashfs_dir_entry *dire;
1933     +
1934     + TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
1935     +
1936     + dire = kmalloc(sizeof(struct squashfs_dir_entry) +
1937     + SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
1938     + if (dire == NULL) {
1939     + ERROR("Failed to allocate squashfs_dir_entry\n");
1940     + goto finish;
1941     + }
1942     +
1943     + while(file->f_pos < 3) {
1944     + char *name;
1945     + int size, i_ino;
1946     +
1947     + if(file->f_pos == 0) {
1948     + name = ".";
1949     + size = 1;
1950     + i_ino = i->i_ino;
1951     + } else {
1952     + name = "..";
1953     + size = 2;
1954     + i_ino = SQUASHFS_I(i)->u.s2.parent_inode;
1955     + }
1956     + TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n",
1957     + (unsigned int) dirent, name, size, (int)
1958     + file->f_pos, i_ino, squashfs_filetype_table[1]);
1959     +
1960     + if (filldir(dirent, name, size, file->f_pos, i_ino,
1961     + squashfs_filetype_table[1]) < 0) {
1962     + TRACE("Filldir returned less than 0\n");
1963     + goto finish;
1964     + }
1965     + file->f_pos += size;
1966     + }
1967     +
1968     + length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
1969     + SQUASHFS_I(i)->u.s2.directory_index_start,
1970     + SQUASHFS_I(i)->u.s2.directory_index_offset,
1971     + SQUASHFS_I(i)->u.s2.directory_index_count, file->f_pos);
1972     +
1973     + while (length < i_size_read(i)) {
1974     + /* read directory header */
1975     + if (msblk->swap) {
1976     + struct squashfs_dir_header sdirh;
1977     +
1978     + if (!squashfs_get_cached_block(i->i_sb, &sdirh, next_block,
1979     + next_offset, sizeof(sdirh), &next_block, &next_offset))
1980     + goto failed_read;
1981     +
1982     + length += sizeof(sdirh);
1983     + SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
1984     + } else {
1985     + if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block,
1986     + next_offset, sizeof(dirh), &next_block, &next_offset))
1987     + goto failed_read;
1988     +
1989     + length += sizeof(dirh);
1990     + }
1991     +
1992     + dir_count = dirh.count + 1;
1993     + while (dir_count--) {
1994     + if (msblk->swap) {
1995     + struct squashfs_dir_entry sdire;
1996     + if (!squashfs_get_cached_block(i->i_sb, &sdire, next_block,
1997     + next_offset, sizeof(sdire), &next_block, &next_offset))
1998     + goto failed_read;
1999     +
2000     + length += sizeof(sdire);
2001     + SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
2002     + } else {
2003     + if (!squashfs_get_cached_block(i->i_sb, dire, next_block,
2004     + next_offset, sizeof(*dire), &next_block, &next_offset))
2005     + goto failed_read;
2006     +
2007     + length += sizeof(*dire);
2008     + }
2009     +
2010     + if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block,
2011     + next_offset, dire->size + 1, &next_block, &next_offset))
2012     + goto failed_read;
2013     +
2014     + length += dire->size + 1;
2015     +
2016     + if (file->f_pos >= length)
2017     + continue;
2018     +
2019     + dire->name[dire->size + 1] = '\0';
2020     +
2021     + TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n",
2022     + (unsigned int) dirent, dire->name, dire->size + 1,
2023     + (int) file->f_pos, dirh.start_block, dire->offset,
2024     + dirh.inode_number + dire->inode_number,
2025     + squashfs_filetype_table[dire->type]);
2026     +
2027     + if (filldir(dirent, dire->name, dire->size + 1, file->f_pos,
2028     + dirh.inode_number + dire->inode_number,
2029     + squashfs_filetype_table[dire->type]) < 0) {
2030     + TRACE("Filldir returned less than 0\n");
2031     + goto finish;
2032     + }
2033     + file->f_pos = length;
2034     + }
2035     + }
2036     +
2037     +finish:
2038     + kfree(dire);
2039     + return 0;
2040     +
2041     +failed_read:
2042     + ERROR("Unable to read directory block [%llx:%x]\n", next_block,
2043     + next_offset);
2044     + kfree(dire);
2045     + return 0;
2046     +}
2047     +
2048     +
2049     +static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry,
2050     + struct nameidata *nd)
2051     +{
2052     + const unsigned char *name = dentry->d_name.name;
2053     + int len = dentry->d_name.len;
2054     + struct inode *inode = NULL;
2055     + struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
2056     + struct squashfs_super_block *sblk = &msblk->sblk;
2057     + long long next_block = SQUASHFS_I(i)->start_block +
2058     + sblk->directory_table_start;
2059     + int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count;
2060     + struct squashfs_dir_header dirh;
2061     + struct squashfs_dir_entry *dire;
2062     +
2063     + TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
2064     +
2065     + dire = kmalloc(sizeof(struct squashfs_dir_entry) +
2066     + SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
2067     + if (dire == NULL) {
2068     + ERROR("Failed to allocate squashfs_dir_entry\n");
2069     + goto exit_lookup;
2070     + }
2071     +
2072     + if (len > SQUASHFS_NAME_LEN)
2073     + goto exit_lookup;
2074     +
2075     + length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
2076     + SQUASHFS_I(i)->u.s2.directory_index_start,
2077     + SQUASHFS_I(i)->u.s2.directory_index_offset,
2078     + SQUASHFS_I(i)->u.s2.directory_index_count, name, len);
2079     +
2080     + while (length < i_size_read(i)) {
2081     + /* read directory header */
2082     + if (msblk->swap) {
2083     + struct squashfs_dir_header sdirh;
2084     + if (!squashfs_get_cached_block(i->i_sb, &sdirh, next_block,
2085     + next_offset, sizeof(sdirh), &next_block, &next_offset))
2086     + goto failed_read;
2087     +
2088     + length += sizeof(sdirh);
2089     + SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
2090     + } else {
2091     + if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block,
2092     + next_offset, sizeof(dirh), &next_block, &next_offset))
2093     + goto failed_read;
2094     +
2095     + length += sizeof(dirh);
2096     + }
2097     +
2098     + dir_count = dirh.count + 1;
2099     + while (dir_count--) {
2100     + if (msblk->swap) {
2101     + struct squashfs_dir_entry sdire;
2102     + if (!squashfs_get_cached_block(i->i_sb, &sdire, next_block,
2103     + next_offset, sizeof(sdire), &next_block, &next_offset))
2104     + goto failed_read;
2105     +
2106     + length += sizeof(sdire);
2107     + SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
2108     + } else {
2109     + if (!squashfs_get_cached_block(i->i_sb, dire, next_block,
2110     + next_offset, sizeof(*dire), &next_block, &next_offset))
2111     + goto failed_read;
2112     +
2113     + length += sizeof(*dire);
2114     + }
2115     +
2116     + if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block,
2117     + next_offset, dire->size + 1, &next_block, &next_offset))
2118     + goto failed_read;
2119     +
2120     + length += dire->size + 1;
2121     +
2122     + if (name[0] < dire->name[0])
2123     + goto exit_lookup;
2124     +
2125     + if ((len == dire->size + 1) && !strncmp(name, dire->name, len)) {
2126     + squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block,
2127     + dire->offset);
2128     +
2129     + TRACE("calling squashfs_iget for directory entry %s, inode"
2130     + " %x:%x, %d\n", name, dirh.start_block, dire->offset,
2131     + dirh.inode_number + dire->inode_number);
2132     +
2133     + inode = squashfs_iget(i->i_sb, ino, dirh.inode_number + dire->inode_number);
2134     +
2135     + goto exit_lookup;
2136     + }
2137     + }
2138     + }
2139     +
2140     +exit_lookup:
2141     + kfree(dire);
2142     + if (inode)
2143     + return d_splice_alias(inode, dentry);
2144     + d_add(dentry, inode);
2145     + return ERR_PTR(0);
2146     +
2147     +failed_read:
2148     + ERROR("Unable to read directory block [%llx:%x]\n", next_block,
2149     + next_offset);
2150     + goto exit_lookup;
2151     +}
2152     +
2153     +
2154     +static int squashfs_remount(struct super_block *s, int *flags, char *data)
2155     +{
2156     + *flags |= MS_RDONLY;
2157     + return 0;
2158     +}
2159     +
2160     +
2161     +static void squashfs_put_super(struct super_block *s)
2162     +{
2163     + int i;
2164     +
2165     + if (s->s_fs_info) {
2166     + struct squashfs_sb_info *sbi = s->s_fs_info;
2167     + if (sbi->block_cache)
2168     + for (i = 0; i < squashfs_cached_blks; i++)
2169     + if (sbi->block_cache[i].block != SQUASHFS_INVALID_BLK)
2170     + vfree(sbi->block_cache[i].data);
2171     + if (sbi->fragment)
2172     + for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++)
2173     + vfree(sbi->fragment[i].data);
2174     + kfree(sbi->fragment);
2175     + kfree(sbi->block_cache);
2176     + vfree(sbi->read_page);
2177     + kfree(sbi->uid);
2178     + kfree(sbi->fragment_index);
2179     + kfree(sbi->fragment_index_2);
2180     + kfree(sbi->meta_index);
2181     + vfree(sbi->stream.workspace);
2182     + kfree(s->s_fs_info);
2183     + s->s_fs_info = NULL;
2184     + }
2185     +}
2186     +
2187     +
2188     +static int squashfs_get_sb(struct file_system_type *fs_type, int flags,
2189     + const char *dev_name, void *data, struct vfsmount *mnt)
2190     +{
2191     + return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super,
2192     + mnt);
2193     +}
2194     +
2195     +
2196     +static int __init init_squashfs_fs(void)
2197     +{
2198     + int err = init_inodecache();
2199     + if (err)
2200     + goto out;
2201     +
2202     + printk(KERN_INFO "squashfs: version 3.3 (2007/10/31) "
2203     + "Phillip Lougher\n");
2204     +
2205     + err = register_filesystem(&squashfs_fs_type);
2206     + if (err)
2207     + destroy_inodecache();
2208     +
2209     +out:
2210     + return err;
2211     +}
2212     +
2213     +
2214     +static void __exit exit_squashfs_fs(void)
2215     +{
2216     + unregister_filesystem(&squashfs_fs_type);
2217     + destroy_inodecache();
2218     +}
2219     +
2220     +
2221     +static struct kmem_cache * squashfs_inode_cachep;
2222     +
2223     +
2224     +static struct inode *squashfs_alloc_inode(struct super_block *sb)
2225     +{
2226     + struct squashfs_inode_info *ei;
2227     + ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL);
2228     + return ei ? &ei->vfs_inode : NULL;
2229     +}
2230     +
2231     +
2232     +static void squashfs_destroy_inode(struct inode *inode)
2233     +{
2234     + kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode));
2235     +}
2236     +
2237     +
2238     +static void init_once(struct kmem_cache *cachep, void *foo)
2239     +{
2240     + struct squashfs_inode_info *ei = foo;
2241     +
2242     + inode_init_once(&ei->vfs_inode);
2243     +}
2244     +
2245     +
2246     +static int __init init_inodecache(void)
2247     +{
2248     + squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache",
2249     + sizeof(struct squashfs_inode_info), 0,
2250     + SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, init_once);
2251     + if (squashfs_inode_cachep == NULL)
2252     + return -ENOMEM;
2253     + return 0;
2254     +}
2255     +
2256     +
2257     +static void destroy_inodecache(void)
2258     +{
2259     + kmem_cache_destroy(squashfs_inode_cachep);
2260     +}
2261     +
2262     +
2263     +module_init(init_squashfs_fs);
2264     +module_exit(exit_squashfs_fs);
2265     +MODULE_DESCRIPTION("squashfs 3.2-r2-CVS, a compressed read-only filesystem");
2266     +MODULE_AUTHOR("Phillip Lougher <phillip@lougher.demon.co.uk>");
2267     +MODULE_LICENSE("GPL");
2268     diff -x .gitignore -Nurp linux-2.6.24/fs/squashfs/Makefile linux-2.6.24-squashfs3.3/fs/squashfs/Makefile
2269     --- linux-2.6.24/fs/squashfs/Makefile 1970-01-01 01:00:00.000000000 +0100
2270     +++ linux-2.6.24-squashfs3.3/fs/squashfs/Makefile 2005-11-20 14:31:00.000000000 +0000
2271     @@ -0,0 +1,7 @@
2272     +#
2273     +# Makefile for the linux squashfs routines.
2274     +#
2275     +
2276     +obj-$(CONFIG_SQUASHFS) += squashfs.o
2277     +squashfs-y += inode.o
2278     +squashfs-y += squashfs2_0.o
2279     diff -x .gitignore -Nurp linux-2.6.24/fs/squashfs/squashfs2_0.c linux-2.6.24-squashfs3.3/fs/squashfs/squashfs2_0.c
2280     --- linux-2.6.24/fs/squashfs/squashfs2_0.c 1970-01-01 01:00:00.000000000 +0100
2281     +++ linux-2.6.24-squashfs3.3/fs/squashfs/squashfs2_0.c 2007-10-25 00:43:59.000000000 +0100
2282     @@ -0,0 +1,740 @@
2283     +/*
2284     + * Squashfs - a compressed read only filesystem for Linux
2285     + *
2286     + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
2287     + * Phillip Lougher <phillip@lougher.demon.co.uk>
2288     + *
2289     + * This program is free software; you can redistribute it and/or
2290     + * modify it under the terms of the GNU General Public License
2291     + * as published by the Free Software Foundation; either version 2,
2292     + * or (at your option) any later version.
2293     + *
2294     + * This program is distributed in the hope that it will be useful,
2295     + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2296     + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2297     + * GNU General Public License for more details.
2298     + *
2299     + * You should have received a copy of the GNU General Public License
2300     + * along with this program; if not, write to the Free Software
2301     + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2302     + *
2303     + * squashfs2_0.c
2304     + */
2305     +
2306     +#include <linux/squashfs_fs.h>
2307     +#include <linux/module.h>
2308     +#include <linux/zlib.h>
2309     +#include <linux/fs.h>
2310     +#include <linux/squashfs_fs_sb.h>
2311     +#include <linux/squashfs_fs_i.h>
2312     +
2313     +#include "squashfs.h"
2314     +static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir);
2315     +static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *,
2316     + struct nameidata *);
2317     +
2318     +static struct file_operations squashfs_dir_ops_2 = {
2319     + .read = generic_read_dir,
2320     + .readdir = squashfs_readdir_2
2321     +};
2322     +
2323     +static struct inode_operations squashfs_dir_inode_ops_2 = {
2324     + .lookup = squashfs_lookup_2
2325     +};
2326     +
2327     +static unsigned char squashfs_filetype_table[] = {
2328     + DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
2329     +};
2330     +
2331     +static int read_fragment_index_table_2(struct super_block *s)
2332     +{
2333     + struct squashfs_sb_info *msblk = s->s_fs_info;
2334     + struct squashfs_super_block *sblk = &msblk->sblk;
2335     +
2336     + if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2
2337     + (sblk->fragments), GFP_KERNEL))) {
2338     + ERROR("Failed to allocate uid/gid table\n");
2339     + return 0;
2340     + }
2341     +
2342     + if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) &&
2343     + !squashfs_read_data(s, (char *)
2344     + msblk->fragment_index_2,
2345     + sblk->fragment_table_start,
2346     + SQUASHFS_FRAGMENT_INDEX_BYTES_2
2347     + (sblk->fragments) |
2348     + SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) {
2349     + ERROR("unable to read fragment index table\n");
2350     + return 0;
2351     + }
2352     +
2353     + if (msblk->swap) {
2354     + int i;
2355     + unsigned int fragment;
2356     +
2357     + for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments);
2358     + i++) {
2359     + SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment),
2360     + &msblk->fragment_index_2[i], 1);
2361     + msblk->fragment_index_2[i] = fragment;
2362     + }
2363     + }
2364     +
2365     + return 1;
2366     +}
2367     +
2368     +
2369     +static int get_fragment_location_2(struct super_block *s, unsigned int fragment,
2370     + long long *fragment_start_block,
2371     + unsigned int *fragment_size)
2372     +{
2373     + struct squashfs_sb_info *msblk = s->s_fs_info;
2374     + long long start_block =
2375     + msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)];
2376     + int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment);
2377     + struct squashfs_fragment_entry_2 fragment_entry;
2378     +
2379     + if (msblk->swap) {
2380     + struct squashfs_fragment_entry_2 sfragment_entry;
2381     +
2382     + if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
2383     + start_block, offset,
2384     + sizeof(sfragment_entry), &start_block,
2385     + &offset))
2386     + goto out;
2387     + SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry);
2388     + } else
2389     + if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
2390     + start_block, offset,
2391     + sizeof(fragment_entry), &start_block,
2392     + &offset))
2393     + goto out;
2394     +
2395     + *fragment_start_block = fragment_entry.start_block;
2396     + *fragment_size = fragment_entry.size;
2397     +
2398     + return 1;
2399     +
2400     +out:
2401     + return 0;
2402     +}
2403     +
2404     +
2405     +static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i,
2406     + struct squashfs_base_inode_header_2 *inodeb, unsigned int ino)
2407     +{
2408     + struct squashfs_super_block *sblk = &msblk->sblk;
2409     +
2410     + i->i_ino = ino;
2411     + i->i_mtime.tv_sec = sblk->mkfs_time;
2412     + i->i_atime.tv_sec = sblk->mkfs_time;
2413     + i->i_ctime.tv_sec = sblk->mkfs_time;
2414     + i->i_uid = msblk->uid[inodeb->uid];
2415     + i->i_mode = inodeb->mode;
2416     + i->i_nlink = 1;
2417     + i->i_size = 0;
2418     + if (inodeb->guid == SQUASHFS_GUIDS)
2419     + i->i_gid = i->i_uid;
2420     + else
2421     + i->i_gid = msblk->guid[inodeb->guid];
2422     +}
2423     +
2424     +
2425     +static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode)
2426     +{
2427     + struct super_block *s = i->i_sb;
2428     + struct squashfs_sb_info *msblk = s->s_fs_info;
2429     + struct squashfs_super_block *sblk = &msblk->sblk;
2430     + unsigned int block = SQUASHFS_INODE_BLK(inode) +
2431     + sblk->inode_table_start;
2432     + unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
2433     + unsigned int ino = SQUASHFS_MK_VFS_INODE(block -
2434     + sblk->inode_table_start, offset);
2435     + long long next_block;
2436     + unsigned int next_offset;
2437     + union squashfs_inode_header_2 id, sid;
2438     + struct squashfs_base_inode_header_2 *inodeb = &id.base,
2439     + *sinodeb = &sid.base;
2440     +
2441     + TRACE("Entered squashfs_read_inode_2\n");
2442     +
2443     + if (msblk->swap) {
2444     + if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
2445     + offset, sizeof(*sinodeb), &next_block,
2446     + &next_offset))
2447     + goto failed_read;
2448     + SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb,
2449     + sizeof(*sinodeb));
2450     + } else
2451     + if (!squashfs_get_cached_block(s, (char *) inodeb, block,
2452     + offset, sizeof(*inodeb), &next_block,
2453     + &next_offset))
2454     + goto failed_read;
2455     +
2456     + squashfs_new_inode(msblk, i, inodeb, ino);
2457     +
2458     + switch(inodeb->inode_type) {
2459     + case SQUASHFS_FILE_TYPE: {
2460     + struct squashfs_reg_inode_header_2 *inodep = &id.reg;
2461     + struct squashfs_reg_inode_header_2 *sinodep = &sid.reg;
2462     + long long frag_blk;
2463     + unsigned int frag_size = 0;
2464     +
2465     + if (msblk->swap) {
2466     + if (!squashfs_get_cached_block(s, (char *)
2467     + sinodep, block, offset,
2468     + sizeof(*sinodep), &next_block,
2469     + &next_offset))
2470     + goto failed_read;
2471     + SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep);
2472     + } else
2473     + if (!squashfs_get_cached_block(s, (char *)
2474     + inodep, block, offset,
2475     + sizeof(*inodep), &next_block,
2476     + &next_offset))
2477     + goto failed_read;
2478     +
2479     + frag_blk = SQUASHFS_INVALID_BLK;
2480     + if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
2481     + !get_fragment_location_2(s,
2482     + inodep->fragment, &frag_blk, &frag_size))
2483     + goto failed_read;
2484     +
2485     + i->i_size = inodep->file_size;
2486     + i->i_fop = &generic_ro_fops;
2487     + i->i_mode |= S_IFREG;
2488     + i->i_mtime.tv_sec = inodep->mtime;
2489     + i->i_atime.tv_sec = inodep->mtime;
2490     + i->i_ctime.tv_sec = inodep->mtime;
2491     + i->i_blocks = ((i->i_size - 1) >> 9) + 1;
2492     + SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
2493     + SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
2494     + SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
2495     + SQUASHFS_I(i)->start_block = inodep->start_block;
2496     + SQUASHFS_I(i)->u.s1.block_list_start = next_block;
2497     + SQUASHFS_I(i)->offset = next_offset;
2498     + i->i_data.a_ops = &squashfs_aops;
2499     +
2500     + TRACE("File inode %x:%x, start_block %x, "
2501     + "block_list_start %llx, offset %x\n",
2502     + SQUASHFS_INODE_BLK(inode), offset,
2503     + inodep->start_block, next_block,
2504     + next_offset);
2505     + break;
2506     + }
2507     + case SQUASHFS_DIR_TYPE: {
2508     + struct squashfs_dir_inode_header_2 *inodep = &id.dir;
2509     + struct squashfs_dir_inode_header_2 *sinodep = &sid.dir;
2510     +
2511     + if (msblk->swap) {
2512     + if (!squashfs_get_cached_block(s, (char *)
2513     + sinodep, block, offset,
2514     + sizeof(*sinodep), &next_block,
2515     + &next_offset))
2516     + goto failed_read;
2517     + SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep);
2518     + } else
2519     + if (!squashfs_get_cached_block(s, (char *)
2520     + inodep, block, offset,
2521     + sizeof(*inodep), &next_block,
2522     + &next_offset))
2523     + goto failed_read;
2524     +
2525     + i->i_size = inodep->file_size;
2526     + i->i_op = &squashfs_dir_inode_ops_2;
2527     + i->i_fop = &squashfs_dir_ops_2;
2528     + i->i_mode |= S_IFDIR;
2529     + i->i_mtime.tv_sec = inodep->mtime;
2530     + i->i_atime.tv_sec = inodep->mtime;
2531     + i->i_ctime.tv_sec = inodep->mtime;
2532     + SQUASHFS_I(i)->start_block = inodep->start_block;
2533     + SQUASHFS_I(i)->offset = inodep->offset;
2534     + SQUASHFS_I(i)->u.s2.directory_index_count = 0;
2535     + SQUASHFS_I(i)->u.s2.parent_inode = 0;
2536     +
2537     + TRACE("Directory inode %x:%x, start_block %x, offset "
2538     + "%x\n", SQUASHFS_INODE_BLK(inode),
2539     + offset, inodep->start_block,
2540     + inodep->offset);
2541     + break;
2542     + }
2543     + case SQUASHFS_LDIR_TYPE: {
2544     + struct squashfs_ldir_inode_header_2 *inodep = &id.ldir;
2545     + struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir;
2546     +
2547     + if (msblk->swap) {
2548     + if (!squashfs_get_cached_block(s, (char *)
2549     + sinodep, block, offset,
2550     + sizeof(*sinodep), &next_block,
2551     + &next_offset))
2552     + goto failed_read;
2553     + SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep,
2554     + sinodep);
2555     + } else
2556     + if (!squashfs_get_cached_block(s, (char *)
2557     + inodep, block, offset,
2558     + sizeof(*inodep), &next_block,
2559     + &next_offset))
2560     + goto failed_read;
2561     +
2562     + i->i_size = inodep->file_size;
2563     + i->i_op = &squashfs_dir_inode_ops_2;
2564     + i->i_fop = &squashfs_dir_ops_2;
2565     + i->i_mode |= S_IFDIR;
2566     + i->i_mtime.tv_sec = inodep->mtime;
2567     + i->i_atime.tv_sec = inodep->mtime;
2568     + i->i_ctime.tv_sec = inodep->mtime;
2569     + SQUASHFS_I(i)->start_block = inodep->start_block;
2570     + SQUASHFS_I(i)->offset = inodep->offset;
2571     + SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
2572     + SQUASHFS_I(i)->u.s2.directory_index_offset =
2573     + next_offset;
2574     + SQUASHFS_I(i)->u.s2.directory_index_count =
2575     + inodep->i_count;
2576     + SQUASHFS_I(i)->u.s2.parent_inode = 0;
2577     +
2578     + TRACE("Long directory inode %x:%x, start_block %x, "
2579     + "offset %x\n",
2580     + SQUASHFS_INODE_BLK(inode), offset,
2581     + inodep->start_block, inodep->offset);
2582     + break;
2583     + }
2584     + case SQUASHFS_SYMLINK_TYPE: {
2585     + struct squashfs_symlink_inode_header_2 *inodep =
2586     + &id.symlink;
2587     + struct squashfs_symlink_inode_header_2 *sinodep =
2588     + &sid.symlink;
2589     +
2590     + if (msblk->swap) {
2591     + if (!squashfs_get_cached_block(s, (char *)
2592     + sinodep, block, offset,
2593     + sizeof(*sinodep), &next_block,
2594     + &next_offset))
2595     + goto failed_read;
2596     + SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
2597     + sinodep);
2598     + } else
2599     + if (!squashfs_get_cached_block(s, (char *)
2600     + inodep, block, offset,
2601     + sizeof(*inodep), &next_block,
2602     + &next_offset))
2603     + goto failed_read;
2604     +
2605     + i->i_size = inodep->symlink_size;
2606     + i->i_op = &page_symlink_inode_operations;
2607     + i->i_data.a_ops = &squashfs_symlink_aops;
2608     + i->i_mode |= S_IFLNK;
2609     + SQUASHFS_I(i)->start_block = next_block;
2610     + SQUASHFS_I(i)->offset = next_offset;
2611     +
2612     + TRACE("Symbolic link inode %x:%x, start_block %llx, "
2613     + "offset %x\n",
2614     + SQUASHFS_INODE_BLK(inode), offset,
2615     + next_block, next_offset);
2616     + break;
2617     + }
2618     + case SQUASHFS_BLKDEV_TYPE:
2619     + case SQUASHFS_CHRDEV_TYPE: {
2620     + struct squashfs_dev_inode_header_2 *inodep = &id.dev;
2621     + struct squashfs_dev_inode_header_2 *sinodep = &sid.dev;
2622     +
2623     + if (msblk->swap) {
2624     + if (!squashfs_get_cached_block(s, (char *)
2625     + sinodep, block, offset,
2626     + sizeof(*sinodep), &next_block,
2627     + &next_offset))
2628     + goto failed_read;
2629     + SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep);
2630     + } else
2631     + if (!squashfs_get_cached_block(s, (char *)
2632     + inodep, block, offset,
2633     + sizeof(*inodep), &next_block,
2634     + &next_offset))
2635     + goto failed_read;
2636     +
2637     + i->i_mode |= (inodeb->inode_type ==
2638     + SQUASHFS_CHRDEV_TYPE) ? S_IFCHR :
2639     + S_IFBLK;
2640     + init_special_inode(i, i->i_mode,
2641     + old_decode_dev(inodep->rdev));
2642     +
2643     + TRACE("Device inode %x:%x, rdev %x\n",
2644     + SQUASHFS_INODE_BLK(inode), offset,
2645     + inodep->rdev);
2646     + break;
2647     + }
2648     + case SQUASHFS_FIFO_TYPE:
2649     + case SQUASHFS_SOCKET_TYPE: {
2650     +
2651     + i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
2652     + ? S_IFIFO : S_IFSOCK;
2653     + init_special_inode(i, i->i_mode, 0);
2654     + break;
2655     + }
2656     + default:
2657     + ERROR("Unknown inode type %d in squashfs_iget!\n",
2658     + inodeb->inode_type);
2659     + goto failed_read1;
2660     + }
2661     +
2662     + return 1;
2663     +
2664     +failed_read:
2665     + ERROR("Unable to read inode [%x:%x]\n", block, offset);
2666     +
2667     +failed_read1:
2668     + return 0;
2669     +}
2670     +
2671     +
2672     +static int get_dir_index_using_offset(struct super_block *s, long long
2673     + *next_block, unsigned int *next_offset,
2674     + long long index_start,
2675     + unsigned int index_offset, int i_count,
2676     + long long f_pos)
2677     +{
2678     + struct squashfs_sb_info *msblk = s->s_fs_info;
2679     + struct squashfs_super_block *sblk = &msblk->sblk;
2680     + int i, length = 0;
2681     + struct squashfs_dir_index_2 index;
2682     +
2683     + TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
2684     + i_count, (unsigned int) f_pos);
2685     +
2686     + if (f_pos == 0)
2687     + goto finish;
2688     +
2689     + for (i = 0; i < i_count; i++) {
2690     + if (msblk->swap) {
2691     + struct squashfs_dir_index_2 sindex;
2692     + squashfs_get_cached_block(s, (char *) &sindex,
2693     + index_start, index_offset,
2694     + sizeof(sindex), &index_start,
2695     + &index_offset);
2696     + SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex);
2697     + } else
2698     + squashfs_get_cached_block(s, (char *) &index,
2699     + index_start, index_offset,
2700     + sizeof(index), &index_start,
2701     + &index_offset);
2702     +
2703     + if (index.index > f_pos)
2704     + break;
2705     +
2706     + squashfs_get_cached_block(s, NULL, index_start, index_offset,
2707     + index.size + 1, &index_start,
2708     + &index_offset);
2709     +
2710     + length = index.index;
2711     + *next_block = index.start_block + sblk->directory_table_start;
2712     + }
2713     +
2714     + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
2715     +
2716     +finish:
2717     + return length;
2718     +}
2719     +
2720     +
2721     +static int get_dir_index_using_name(struct super_block *s, long long
2722     + *next_block, unsigned int *next_offset,
2723     + long long index_start,
2724     + unsigned int index_offset, int i_count,
2725     + const char *name, int size)
2726     +{
2727     + struct squashfs_sb_info *msblk = s->s_fs_info;
2728     + struct squashfs_super_block *sblk = &msblk->sblk;
2729     + int i, length = 0;
2730     + struct squashfs_dir_index_2 *index;
2731     + char *str;
2732     +
2733     + TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
2734     +
2735     + if (!(str = kmalloc(sizeof(struct squashfs_dir_index) +
2736     + (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) {
2737     + ERROR("Failed to allocate squashfs_dir_index\n");
2738     + goto failure;
2739     + }
2740     +
2741     + index = (struct squashfs_dir_index_2 *) (str + SQUASHFS_NAME_LEN + 1);
2742     + strncpy(str, name, size);
2743     + str[size] = '\0';
2744     +
2745     + for (i = 0; i < i_count; i++) {
2746     + if (msblk->swap) {
2747     + struct squashfs_dir_index_2 sindex;
2748     + squashfs_get_cached_block(s, (char *) &sindex,
2749     + index_start, index_offset,
2750     + sizeof(sindex), &index_start,
2751     + &index_offset);
2752     + SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex);
2753     + } else
2754     + squashfs_get_cached_block(s, (char *) index,
2755     + index_start, index_offset,
2756     + sizeof(struct squashfs_dir_index_2),
2757     + &index_start, &index_offset);
2758     +
2759     + squashfs_get_cached_block(s, index->name, index_start,
2760     + index_offset, index->size + 1,
2761     + &index_start, &index_offset);
2762     +
2763     + index->name[index->size + 1] = '\0';
2764     +
2765     + if (strcmp(index->name, str) > 0)
2766     + break;
2767     +
2768     + length = index->index;
2769     + *next_block = index->start_block + sblk->directory_table_start;
2770     + }
2771     +
2772     + *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
2773     + kfree(str);
2774     +failure:
2775     + return length;
2776     +}
2777     +
2778     +
2779     +static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir)
2780     +{
2781     + struct inode *i = file->f_dentry->d_inode;
2782     + struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
2783     + struct squashfs_super_block *sblk = &msblk->sblk;
2784     + long long next_block = SQUASHFS_I(i)->start_block +
2785     + sblk->directory_table_start;
2786     + int next_offset = SQUASHFS_I(i)->offset, length = 0,
2787     + dir_count;
2788     + struct squashfs_dir_header_2 dirh;
2789     + struct squashfs_dir_entry_2 *dire;
2790     +
2791     + TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset);
2792     +
2793     + if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
2794     + SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
2795     + ERROR("Failed to allocate squashfs_dir_entry\n");
2796     + goto finish;
2797     + }
2798     +
2799     + length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
2800     + SQUASHFS_I(i)->u.s2.directory_index_start,
2801     + SQUASHFS_I(i)->u.s2.directory_index_offset,
2802     + SQUASHFS_I(i)->u.s2.directory_index_count,
2803     + file->f_pos);
2804     +
2805     + while (length < i_size_read(i)) {
2806     + /* read directory header */
2807     + if (msblk->swap) {
2808     + struct squashfs_dir_header_2 sdirh;
2809     +
2810     + if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
2811     + next_block, next_offset, sizeof(sdirh),
2812     + &next_block, &next_offset))
2813     + goto failed_read;
2814     +
2815     + length += sizeof(sdirh);
2816     + SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
2817     + } else {
2818     + if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
2819     + next_block, next_offset, sizeof(dirh),
2820     + &next_block, &next_offset))
2821     + goto failed_read;
2822     +
2823     + length += sizeof(dirh);
2824     + }
2825     +
2826     + dir_count = dirh.count + 1;
2827     + while (dir_count--) {
2828     + if (msblk->swap) {
2829     + struct squashfs_dir_entry_2 sdire;
2830     + if (!squashfs_get_cached_block(i->i_sb, (char *)
2831     + &sdire, next_block, next_offset,
2832     + sizeof(sdire), &next_block,
2833     + &next_offset))
2834     + goto failed_read;
2835     +
2836     + length += sizeof(sdire);
2837     + SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
2838     + } else {
2839     + if (!squashfs_get_cached_block(i->i_sb, (char *)
2840     + dire, next_block, next_offset,
2841     + sizeof(*dire), &next_block,
2842     + &next_offset))
2843     + goto failed_read;
2844     +
2845     + length += sizeof(*dire);
2846     + }
2847     +
2848     + if (!squashfs_get_cached_block(i->i_sb, dire->name,
2849     + next_block, next_offset,
2850     + dire->size + 1, &next_block,
2851     + &next_offset))
2852     + goto failed_read;
2853     +
2854     + length += dire->size + 1;
2855     +
2856     + if (file->f_pos >= length)
2857     + continue;
2858     +
2859     + dire->name[dire->size + 1] = '\0';
2860     +
2861     + TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n",
2862     + (unsigned int) dirent, dire->name,
2863     + dire->size + 1, (int) file->f_pos,
2864     + dirh.start_block, dire->offset,
2865     + squashfs_filetype_table[dire->type]);
2866     +
2867     + if (filldir(dirent, dire->name, dire->size + 1,
2868     + file->f_pos, SQUASHFS_MK_VFS_INODE(
2869     + dirh.start_block, dire->offset),
2870     + squashfs_filetype_table[dire->type])
2871     + < 0) {
2872     + TRACE("Filldir returned less than 0\n");
2873     + goto finish;
2874     + }
2875     + file->f_pos = length;
2876     + }
2877     + }
2878     +
2879     +finish:
2880     + kfree(dire);
2881     + return 0;
2882     +
2883     +failed_read:
2884     + ERROR("Unable to read directory block [%llx:%x]\n", next_block,
2885     + next_offset);
2886     + kfree(dire);
2887     + return 0;
2888     +}
2889     +
2890     +
2891     +static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry,
2892     + struct nameidata *nd)
2893     +{
2894     + const unsigned char *name = dentry->d_name.name;
2895     + int len = dentry->d_name.len;
2896     + struct inode *inode = NULL;
2897     + struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
2898     + struct squashfs_super_block *sblk = &msblk->sblk;
2899     + long long next_block = SQUASHFS_I(i)->start_block +
2900     + sblk->directory_table_start;
2901     + int next_offset = SQUASHFS_I(i)->offset, length = 0,
2902     + dir_count;
2903     + struct squashfs_dir_header_2 dirh;
2904     + struct squashfs_dir_entry_2 *dire;
2905     + int sorted = sblk->s_major == 2 && sblk->s_minor >= 1;
2906     +
2907     + TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset);
2908     +
2909     + if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
2910     + SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
2911     + ERROR("Failed to allocate squashfs_dir_entry\n");
2912     + goto exit_loop;
2913     + }
2914     +
2915     + if (len > SQUASHFS_NAME_LEN)
2916     + goto exit_loop;
2917     +
2918     + length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
2919     + SQUASHFS_I(i)->u.s2.directory_index_start,
2920     + SQUASHFS_I(i)->u.s2.directory_index_offset,
2921     + SQUASHFS_I(i)->u.s2.directory_index_count, name,
2922     + len);
2923     +
2924     + while (length < i_size_read(i)) {
2925     + /* read directory header */
2926     + if (msblk->swap) {
2927     + struct squashfs_dir_header_2 sdirh;
2928     + if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
2929     + next_block, next_offset, sizeof(sdirh),
2930     + &next_block, &next_offset))
2931     + goto failed_read;
2932     +
2933     + length += sizeof(sdirh);
2934     + SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
2935     + } else {
2936     + if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
2937     + next_block, next_offset, sizeof(dirh),
2938     + &next_block, &next_offset))
2939     + goto failed_read;
2940     +
2941     + length += sizeof(dirh);
2942     + }
2943     +
2944     + dir_count = dirh.count + 1;
2945     + while (dir_count--) {
2946     + if (msblk->swap) {
2947     + struct squashfs_dir_entry_2 sdire;
2948     + if (!squashfs_get_cached_block(i->i_sb, (char *)
2949     + &sdire, next_block,next_offset,
2950     + sizeof(sdire), &next_block,
2951     + &next_offset))
2952     + goto failed_read;
2953     +
2954     + length += sizeof(sdire);
2955     + SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
2956     + } else {
2957     + if (!squashfs_get_cached_block(i->i_sb, (char *)
2958     + dire, next_block,next_offset,
2959     + sizeof(*dire), &next_block,
2960     + &next_offset))
2961     + goto failed_read;
2962     +
2963     + length += sizeof(*dire);
2964     + }
2965     +
2966     + if (!squashfs_get_cached_block(i->i_sb, dire->name,
2967     + next_block, next_offset, dire->size + 1,
2968     + &next_block, &next_offset))
2969     + goto failed_read;
2970     +
2971     + length += dire->size + 1;
2972     +
2973     + if (sorted && name[0] < dire->name[0])
2974     + goto exit_loop;
2975     +
2976     + if ((len == dire->size + 1) && !strncmp(name,
2977     + dire->name, len)) {
2978     + squashfs_inode_t ino =
2979     + SQUASHFS_MKINODE(dirh.start_block,
2980     + dire->offset);
2981     + unsigned int inode_number = SQUASHFS_MK_VFS_INODE(dirh.start_block,
2982     + dire->offset);
2983     +
2984     + TRACE("calling squashfs_iget for directory "
2985     + "entry %s, inode %x:%x, %lld\n", name,
2986     + dirh.start_block, dire->offset, ino);
2987     +
2988     + inode = squashfs_iget(i->i_sb, ino, inode_number);
2989     +
2990     + goto exit_loop;
2991     + }
2992     + }
2993     + }
2994     +
2995     +exit_loop:
2996     + kfree(dire);
2997     + d_add(dentry, inode);
2998     + return ERR_PTR(0);
2999     +
3000     +failed_read:
3001     + ERROR("Unable to read directory block [%llx:%x]\n", next_block,
3002     + next_offset);
3003     + goto exit_loop;
3004     +}
3005     +
3006     +
3007     +int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
3008     +{
3009     + struct squashfs_super_block *sblk = &msblk->sblk;
3010     +
3011     + msblk->read_inode = squashfs_read_inode_2;
3012     + msblk->read_fragment_index_table = read_fragment_index_table_2;
3013     +
3014     + sblk->bytes_used = sblk->bytes_used_2;
3015     + sblk->uid_start = sblk->uid_start_2;
3016     + sblk->guid_start = sblk->guid_start_2;
3017     + sblk->inode_table_start = sblk->inode_table_start_2;
3018     + sblk->directory_table_start = sblk->directory_table_start_2;
3019     + sblk->fragment_table_start = sblk->fragment_table_start_2;
3020     +
3021     + return 1;
3022     +}
3023     diff -x .gitignore -Nurp linux-2.6.24/fs/squashfs/squashfs.h linux-2.6.24-squashfs3.3/fs/squashfs/squashfs.h
3024     --- linux-2.6.24/fs/squashfs/squashfs.h 1970-01-01 01:00:00.000000000 +0100
3025     +++ linux-2.6.24-squashfs3.3/fs/squashfs/squashfs.h 2007-08-19 04:23:16.000000000 +0100
3026     @@ -0,0 +1,86 @@
3027     +/*
3028     + * Squashfs - a compressed read only filesystem for Linux
3029     + *
3030     + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
3031     + * Phillip Lougher <phillip@lougher.demon.co.uk>
3032     + *
3033     + * This program is free software; you can redistribute it and/or
3034     + * modify it under the terms of the GNU General Public License
3035     + * as published by the Free Software Foundation; either version 2,
3036     + * or (at your option) any later version.
3037     + *
3038     + * This program is distributed in the hope that it will be useful,
3039     + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3040     + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3041     + * GNU General Public License for more details.
3042     + *
3043     + * You should have received a copy of the GNU General Public License
3044     + * along with this program; if not, write to the Free Software
3045     + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3046     + *
3047     + * squashfs.h
3048     + */
3049     +
3050     +#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
3051     +#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
3052     +#endif
3053     +
3054     +#ifdef SQUASHFS_TRACE
3055     +#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args)
3056     +#else
3057     +#define TRACE(s, args...) {}
3058     +#endif
3059     +
3060     +#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args)
3061     +
3062     +#define SERROR(s, args...) do { \
3063     + if (!silent) \
3064     + printk(KERN_ERR "SQUASHFS error: "s, ## args);\
3065     + } while(0)
3066     +
3067     +#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args)
3068     +
3069     +static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode)
3070     +{
3071     + return list_entry(inode, struct squashfs_inode_info, vfs_inode);
3072     +}
3073     +
3074     +#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY)
3075     +#define SQSH_EXTERN
3076     +extern unsigned int squashfs_read_data(struct super_block *s, char *buffer,
3077     + long long index, unsigned int length,
3078     + long long *next_index, int srclength);
3079     +extern int squashfs_get_cached_block(struct super_block *s, void *buffer,
3080     + long long block, unsigned int offset,
3081     + int length, long long *next_block,
3082     + unsigned int *next_offset);
3083     +extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct
3084     + squashfs_fragment_cache *fragment);
3085     +extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block
3086     + *s, long long start_block,
3087     + int length);
3088     +extern struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number);
3089     +extern const struct address_space_operations squashfs_symlink_aops;
3090     +extern const struct address_space_operations squashfs_aops;
3091     +extern struct inode_operations squashfs_dir_inode_ops;
3092     +#else
3093     +#define SQSH_EXTERN static
3094     +#endif
3095     +
3096     +#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
3097     +extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk);
3098     +#else
3099     +static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk)
3100     +{
3101     + return 0;
3102     +}
3103     +#endif
3104     +
3105     +#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
3106     +extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk);
3107     +#else
3108     +static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
3109     +{
3110     + return 0;
3111     +}
3112     +#endif
3113     diff -x .gitignore -Nurp linux-2.6.24/include/linux/squashfs_fs.h linux-2.6.24-squashfs3.3/include/linux/squashfs_fs.h
3114     --- linux-2.6.24/include/linux/squashfs_fs.h 1970-01-01 01:00:00.000000000 +0100
3115     +++ linux-2.6.24-squashfs3.3/include/linux/squashfs_fs.h 2007-11-01 03:50:57.000000000 +0000
3116     @@ -0,0 +1,935 @@
3117     +#ifndef SQUASHFS_FS
3118     +#define SQUASHFS_FS
3119     +
3120     +/*
3121     + * Squashfs
3122     + *
3123     + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
3124     + * Phillip Lougher <phillip@lougher.demon.co.uk>
3125     + *
3126     + * This program is free software; you can redistribute it and/or
3127     + * modify it under the terms of the GNU General Public License
3128     + * as published by the Free Software Foundation; either version 2,
3129     + * or (at your option) any later version.
3130     + *
3131     + * This program is distributed in the hope that it will be useful,
3132     + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3133     + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3134     + * GNU General Public License for more details.
3135     + *
3136     + * You should have received a copy of the GNU General Public License
3137     + * along with this program; if not, write to the Free Software
3138     + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
3139     + *
3140     + * squashfs_fs.h
3141     + */
3142     +
3143     +#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY
3144     +#define CONFIG_SQUASHFS_2_0_COMPATIBILITY
3145     +#endif
3146     +
3147     +#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
3148     +#define SQUASHFS_MAJOR 3
3149     +#define SQUASHFS_MINOR 1
3150     +#define SQUASHFS_MAGIC 0x73717368
3151     +#define SQUASHFS_MAGIC_SWAP 0x68737173
3152     +#define SQUASHFS_START 0
3153     +
3154     +/* size of metadata (inode and directory) blocks */
3155     +#define SQUASHFS_METADATA_SIZE 8192
3156     +#define SQUASHFS_METADATA_LOG 13
3157     +
3158     +/* default size of data blocks */
3159     +#define SQUASHFS_FILE_SIZE 131072
3160     +#define SQUASHFS_FILE_LOG 17
3161     +
3162     +#define SQUASHFS_FILE_MAX_SIZE 1048576
3163     +
3164     +/* Max number of uids and gids */
3165     +#define SQUASHFS_UIDS 256
3166     +#define SQUASHFS_GUIDS 255
3167     +
3168     +/* Max length of filename (not 255) */
3169     +#define SQUASHFS_NAME_LEN 256
3170     +
3171     +#define SQUASHFS_INVALID ((long long) 0xffffffffffff)
3172     +#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff)
3173     +#define SQUASHFS_INVALID_BLK ((long long) -1)
3174     +#define SQUASHFS_USED_BLK ((long long) -2)
3175     +
3176     +/* Filesystem flags */
3177     +#define SQUASHFS_NOI 0
3178     +#define SQUASHFS_NOD 1
3179     +#define SQUASHFS_CHECK 2
3180     +#define SQUASHFS_NOF 3
3181     +#define SQUASHFS_NO_FRAG 4
3182     +#define SQUASHFS_ALWAYS_FRAG 5
3183     +#define SQUASHFS_DUPLICATE 6
3184     +#define SQUASHFS_EXPORT 7
3185     +
3186     +#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1)
3187     +
3188     +#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \
3189     + SQUASHFS_NOI)
3190     +
3191     +#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \
3192     + SQUASHFS_NOD)
3193     +
3194     +#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
3195     + SQUASHFS_NOF)
3196     +
3197     +#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
3198     + SQUASHFS_NO_FRAG)
3199     +
3200     +#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
3201     + SQUASHFS_ALWAYS_FRAG)
3202     +
3203     +#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \
3204     + SQUASHFS_DUPLICATE)
3205     +
3206     +#define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \
3207     + SQUASHFS_EXPORT)
3208     +
3209     +#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \
3210     + SQUASHFS_CHECK)
3211     +
3212     +#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \
3213     + duplicate_checking, exortable) (noi | (nod << 1) | (check_data << 2) \
3214     + | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \
3215     + (duplicate_checking << 6) | (exportable << 7))
3216     +
3217     +/* Max number of types and file types */
3218     +#define SQUASHFS_DIR_TYPE 1
3219     +#define SQUASHFS_FILE_TYPE 2
3220     +#define SQUASHFS_SYMLINK_TYPE 3
3221     +#define SQUASHFS_BLKDEV_TYPE 4
3222     +#define SQUASHFS_CHRDEV_TYPE 5
3223     +#define SQUASHFS_FIFO_TYPE 6
3224     +#define SQUASHFS_SOCKET_TYPE 7
3225     +#define SQUASHFS_LDIR_TYPE 8
3226     +#define SQUASHFS_LREG_TYPE 9
3227     +
3228     +/* 1.0 filesystem type definitions */
3229     +#define SQUASHFS_TYPES 5
3230     +#define SQUASHFS_IPC_TYPE 0
3231     +
3232     +/* Flag whether block is compressed or uncompressed, bit is set if block is
3233     + * uncompressed */
3234     +#define SQUASHFS_COMPRESSED_BIT (1 << 15)
3235     +
3236     +#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
3237     + (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT)
3238     +
3239     +#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT))
3240     +
3241     +#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24)
3242     +
3243     +#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) ((B) & \
3244     + ~SQUASHFS_COMPRESSED_BIT_BLOCK)
3245     +
3246     +#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
3247     +
3248     +/*
3249     + * Inode number ops. Inodes consist of a compressed block number, and an
3250     + * uncompressed offset within that block
3251     + */
3252     +#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16))
3253     +
3254     +#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff))
3255     +
3256     +#define SQUASHFS_MKINODE(A, B) ((squashfs_inode_t)(((squashfs_inode_t) (A)\
3257     + << 16) + (B)))
3258     +
3259     +/* Compute 32 bit VFS inode number from squashfs inode number */
3260     +#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \
3261     + ((b) >> 2) + 1))
3262     +/* XXX */
3263     +
3264     +/* Translate between VFS mode and squashfs mode */
3265     +#define SQUASHFS_MODE(a) ((a) & 0xfff)
3266     +
3267     +/* fragment and fragment table defines */
3268     +#define SQUASHFS_FRAGMENT_BYTES(A) ((A) * sizeof(struct squashfs_fragment_entry))
3269     +
3270     +#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \
3271     + SQUASHFS_METADATA_SIZE)
3272     +
3273     +#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \
3274     + SQUASHFS_METADATA_SIZE)
3275     +
3276     +#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \
3277     + SQUASHFS_METADATA_SIZE - 1) / \
3278     + SQUASHFS_METADATA_SIZE)
3279     +
3280     +#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\
3281     + sizeof(long long))
3282     +
3283     +/* inode lookup table defines */
3284     +#define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(squashfs_inode_t))
3285     +
3286     +#define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \
3287     + SQUASHFS_METADATA_SIZE)
3288     +
3289     +#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \
3290     + SQUASHFS_METADATA_SIZE)
3291     +
3292     +#define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \
3293     + SQUASHFS_METADATA_SIZE - 1) / \
3294     + SQUASHFS_METADATA_SIZE)
3295     +
3296     +#define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\
3297     + sizeof(long long))
3298     +
3299     +/* cached data constants for filesystem */
3300     +#define SQUASHFS_CACHED_BLKS 8
3301     +
3302     +#define SQUASHFS_MAX_FILE_SIZE_LOG 64
3303     +
3304     +#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \
3305     + (SQUASHFS_MAX_FILE_SIZE_LOG - 2))
3306     +
3307     +#define SQUASHFS_MARKER_BYTE 0xff
3308     +
3309     +/* meta index cache */
3310     +#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
3311     +#define SQUASHFS_META_ENTRIES 31
3312     +#define SQUASHFS_META_NUMBER 8
3313     +#define SQUASHFS_SLOTS 4
3314     +
3315     +struct meta_entry {
3316     + long long data_block;
3317     + unsigned int index_block;
3318     + unsigned short offset;
3319     + unsigned short pad;
3320     +};
3321     +
3322     +struct meta_index {
3323     + unsigned int inode_number;
3324     + unsigned int offset;
3325     + unsigned short entries;
3326     + unsigned short skip;
3327     + unsigned short locked;
3328     + unsigned short pad;
3329     + struct meta_entry meta_entry[SQUASHFS_META_ENTRIES];
3330     +};
3331     +
3332     +
3333     +/*
3334     + * definitions for structures on disk
3335     + */
3336     +
3337     +typedef long long squashfs_block_t;
3338     +typedef long long squashfs_inode_t;
3339     +
3340     +struct squashfs_super_block {
3341     + unsigned int s_magic;
3342     + unsigned int inodes;
3343     + unsigned int bytes_used_2;
3344     + unsigned int uid_start_2;
3345     + unsigned int guid_start_2;
3346     + unsigned int inode_table_start_2;
3347     + unsigned int directory_table_start_2;
3348     + unsigned int s_major:16;
3349     + unsigned int s_minor:16;
3350     + unsigned int block_size_1:16;
3351     + unsigned int block_log:16;
3352     + unsigned int flags:8;
3353     + unsigned int no_uids:8;
3354     + unsigned int no_guids:8;
3355     + unsigned int mkfs_time /* time of filesystem creation */;
3356     + squashfs_inode_t root_inode;
3357     + unsigned int block_size;
3358     + unsigned int fragments;
3359     + unsigned int fragment_table_start_2;
3360     + long long bytes_used;
3361     + long long uid_start;
3362     + long long guid_start;
3363     + long long inode_table_start;
3364     + long long directory_table_start;
3365     + long long fragment_table_start;
3366     + long long lookup_table_start;
3367     +} __attribute__ ((packed));
3368     +
3369     +struct squashfs_dir_index {
3370     + unsigned int index;
3371     + unsigned int start_block;
3372     + unsigned char size;
3373     + unsigned char name[0];
3374     +} __attribute__ ((packed));
3375     +
3376     +#define SQUASHFS_BASE_INODE_HEADER \
3377     + unsigned int inode_type:4; \
3378     + unsigned int mode:12; \
3379     + unsigned int uid:8; \
3380     + unsigned int guid:8; \
3381     + unsigned int mtime; \
3382     + unsigned int inode_number;
3383     +
3384     +struct squashfs_base_inode_header {
3385     + SQUASHFS_BASE_INODE_HEADER;
3386     +} __attribute__ ((packed));
3387     +
3388     +struct squashfs_ipc_inode_header {
3389     + SQUASHFS_BASE_INODE_HEADER;
3390     + unsigned int nlink;
3391     +} __attribute__ ((packed));
3392     +
3393     +struct squashfs_dev_inode_header {
3394     + SQUASHFS_BASE_INODE_HEADER;
3395     + unsigned int nlink;
3396     + unsigned short rdev;
3397     +} __attribute__ ((packed));
3398     +
3399     +struct squashfs_symlink_inode_header {
3400     + SQUASHFS_BASE_INODE_HEADER;
3401     + unsigned int nlink;
3402     + unsigned short symlink_size;
3403     + char symlink[0];
3404     +} __attribute__ ((packed));
3405     +
3406     +struct squashfs_reg_inode_header {
3407     + SQUASHFS_BASE_INODE_HEADER;
3408     + squashfs_block_t start_block;
3409     + unsigned int fragment;
3410     + unsigned int offset;
3411     + unsigned int file_size;
3412     + unsigned short block_list[0];
3413     +} __attribute__ ((packed));
3414     +
3415     +struct squashfs_lreg_inode_header {
3416     + SQUASHFS_BASE_INODE_HEADER;
3417     + unsigned int nlink;
3418     + squashfs_block_t start_block;
3419     + unsigned int fragment;
3420     + unsigned int offset;
3421     + long long file_size;
3422     + unsigned short block_list[0];
3423     +} __attribute__ ((packed));
3424     +
3425     +struct squashfs_dir_inode_header {
3426     + SQUASHFS_BASE_INODE_HEADER;
3427     + unsigned int nlink;
3428     + unsigned int file_size:19;
3429     + unsigned int offset:13;
3430     + unsigned int start_block;
3431     + unsigned int parent_inode;
3432     +} __attribute__ ((packed));
3433     +
3434     +struct squashfs_ldir_inode_header {
3435     + SQUASHFS_BASE_INODE_HEADER;
3436     + unsigned int nlink;
3437     + unsigned int file_size:27;
3438     + unsigned int offset:13;
3439     + unsigned int start_block;
3440     + unsigned int i_count:16;
3441     + unsigned int parent_inode;
3442     + struct squashfs_dir_index index[0];
3443     +} __attribute__ ((packed));
3444     +
3445     +union squashfs_inode_header {
3446     + struct squashfs_base_inode_header base;
3447     + struct squashfs_dev_inode_header dev;
3448     + struct squashfs_symlink_inode_header symlink;
3449     + struct squashfs_reg_inode_header reg;
3450     + struct squashfs_lreg_inode_header lreg;
3451     + struct squashfs_dir_inode_header dir;
3452     + struct squashfs_ldir_inode_header ldir;
3453     + struct squashfs_ipc_inode_header ipc;
3454     +};
3455     +
3456     +struct squashfs_dir_entry {
3457     + unsigned int offset:13;
3458     + unsigned int type:3;
3459     + unsigned int size:8;
3460     + int inode_number:16;
3461     + char name[0];
3462     +} __attribute__ ((packed));
3463     +
3464     +struct squashfs_dir_header {
3465     + unsigned int count:8;
3466     + unsigned int start_block;
3467     + unsigned int inode_number;
3468     +} __attribute__ ((packed));
3469     +
3470     +struct squashfs_fragment_entry {
3471     + long long start_block;
3472     + unsigned int size;
3473     + unsigned int pending;
3474     +} __attribute__ ((packed));
3475     +
3476     +extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
3477     +extern int squashfs_uncompress_init(void);
3478     +extern int squashfs_uncompress_exit(void);
3479     +
3480     +/*
3481     + * macros to convert each packed bitfield structure from little endian to big
3482     + * endian and vice versa. These are needed when creating or using a filesystem
3483     + * on a machine with different byte ordering to the target architecture.
3484     + *
3485     + */
3486     +
3487     +#define SQUASHFS_SWAP_START \
3488     + int bits;\
3489     + int b_pos;\
3490     + unsigned long long val;\
3491     + unsigned char *s;\
3492     + unsigned char *d;
3493     +
3494     +#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
3495     + SQUASHFS_SWAP_START\
3496     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\
3497     + SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
3498     + SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
3499     + SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
3500     + SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
3501     + SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
3502     + SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
3503     + SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
3504     + SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
3505     + SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
3506     + SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
3507     + SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
3508     + SQUASHFS_SWAP((s)->flags, d, 288, 8);\
3509     + SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
3510     + SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
3511     + SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
3512     + SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
3513     + SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
3514     + SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
3515     + SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
3516     + SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
3517     + SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
3518     + SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
3519     + SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
3520     + SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
3521     + SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
3522     + SQUASHFS_SWAP((s)->lookup_table_start, d, 888, 64);\
3523     +}
3524     +
3525     +#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
3526     + SQUASHFS_MEMSET(s, d, n);\
3527     + SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
3528     + SQUASHFS_SWAP((s)->mode, d, 4, 12);\
3529     + SQUASHFS_SWAP((s)->uid, d, 16, 8);\
3530     + SQUASHFS_SWAP((s)->guid, d, 24, 8);\
3531     + SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
3532     + SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
3533     +
3534     +#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
3535     + SQUASHFS_SWAP_START\
3536     + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
3537     +}
3538     +
3539     +#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\
3540     + SQUASHFS_SWAP_START\
3541     + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3542     + sizeof(struct squashfs_ipc_inode_header))\
3543     + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3544     +}
3545     +
3546     +#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
3547     + SQUASHFS_SWAP_START\
3548     + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3549     + sizeof(struct squashfs_dev_inode_header)); \
3550     + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3551     + SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
3552     +}
3553     +
3554     +#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
3555     + SQUASHFS_SWAP_START\
3556     + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3557     + sizeof(struct squashfs_symlink_inode_header));\
3558     + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3559     + SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
3560     +}
3561     +
3562     +#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
3563     + SQUASHFS_SWAP_START\
3564     + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3565     + sizeof(struct squashfs_reg_inode_header));\
3566     + SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
3567     + SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
3568     + SQUASHFS_SWAP((s)->offset, d, 192, 32);\
3569     + SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
3570     +}
3571     +
3572     +#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\
3573     + SQUASHFS_SWAP_START\
3574     + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3575     + sizeof(struct squashfs_lreg_inode_header));\
3576     + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3577     + SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
3578     + SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
3579     + SQUASHFS_SWAP((s)->offset, d, 224, 32);\
3580     + SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
3581     +}
3582     +
3583     +#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
3584     + SQUASHFS_SWAP_START\
3585     + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3586     + sizeof(struct squashfs_dir_inode_header));\
3587     + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3588     + SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
3589     + SQUASHFS_SWAP((s)->offset, d, 147, 13);\
3590     + SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
3591     + SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
3592     +}
3593     +
3594     +#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\
3595     + SQUASHFS_SWAP_START\
3596     + SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
3597     + sizeof(struct squashfs_ldir_inode_header));\
3598     + SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
3599     + SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
3600     + SQUASHFS_SWAP((s)->offset, d, 155, 13);\
3601     + SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
3602     + SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
3603     + SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
3604     +}
3605     +
3606     +#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\
3607     + SQUASHFS_SWAP_START\
3608     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\
3609     + SQUASHFS_SWAP((s)->index, d, 0, 32);\
3610     + SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
3611     + SQUASHFS_SWAP((s)->size, d, 64, 8);\
3612     +}
3613     +
3614     +#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
3615     + SQUASHFS_SWAP_START\
3616     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\
3617     + SQUASHFS_SWAP((s)->count, d, 0, 8);\
3618     + SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
3619     + SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
3620     +}
3621     +
3622     +#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
3623     + SQUASHFS_SWAP_START\
3624     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\
3625     + SQUASHFS_SWAP((s)->offset, d, 0, 13);\
3626     + SQUASHFS_SWAP((s)->type, d, 13, 3);\
3627     + SQUASHFS_SWAP((s)->size, d, 16, 8);\
3628     + SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
3629     +}
3630     +
3631     +#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\
3632     + SQUASHFS_SWAP_START\
3633     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\
3634     + SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
3635     + SQUASHFS_SWAP((s)->size, d, 64, 32);\
3636     +}
3637     +
3638     +#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1)
3639     +
3640     +#define SQUASHFS_SWAP_SHORTS(s, d, n) {\
3641     + int entry;\
3642     + int bit_position;\
3643     + SQUASHFS_SWAP_START\
3644     + SQUASHFS_MEMSET(s, d, n * 2);\
3645     + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
3646     + 16)\
3647     + SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
3648     +}
3649     +
3650     +#define SQUASHFS_SWAP_INTS(s, d, n) {\
3651     + int entry;\
3652     + int bit_position;\
3653     + SQUASHFS_SWAP_START\
3654     + SQUASHFS_MEMSET(s, d, n * 4);\
3655     + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
3656     + 32)\
3657     + SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
3658     +}
3659     +
3660     +#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\
3661     + int entry;\
3662     + int bit_position;\
3663     + SQUASHFS_SWAP_START\
3664     + SQUASHFS_MEMSET(s, d, n * 8);\
3665     + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
3666     + 64)\
3667     + SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
3668     +}
3669     +
3670     +#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
3671     + int entry;\
3672     + int bit_position;\
3673     + SQUASHFS_SWAP_START\
3674     + SQUASHFS_MEMSET(s, d, n * bits / 8);\
3675     + for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
3676     + bits)\
3677     + SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
3678     +}
3679     +
3680     +#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
3681     +#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
3682     +
3683     +#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
3684     +
3685     +struct squashfs_base_inode_header_1 {
3686     + unsigned int inode_type:4;
3687     + unsigned int mode:12; /* protection */
3688     + unsigned int uid:4; /* index into uid table */
3689     + unsigned int guid:4; /* index into guid table */
3690     +} __attribute__ ((packed));
3691     +
3692     +struct squashfs_ipc_inode_header_1 {
3693     + unsigned int inode_type:4;
3694     + unsigned int mode:12; /* protection */
3695     + unsigned int uid:4; /* index into uid table */
3696     + unsigned int guid:4; /* index into guid table */
3697     + unsigned int type:4;
3698     + unsigned int offset:4;
3699     +} __attribute__ ((packed));
3700     +
3701     +struct squashfs_dev_inode_header_1 {
3702     + unsigned int inode_type:4;
3703     + unsigned int mode:12; /* protection */
3704     + unsigned int uid:4; /* index into uid table */
3705     + unsigned int guid:4; /* index into guid table */
3706     + unsigned short rdev;
3707     +} __attribute__ ((packed));
3708     +
3709     +struct squashfs_symlink_inode_header_1 {
3710     + unsigned int inode_type:4;
3711     + unsigned int mode:12; /* protection */
3712     + unsigned int uid:4; /* index into uid table */
3713     + unsigned int guid:4; /* index into guid table */
3714     + unsigned short symlink_size;
3715     + char symlink[0];
3716     +} __attribute__ ((packed));
3717     +
3718     +struct squashfs_reg_inode_header_1 {
3719     + unsigned int inode_type:4;
3720     + unsigned int mode:12; /* protection */
3721     + unsigned int uid:4; /* index into uid table */
3722     + unsigned int guid:4; /* index into guid table */
3723     + unsigned int mtime;
3724     + unsigned int start_block;
3725     + unsigned int file_size:32;
3726     + unsigned short block_list[0];
3727     +} __attribute__ ((packed));
3728     +
3729     +struct squashfs_dir_inode_header_1 {
3730     + unsigned int inode_type:4;
3731     + unsigned int mode:12; /* protection */
3732     + unsigned int uid:4; /* index into uid table */
3733     + unsigned int guid:4; /* index into guid table */
3734     + unsigned int file_size:19;
3735     + unsigned int offset:13;
3736     + unsigned int mtime;
3737     + unsigned int start_block:24;
3738     +} __attribute__ ((packed));
3739     +
3740     +union squashfs_inode_header_1 {
3741     + struct squashfs_base_inode_header_1 base;
3742     + struct squashfs_dev_inode_header_1 dev;
3743     + struct squashfs_symlink_inode_header_1 symlink;
3744     + struct squashfs_reg_inode_header_1 reg;
3745     + struct squashfs_dir_inode_header_1 dir;
3746     + struct squashfs_ipc_inode_header_1 ipc;
3747     +};
3748     +
3749     +#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
3750     + SQUASHFS_MEMSET(s, d, n);\
3751     + SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
3752     + SQUASHFS_SWAP((s)->mode, d, 4, 12);\
3753     + SQUASHFS_SWAP((s)->uid, d, 16, 4);\
3754     + SQUASHFS_SWAP((s)->guid, d, 20, 4);
3755     +
3756     +#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
3757     + SQUASHFS_SWAP_START\
3758     + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
3759     +}
3760     +
3761     +#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
3762     + SQUASHFS_SWAP_START\
3763     + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
3764     + sizeof(struct squashfs_ipc_inode_header_1));\
3765     + SQUASHFS_SWAP((s)->type, d, 24, 4);\
3766     + SQUASHFS_SWAP((s)->offset, d, 28, 4);\
3767     +}
3768     +
3769     +#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
3770     + SQUASHFS_SWAP_START\
3771     + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
3772     + sizeof(struct squashfs_dev_inode_header_1));\
3773     + SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
3774     +}
3775     +
3776     +#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
3777     + SQUASHFS_SWAP_START\
3778     + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
3779     + sizeof(struct squashfs_symlink_inode_header_1));\
3780     + SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
3781     +}
3782     +
3783     +#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
3784     + SQUASHFS_SWAP_START\
3785     + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
3786     + sizeof(struct squashfs_reg_inode_header_1));\
3787     + SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
3788     + SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
3789     + SQUASHFS_SWAP((s)->file_size, d, 88, 32);\
3790     +}
3791     +
3792     +#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
3793     + SQUASHFS_SWAP_START\
3794     + SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
3795     + sizeof(struct squashfs_dir_inode_header_1));\
3796     + SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
3797     + SQUASHFS_SWAP((s)->offset, d, 43, 13);\
3798     + SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
3799     + SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
3800     +}
3801     +
3802     +#endif
3803     +
3804     +#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
3805     +
3806     +struct squashfs_dir_index_2 {
3807     + unsigned int index:27;
3808     + unsigned int start_block:29;
3809     + unsigned char size;
3810     + unsigned char name[0];
3811     +} __attribute__ ((packed));
3812     +
3813     +struct squashfs_base_inode_header_2 {
3814     + unsigned int inode_type:4;
3815     + unsigned int mode:12; /* protection */
3816     + unsigned int uid:8; /* index into uid table */
3817     + unsigned int guid:8; /* index into guid table */
3818     +} __attribute__ ((packed));
3819     +
3820     +struct squashfs_ipc_inode_header_2 {
3821     + unsigned int inode_type:4;
3822     + unsigned int mode:12; /* protection */
3823     + unsigned int uid:8; /* index into uid table */
3824     + unsigned int guid:8; /* index into guid table */
3825     +} __attribute__ ((packed));
3826     +
3827     +struct squashfs_dev_inode_header_2 {
3828     + unsigned int inode_type:4;
3829     + unsigned int mode:12; /* protection */
3830     + unsigned int uid:8; /* index into uid table */
3831     + unsigned int guid:8; /* index into guid table */
3832     + unsigned short rdev;
3833     +} __attribute__ ((packed));
3834     +
3835     +struct squashfs_symlink_inode_header_2 {
3836     + unsigned int inode_type:4;
3837     + unsigned int mode:12; /* protection */
3838     + unsigned int uid:8; /* index into uid table */
3839     + unsigned int guid:8; /* index into guid table */
3840     + unsigned short symlink_size;
3841     + char symlink[0];
3842     +} __attribute__ ((packed));
3843     +
3844     +struct squashfs_reg_inode_header_2 {
3845     + unsigned int inode_type:4;
3846     + unsigned int mode:12; /* protection */
3847     + unsigned int uid:8; /* index into uid table */
3848     + unsigned int guid:8; /* index into guid table */
3849     + unsigned int mtime;
3850     + unsigned int start_block;
3851     + unsigned int fragment;
3852     + unsigned int offset;
3853     + unsigned int file_size:32;
3854     + unsigned short block_list[0];
3855     +} __attribute__ ((packed));
3856     +
3857     +struct squashfs_dir_inode_header_2 {
3858     + unsigned int inode_type:4;
3859     + unsigned int mode:12; /* protection */
3860     + unsigned int uid:8; /* index into uid table */
3861     + unsigned int guid:8; /* index into guid table */
3862     + unsigned int file_size:19;
3863     + unsigned int offset:13;
3864     + unsigned int mtime;
3865     + unsigned int start_block:24;
3866     +} __attribute__ ((packed));
3867     +
3868     +struct squashfs_ldir_inode_header_2 {
3869     + unsigned int inode_type:4;
3870     + unsigned int mode:12; /* protection */
3871     + unsigned int uid:8; /* index into uid table */
3872     + unsigned int guid:8; /* index into guid table */
3873     + unsigned int file_size:27;
3874     + unsigned int offset:13;
3875     + unsigned int mtime;
3876     + unsigned int start_block:24;
3877     + unsigned int i_count:16;
3878     + struct squashfs_dir_index_2 index[0];
3879     +} __attribute__ ((packed));
3880     +
3881     +union squashfs_inode_header_2 {
3882     + struct squashfs_base_inode_header_2 base;
3883     + struct squashfs_dev_inode_header_2 dev;
3884     + struct squashfs_symlink_inode_header_2 symlink;
3885     + struct squashfs_reg_inode_header_2 reg;
3886     + struct squashfs_dir_inode_header_2 dir;
3887     + struct squashfs_ldir_inode_header_2 ldir;
3888     + struct squashfs_ipc_inode_header_2 ipc;
3889     +};
3890     +
3891     +struct squashfs_dir_header_2 {
3892     + unsigned int count:8;
3893     + unsigned int start_block:24;
3894     +} __attribute__ ((packed));
3895     +
3896     +struct squashfs_dir_entry_2 {
3897     + unsigned int offset:13;
3898     + unsigned int type:3;
3899     + unsigned int size:8;
3900     + char name[0];
3901     +} __attribute__ ((packed));
3902     +
3903     +struct squashfs_fragment_entry_2 {
3904     + unsigned int start_block;
3905     + unsigned int size;
3906     +} __attribute__ ((packed));
3907     +
3908     +#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
3909     + SQUASHFS_MEMSET(s, d, n);\
3910     + SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
3911     + SQUASHFS_SWAP((s)->mode, d, 4, 12);\
3912     + SQUASHFS_SWAP((s)->uid, d, 16, 8);\
3913     + SQUASHFS_SWAP((s)->guid, d, 24, 8);\
3914     +
3915     +#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
3916     + SQUASHFS_SWAP_START\
3917     + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
3918     +}
3919     +
3920     +#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
3921     + SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
3922     +
3923     +#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
3924     + SQUASHFS_SWAP_START\
3925     + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
3926     + sizeof(struct squashfs_dev_inode_header_2)); \
3927     + SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
3928     +}
3929     +
3930     +#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
3931     + SQUASHFS_SWAP_START\
3932     + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
3933     + sizeof(struct squashfs_symlink_inode_header_2));\
3934     + SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
3935     +}
3936     +
3937     +#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
3938     + SQUASHFS_SWAP_START\
3939     + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
3940     + sizeof(struct squashfs_reg_inode_header_2));\
3941     + SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
3942     + SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
3943     + SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
3944     + SQUASHFS_SWAP((s)->offset, d, 128, 32);\
3945     + SQUASHFS_SWAP((s)->file_size, d, 160, 32);\
3946     +}
3947     +
3948     +#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
3949     + SQUASHFS_SWAP_START\
3950     + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
3951     + sizeof(struct squashfs_dir_inode_header_2));\
3952     + SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
3953     + SQUASHFS_SWAP((s)->offset, d, 51, 13);\
3954     + SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
3955     + SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
3956     +}
3957     +
3958     +#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
3959     + SQUASHFS_SWAP_START\
3960     + SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
3961     + sizeof(struct squashfs_ldir_inode_header_2));\
3962     + SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
3963     + SQUASHFS_SWAP((s)->offset, d, 59, 13);\
3964     + SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
3965     + SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
3966     + SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
3967     +}
3968     +
3969     +#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
3970     + SQUASHFS_SWAP_START\
3971     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
3972     + SQUASHFS_SWAP((s)->index, d, 0, 27);\
3973     + SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
3974     + SQUASHFS_SWAP((s)->size, d, 56, 8);\
3975     +}
3976     +#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
3977     + SQUASHFS_SWAP_START\
3978     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
3979     + SQUASHFS_SWAP((s)->count, d, 0, 8);\
3980     + SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
3981     +}
3982     +
3983     +#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
3984     + SQUASHFS_SWAP_START\
3985     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
3986     + SQUASHFS_SWAP((s)->offset, d, 0, 13);\
3987     + SQUASHFS_SWAP((s)->type, d, 13, 3);\
3988     + SQUASHFS_SWAP((s)->size, d, 16, 8);\
3989     +}
3990     +
3991     +#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
3992     + SQUASHFS_SWAP_START\
3993     + SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
3994     + SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
3995     + SQUASHFS_SWAP((s)->size, d, 32, 32);\
3996     +}
3997     +
3998     +#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n)
3999     +
4000     +/* fragment and fragment table defines */
4001     +#define SQUASHFS_FRAGMENT_BYTES_2(A) (A * sizeof(struct squashfs_fragment_entry_2))
4002     +
4003     +#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \
4004     + SQUASHFS_METADATA_SIZE)
4005     +
4006     +#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \
4007     + SQUASHFS_METADATA_SIZE)
4008     +
4009     +#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \
4010     + SQUASHFS_METADATA_SIZE - 1) / \
4011     + SQUASHFS_METADATA_SIZE)
4012     +
4013     +#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\
4014     + sizeof(int))
4015     +
4016     +#endif
4017     +
4018     +#ifdef __KERNEL__
4019     +
4020     +/*
4021     + * macros used to swap each structure entry, taking into account
4022     + * bitfields and different bitfield placing conventions on differing
4023     + * architectures
4024     + */
4025     +
4026     +#include <asm/byteorder.h>
4027     +
4028     +#ifdef __BIG_ENDIAN
4029     + /* convert from little endian to big endian */
4030     +#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
4031     + tbits, b_pos)
4032     +#else
4033     + /* convert from big endian to little endian */
4034     +#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
4035     + tbits, 64 - tbits - b_pos)
4036     +#endif
4037     +
4038     +#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
4039     + b_pos = pos % 8;\
4040     + val = 0;\
4041     + s = (unsigned char *)p + (pos / 8);\
4042     + d = ((unsigned char *) &val) + 7;\
4043     + for(bits = 0; bits < (tbits + b_pos); bits += 8) \
4044     + *d-- = *s++;\
4045     + value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
4046     +}
4047     +
4048     +#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n);
4049     +
4050     +#endif
4051     +#endif
4052     diff -x .gitignore -Nurp linux-2.6.24/include/linux/squashfs_fs_i.h linux-2.6.24-squashfs3.3/include/linux/squashfs_fs_i.h
4053     --- linux-2.6.24/include/linux/squashfs_fs_i.h 1970-01-01 01:00:00.000000000 +0100
4054     +++ linux-2.6.24-squashfs3.3/include/linux/squashfs_fs_i.h 2007-08-19 04:24:08.000000000 +0100
4055     @@ -0,0 +1,45 @@
4056     +#ifndef SQUASHFS_FS_I
4057     +#define SQUASHFS_FS_I
4058     +/*
4059     + * Squashfs
4060     + *
4061     + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
4062     + * Phillip Lougher <phillip@lougher.demon.co.uk>
4063     + *
4064     + * This program is free software; you can redistribute it and/or
4065     + * modify it under the terms of the GNU General Public License
4066     + * as published by the Free Software Foundation; either version 2,
4067     + * or (at your option) any later version.
4068     + *
4069     + * This program is distributed in the hope that it will be useful,
4070     + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4071     + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4072     + * GNU General Public License for more details.
4073     + *
4074     + * You should have received a copy of the GNU General Public License
4075     + * along with this program; if not, write to the Free Software
4076     + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4077     + *
4078     + * squashfs_fs_i.h
4079     + */
4080     +
4081     +struct squashfs_inode_info {
4082     + long long start_block;
4083     + unsigned int offset;
4084     + union {
4085     + struct {
4086     + long long fragment_start_block;
4087     + unsigned int fragment_size;
4088     + unsigned int fragment_offset;
4089     + long long block_list_start;
4090     + } s1;
4091     + struct {
4092     + long long directory_index_start;
4093     + unsigned int directory_index_offset;
4094     + unsigned int directory_index_count;
4095     + unsigned int parent_inode;
4096     + } s2;
4097     + } u;
4098     + struct inode vfs_inode;
4099     +};
4100     +#endif
4101     diff -x .gitignore -Nurp linux-2.6.24/include/linux/squashfs_fs_sb.h linux-2.6.24-squashfs3.3/include/linux/squashfs_fs_sb.h
4102     --- linux-2.6.24/include/linux/squashfs_fs_sb.h 1970-01-01 01:00:00.000000000 +0100
4103     +++ linux-2.6.24-squashfs3.3/include/linux/squashfs_fs_sb.h 2007-08-19 04:24:26.000000000 +0100
4104     @@ -0,0 +1,76 @@
4105     +#ifndef SQUASHFS_FS_SB
4106     +#define SQUASHFS_FS_SB
4107     +/*
4108     + * Squashfs
4109     + *
4110     + * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
4111     + * Phillip Lougher <phillip@lougher.demon.co.uk>
4112     + *
4113     + * This program is free software; you can redistribute it and/or
4114     + * modify it under the terms of the GNU General Public License
4115     + * as published by the Free Software Foundation; either version 2,
4116     + * or (at your option) any later version.
4117     + *
4118     + * This program is distributed in the hope that it will be useful,
4119     + * but WITHOUT ANY WARRANTY; without even the implied warranty of
4120     + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4121     + * GNU General Public License for more details.
4122     + *
4123     + * You should have received a copy of the GNU General Public License
4124     + * along with this program; if not, write to the Free Software
4125     + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4126     + *
4127     + * squashfs_fs_sb.h
4128     + */
4129     +
4130     +#include <linux/squashfs_fs.h>
4131     +
4132     +struct squashfs_cache {
4133     + long long block;
4134     + int length;
4135     + long long next_index;
4136     + char *data;
4137     +};
4138     +
4139     +struct squashfs_fragment_cache {
4140     + long long block;
4141     + int length;
4142     + unsigned int locked;
4143     + char *data;
4144     +};
4145     +
4146     +struct squashfs_sb_info {
4147     + struct squashfs_super_block sblk;
4148     + int devblksize;
4149     + int devblksize_log2;
4150     + int swap;
4151     + struct squashfs_cache *block_cache;
4152     + struct squashfs_fragment_cache *fragment;
4153     + int next_cache;
4154     + int next_fragment;
4155     + int next_meta_index;
4156     + unsigned int *uid;
4157     + unsigned int *guid;
4158     + long long *fragment_index;
4159     + unsigned int *fragment_index_2;
4160     + char *read_page;
4161     + struct mutex read_data_mutex;
4162     + struct mutex read_page_mutex;
4163     + struct mutex block_cache_mutex;
4164     + struct mutex fragment_mutex;
4165     + struct mutex meta_index_mutex;
4166     + wait_queue_head_t waitq;
4167     + wait_queue_head_t fragment_wait_queue;
4168     + struct meta_index *meta_index;
4169     + z_stream stream;
4170     + long long *inode_lookup_table;
4171     + int unused_cache_blks;
4172     + int unused_frag_blks;
4173     + int (*read_inode)(struct inode *i, squashfs_inode_t \
4174     + inode);
4175     + long long (*read_blocklist)(struct inode *inode, int \
4176     + index, int readahead_blks, char *block_list, \
4177     + unsigned short **block_p, unsigned int *bsize);
4178     + int (*read_fragment_index_table)(struct super_block *s);
4179     +};
4180     +#endif
4181     diff -x .gitignore -Nurp linux-2.6.24/init/do_mounts_rd.c linux-2.6.24-squashfs3.3/init/do_mounts_rd.c
4182     --- linux-2.6.24/init/do_mounts_rd.c 2007-10-25 17:41:49.000000000 +0100
4183     +++ linux-2.6.24-squashfs3.3/init/do_mounts_rd.c 2007-11-01 05:06:25.000000000 +0000
4184     @@ -5,6 +5,7 @@
4185     #include <linux/ext2_fs.h>
4186     #include <linux/romfs_fs.h>
4187     #include <linux/cramfs_fs.h>
4188     +#include <linux/squashfs_fs.h>
4189     #include <linux/initrd.h>
4190     #include <linux/string.h>
4191    
4192     @@ -39,6 +40,7 @@ static int __init crd_load(int in_fd, in
4193     * numbers could not be found.
4194     *
4195     * We currently check for the following magic numbers:
4196     + * squashfs
4197     * minix
4198     * ext2
4199     * romfs
4200     @@ -53,6 +55,7 @@ identify_ramdisk_image(int fd, int start
4201     struct ext2_super_block *ext2sb;
4202     struct romfs_super_block *romfsb;
4203     struct cramfs_super *cramfsb;
4204     + struct squashfs_super_block *squashfsb;
4205     int nblocks = -1;
4206     unsigned char *buf;
4207    
4208     @@ -64,6 +67,7 @@ identify_ramdisk_image(int fd, int start
4209     ext2sb = (struct ext2_super_block *) buf;
4210     romfsb = (struct romfs_super_block *) buf;
4211     cramfsb = (struct cramfs_super *) buf;
4212     + squashfsb = (struct squashfs_super_block *) buf;
4213     memset(buf, 0xe5, size);
4214    
4215     /*
4216     @@ -101,6 +105,18 @@ identify_ramdisk_image(int fd, int start
4217     goto done;
4218     }
4219    
4220     + /* squashfs is at block zero too */
4221     + if (squashfsb->s_magic == SQUASHFS_MAGIC) {
4222     + printk(KERN_NOTICE
4223     + "RAMDISK: squashfs filesystem found at block %d\n",
4224     + start_block);
4225     + if (squashfsb->s_major < 3)
4226     + nblocks = (squashfsb->bytes_used_2+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
4227     + else
4228     + nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
4229     + goto done;
4230     + }
4231     +
4232     /*
4233     * Read block 1 to test for minix and ext2 superblock
4234     */