Magellan Linux

Annotation of /trunk/kernel26-magellan/patches-2.6.25-r4/0152-2.6.25-squashfs-3.3-2.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 664 - (hide annotations) (download)
Thu Jul 10 13:03:47 2008 UTC (15 years, 10 months ago) by niro
File size: 127993 byte(s)
-2.6.25-magellan-r4; updated to linux-2.6.25.10

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