Magellan Linux

Annotation of /trunk/kernel26-alx/patches-2.6.27-r3/0152-2.6.27-squashfs-3.4.patch

Parent Directory Parent Directory | Revision Log Revision Log


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