Notice: the grml team is migrating from Mercurial to Git.
Please visit git.grml.org instead!
| author | mika@grmlvrs |
| Sun Mar 09 00:35:19 2008 +0000 (8 months ago) | |
| changeset 112 | 08d47dec6bb4 |
| manifest | 08d47dec6bb4 |
| parent 109 | 9346c2aaa908 |
| child 113 | d86d4fb87702 |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000+++ b/2.6.25/4000_ipw2200-1.1.4-inject.patch Sun Mar 09 00:35:19 2008 +0000@@ -0,0 +1,90 @@+From 805fa07d7f45a5634d311d0b3d8c0c071c8cfbf2 Mon Sep 17 00:00:00 2001+From: Michael Prokop <mika@grml.org>+Date: Sat, 8 Mar 2008 15:27:58 +0000+Subject: [PATCH 2/4] Apply 4000_ipw2200-1.1.4-inject.patch+++Signed-off-by: Michael Prokop <mika@grml.org>++diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c+index a56d9fc..4b43fc8 100644+--- a/drivers/net/wireless/ipw2200.c++++ b/drivers/net/wireless/ipw2200.c+@@ -1906,6 +1906,66 @@ static ssize_t show_channels(struct device *d,++ static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);+++static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, int pri);++++/* SYSFS INJECT */++static ssize_t store_inject(struct device *d,++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12)++ struct device_attribute *attr,++#endif++ const char *buf, size_t count)++{++ struct ipw_priv *priv = (struct ipw_priv *)d->driver_data;++ struct ieee80211_device *ieee = priv->ieee;++ struct ieee80211_txb * txb;++ struct sk_buff *skb_frag;++ unsigned char * newbuf;++ unsigned long flags;++++ // should test (ieee->is_queue_full)++++ // Fw only accepts data, so avoid accidental fw errors.++ if ( (buf[0]&0x0c) != '\x08') {++ //printk("ipw2200: inject: discarding non-data frame (type=%02X)\n",(int)(unsigned char)buf[0]);++ return count;++ }++++ if (count>1500) {++ count=1500;++ printk("ipw2200: inject: cutting down frame to 1500 bytes\n");++ }++++ spin_lock_irqsave(&priv->lock, flags);++++ // Create a txb with one skb++ txb = kmalloc(sizeof(struct ieee80211_txb) + sizeof(u8 *), GFP_ATOMIC);++ if (!txb)++ goto nosepuede;++ txb->nr_frags=1;++ txb->frag_size = ieee->tx_headroom;++ txb->fragments[0]=__dev_alloc_skb(count + ieee->tx_headroom, GFP_ATOMIC);++ if (!txb->fragments[0]) {++ kfree(txb);++ goto nosepuede;++ }++ skb_reserve(txb->fragments[0], ieee->tx_headroom);++ txb->encrypted=0;++ txb->payload_size=count;++ skb_frag = txb->fragments[0];++ newbuf=skb_put(skb_frag, count);++++ // copy data into txb->skb and send it++ memcpy(newbuf, buf, count);++++ ipw_tx_skb(priv, txb, 0);++++nosepuede:++ spin_unlock_irqrestore(&priv->lock, flags);++ return count;++}++++static DEVICE_ATTR(inject, S_IWUSR, NULL, store_inject);+++ static void notify_wx_assoc_event(struct ipw_priv *priv)+ {+ union iwreq_data wrqu;+@@ -11497,6 +11557,7 @@ static struct attribute *ipw_sysfs_entries[] = {+ #ifdef CONFIG_IPW2200_PROMISCUOUS+ &dev_attr_rtap_iface.attr,+ &dev_attr_rtap_filter.attr,++ &dev_attr_inject.attr,+ #endif+ NULL+ };+--+1.5.4.3+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000+++ b/2.6.25/4300_squashfs-3.3-for-2.6.25.patch Sun Mar 09 00:35:19 2008 +0000@@ -0,0 +1,4229 @@+From d1eb4b6c0a6eab1cf2df15581f6a372908693ce7 Mon Sep 17 00:00:00 2001+From: Michael Prokop <mika@grmlvrs.(none)>+Date: Sat, 8 Mar 2008 15:21:14 +0000+Subject: [PATCH 1/4] SquashFS for 2.6.25-rc4++Apply patch from+http://sourceforge.net/mailarchive/forum.php?thread_name=47C5A849.1020309%40intellitree.com&forum_name=squashfs-devel++Signed-off-by: Michael Prokop <mika@grml.org>++diff --git a/fs/Kconfig b/fs/Kconfig+index d731282..cab44a1 100644+--- a/fs/Kconfig++++ b/fs/Kconfig+@@ -1367,6 +1367,56 @@ config CRAMFS++ If unsure, say N.+++config SQUASHFS++ tristate "SquashFS 3.3 - Squashed file system support"++ select ZLIB_INFLATE++ help++ Saying Y here includes support for SquashFS 3.3 (a Compressed++ Read-Only File System). Squashfs is a highly compressed read-only++ filesystem for Linux. It uses zlib compression to compress both++ files, inodes and directories. Inodes in the system are very small++ and all blocks are packed to minimise data overhead. Block sizes++ greater than 4K are supported up to a maximum of 1 Mbytes (default++ block size 128K). SquashFS 3.3 supports 64 bit filesystems and files++ (larger than 4GB), full uid/gid information, hard links and timestamps.++++ Squashfs is intended for general read-only filesystem use, for++ archival use (i.e. in cases where a .tar.gz file may be used), and in++ embedded systems where low overhead is needed. Further information++ and filesystem tools are available from http://squashfs.sourceforge.net.++++ If you want to compile this as a module ( = code which can be++ inserted in and removed from the running kernel whenever you want),++ say M here and read <file:Documentation/modules.txt>. The module++ will be called squashfs. Note that the root file system (the one++ containing the directory /) cannot be compiled as a module.++++ If unsure, say N.++++config SQUASHFS_EMBEDDED++++ bool "Additional option for memory-constrained systems"++ depends on SQUASHFS++ default n++ help++ Saying Y here allows you to specify cache size.++++ If unsure, say N.++++config SQUASHFS_FRAGMENT_CACHE_SIZE++ int "Number of fragments cached" if SQUASHFS_EMBEDDED++ depends on SQUASHFS++ default "3"++ help++ By default SquashFS caches the last 3 fragments read from++ the filesystem. Increasing this amount may mean SquashFS++ has to re-read fragments less often from disk, at the expense++ of extra system memory. Decreasing this amount will mean++ SquashFS uses less memory at the expense of extra reads from disk.++++ Note there must be at least one cached fragment. Anything++ much more than three will probably not make much difference.+++ config VXFS_FS+ tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"+ depends on BLOCK+diff --git a/fs/Makefile b/fs/Makefile+index 1e7a11b..3faf857 100644+--- a/fs/Makefile++++ b/fs/Makefile+@@ -73,6 +73,7 @@ obj-$(CONFIG_JBD) += jbd/+ obj-$(CONFIG_JBD2) += jbd2/+ obj-$(CONFIG_EXT2_FS) += ext2/+ obj-$(CONFIG_CRAMFS) += cramfs/++obj-$(CONFIG_SQUASHFS) += squashfs/+ obj-y += ramfs/+ obj-$(CONFIG_HUGETLBFS) += hugetlbfs/+ obj-$(CONFIG_CODA_FS) += coda/+diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile+new file mode 100644+index 0000000..1bc7b06+--- /dev/null++++ b/fs/squashfs/Makefile+@@ -0,0 +1,7 @@++#++# Makefile for the linux squashfs routines.++#++++obj-$(CONFIG_SQUASHFS) += squashfs.o++squashfs-y += inode.o++squashfs-y += squashfs2_0.o+diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c+new file mode 100644+index 0000000..463539a+--- /dev/null++++ b/fs/squashfs/inode.c+@@ -0,0 +1,2157 @@++/*++ * Squashfs - a compressed read only filesystem for Linux++ *++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007++ * Phillip Lougher <phillip@lougher.demon.co.uk>++ *++ * This program is free software; you can redistribute it and/or++ * modify it under the terms of the GNU General Public License++ * as published by the Free Software Foundation; either version 2,++ * or (at your option) any later version.++ *++ * This program is distributed in the hope that it will be useful,++ * but WITHOUT ANY WARRANTY; without even the implied warranty of++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the++ * GNU General Public License for more details.++ *++ * You should have received a copy of the GNU General Public License++ * along with this program; if not, write to the Free Software++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.++ *++ * inode.c++ */++++#include <linux/squashfs_fs.h>++#include <linux/module.h>++#include <linux/zlib.h>++#include <linux/fs.h>++#include <linux/squashfs_fs_sb.h>++#include <linux/squashfs_fs_i.h>++#include <linux/buffer_head.h>++#include <linux/exportfs.h>++#include <linux/vfs.h>++#include <linux/vmalloc.h>++#include <linux/smp_lock.h>++#include <linux/exportfs.h>++++#include "squashfs.h"++++int squashfs_cached_blks;++++static struct dentry *squashfs_get_parent(struct dentry *child);++static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode);++static int squashfs_statfs(struct dentry *, struct kstatfs *);++static int squashfs_symlink_readpage(struct file *file, struct page *page);++static long long read_blocklist(struct inode *inode, int index,++ int readahead_blks, char *block_list,++ unsigned short **block_p, unsigned int *bsize);++static int squashfs_readpage(struct file *file, struct page *page);++static int squashfs_readdir(struct file *, void *, filldir_t);++static struct dentry *squashfs_lookup(struct inode *, struct dentry *,++ struct nameidata *);++static int squashfs_remount(struct super_block *s, int *flags, char *data);++static void squashfs_put_super(struct super_block *);++static int squashfs_get_sb(struct file_system_type *,int, const char *, void *,++ struct vfsmount *);++static struct inode *squashfs_alloc_inode(struct super_block *sb);++static void squashfs_destroy_inode(struct inode *inode);++static int init_inodecache(void);++static void destroy_inodecache(void);++++static struct file_system_type squashfs_fs_type = {++ .owner = THIS_MODULE,++ .name = "squashfs",++ .get_sb = squashfs_get_sb,++ .kill_sb = kill_block_super,++ .fs_flags = FS_REQUIRES_DEV++};++++static const unsigned char squashfs_filetype_table[] = {++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK++};++++static struct super_operations squashfs_super_ops = {++ .alloc_inode = squashfs_alloc_inode,++ .destroy_inode = squashfs_destroy_inode,++ .statfs = squashfs_statfs,++ .put_super = squashfs_put_super,++ .remount_fs = squashfs_remount++};++++static struct super_operations squashfs_export_super_ops = {++ .alloc_inode = squashfs_alloc_inode,++ .destroy_inode = squashfs_destroy_inode,++ .statfs = squashfs_statfs,++ .put_super = squashfs_put_super,++};++++static struct export_operations squashfs_export_ops = {++ .get_parent = squashfs_get_parent++};++++SQSH_EXTERN const struct address_space_operations squashfs_symlink_aops = {++ .readpage = squashfs_symlink_readpage++};++++SQSH_EXTERN const struct address_space_operations squashfs_aops = {++ .readpage = squashfs_readpage++};++++static const struct file_operations squashfs_dir_ops = {++ .read = generic_read_dir,++ .readdir = squashfs_readdir++};++++SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = {++ .lookup = squashfs_lookup++};++++++static struct buffer_head *get_block_length(struct super_block *s,++ int *cur_index, int *offset, int *c_byte)++{++ struct squashfs_sb_info *msblk = s->s_fs_info;++ unsigned short temp;++ struct buffer_head *bh;++++ if (!(bh = sb_bread(s, *cur_index)))++ goto out;++++ if (msblk->devblksize - *offset == 1) {++ if (msblk->swap)++ ((unsigned char *) &temp)[1] = *((unsigned char *)++ (bh->b_data + *offset));++ else++ ((unsigned char *) &temp)[0] = *((unsigned char *)++ (bh->b_data + *offset));++ brelse(bh);++ if (!(bh = sb_bread(s, ++(*cur_index))))++ goto out;++ if (msblk->swap)++ ((unsigned char *) &temp)[0] = *((unsigned char *)++ bh->b_data);++ else++ ((unsigned char *) &temp)[1] = *((unsigned char *)++ bh->b_data);++ *c_byte = temp;++ *offset = 1;++ } else {++ if (msblk->swap) {++ ((unsigned char *) &temp)[1] = *((unsigned char *)++ (bh->b_data + *offset));++ ((unsigned char *) &temp)[0] = *((unsigned char *)++ (bh->b_data + *offset + 1));++ } else {++ ((unsigned char *) &temp)[0] = *((unsigned char *)++ (bh->b_data + *offset));++ ((unsigned char *) &temp)[1] = *((unsigned char *)++ (bh->b_data + *offset + 1));++ }++ *c_byte = temp;++ *offset += 2;++ }++++ if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) {++ if (*offset == msblk->devblksize) {++ brelse(bh);++ if (!(bh = sb_bread(s, ++(*cur_index))))++ goto out;++ *offset = 0;++ }++ if (*((unsigned char *) (bh->b_data + *offset)) !=++ SQUASHFS_MARKER_BYTE) {++ ERROR("Metadata block marker corrupt @ %x\n",++ *cur_index);++ brelse(bh);++ goto out;++ }++ (*offset)++;++ }++ return bh;++++out:++ return NULL;++}++++++SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,++ long long index, unsigned int length,++ long long *next_index, int srclength)++{++ struct squashfs_sb_info *msblk = s->s_fs_info;++ struct squashfs_super_block *sblk = &msblk->sblk;++ struct buffer_head **bh;++ unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);++ unsigned int cur_index = index >> msblk->devblksize_log2;++ int bytes, avail_bytes, b = 0, k = 0;++ unsigned int compressed;++ unsigned int c_byte = length;++++ bh = kmalloc(((sblk->block_size >> msblk->devblksize_log2) + 1) *++ sizeof(struct buffer_head *), GFP_KERNEL);++ if (bh == NULL)++ goto read_failure;++++ if (c_byte) {++ bytes = msblk->devblksize - offset;++ compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);++ c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);++++ TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index,++ compressed ? "" : "un", (unsigned int) c_byte, srclength);++++ if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used)++ goto read_failure;++++ bh[0] = sb_getblk(s, cur_index);++ if (bh[0] == NULL)++ goto block_release;++++ for (b = 1; bytes < c_byte; b++) {++ bh[b] = sb_getblk(s, ++cur_index);++ if (bh[b] == NULL)++ goto block_release;++ bytes += msblk->devblksize;++ }++ ll_rw_block(READ, b, bh);++ } else {++ if (index < 0 || (index + 2) > sblk->bytes_used)++ goto read_failure;++++ bh[0] = get_block_length(s, &cur_index, &offset, &c_byte);++ if (bh[0] == NULL)++ goto read_failure;++++ bytes = msblk->devblksize - offset;++ compressed = SQUASHFS_COMPRESSED(c_byte);++ c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);++++ TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed++ ? "" : "un", (unsigned int) c_byte);++++ if (c_byte > srclength || (index + c_byte) > sblk->bytes_used)++ goto read_failure;++++ for (b = 1; bytes < c_byte; b++) {++ bh[b] = sb_getblk(s, ++cur_index);++ if (bh[b] == NULL)++ goto block_release;++ bytes += msblk->devblksize;++ }++ ll_rw_block(READ, b - 1, bh + 1);++ }++++ if (compressed) {++ int zlib_err = 0;++++ /*++ * uncompress block++ */++++ mutex_lock(&msblk->read_data_mutex);++++ msblk->stream.next_out = buffer;++ msblk->stream.avail_out = srclength;++++ for (bytes = 0; k < b; k++) {++ avail_bytes = min(c_byte - bytes, msblk->devblksize - offset);++++ wait_on_buffer(bh[k]);++ if (!buffer_uptodate(bh[k]))++ goto release_mutex;++++ msblk->stream.next_in = bh[k]->b_data + offset;++ msblk->stream.avail_in = avail_bytes;++++ if (k == 0) {++ zlib_err = zlib_inflateInit(&msblk->stream);++ if (zlib_err != Z_OK) {++ ERROR("zlib_inflateInit returned unexpected result 0x%x,"++ " srclength %d\n", zlib_err, srclength);++ goto release_mutex;++ }++++ if (avail_bytes == 0) {++ offset = 0;++ brelse(bh[k]);++ continue;++ }++ }++++ zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH);++ if (zlib_err != Z_OK && zlib_err != Z_STREAM_END) {++ ERROR("zlib_inflate returned unexpected result 0x%x,"++ " srclength %d, avail_in %d, avail_out %d\n", zlib_err,++ srclength, msblk->stream.avail_in, msblk->stream.avail_out);++ goto release_mutex;++ }++++ bytes += avail_bytes;++ offset = 0;++ brelse(bh[k]);++ }++++ if (zlib_err != Z_STREAM_END)++ goto release_mutex;++++ zlib_err = zlib_inflateEnd(&msblk->stream);++ if (zlib_err != Z_OK) {++ ERROR("zlib_inflateEnd returned unexpected result 0x%x,"++ " srclength %d\n", zlib_err, srclength);++ goto release_mutex;++ }++ bytes = msblk->stream.total_out;++ mutex_unlock(&msblk->read_data_mutex);++ } else {++ int i;++++ for(i = 0; i < b; i++) {++ wait_on_buffer(bh[i]);++ if (!buffer_uptodate(bh[i]))++ goto block_release;++ }++++ for (bytes = 0; k < b; k++) {++ avail_bytes = min(c_byte - bytes, msblk->devblksize - offset);++++ memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes);++ bytes += avail_bytes;++ offset = 0;++ brelse(bh[k]);++ }++ }++++ if (next_index)++ *next_index = index + c_byte + (length ? 0 :++ (SQUASHFS_CHECK_DATA(msblk->sblk.flags) ? 3 : 2));++++ kfree(bh);++ return bytes;++++release_mutex:++ mutex_unlock(&msblk->read_data_mutex);++++block_release:++ for (; k < b; k++)++ brelse(bh[k]);++++read_failure:++ ERROR("sb_bread failed reading block 0x%x\n", cur_index);++ kfree(bh);++ return 0;++}++++++SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, void *buffer,++ long long block, unsigned int offset,++ int length, long long *next_block,++ unsigned int *next_offset)++{++ struct squashfs_sb_info *msblk = s->s_fs_info;++ int n, i, bytes, return_length = length;++ long long next_index;++++ TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);++++ while (1) {++ for (i = 0; i < squashfs_cached_blks; i++)++ if (msblk->block_cache[i].block == block)++ break;++++ mutex_lock(&msblk->block_cache_mutex);++++ if (i == squashfs_cached_blks) {++ /* read inode header block */++ if (msblk->unused_cache_blks == 0) {++ mutex_unlock(&msblk->block_cache_mutex);++ wait_event(msblk->waitq, msblk->unused_cache_blks);++ continue;++ }++++ i = msblk->next_cache;++ for (n = 0; n < squashfs_cached_blks; n++) {++ if (msblk->block_cache[i].block != SQUASHFS_USED_BLK)++ break;++ i = (i + 1) % squashfs_cached_blks;++ }++++ msblk->next_cache = (i + 1) % squashfs_cached_blks;++++ if (msblk->block_cache[i].block == SQUASHFS_INVALID_BLK) {++ msblk->block_cache[i].data = vmalloc(SQUASHFS_METADATA_SIZE);++ if (msblk->block_cache[i].data == NULL) {++ ERROR("Failed to allocate cache block\n");++ mutex_unlock(&msblk->block_cache_mutex);++ goto out;++ }++ }++++ msblk->block_cache[i].block = SQUASHFS_USED_BLK;++ msblk->unused_cache_blks --;++ mutex_unlock(&msblk->block_cache_mutex);++++ msblk->block_cache[i].length = squashfs_read_data(s,++ msblk->block_cache[i].data, block, 0, &next_index,++ SQUASHFS_METADATA_SIZE);++++ if (msblk->block_cache[i].length == 0) {++ ERROR("Unable to read cache block [%llx:%x]\n", block, offset);++ mutex_lock(&msblk->block_cache_mutex);++ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;++ msblk->unused_cache_blks ++;++ smp_mb();++ vfree(msblk->block_cache[i].data);++ wake_up(&msblk->waitq);++ mutex_unlock(&msblk->block_cache_mutex);++ goto out;++ }++++ mutex_lock(&msblk->block_cache_mutex);++ msblk->block_cache[i].block = block;++ msblk->block_cache[i].next_index = next_index;++ msblk->unused_cache_blks ++;++ smp_mb();++ wake_up(&msblk->waitq);++ TRACE("Read cache block [%llx:%x]\n", block, offset);++ }++++ if (msblk->block_cache[i].block != block) {++ mutex_unlock(&msblk->block_cache_mutex);++ continue;++ }++++ bytes = msblk->block_cache[i].length - offset;++++ if (bytes < 1) {++ mutex_unlock(&msblk->block_cache_mutex);++ goto out;++ } else if (bytes >= length) {++ if (buffer)++ memcpy(buffer, msblk->block_cache[i].data + offset, length);++ if (msblk->block_cache[i].length - offset == length) {++ *next_block = msblk->block_cache[i].next_index;++ *next_offset = 0;++ } else {++ *next_block = block;++ *next_offset = offset + length;++ }++ mutex_unlock(&msblk->block_cache_mutex);++ goto finish;++ } else {++ if (buffer) {++ memcpy(buffer, msblk->block_cache[i].data + offset, bytes);++ buffer = (char *) buffer + bytes;++ }++ block = msblk->block_cache[i].next_index;++ mutex_unlock(&msblk->block_cache_mutex);++ length -= bytes;++ offset = 0;++ }++ }++++finish:++ return return_length;++out:++ return 0;++}++++++static int get_fragment_location(struct super_block *s, unsigned int fragment,++ long long *fragment_start_block,++ unsigned int *fragment_size)++{++ struct squashfs_sb_info *msblk = s->s_fs_info;++ long long start_block =++ msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);++ struct squashfs_fragment_entry fragment_entry;++++ if (msblk->swap) {++ struct squashfs_fragment_entry sfragment_entry;++++ if (!squashfs_get_cached_block(s, &sfragment_entry, start_block, offset,++ sizeof(sfragment_entry), &start_block, &offset))++ goto out;++ SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);++ } else++ if (!squashfs_get_cached_block(s, &fragment_entry, start_block, offset,++ sizeof(fragment_entry), &start_block, &offset))++ goto out;++++ *fragment_start_block = fragment_entry.start_block;++ *fragment_size = fragment_entry.size;++++ return 1;++++out:++ return 0;++}++++++SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk,++ struct squashfs_fragment_cache *fragment)++{++ mutex_lock(&msblk->fragment_mutex);++ fragment->locked --;++ if (fragment->locked == 0) {++ msblk->unused_frag_blks ++;++ smp_mb();++ wake_up(&msblk->fragment_wait_queue);++ }++ mutex_unlock(&msblk->fragment_mutex);++}++++++SQSH_EXTERN++struct squashfs_fragment_cache *get_cached_fragment(struct super_block *s,++ long long start_block, int length)++{++ int i, n;++ struct squashfs_sb_info *msblk = s->s_fs_info;++ struct squashfs_super_block *sblk = &msblk->sblk;++++ while (1) {++ mutex_lock(&msblk->fragment_mutex);++++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&++ msblk->fragment[i].block != start_block; i++);++++ if (i == SQUASHFS_CACHED_FRAGMENTS) {++ if (msblk->unused_frag_blks == 0) {++ mutex_unlock(&msblk->fragment_mutex);++ wait_event(msblk->fragment_wait_queue, msblk->unused_frag_blks);++ continue;++ }++++ i = msblk->next_fragment;++ for (n = 0; n < SQUASHFS_CACHED_FRAGMENTS; n++) {++ if (msblk->fragment[i].locked == 0)++ break;++ i = (i + 1) % SQUASHFS_CACHED_FRAGMENTS;++ }++++ msblk->next_fragment = (msblk->next_fragment + 1) %++ SQUASHFS_CACHED_FRAGMENTS;++++ if (msblk->fragment[i].data == NULL) {++ msblk->fragment[i].data = vmalloc(sblk->block_size);++ if (msblk->fragment[i].data == NULL) {++ ERROR("Failed to allocate fragment cache block\n");++ mutex_unlock(&msblk->fragment_mutex);++ goto out;++ }++ }++++ msblk->unused_frag_blks --;++ msblk->fragment[i].block = SQUASHFS_INVALID_BLK;++ msblk->fragment[i].locked = 1;++ mutex_unlock(&msblk->fragment_mutex);++++ msblk->fragment[i].length = squashfs_read_data(s,++ msblk->fragment[i].data, start_block, length, NULL,++ sblk->block_size);++++ if (msblk->fragment[i].length == 0) {++ ERROR("Unable to read fragment cache block [%llx]\n", start_block);++ msblk->fragment[i].locked = 0;++ msblk->unused_frag_blks ++;++ smp_mb();++ wake_up(&msblk->fragment_wait_queue);++ goto out;++ }++++ mutex_lock(&msblk->fragment_mutex);++ msblk->fragment[i].block = start_block;++ TRACE("New fragment %d, start block %lld, locked %d\n",++ i, msblk->fragment[i].block, msblk->fragment[i].locked);++ mutex_unlock(&msblk->fragment_mutex);++ break;++ }++++ if (msblk->fragment[i].locked == 0)++ msblk->unused_frag_blks --;++ msblk->fragment[i].locked++;++ mutex_unlock(&msblk->fragment_mutex);++ TRACE("Got fragment %d, start block %lld, locked %d\n", i,++ msblk->fragment[i].block, msblk->fragment[i].locked);++ break;++ }++++ return &msblk->fragment[i];++++out:++ return NULL;++}++++++static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i,++ struct squashfs_base_inode_header *inodeb)++{++ i->i_ino = inodeb->inode_number;++ i->i_mtime.tv_sec = inodeb->mtime;++ i->i_atime.tv_sec = inodeb->mtime;++ i->i_ctime.tv_sec = inodeb->mtime;++ i->i_uid = msblk->uid[inodeb->uid];++ i->i_mode = inodeb->mode;++ i->i_size = 0;++++ if (inodeb->guid == SQUASHFS_GUIDS)++ i->i_gid = i->i_uid;++ else++ i->i_gid = msblk->guid[inodeb->guid];++}++++++static struct dentry *squashfs_get_parent(struct dentry *child)++{++ struct inode *i = child->d_inode;++ struct inode *parent = iget_locked(i->i_sb, SQUASHFS_I(i)->u.s2.parent_inode);++ struct dentry *rv;++++ TRACE("Entered squashfs_get_parent\n");++++ if(parent == NULL) {++ rv = ERR_PTR(-EACCES);++ goto out;++ }++++ rv = d_alloc_anon(parent);++ if(parent->i_state & I_NEW) {++ unlock_new_inode(parent);++ }++++ if(rv == NULL)++ rv = ERR_PTR(-ENOMEM);++++out:++ return rv;++}++++++SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s,++ squashfs_inode_t inode, unsigned int inode_number)++{++ struct squashfs_sb_info *msblk = s->s_fs_info;++ struct inode *i = iget_locked(s, inode_number);++++ TRACE("Entered squashfs_iget\n");++++ if(!i)++ return ERR_PTR(-ENOMEM);++++ if(i && (i->i_state & I_NEW)) {++ (msblk->read_inode)(i, inode);++ unlock_new_inode(i);++ }++++ return i;++}++++++static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode)++{++ struct super_block *s = i->i_sb;++ struct squashfs_sb_info *msblk = s->s_fs_info;++ struct squashfs_super_block *sblk = &msblk->sblk;++ long long block = SQUASHFS_INODE_BLK(inode) + sblk->inode_table_start;++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode);++ long long next_block;++ unsigned int next_offset;++ union squashfs_inode_header id, sid;++ struct squashfs_base_inode_header *inodeb = &id.base, *sinodeb = &sid.base;++++ TRACE("Entered squashfs_read_inode\n");++++ if (msblk->swap) {++ if (!squashfs_get_cached_block(s, sinodeb, block, offset,++ sizeof(*sinodeb), &next_block, &next_offset))++ goto failed_read;++ SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb, sizeof(*sinodeb));++ } else++ if (!squashfs_get_cached_block(s, inodeb, block, offset,++ sizeof(*inodeb), &next_block, &next_offset))++ goto failed_read;++++ squashfs_new_inode(msblk, i, inodeb);++++ switch(inodeb->inode_type) {++ case SQUASHFS_FILE_TYPE: {++ unsigned int frag_size;++ long long frag_blk;++ struct squashfs_reg_inode_header *inodep = &id.reg;++ struct squashfs_reg_inode_header *sinodep = &sid.reg;++++ if (msblk->swap) {++ if (!squashfs_get_cached_block(s, sinodep, block, offset,++ sizeof(*sinodep), &next_block, &next_offset))++ goto failed_read;++ SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);++ } else++ if (!squashfs_get_cached_block(s, inodep, block, offset,++ sizeof(*inodep), &next_block, &next_offset))++ goto failed_read;++++ frag_blk = SQUASHFS_INVALID_BLK;++++ if (inodep->fragment != SQUASHFS_INVALID_FRAG)++ if(!get_fragment_location(s, inodep->fragment, &frag_blk,++ &frag_size))++ goto failed_read;++++ i->i_nlink = 1;++ i->i_size = inodep->file_size;++ i->i_fop = &generic_ro_fops;++ i->i_mode |= S_IFREG;++ i->i_blocks = ((i->i_size - 1) >> 9) + 1;++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;++ SQUASHFS_I(i)->start_block = inodep->start_block;++ SQUASHFS_I(i)->u.s1.block_list_start = next_block;++ SQUASHFS_I(i)->offset = next_offset;++ i->i_data.a_ops = &squashfs_aops;++++ TRACE("File inode %x:%x, start_block %llx, "++ "block_list_start %llx, offset %x\n",++ SQUASHFS_INODE_BLK(inode), offset,++ inodep->start_block, next_block,++ next_offset);++ break;++ }++ case SQUASHFS_LREG_TYPE: {++ unsigned int frag_size;++ long long frag_blk;++ struct squashfs_lreg_inode_header *inodep = &id.lreg;++ struct squashfs_lreg_inode_header *sinodep = &sid.lreg;++++ if (msblk->swap) {++ if (!squashfs_get_cached_block(s, sinodep, block, offset,++ sizeof(*sinodep), &next_block, &next_offset))++ goto failed_read;++ SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);++ } else++ if (!squashfs_get_cached_block(s, inodep, block, offset,++ sizeof(*inodep), &next_block, &next_offset))++ goto failed_read;++++ frag_blk = SQUASHFS_INVALID_BLK;++++ if (inodep->fragment != SQUASHFS_INVALID_FRAG)++ if (!get_fragment_location(s, inodep->fragment, &frag_blk,++ &frag_size))++ goto failed_read;++++ i->i_nlink = inodep->nlink;++ i->i_size = inodep->file_size;++ i->i_fop = &generic_ro_fops;++ i->i_mode |= S_IFREG;++ i->i_blocks = ((i->i_size - 1) >> 9) + 1;++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;++ SQUASHFS_I(i)->start_block = inodep->start_block;++ SQUASHFS_I(i)->u.s1.block_list_start = next_block;++ SQUASHFS_I(i)->offset = next_offset;++ i->i_data.a_ops = &squashfs_aops;++++ TRACE("File inode %x:%x, start_block %llx, "++ "block_list_start %llx, offset %x\n",++ SQUASHFS_INODE_BLK(inode), offset,++ inodep->start_block, next_block,++ next_offset);++ break;++ }++ case SQUASHFS_DIR_TYPE: {++ struct squashfs_dir_inode_header *inodep = &id.dir;++ struct squashfs_dir_inode_header *sinodep = &sid.dir;++++ if (msblk->swap) {++ if (!squashfs_get_cached_block(s, sinodep, block, offset,++ sizeof(*sinodep), &next_block, &next_offset))++ goto failed_read;++ SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);++ } else++ if (!squashfs_get_cached_block(s, inodep, block, offset,++ sizeof(*inodep), &next_block, &next_offset))++ goto failed_read;++++ i->i_nlink = inodep->nlink;++ i->i_size = inodep->file_size;++ i->i_op = &squashfs_dir_inode_ops;++ i->i_fop = &squashfs_dir_ops;++ i->i_mode |= S_IFDIR;++ SQUASHFS_I(i)->start_block = inodep->start_block;++ SQUASHFS_I(i)->offset = inodep->offset;++ SQUASHFS_I(i)->u.s2.directory_index_count = 0;++ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;++++ TRACE("Directory inode %x:%x, start_block %x, offset "++ "%x\n", SQUASHFS_INODE_BLK(inode),++ offset, inodep->start_block,++ inodep->offset);++ break;++ }++ case SQUASHFS_LDIR_TYPE: {++ struct squashfs_ldir_inode_header *inodep = &id.ldir;++ struct squashfs_ldir_inode_header *sinodep = &sid.ldir;++++ if (msblk->swap) {++ if (!squashfs_get_cached_block(s, sinodep, block, offset,++ sizeof(*sinodep), &next_block, &next_offset))++ goto failed_read;++ SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep, sinodep);++ } else++ if (!squashfs_get_cached_block(s, inodep, block, offset,++ sizeof(*inodep), &next_block, &next_offset))++ goto failed_read;++++ i->i_nlink = inodep->nlink;++ i->i_size = inodep->file_size;++ i->i_op = &squashfs_dir_inode_ops;++ i->i_fop = &squashfs_dir_ops;++ i->i_mode |= S_IFDIR;++ SQUASHFS_I(i)->start_block = inodep->start_block;++ SQUASHFS_I(i)->offset = inodep->offset;++ SQUASHFS_I(i)->u.s2.directory_index_start = next_block;++ SQUASHFS_I(i)->u.s2.directory_index_offset = next_offset;++ SQUASHFS_I(i)->u.s2.directory_index_count = inodep->i_count;++ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;++++ TRACE("Long directory inode %x:%x, start_block %x, offset %x\n",++ SQUASHFS_INODE_BLK(inode), offset,++ inodep->start_block, inodep->offset);++ break;++ }++ case SQUASHFS_SYMLINK_TYPE: {++ struct squashfs_symlink_inode_header *inodep = &id.symlink;++ struct squashfs_symlink_inode_header *sinodep = &sid.symlink;++++ if (msblk->swap) {++ if (!squashfs_get_cached_block(s, sinodep, block, offset,++ sizeof(*sinodep), &next_block, &next_offset))++ goto failed_read;++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, sinodep);++ } else++ if (!squashfs_get_cached_block(s, inodep, block, offset,++ sizeof(*inodep), &next_block, &next_offset))++ goto failed_read;++++ i->i_nlink = inodep->nlink;++ i->i_size = inodep->symlink_size;++ i->i_op = &page_symlink_inode_operations;++ i->i_data.a_ops = &squashfs_symlink_aops;++ i->i_mode |= S_IFLNK;++ SQUASHFS_I(i)->start_block = next_block;++ SQUASHFS_I(i)->offset = next_offset;++++ TRACE("Symbolic link inode %x:%x, start_block %llx, offset %x\n",++ SQUASHFS_INODE_BLK(inode), offset,++ next_block, next_offset);++ break;++ }++ case SQUASHFS_BLKDEV_TYPE:++ case SQUASHFS_CHRDEV_TYPE: {++ struct squashfs_dev_inode_header *inodep = &id.dev;++ struct squashfs_dev_inode_header *sinodep = &sid.dev;++++ if (msblk->swap) {++ if (!squashfs_get_cached_block(s, sinodep, block, offset,++ sizeof(*sinodep), &next_block, &next_offset))++ goto failed_read;++ SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);++ } else++ if (!squashfs_get_cached_block(s, inodep, block, offset,++ sizeof(*inodep), &next_block, &next_offset))++ goto failed_read;++++ i->i_nlink = inodep->nlink;++ i->i_mode |= (inodeb->inode_type == SQUASHFS_CHRDEV_TYPE) ?++ S_IFCHR : S_IFBLK;++ init_special_inode(i, i->i_mode, old_decode_dev(inodep->rdev));++++ TRACE("Device inode %x:%x, rdev %x\n",++ SQUASHFS_INODE_BLK(inode), offset, inodep->rdev);++ break;++ }++ case SQUASHFS_FIFO_TYPE:++ case SQUASHFS_SOCKET_TYPE: {++ struct squashfs_ipc_inode_header *inodep = &id.ipc;++ struct squashfs_ipc_inode_header *sinodep = &sid.ipc;++++ if (msblk->swap) {++ if (!squashfs_get_cached_block(s, sinodep, block, offset,++ sizeof(*sinodep), &next_block, &next_offset))++ goto failed_read;++ SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);++ } else++ if (!squashfs_get_cached_block(s, inodep, block, offset,++ sizeof(*inodep), &next_block, &next_offset))++ goto failed_read;++++ i->i_nlink = inodep->nlink;++ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)++ ? S_IFIFO : S_IFSOCK;++ init_special_inode(i, i->i_mode, 0);++ break;++ }++ default:++ ERROR("Unknown inode type %d in squashfs_iget!\n",++ inodeb->inode_type);++ goto failed_read1;++ }++++ return 1;++++failed_read:++ ERROR("Unable to read inode [%llx:%x]\n", block, offset);++++failed_read1:++ make_bad_inode(i);++ return 0;++}++++++static int read_inode_lookup_table(struct super_block *s)++{++ struct squashfs_sb_info *msblk = s->s_fs_info;++ struct squashfs_super_block *sblk = &msblk->sblk;++ unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(sblk->inodes);++++ TRACE("In read_inode_lookup_table, length %d\n", length);++++ /* Allocate inode lookup table */++ msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL);++ if (msblk->inode_lookup_table == NULL) {++ ERROR("Failed to allocate inode lookup table\n");++ return 0;++ }++++ if (!squashfs_read_data(s, (char *) msblk->inode_lookup_table,++ sblk->lookup_table_start, length |++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) {++ ERROR("unable to read inode lookup table\n");++ return 0;++ }++++ if (msblk->swap) {++ int i;++ long long block;++++ for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) {++ /* XXX */++ SQUASHFS_SWAP_LOOKUP_BLOCKS((&block),++ &msblk->inode_lookup_table[i], 1);++ msblk->inode_lookup_table[i] = block;++ }++ }++++ return 1;++}++++++static int read_fragment_index_table(struct super_block *s)++{++ struct squashfs_sb_info *msblk = s->s_fs_info;++ struct squashfs_super_block *sblk = &msblk->sblk;++ unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments);++++ if(length == 0)++ return 1;++++ /* Allocate fragment index table */++ msblk->fragment_index = kmalloc(length, GFP_KERNEL);++ if (msblk->fragment_index == NULL) {++ ERROR("Failed to allocate fragment index table\n");++ return 0;++ }++++ if (!squashfs_read_data(s, (char *) msblk->fragment_index,++ sblk->fragment_table_start, length |++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) {++ ERROR("unable to read fragment index table\n");++ return 0;++ }++++ if (msblk->swap) {++ int i;++ long long fragment;++++ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) {++ /* XXX */++ SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),++ &msblk->fragment_index[i], 1);++ msblk->fragment_index[i] = fragment;++ }++ }++++ return 1;++}++++++static int readahead_metadata(struct super_block *s)++{++ struct squashfs_sb_info *msblk = s->s_fs_info;++ int i;++++ squashfs_cached_blks = SQUASHFS_CACHED_BLKS;++++ /* Init inode_table block pointer array */++ msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *++ squashfs_cached_blks, GFP_KERNEL);++ if (msblk->block_cache == NULL) {++ ERROR("Failed to allocate block cache\n");++ goto failed;++ }++++ for (i = 0; i < squashfs_cached_blks; i++)++ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;++++ msblk->next_cache = 0;++ msblk->unused_cache_blks = squashfs_cached_blks;++++ return 1;++++failed:++ return 0;++}++++++static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)++{++ struct squashfs_super_block *sblk = &msblk->sblk;++++ msblk->read_inode = squashfs_read_inode;++ msblk->read_blocklist = read_blocklist;++ msblk->read_fragment_index_table = read_fragment_index_table;++++ if (sblk->s_major == 1) {++ if (!squashfs_1_0_supported(msblk)) {++ SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "++ "are unsupported\n");++ SERROR("Please recompile with Squashfs 1.0 support enabled\n");++ return 0;++ }++ } else if (sblk->s_major == 2) {++ if (!squashfs_2_0_supported(msblk)) {++ SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "++ "are unsupported\n");++ SERROR("Please recompile with Squashfs 2.0 support enabled\n");++ return 0;++ }++ } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >++ SQUASHFS_MINOR) {++ SERROR("Major/Minor mismatch, trying to mount newer %d.%d "++ "filesystem\n", sblk->s_major, sblk->s_minor);++ SERROR("Please update your kernel\n");++ return 0;++ }++++ return 1;++}++++++static int squashfs_fill_super(struct super_block *s, void *data, int silent)++{++ struct squashfs_sb_info *msblk;++ struct squashfs_super_block *sblk;++ int i;++ char b[BDEVNAME_SIZE];++ struct inode *root;++++ TRACE("Entered squashfs_fill_superblock\n");++++ s->s_fs_info = kzalloc(sizeof(struct squashfs_sb_info), GFP_KERNEL);++ if (s->s_fs_info == NULL) {++ ERROR("Failed to allocate superblock\n");++ goto failure;++ }++ msblk = s->s_fs_info;++++ msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize());++ if (msblk->stream.workspace == NULL) {++ ERROR("Failed to allocate zlib workspace\n");++ goto failure;++ }++ sblk = &msblk->sblk;++++ msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE);++ msblk->devblksize_log2 = ffz(~msblk->devblksize);++++ mutex_init(&msblk->read_data_mutex);++ mutex_init(&msblk->read_page_mutex);++ mutex_init(&msblk->block_cache_mutex);++ mutex_init(&msblk->fragment_mutex);++ mutex_init(&msblk->meta_index_mutex);++++ init_waitqueue_head(&msblk->waitq);++ init_waitqueue_head(&msblk->fragment_wait_queue);++++ /* sblk->bytes_used is checked in squashfs_read_data to ensure reads are not++ * beyond filesystem end. As we're using squashfs_read_data to read sblk here,++ * first set sblk->bytes_used to a useful value */++ sblk->bytes_used = sizeof(struct squashfs_super_block);++ if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,++ sizeof(struct squashfs_super_block) |++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, sizeof(struct squashfs_super_block))) {++ SERROR("unable to read superblock\n");++ goto failed_mount;++ }++++ /* Check it is a SQUASHFS superblock */++ if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) {++ if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) {++ struct squashfs_super_block ssblk;++++ WARNING("Mounting a different endian SQUASHFS filesystem on %s\n",++ bdevname(s->s_bdev, b));++++ SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);++ memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));++ msblk->swap = 1;++ } else {++ SERROR("Can't find a SQUASHFS superblock on %s\n",++ bdevname(s->s_bdev, b));++ goto failed_mount;++ }++ }++++ /* Check the MAJOR & MINOR versions */++ if(!supported_squashfs_filesystem(msblk, silent))++ goto failed_mount;++++ /* Check the filesystem does not extend beyond the end of the++ block device */++ if(sblk->bytes_used < 0 || sblk->bytes_used > i_size_read(s->s_bdev->bd_inode))++ goto failed_mount;++++ /* Check the root inode for sanity */++ if (SQUASHFS_INODE_OFFSET(sblk->root_inode) > SQUASHFS_METADATA_SIZE)++ goto failed_mount;++++ TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b));++ TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sblk->flags)++ ? "un" : "");++ TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)++ ? "un" : "");++ TRACE("Check data is %spresent in the filesystem\n",++ SQUASHFS_CHECK_DATA(sblk->flags) ? "" : "not ");++ TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);++ TRACE("Block size %d\n", sblk->block_size);++ TRACE("Number of inodes %d\n", sblk->inodes);++ if (sblk->s_major > 1)++ TRACE("Number of fragments %d\n", sblk->fragments);++ TRACE("Number of uids %d\n", sblk->no_uids);++ TRACE("Number of gids %d\n", sblk->no_guids);++ TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);++ TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);++ if (sblk->s_major > 1)++ TRACE("sblk->fragment_table_start %llx\n", sblk->fragment_table_start);++ TRACE("sblk->uid_start %llx\n", sblk->uid_start);++++ s->s_maxbytes = MAX_LFS_FILESIZE;++ s->s_flags |= MS_RDONLY;++ s->s_op = &squashfs_super_ops;++++ if (readahead_metadata(s) == 0)++ goto failed_mount;++++ /* Allocate read_page block */++ msblk->read_page = vmalloc(sblk->block_size);++ if (msblk->read_page == NULL) {++ ERROR("Failed to allocate read_page block\n");++ goto failed_mount;++ }++++ /* Allocate uid and gid tables */++ msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *++ sizeof(unsigned int), GFP_KERNEL);++ if (msblk->uid == NULL) {++ ERROR("Failed to allocate uid/gid table\n");++ goto failed_mount;++ }++ msblk->guid = msblk->uid + sblk->no_uids;++++ if (msblk->swap) {++ unsigned int suid[sblk->no_uids + sblk->no_guids];++++ if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,++ ((sblk->no_uids + sblk->no_guids) *++ sizeof(unsigned int)) |++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) {++ ERROR("unable to read uid/gid table\n");++ goto failed_mount;++ }++++ SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids +++ sblk->no_guids), (sizeof(unsigned int) * 8));++ } else++ if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,++ ((sblk->no_uids + sblk->no_guids) *++ sizeof(unsigned int)) |++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) {++ ERROR("unable to read uid/gid table\n");++ goto failed_mount;++ }++++++ if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))++ goto allocate_root;++++ msblk->fragment = kzalloc(sizeof(struct squashfs_fragment_cache) *++ SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL);++ if (msblk->fragment == NULL) {++ ERROR("Failed to allocate fragment block cache\n");++ goto failed_mount;++ }++++ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {++ msblk->fragment[i].block = SQUASHFS_INVALID_BLK;++ }++++ msblk->next_fragment = 0;++ msblk->unused_frag_blks = SQUASHFS_CACHED_FRAGMENTS;++++ /* Allocate and read fragment index table */++ if (msblk->read_fragment_index_table(s) == 0)++ goto failed_mount;++++ if(sblk->s_major < 3 || sblk->lookup_table_start == SQUASHFS_INVALID_BLK)++ goto allocate_root;++++ /* Allocate and read inode lookup table */++ if (read_inode_lookup_table(s) == 0)++ goto failed_mount;++++ s->s_op = &squashfs_export_super_ops;++ s->s_export_op = &squashfs_export_ops;++++allocate_root:++ root = new_inode(s);++ if ((msblk->read_inode)(root, sblk->root_inode) == 0)++ goto failed_mount;++ insert_inode_hash(root);++++ s->s_root = d_alloc_root(root);++ if (s->s_root == NULL) {++ ERROR("Root inode create failed\n");++ iput(root);++ goto failed_mount;++ }++++ TRACE("Leaving squashfs_fill_super\n");++ return 0;++++failed_mount:++ kfree(msblk->inode_lookup_table);++ kfree(msblk->fragment_index);++ kfree(msblk->fragment);++ kfree(msblk->uid);++ vfree(msblk->read_page);++ kfree(msblk->block_cache);++ kfree(msblk->fragment_index_2);++ vfree(msblk->stream.workspace);++ kfree(s->s_fs_info);++ s->s_fs_info = NULL;++ return -EINVAL;++++failure:++ return -ENOMEM;++}++++++static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)++{++ struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info;++ struct squashfs_super_block *sblk = &msblk->sblk;++++ TRACE("Entered squashfs_statfs\n");++++ buf->f_type = SQUASHFS_MAGIC;++ buf->f_bsize = sblk->block_size;++ buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1;++ buf->f_bfree = buf->f_bavail = 0;++ buf->f_files = sblk->inodes;++ buf->f_ffree = 0;++ buf->f_namelen = SQUASHFS_NAME_LEN;++++ return 0;++}++++++static int squashfs_symlink_readpage(struct file *file, struct page *page)++{++ struct inode *inode = page->mapping->host;++ int index = page->index << PAGE_CACHE_SHIFT, length, bytes, avail_bytes;++ long long block = SQUASHFS_I(inode)->start_block;++ int offset = SQUASHFS_I(inode)->offset;++ void *pageaddr = kmap(page);++++ TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "++ "%llx, offset %x\n", page->index,++ SQUASHFS_I(inode)->start_block,++ SQUASHFS_I(inode)->offset);++++ for (length = 0; length < index; length += bytes) {++ bytes = squashfs_get_cached_block(inode->i_sb, NULL, block,++ offset, PAGE_CACHE_SIZE, &block, &offset);++ if (bytes == 0) {++ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);++ goto skip_read;++ }++ }++++ if (length != index) {++ ERROR("(squashfs_symlink_readpage) length != index\n");++ bytes = 0;++ goto skip_read;++ }++++ avail_bytes = min_t(int, i_size_read(inode) - length, PAGE_CACHE_SIZE);++++ bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset,++ avail_bytes, &block, &offset);++ if (bytes == 0)++ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);++++skip_read:++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);++ kunmap(page);++ flush_dcache_page(page);++ SetPageUptodate(page);++ unlock_page(page);++++ return 0;++}++++++struct meta_index *locate_meta_index(struct inode *inode, int index, int offset)++{++ struct meta_index *meta = NULL;++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;++ int i;++++ mutex_lock(&msblk->meta_index_mutex);++++ TRACE("locate_meta_index: index %d, offset %d\n", index, offset);++++ if (msblk->meta_index == NULL)++ goto not_allocated;++++ for (i = 0; i < SQUASHFS_META_NUMBER; i ++) {++ if (msblk->meta_index[i].inode_number == inode->i_ino &&++ msblk->meta_index[i].offset >= offset &&++ msblk->meta_index[i].offset <= index &&++ msblk->meta_index[i].locked == 0) {++ TRACE("locate_meta_index: entry %d, offset %d\n", i,++ msblk->meta_index[i].offset);++ meta = &msblk->meta_index[i];++ offset = meta->offset;++ }++ }++++ if (meta)++ meta->locked = 1;++++not_allocated:++ mutex_unlock(&msblk->meta_index_mutex);++++ return meta;++}++++++struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip)++{++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;++ struct meta_index *meta = NULL;++ int i;++++ mutex_lock(&msblk->meta_index_mutex);++++ TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);++++ if (msblk->meta_index == NULL) {++ msblk->meta_index = kmalloc(sizeof(struct meta_index) *++ SQUASHFS_META_NUMBER, GFP_KERNEL);++ if (msblk->meta_index == NULL) {++ ERROR("Failed to allocate meta_index\n");++ goto failed;++ }++ for (i = 0; i < SQUASHFS_META_NUMBER; i++) {++ msblk->meta_index[i].inode_number = 0;++ msblk->meta_index[i].locked = 0;++ }++ msblk->next_meta_index = 0;++ }++++ for (i = SQUASHFS_META_NUMBER; i &&++ msblk->meta_index[msblk->next_meta_index].locked; i --)++ msblk->next_meta_index = (msblk->next_meta_index + 1) %++ SQUASHFS_META_NUMBER;++++ if (i == 0) {++ TRACE("empty_meta_index: failed!\n");++ goto failed;++ }++++ TRACE("empty_meta_index: returned meta entry %d, %p\n",++ msblk->next_meta_index,++ &msblk->meta_index[msblk->next_meta_index]);++++ meta = &msblk->meta_index[msblk->next_meta_index];++ msblk->next_meta_index = (msblk->next_meta_index + 1) %++ SQUASHFS_META_NUMBER;++++ meta->inode_number = inode->i_ino;++ meta->offset = offset;++ meta->skip = skip;++ meta->entries = 0;++ meta->locked = 1;++++failed:++ mutex_unlock(&msblk->meta_index_mutex);++ return meta;++}++++++void release_meta_index(struct inode *inode, struct meta_index *meta)++{++ meta->locked = 0;++ smp_mb();++}++++++static int read_block_index(struct super_block *s, int blocks, char *block_list,++ long long *start_block, int *offset)++{++ struct squashfs_sb_info *msblk = s->s_fs_info;++ unsigned int *block_listp;++ int block = 0;++++ if (msblk->swap) {++ char sblock_list[blocks << 2];++++ if (!squashfs_get_cached_block(s, sblock_list, *start_block,++ *offset, blocks << 2, start_block, offset)) {++ ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset);++ goto failure;++ }++ SQUASHFS_SWAP_INTS(((unsigned int *)block_list),++ ((unsigned int *)sblock_list), blocks);++ } else {++ if (!squashfs_get_cached_block(s, block_list, *start_block,++ *offset, blocks << 2, start_block, offset)) {++ ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset);++ goto failure;++ }++ }++++ for (block_listp = (unsigned int *) block_list; blocks;++ block_listp++, blocks --)++ block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);++++ return block;++++failure:++ return -1;++}++++++#define SIZE 256++++static inline int calculate_skip(int blocks) {++ int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES);++ return skip >= 7 ? 7 : skip + 1;++}++++++static int get_meta_index(struct inode *inode, int index,++ long long *index_block, int *index_offset,++ long long *data_block, char *block_list)++{++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;++ struct squashfs_super_block *sblk = &msblk->sblk;++ int skip = calculate_skip(i_size_read(inode) >> sblk->block_log);++ int offset = 0;++ struct meta_index *meta;++ struct meta_entry *meta_entry;++ long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start;++ int cur_offset = SQUASHFS_I(inode)->offset;++ long long cur_data_block = SQUASHFS_I(inode)->start_block;++ int i;++++ index /= SQUASHFS_META_INDEXES * skip;++++ while (offset < index) {++ meta = locate_meta_index(inode, index, offset + 1);++++ if (meta == NULL) {++ meta = empty_meta_index(inode, offset + 1, skip);++ if (meta == NULL)++ goto all_done;++ } else {++ if(meta->entries == 0)++ goto failed;++ /* XXX */++ offset = index < meta->offset + meta->entries ? index :++ meta->offset + meta->entries - 1;++ /* XXX */++ meta_entry = &meta->meta_entry[offset - meta->offset];++ cur_index_block = meta_entry->index_block + sblk->inode_table_start;++ cur_offset = meta_entry->offset;++ cur_data_block = meta_entry->data_block;++ TRACE("get_meta_index: offset %d, meta->offset %d, "++ "meta->entries %d\n", offset, meta->offset, meta->entries);++ TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"++ " data_block 0x%llx\n", cur_index_block,++ cur_offset, cur_data_block);++ }++++ for (i = meta->offset + meta->entries; i <= index &&++ i < meta->offset + SQUASHFS_META_ENTRIES; i++) {++ int blocks = skip * SQUASHFS_META_INDEXES;++++ while (blocks) {++ int block = blocks > (SIZE >> 2) ? (SIZE >> 2) : blocks;++ int res = read_block_index(inode->i_sb, block, block_list,++ &cur_index_block, &cur_offset);++++ if (res == -1)++ goto failed;++++ cur_data_block += res;++ blocks -= block;++ }++++ meta_entry = &meta->meta_entry[i - meta->offset];++ meta_entry->index_block = cur_index_block - sblk->inode_table_start;++ meta_entry->offset = cur_offset;++ meta_entry->data_block = cur_data_block;++ meta->entries ++;++ offset ++;++ }++++ TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",++ meta->offset, meta->entries);++++ release_meta_index(inode, meta);++ }++++all_done:++ *index_block = cur_index_block;++ *index_offset = cur_offset;++ *data_block = cur_data_block;++++ return offset * SQUASHFS_META_INDEXES * skip;++++failed:++ release_meta_index(inode, meta);++ return -1;++}++++++static long long read_blocklist(struct inode *inode, int index,++ int readahead_blks, char *block_list,++ unsigned short **block_p, unsigned int *bsize)++{++ long long block_ptr;++ int offset;++ long long block;++ int res = get_meta_index(inode, index, &block_ptr, &offset, &block,++ block_list);++++ TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"++ " 0x%x, block 0x%llx\n", res, index, block_ptr, offset, block);++++ if(res == -1)++ goto failure;++++ index -= res;