Magellan Linux

Annotation of /trunk/kernel26-alx/patches-2.6.28-r2/0152-2.6.28-squashfs-3.4-2.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 874 - (hide annotations) (download)
Mon Aug 3 21:00:35 2009 UTC (14 years, 9 months ago) by niro
File size: 126972 byte(s)
-2.6.28-alx-r2: disabled config_sysfs_deprecated{,_v2}

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