10aeb6601e77c348064513052bf90a11952a190d0plougher/*
20aeb6601e77c348064513052bf90a11952a190d0plougher * Squashfs - a compressed read only filesystem for Linux
30aeb6601e77c348064513052bf90a11952a190d0plougher *
40aeb6601e77c348064513052bf90a11952a190d0plougher * Copyright (c) 2002, 2003, 2004, 2005, 2006
5f6cd337f8de328e2b448b9f29c00d9132748f7feplougher * Phillip Lougher <phillip@lougher.demon.co.uk>
60aeb6601e77c348064513052bf90a11952a190d0plougher *
70aeb6601e77c348064513052bf90a11952a190d0plougher * This program is free software; you can redistribute it and/or
80aeb6601e77c348064513052bf90a11952a190d0plougher * modify it under the terms of the GNU General Public License
90aeb6601e77c348064513052bf90a11952a190d0plougher * as published by the Free Software Foundation; either version 2,
100aeb6601e77c348064513052bf90a11952a190d0plougher * or (at your option) any later version.
110aeb6601e77c348064513052bf90a11952a190d0plougher *
120aeb6601e77c348064513052bf90a11952a190d0plougher * This program is distributed in the hope that it will be useful,
130aeb6601e77c348064513052bf90a11952a190d0plougher * but WITHOUT ANY WARRANTY; without even the implied warranty of
140aeb6601e77c348064513052bf90a11952a190d0plougher * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
150aeb6601e77c348064513052bf90a11952a190d0plougher * GNU General Public License for more details.
160aeb6601e77c348064513052bf90a11952a190d0plougher *
170aeb6601e77c348064513052bf90a11952a190d0plougher * You should have received a copy of the GNU General Public License
180aeb6601e77c348064513052bf90a11952a190d0plougher * along with this program; if not, write to the Free Software
190aeb6601e77c348064513052bf90a11952a190d0plougher * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
200aeb6601e77c348064513052bf90a11952a190d0plougher *
210aeb6601e77c348064513052bf90a11952a190d0plougher * inode.c
220aeb6601e77c348064513052bf90a11952a190d0plougher */
230aeb6601e77c348064513052bf90a11952a190d0plougher
240aeb6601e77c348064513052bf90a11952a190d0plougher#include <linux/types.h>
250aeb6601e77c348064513052bf90a11952a190d0plougher#include <linux/squashfs_fs.h>
260aeb6601e77c348064513052bf90a11952a190d0plougher#include <linux/module.h>
270aeb6601e77c348064513052bf90a11952a190d0plougher#include <linux/errno.h>
280aeb6601e77c348064513052bf90a11952a190d0plougher#include <linux/slab.h>
29410dd958c15c73d91e877a0afe085bfaee37d9ffplougher#include <linux/zlib.h>
300aeb6601e77c348064513052bf90a11952a190d0plougher#include <linux/fs.h>
310aeb6601e77c348064513052bf90a11952a190d0plougher#include <linux/smp_lock.h>
320aeb6601e77c348064513052bf90a11952a190d0plougher#include <linux/locks.h>
330aeb6601e77c348064513052bf90a11952a190d0plougher#include <linux/init.h>
340aeb6601e77c348064513052bf90a11952a190d0plougher#include <linux/dcache.h>
350aeb6601e77c348064513052bf90a11952a190d0plougher#include <linux/wait.h>
360aeb6601e77c348064513052bf90a11952a190d0plougher#include <linux/blkdev.h>
370aeb6601e77c348064513052bf90a11952a190d0plougher#include <linux/vmalloc.h>
380aeb6601e77c348064513052bf90a11952a190d0plougher#include <asm/uaccess.h>
390aeb6601e77c348064513052bf90a11952a190d0plougher#include <asm/semaphore.h>
400aeb6601e77c348064513052bf90a11952a190d0plougher
410aeb6601e77c348064513052bf90a11952a190d0plougher#include "squashfs.h"
420aeb6601e77c348064513052bf90a11952a190d0plougher
430aeb6601e77c348064513052bf90a11952a190d0plougherstatic struct super_block *squashfs_read_super(struct super_block *, void *, int);
440aeb6601e77c348064513052bf90a11952a190d0plougherstatic void squashfs_put_super(struct super_block *);
450aeb6601e77c348064513052bf90a11952a190d0plougherstatic int squashfs_statfs(struct super_block *, struct statfs *);
460aeb6601e77c348064513052bf90a11952a190d0plougherstatic int squashfs_symlink_readpage(struct file *file, struct page *page);
470aeb6601e77c348064513052bf90a11952a190d0plougherstatic int squashfs_readpage(struct file *file, struct page *page);
480aeb6601e77c348064513052bf90a11952a190d0plougherstatic int squashfs_readpage4K(struct file *file, struct page *page);
490aeb6601e77c348064513052bf90a11952a190d0plougherstatic int squashfs_readdir(struct file *, void *, filldir_t);
500aeb6601e77c348064513052bf90a11952a190d0plougherstatic struct dentry *squashfs_lookup(struct inode *, struct dentry *);
510aeb6601e77c348064513052bf90a11952a190d0plougherstatic struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode);
520aeb6601e77c348064513052bf90a11952a190d0plougherstatic long long read_blocklist(struct inode *inode, int index,
530aeb6601e77c348064513052bf90a11952a190d0plougher				int readahead_blks, char *block_list,
540aeb6601e77c348064513052bf90a11952a190d0plougher				unsigned short **block_p, unsigned int *bsize);
550aeb6601e77c348064513052bf90a11952a190d0plougher
560aeb6601e77c348064513052bf90a11952a190d0plougherstatic DECLARE_FSTYPE_DEV(squashfs_fs_type, "squashfs", squashfs_read_super);
570aeb6601e77c348064513052bf90a11952a190d0plougher
580aeb6601e77c348064513052bf90a11952a190d0plougherstatic unsigned char squashfs_filetype_table[] = {
590aeb6601e77c348064513052bf90a11952a190d0plougher	DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
600aeb6601e77c348064513052bf90a11952a190d0plougher};
610aeb6601e77c348064513052bf90a11952a190d0plougher
620aeb6601e77c348064513052bf90a11952a190d0plougherstatic struct super_operations squashfs_ops = {
630aeb6601e77c348064513052bf90a11952a190d0plougher	.statfs = squashfs_statfs,
640aeb6601e77c348064513052bf90a11952a190d0plougher	.put_super = squashfs_put_super,
650aeb6601e77c348064513052bf90a11952a190d0plougher};
660aeb6601e77c348064513052bf90a11952a190d0plougher
670aeb6601e77c348064513052bf90a11952a190d0plougherSQSH_EXTERN struct address_space_operations squashfs_symlink_aops = {
680aeb6601e77c348064513052bf90a11952a190d0plougher	.readpage = squashfs_symlink_readpage
690aeb6601e77c348064513052bf90a11952a190d0plougher};
700aeb6601e77c348064513052bf90a11952a190d0plougher
710aeb6601e77c348064513052bf90a11952a190d0plougherSQSH_EXTERN struct address_space_operations squashfs_aops = {
720aeb6601e77c348064513052bf90a11952a190d0plougher	.readpage = squashfs_readpage
730aeb6601e77c348064513052bf90a11952a190d0plougher};
740aeb6601e77c348064513052bf90a11952a190d0plougher
750aeb6601e77c348064513052bf90a11952a190d0plougherSQSH_EXTERN struct address_space_operations squashfs_aops_4K = {
760aeb6601e77c348064513052bf90a11952a190d0plougher	.readpage = squashfs_readpage4K
770aeb6601e77c348064513052bf90a11952a190d0plougher};
780aeb6601e77c348064513052bf90a11952a190d0plougher
790aeb6601e77c348064513052bf90a11952a190d0plougherstatic struct file_operations squashfs_dir_ops = {
800aeb6601e77c348064513052bf90a11952a190d0plougher	.read = generic_read_dir,
810aeb6601e77c348064513052bf90a11952a190d0plougher	.readdir = squashfs_readdir
820aeb6601e77c348064513052bf90a11952a190d0plougher};
830aeb6601e77c348064513052bf90a11952a190d0plougher
840aeb6601e77c348064513052bf90a11952a190d0plougherstatic struct inode_operations squashfs_dir_inode_ops = {
850aeb6601e77c348064513052bf90a11952a190d0plougher	.lookup = squashfs_lookup
860aeb6601e77c348064513052bf90a11952a190d0plougher};
870aeb6601e77c348064513052bf90a11952a190d0plougher
880aeb6601e77c348064513052bf90a11952a190d0plougherstatic struct buffer_head *get_block_length(struct super_block *s,
890aeb6601e77c348064513052bf90a11952a190d0plougher				int *cur_index, int *offset, int *c_byte)
900aeb6601e77c348064513052bf90a11952a190d0plougher{
910aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
920aeb6601e77c348064513052bf90a11952a190d0plougher	unsigned short temp;
930aeb6601e77c348064513052bf90a11952a190d0plougher	struct buffer_head *bh;
940aeb6601e77c348064513052bf90a11952a190d0plougher
950aeb6601e77c348064513052bf90a11952a190d0plougher	if (!(bh = sb_bread(s, *cur_index)))
960aeb6601e77c348064513052bf90a11952a190d0plougher		goto out;
970aeb6601e77c348064513052bf90a11952a190d0plougher
980aeb6601e77c348064513052bf90a11952a190d0plougher	if (msblk->devblksize - *offset == 1) {
990aeb6601e77c348064513052bf90a11952a190d0plougher		if (msblk->swap)
1000aeb6601e77c348064513052bf90a11952a190d0plougher			((unsigned char *) &temp)[1] = *((unsigned char *)
1010aeb6601e77c348064513052bf90a11952a190d0plougher				(bh->b_data + *offset));
1020aeb6601e77c348064513052bf90a11952a190d0plougher		else
1030aeb6601e77c348064513052bf90a11952a190d0plougher			((unsigned char *) &temp)[0] = *((unsigned char *)
1040aeb6601e77c348064513052bf90a11952a190d0plougher				(bh->b_data + *offset));
1050aeb6601e77c348064513052bf90a11952a190d0plougher		brelse(bh);
1060aeb6601e77c348064513052bf90a11952a190d0plougher		if (!(bh = sb_bread(s, ++(*cur_index))))
1070aeb6601e77c348064513052bf90a11952a190d0plougher			goto out;
1080aeb6601e77c348064513052bf90a11952a190d0plougher		if (msblk->swap)
1090aeb6601e77c348064513052bf90a11952a190d0plougher			((unsigned char *) &temp)[0] = *((unsigned char *)
1100aeb6601e77c348064513052bf90a11952a190d0plougher				bh->b_data);
1110aeb6601e77c348064513052bf90a11952a190d0plougher		else
1120aeb6601e77c348064513052bf90a11952a190d0plougher			((unsigned char *) &temp)[1] = *((unsigned char *)
1130aeb6601e77c348064513052bf90a11952a190d0plougher				bh->b_data);
1140aeb6601e77c348064513052bf90a11952a190d0plougher		*c_byte = temp;
1150aeb6601e77c348064513052bf90a11952a190d0plougher		*offset = 1;
1160aeb6601e77c348064513052bf90a11952a190d0plougher	} else {
1170aeb6601e77c348064513052bf90a11952a190d0plougher		if (msblk->swap) {
1180aeb6601e77c348064513052bf90a11952a190d0plougher			((unsigned char *) &temp)[1] = *((unsigned char *)
1190aeb6601e77c348064513052bf90a11952a190d0plougher				(bh->b_data + *offset));
1200aeb6601e77c348064513052bf90a11952a190d0plougher			((unsigned char *) &temp)[0] = *((unsigned char *)
1210aeb6601e77c348064513052bf90a11952a190d0plougher				(bh->b_data + *offset + 1));
1220aeb6601e77c348064513052bf90a11952a190d0plougher		} else {
1230aeb6601e77c348064513052bf90a11952a190d0plougher			((unsigned char *) &temp)[0] = *((unsigned char *)
1240aeb6601e77c348064513052bf90a11952a190d0plougher				(bh->b_data + *offset));
1250aeb6601e77c348064513052bf90a11952a190d0plougher			((unsigned char *) &temp)[1] = *((unsigned char *)
1260aeb6601e77c348064513052bf90a11952a190d0plougher				(bh->b_data + *offset + 1));
1270aeb6601e77c348064513052bf90a11952a190d0plougher		}
1280aeb6601e77c348064513052bf90a11952a190d0plougher		*c_byte = temp;
1290aeb6601e77c348064513052bf90a11952a190d0plougher		*offset += 2;
1300aeb6601e77c348064513052bf90a11952a190d0plougher	}
1310aeb6601e77c348064513052bf90a11952a190d0plougher
1320aeb6601e77c348064513052bf90a11952a190d0plougher	if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) {
1330aeb6601e77c348064513052bf90a11952a190d0plougher		if (*offset == msblk->devblksize) {
1340aeb6601e77c348064513052bf90a11952a190d0plougher			brelse(bh);
1350aeb6601e77c348064513052bf90a11952a190d0plougher			if (!(bh = sb_bread(s, ++(*cur_index))))
1360aeb6601e77c348064513052bf90a11952a190d0plougher				goto out;
1370aeb6601e77c348064513052bf90a11952a190d0plougher			*offset = 0;
1380aeb6601e77c348064513052bf90a11952a190d0plougher		}
1390aeb6601e77c348064513052bf90a11952a190d0plougher		if (*((unsigned char *) (bh->b_data + *offset)) !=
1400aeb6601e77c348064513052bf90a11952a190d0plougher						SQUASHFS_MARKER_BYTE) {
1410aeb6601e77c348064513052bf90a11952a190d0plougher			ERROR("Metadata block marker corrupt @ %x\n",
1420aeb6601e77c348064513052bf90a11952a190d0plougher						*cur_index);
1430aeb6601e77c348064513052bf90a11952a190d0plougher			brelse(bh);
1440aeb6601e77c348064513052bf90a11952a190d0plougher			goto out;
1450aeb6601e77c348064513052bf90a11952a190d0plougher		}
1460aeb6601e77c348064513052bf90a11952a190d0plougher		(*offset)++;
1470aeb6601e77c348064513052bf90a11952a190d0plougher	}
1480aeb6601e77c348064513052bf90a11952a190d0plougher	return bh;
1490aeb6601e77c348064513052bf90a11952a190d0plougher
1500aeb6601e77c348064513052bf90a11952a190d0plougherout:
1510aeb6601e77c348064513052bf90a11952a190d0plougher	return NULL;
1520aeb6601e77c348064513052bf90a11952a190d0plougher}
1530aeb6601e77c348064513052bf90a11952a190d0plougher
1540aeb6601e77c348064513052bf90a11952a190d0plougher
1550aeb6601e77c348064513052bf90a11952a190d0plougherSQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
1560aeb6601e77c348064513052bf90a11952a190d0plougher			long long index, unsigned int length,
1570aeb6601e77c348064513052bf90a11952a190d0plougher			long long *next_index)
1580aeb6601e77c348064513052bf90a11952a190d0plougher{
1590aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
1600aeb6601e77c348064513052bf90a11952a190d0plougher	struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >>
1610aeb6601e77c348064513052bf90a11952a190d0plougher			msblk->devblksize_log2) + 2];
1620aeb6601e77c348064513052bf90a11952a190d0plougher	unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
1630aeb6601e77c348064513052bf90a11952a190d0plougher	unsigned int cur_index = index >> msblk->devblksize_log2;
1640aeb6601e77c348064513052bf90a11952a190d0plougher	int bytes, avail_bytes, b = 0, k;
1650aeb6601e77c348064513052bf90a11952a190d0plougher	char *c_buffer;
1660aeb6601e77c348064513052bf90a11952a190d0plougher	unsigned int compressed;
1670aeb6601e77c348064513052bf90a11952a190d0plougher	unsigned int c_byte = length;
1680aeb6601e77c348064513052bf90a11952a190d0plougher
1690aeb6601e77c348064513052bf90a11952a190d0plougher	if (c_byte) {
1700aeb6601e77c348064513052bf90a11952a190d0plougher		bytes = msblk->devblksize - offset;
1710aeb6601e77c348064513052bf90a11952a190d0plougher		compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
1720aeb6601e77c348064513052bf90a11952a190d0plougher		c_buffer = compressed ? msblk->read_data : buffer;
1730aeb6601e77c348064513052bf90a11952a190d0plougher		c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
1740aeb6601e77c348064513052bf90a11952a190d0plougher
1750aeb6601e77c348064513052bf90a11952a190d0plougher		TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
1760aeb6601e77c348064513052bf90a11952a190d0plougher					? "" : "un", (unsigned int) c_byte);
1770aeb6601e77c348064513052bf90a11952a190d0plougher
1780aeb6601e77c348064513052bf90a11952a190d0plougher		if (!(bh[0] = sb_getblk(s, cur_index)))
1790aeb6601e77c348064513052bf90a11952a190d0plougher			goto block_release;
1800aeb6601e77c348064513052bf90a11952a190d0plougher
1810aeb6601e77c348064513052bf90a11952a190d0plougher		for (b = 1; bytes < c_byte; b++) {
1820aeb6601e77c348064513052bf90a11952a190d0plougher			if (!(bh[b] = sb_getblk(s, ++cur_index)))
1830aeb6601e77c348064513052bf90a11952a190d0plougher				goto block_release;
1840aeb6601e77c348064513052bf90a11952a190d0plougher			bytes += msblk->devblksize;
1850aeb6601e77c348064513052bf90a11952a190d0plougher		}
1860aeb6601e77c348064513052bf90a11952a190d0plougher		ll_rw_block(READ, b, bh);
1870aeb6601e77c348064513052bf90a11952a190d0plougher	} else {
1880aeb6601e77c348064513052bf90a11952a190d0plougher		if (!(bh[0] = get_block_length(s, &cur_index, &offset,
1890aeb6601e77c348064513052bf90a11952a190d0plougher								&c_byte)))
1900aeb6601e77c348064513052bf90a11952a190d0plougher			goto read_failure;
1910aeb6601e77c348064513052bf90a11952a190d0plougher
1920aeb6601e77c348064513052bf90a11952a190d0plougher		bytes = msblk->devblksize - offset;
1930aeb6601e77c348064513052bf90a11952a190d0plougher		compressed = SQUASHFS_COMPRESSED(c_byte);
1940aeb6601e77c348064513052bf90a11952a190d0plougher		c_buffer = compressed ? msblk->read_data : buffer;
1950aeb6601e77c348064513052bf90a11952a190d0plougher		c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
1960aeb6601e77c348064513052bf90a11952a190d0plougher
1970aeb6601e77c348064513052bf90a11952a190d0plougher		TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
1980aeb6601e77c348064513052bf90a11952a190d0plougher					? "" : "un", (unsigned int) c_byte);
1990aeb6601e77c348064513052bf90a11952a190d0plougher
2000aeb6601e77c348064513052bf90a11952a190d0plougher		for (b = 1; bytes < c_byte; b++) {
2010aeb6601e77c348064513052bf90a11952a190d0plougher			if (!(bh[b] = sb_getblk(s, ++cur_index)))
2020aeb6601e77c348064513052bf90a11952a190d0plougher				goto block_release;
2030aeb6601e77c348064513052bf90a11952a190d0plougher			bytes += msblk->devblksize;
2040aeb6601e77c348064513052bf90a11952a190d0plougher		}
2050aeb6601e77c348064513052bf90a11952a190d0plougher		ll_rw_block(READ, b - 1, bh + 1);
2060aeb6601e77c348064513052bf90a11952a190d0plougher	}
2070aeb6601e77c348064513052bf90a11952a190d0plougher
2080aeb6601e77c348064513052bf90a11952a190d0plougher	if (compressed)
2090aeb6601e77c348064513052bf90a11952a190d0plougher		down(&msblk->read_data_mutex);
2100aeb6601e77c348064513052bf90a11952a190d0plougher
2110aeb6601e77c348064513052bf90a11952a190d0plougher	for (bytes = 0, k = 0; k < b; k++) {
2120aeb6601e77c348064513052bf90a11952a190d0plougher		avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ?
2130aeb6601e77c348064513052bf90a11952a190d0plougher					msblk->devblksize - offset :
2140aeb6601e77c348064513052bf90a11952a190d0plougher					c_byte - bytes;
2150aeb6601e77c348064513052bf90a11952a190d0plougher		wait_on_buffer(bh[k]);
2160aeb6601e77c348064513052bf90a11952a190d0plougher		if (!buffer_uptodate(bh[k]))
2170aeb6601e77c348064513052bf90a11952a190d0plougher			goto block_release;
2180aeb6601e77c348064513052bf90a11952a190d0plougher		memcpy(c_buffer + bytes, bh[k]->b_data + offset, avail_bytes);
2190aeb6601e77c348064513052bf90a11952a190d0plougher		bytes += avail_bytes;
2200aeb6601e77c348064513052bf90a11952a190d0plougher		offset = 0;
2210aeb6601e77c348064513052bf90a11952a190d0plougher		brelse(bh[k]);
2220aeb6601e77c348064513052bf90a11952a190d0plougher	}
2230aeb6601e77c348064513052bf90a11952a190d0plougher
2240aeb6601e77c348064513052bf90a11952a190d0plougher	/*
2250aeb6601e77c348064513052bf90a11952a190d0plougher	 * uncompress block
2260aeb6601e77c348064513052bf90a11952a190d0plougher	 */
2270aeb6601e77c348064513052bf90a11952a190d0plougher	if (compressed) {
2280aeb6601e77c348064513052bf90a11952a190d0plougher		int zlib_err;
2290aeb6601e77c348064513052bf90a11952a190d0plougher
230410dd958c15c73d91e877a0afe085bfaee37d9ffplougher		msblk->stream.next_in = c_buffer;
231410dd958c15c73d91e877a0afe085bfaee37d9ffplougher		msblk->stream.avail_in = c_byte;
232410dd958c15c73d91e877a0afe085bfaee37d9ffplougher		msblk->stream.next_out = buffer;
233410dd958c15c73d91e877a0afe085bfaee37d9ffplougher		msblk->stream.avail_out = msblk->read_size;
2340aeb6601e77c348064513052bf90a11952a190d0plougher
235410dd958c15c73d91e877a0afe085bfaee37d9ffplougher		if (((zlib_err = zlib_inflateInit(&msblk->stream)) != Z_OK) ||
236410dd958c15c73d91e877a0afe085bfaee37d9ffplougher				((zlib_err = zlib_inflate(&msblk->stream, Z_FINISH))
2370aeb6601e77c348064513052bf90a11952a190d0plougher				 != Z_STREAM_END) || ((zlib_err =
238410dd958c15c73d91e877a0afe085bfaee37d9ffplougher				zlib_inflateEnd(&msblk->stream)) != Z_OK)) {
2390aeb6601e77c348064513052bf90a11952a190d0plougher			ERROR("zlib_fs returned unexpected result 0x%x\n",
2400aeb6601e77c348064513052bf90a11952a190d0plougher				zlib_err);
2410aeb6601e77c348064513052bf90a11952a190d0plougher			bytes = 0;
2420aeb6601e77c348064513052bf90a11952a190d0plougher		} else
243410dd958c15c73d91e877a0afe085bfaee37d9ffplougher			bytes = msblk->stream.total_out;
2440aeb6601e77c348064513052bf90a11952a190d0plougher
2450aeb6601e77c348064513052bf90a11952a190d0plougher		up(&msblk->read_data_mutex);
2460aeb6601e77c348064513052bf90a11952a190d0plougher	}
2470aeb6601e77c348064513052bf90a11952a190d0plougher
2480aeb6601e77c348064513052bf90a11952a190d0plougher	if (next_index)
2490aeb6601e77c348064513052bf90a11952a190d0plougher		*next_index = index + c_byte + (length ? 0 :
2500aeb6601e77c348064513052bf90a11952a190d0plougher				(SQUASHFS_CHECK_DATA(msblk->sblk.flags)
2510aeb6601e77c348064513052bf90a11952a190d0plougher				 ? 3 : 2));
2520aeb6601e77c348064513052bf90a11952a190d0plougher	return bytes;
2530aeb6601e77c348064513052bf90a11952a190d0plougher
2540aeb6601e77c348064513052bf90a11952a190d0plougherblock_release:
2550aeb6601e77c348064513052bf90a11952a190d0plougher	while (--b >= 0)
2560aeb6601e77c348064513052bf90a11952a190d0plougher		brelse(bh[b]);
2570aeb6601e77c348064513052bf90a11952a190d0plougher
2580aeb6601e77c348064513052bf90a11952a190d0plougherread_failure:
2590aeb6601e77c348064513052bf90a11952a190d0plougher	ERROR("sb_bread failed reading block 0x%x\n", cur_index);
2600aeb6601e77c348064513052bf90a11952a190d0plougher	return 0;
2610aeb6601e77c348064513052bf90a11952a190d0plougher}
2620aeb6601e77c348064513052bf90a11952a190d0plougher
2630aeb6601e77c348064513052bf90a11952a190d0plougher
2640aeb6601e77c348064513052bf90a11952a190d0plougherSQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer,
2650aeb6601e77c348064513052bf90a11952a190d0plougher				long long block, unsigned int offset,
2660aeb6601e77c348064513052bf90a11952a190d0plougher				int length, long long *next_block,
2670aeb6601e77c348064513052bf90a11952a190d0plougher				unsigned int *next_offset)
2680aeb6601e77c348064513052bf90a11952a190d0plougher{
2690aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
2700aeb6601e77c348064513052bf90a11952a190d0plougher	int n, i, bytes, return_length = length;
2710aeb6601e77c348064513052bf90a11952a190d0plougher	long long next_index;
2720aeb6601e77c348064513052bf90a11952a190d0plougher
2730aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
2740aeb6601e77c348064513052bf90a11952a190d0plougher
2750aeb6601e77c348064513052bf90a11952a190d0plougher	while ( 1 ) {
2760aeb6601e77c348064513052bf90a11952a190d0plougher		for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
2770aeb6601e77c348064513052bf90a11952a190d0plougher			if (msblk->block_cache[i].block == block)
2780aeb6601e77c348064513052bf90a11952a190d0plougher				break;
2790aeb6601e77c348064513052bf90a11952a190d0plougher
2800aeb6601e77c348064513052bf90a11952a190d0plougher		down(&msblk->block_cache_mutex);
2810aeb6601e77c348064513052bf90a11952a190d0plougher
2820aeb6601e77c348064513052bf90a11952a190d0plougher		if (i == SQUASHFS_CACHED_BLKS) {
2830aeb6601e77c348064513052bf90a11952a190d0plougher			/* read inode header block */
2840aeb6601e77c348064513052bf90a11952a190d0plougher			for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS;
2850aeb6601e77c348064513052bf90a11952a190d0plougher					n ; n --, i = (i + 1) %
2860aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_CACHED_BLKS)
2870aeb6601e77c348064513052bf90a11952a190d0plougher				if (msblk->block_cache[i].block !=
2880aeb6601e77c348064513052bf90a11952a190d0plougher							SQUASHFS_USED_BLK)
2890aeb6601e77c348064513052bf90a11952a190d0plougher					break;
2900aeb6601e77c348064513052bf90a11952a190d0plougher
2910aeb6601e77c348064513052bf90a11952a190d0plougher			if (n == 0) {
2920aeb6601e77c348064513052bf90a11952a190d0plougher				wait_queue_t wait;
2930aeb6601e77c348064513052bf90a11952a190d0plougher
2940aeb6601e77c348064513052bf90a11952a190d0plougher				init_waitqueue_entry(&wait, current);
2950aeb6601e77c348064513052bf90a11952a190d0plougher				add_wait_queue(&msblk->waitq, &wait);
2960aeb6601e77c348064513052bf90a11952a190d0plougher				set_current_state(TASK_UNINTERRUPTIBLE);
2970aeb6601e77c348064513052bf90a11952a190d0plougher 				up(&msblk->block_cache_mutex);
2980aeb6601e77c348064513052bf90a11952a190d0plougher				schedule();
2990aeb6601e77c348064513052bf90a11952a190d0plougher				set_current_state(TASK_RUNNING);
3000aeb6601e77c348064513052bf90a11952a190d0plougher				remove_wait_queue(&msblk->waitq, &wait);
3010aeb6601e77c348064513052bf90a11952a190d0plougher				continue;
3020aeb6601e77c348064513052bf90a11952a190d0plougher			}
3030aeb6601e77c348064513052bf90a11952a190d0plougher			msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS;
3040aeb6601e77c348064513052bf90a11952a190d0plougher
3050aeb6601e77c348064513052bf90a11952a190d0plougher			if (msblk->block_cache[i].block ==
3060aeb6601e77c348064513052bf90a11952a190d0plougher							SQUASHFS_INVALID_BLK) {
3070aeb6601e77c348064513052bf90a11952a190d0plougher				if (!(msblk->block_cache[i].data =
3080aeb6601e77c348064513052bf90a11952a190d0plougher						kmalloc(SQUASHFS_METADATA_SIZE,
3090aeb6601e77c348064513052bf90a11952a190d0plougher						GFP_KERNEL))) {
3100aeb6601e77c348064513052bf90a11952a190d0plougher					ERROR("Failed to allocate cache"
3110aeb6601e77c348064513052bf90a11952a190d0plougher							"block\n");
3120aeb6601e77c348064513052bf90a11952a190d0plougher					up(&msblk->block_cache_mutex);
3130aeb6601e77c348064513052bf90a11952a190d0plougher					goto out;
3140aeb6601e77c348064513052bf90a11952a190d0plougher				}
3150aeb6601e77c348064513052bf90a11952a190d0plougher			}
3160aeb6601e77c348064513052bf90a11952a190d0plougher
3170aeb6601e77c348064513052bf90a11952a190d0plougher			msblk->block_cache[i].block = SQUASHFS_USED_BLK;
3180aeb6601e77c348064513052bf90a11952a190d0plougher			up(&msblk->block_cache_mutex);
3190aeb6601e77c348064513052bf90a11952a190d0plougher
3200aeb6601e77c348064513052bf90a11952a190d0plougher			if (!(msblk->block_cache[i].length =
3210aeb6601e77c348064513052bf90a11952a190d0plougher						squashfs_read_data(s,
3220aeb6601e77c348064513052bf90a11952a190d0plougher						msblk->block_cache[i].data,
3230aeb6601e77c348064513052bf90a11952a190d0plougher						block, 0, &next_index))) {
3240aeb6601e77c348064513052bf90a11952a190d0plougher				ERROR("Unable to read cache block [%llx:%x]\n",
3250aeb6601e77c348064513052bf90a11952a190d0plougher						block, offset);
3260aeb6601e77c348064513052bf90a11952a190d0plougher				goto out;
3270aeb6601e77c348064513052bf90a11952a190d0plougher			}
3280aeb6601e77c348064513052bf90a11952a190d0plougher
3290aeb6601e77c348064513052bf90a11952a190d0plougher			down(&msblk->block_cache_mutex);
3300aeb6601e77c348064513052bf90a11952a190d0plougher			wake_up(&msblk->waitq);
3310aeb6601e77c348064513052bf90a11952a190d0plougher			msblk->block_cache[i].block = block;
3320aeb6601e77c348064513052bf90a11952a190d0plougher			msblk->block_cache[i].next_index = next_index;
3330aeb6601e77c348064513052bf90a11952a190d0plougher			TRACE("Read cache block [%llx:%x]\n", block, offset);
3340aeb6601e77c348064513052bf90a11952a190d0plougher		}
3350aeb6601e77c348064513052bf90a11952a190d0plougher
3360aeb6601e77c348064513052bf90a11952a190d0plougher		if (msblk->block_cache[i].block != block) {
3370aeb6601e77c348064513052bf90a11952a190d0plougher			up(&msblk->block_cache_mutex);
3380aeb6601e77c348064513052bf90a11952a190d0plougher			continue;
3390aeb6601e77c348064513052bf90a11952a190d0plougher		}
3400aeb6601e77c348064513052bf90a11952a190d0plougher
3410aeb6601e77c348064513052bf90a11952a190d0plougher		if ((bytes = msblk->block_cache[i].length - offset) >= length) {
3420aeb6601e77c348064513052bf90a11952a190d0plougher			if (buffer)
3430aeb6601e77c348064513052bf90a11952a190d0plougher				memcpy(buffer, msblk->block_cache[i].data +
3440aeb6601e77c348064513052bf90a11952a190d0plougher						offset, length);
3450aeb6601e77c348064513052bf90a11952a190d0plougher			if (msblk->block_cache[i].length - offset == length) {
3460aeb6601e77c348064513052bf90a11952a190d0plougher				*next_block = msblk->block_cache[i].next_index;
3470aeb6601e77c348064513052bf90a11952a190d0plougher				*next_offset = 0;
3480aeb6601e77c348064513052bf90a11952a190d0plougher			} else {
3490aeb6601e77c348064513052bf90a11952a190d0plougher				*next_block = block;
3500aeb6601e77c348064513052bf90a11952a190d0plougher				*next_offset = offset + length;
3510aeb6601e77c348064513052bf90a11952a190d0plougher			}
3520aeb6601e77c348064513052bf90a11952a190d0plougher			up(&msblk->block_cache_mutex);
3530aeb6601e77c348064513052bf90a11952a190d0plougher			goto finish;
3540aeb6601e77c348064513052bf90a11952a190d0plougher		} else {
3550aeb6601e77c348064513052bf90a11952a190d0plougher			if (buffer) {
3560aeb6601e77c348064513052bf90a11952a190d0plougher				memcpy(buffer, msblk->block_cache[i].data +
3570aeb6601e77c348064513052bf90a11952a190d0plougher						offset, bytes);
3580aeb6601e77c348064513052bf90a11952a190d0plougher				buffer += bytes;
3590aeb6601e77c348064513052bf90a11952a190d0plougher			}
3600aeb6601e77c348064513052bf90a11952a190d0plougher			block = msblk->block_cache[i].next_index;
3610aeb6601e77c348064513052bf90a11952a190d0plougher			up(&msblk->block_cache_mutex);
3620aeb6601e77c348064513052bf90a11952a190d0plougher			length -= bytes;
3630aeb6601e77c348064513052bf90a11952a190d0plougher			offset = 0;
3640aeb6601e77c348064513052bf90a11952a190d0plougher		}
3650aeb6601e77c348064513052bf90a11952a190d0plougher	}
3660aeb6601e77c348064513052bf90a11952a190d0plougher
3670aeb6601e77c348064513052bf90a11952a190d0plougherfinish:
3680aeb6601e77c348064513052bf90a11952a190d0plougher	return return_length;
3690aeb6601e77c348064513052bf90a11952a190d0plougherout:
3700aeb6601e77c348064513052bf90a11952a190d0plougher	return 0;
3710aeb6601e77c348064513052bf90a11952a190d0plougher}
3720aeb6601e77c348064513052bf90a11952a190d0plougher
3730aeb6601e77c348064513052bf90a11952a190d0plougher
3740aeb6601e77c348064513052bf90a11952a190d0plougherstatic int get_fragment_location(struct super_block *s, unsigned int fragment,
3750aeb6601e77c348064513052bf90a11952a190d0plougher				long long *fragment_start_block,
3760aeb6601e77c348064513052bf90a11952a190d0plougher				unsigned int *fragment_size)
3770aeb6601e77c348064513052bf90a11952a190d0plougher{
3780aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
3790aeb6601e77c348064513052bf90a11952a190d0plougher	long long start_block =
3800aeb6601e77c348064513052bf90a11952a190d0plougher		msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];
3810aeb6601e77c348064513052bf90a11952a190d0plougher	int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
3820aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_fragment_entry fragment_entry;
3830aeb6601e77c348064513052bf90a11952a190d0plougher
3840aeb6601e77c348064513052bf90a11952a190d0plougher	if (msblk->swap) {
3850aeb6601e77c348064513052bf90a11952a190d0plougher		struct squashfs_fragment_entry sfragment_entry;
3860aeb6601e77c348064513052bf90a11952a190d0plougher
3870aeb6601e77c348064513052bf90a11952a190d0plougher		if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
3880aeb6601e77c348064513052bf90a11952a190d0plougher					start_block, offset,
3890aeb6601e77c348064513052bf90a11952a190d0plougher					sizeof(sfragment_entry), &start_block,
3900aeb6601e77c348064513052bf90a11952a190d0plougher					&offset))
3910aeb6601e77c348064513052bf90a11952a190d0plougher			goto out;
3920aeb6601e77c348064513052bf90a11952a190d0plougher		SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);
3930aeb6601e77c348064513052bf90a11952a190d0plougher	} else
3940aeb6601e77c348064513052bf90a11952a190d0plougher		if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
3950aeb6601e77c348064513052bf90a11952a190d0plougher					start_block, offset,
3960aeb6601e77c348064513052bf90a11952a190d0plougher					sizeof(fragment_entry), &start_block,
3970aeb6601e77c348064513052bf90a11952a190d0plougher					&offset))
3980aeb6601e77c348064513052bf90a11952a190d0plougher			goto out;
3990aeb6601e77c348064513052bf90a11952a190d0plougher
4000aeb6601e77c348064513052bf90a11952a190d0plougher	*fragment_start_block = fragment_entry.start_block;
4010aeb6601e77c348064513052bf90a11952a190d0plougher	*fragment_size = fragment_entry.size;
4020aeb6601e77c348064513052bf90a11952a190d0plougher
4030aeb6601e77c348064513052bf90a11952a190d0plougher	return 1;
4040aeb6601e77c348064513052bf90a11952a190d0plougher
4050aeb6601e77c348064513052bf90a11952a190d0plougherout:
4060aeb6601e77c348064513052bf90a11952a190d0plougher	return 0;
4070aeb6601e77c348064513052bf90a11952a190d0plougher}
4080aeb6601e77c348064513052bf90a11952a190d0plougher
4090aeb6601e77c348064513052bf90a11952a190d0plougher
4100aeb6601e77c348064513052bf90a11952a190d0plougherSQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct
4110aeb6601e77c348064513052bf90a11952a190d0plougher					squashfs_fragment_cache *fragment)
4120aeb6601e77c348064513052bf90a11952a190d0plougher{
4130aeb6601e77c348064513052bf90a11952a190d0plougher	down(&msblk->fragment_mutex);
4140aeb6601e77c348064513052bf90a11952a190d0plougher	fragment->locked --;
4150aeb6601e77c348064513052bf90a11952a190d0plougher	wake_up(&msblk->fragment_wait_queue);
4160aeb6601e77c348064513052bf90a11952a190d0plougher	up(&msblk->fragment_mutex);
4170aeb6601e77c348064513052bf90a11952a190d0plougher}
4180aeb6601e77c348064513052bf90a11952a190d0plougher
4190aeb6601e77c348064513052bf90a11952a190d0plougher
4200aeb6601e77c348064513052bf90a11952a190d0plougherSQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block
4210aeb6601e77c348064513052bf90a11952a190d0plougher					*s, long long start_block,
4220aeb6601e77c348064513052bf90a11952a190d0plougher					int length)
4230aeb6601e77c348064513052bf90a11952a190d0plougher{
4240aeb6601e77c348064513052bf90a11952a190d0plougher	int i, n;
4250aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
4260aeb6601e77c348064513052bf90a11952a190d0plougher
4270aeb6601e77c348064513052bf90a11952a190d0plougher	while ( 1 ) {
4280aeb6601e77c348064513052bf90a11952a190d0plougher		down(&msblk->fragment_mutex);
4290aeb6601e77c348064513052bf90a11952a190d0plougher
4300aeb6601e77c348064513052bf90a11952a190d0plougher		for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&
4310aeb6601e77c348064513052bf90a11952a190d0plougher				msblk->fragment[i].block != start_block; i++);
4320aeb6601e77c348064513052bf90a11952a190d0plougher
4330aeb6601e77c348064513052bf90a11952a190d0plougher		if (i == SQUASHFS_CACHED_FRAGMENTS) {
4340aeb6601e77c348064513052bf90a11952a190d0plougher			for (i = msblk->next_fragment, n =
4350aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_CACHED_FRAGMENTS; n &&
4360aeb6601e77c348064513052bf90a11952a190d0plougher				msblk->fragment[i].locked; n--, i = (i + 1) %
4370aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_CACHED_FRAGMENTS);
4380aeb6601e77c348064513052bf90a11952a190d0plougher
4390aeb6601e77c348064513052bf90a11952a190d0plougher			if (n == 0) {
4400aeb6601e77c348064513052bf90a11952a190d0plougher				wait_queue_t wait;
4410aeb6601e77c348064513052bf90a11952a190d0plougher
4420aeb6601e77c348064513052bf90a11952a190d0plougher				init_waitqueue_entry(&wait, current);
4430aeb6601e77c348064513052bf90a11952a190d0plougher				add_wait_queue(&msblk->fragment_wait_queue,
4440aeb6601e77c348064513052bf90a11952a190d0plougher									&wait);
4450aeb6601e77c348064513052bf90a11952a190d0plougher				set_current_state(TASK_UNINTERRUPTIBLE);
4460aeb6601e77c348064513052bf90a11952a190d0plougher				up(&msblk->fragment_mutex);
4470aeb6601e77c348064513052bf90a11952a190d0plougher				schedule();
4480aeb6601e77c348064513052bf90a11952a190d0plougher				set_current_state(TASK_RUNNING);
4490aeb6601e77c348064513052bf90a11952a190d0plougher				remove_wait_queue(&msblk->fragment_wait_queue,
4500aeb6601e77c348064513052bf90a11952a190d0plougher									&wait);
4510aeb6601e77c348064513052bf90a11952a190d0plougher				continue;
4520aeb6601e77c348064513052bf90a11952a190d0plougher			}
4530aeb6601e77c348064513052bf90a11952a190d0plougher			msblk->next_fragment = (msblk->next_fragment + 1) %
4540aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_CACHED_FRAGMENTS;
4550aeb6601e77c348064513052bf90a11952a190d0plougher
4560aeb6601e77c348064513052bf90a11952a190d0plougher			if (msblk->fragment[i].data == NULL)
457af371d91a8865df5ab3079887b86c76a48b6e405plougher				if (!(msblk->fragment[i].data = SQUASHFS_ALLOC
458af371d91a8865df5ab3079887b86c76a48b6e405plougher						(SQUASHFS_FILE_MAX_SIZE))) {
4590aeb6601e77c348064513052bf90a11952a190d0plougher					ERROR("Failed to allocate fragment "
4600aeb6601e77c348064513052bf90a11952a190d0plougher							"cache block\n");
4610aeb6601e77c348064513052bf90a11952a190d0plougher					up(&msblk->fragment_mutex);
4620aeb6601e77c348064513052bf90a11952a190d0plougher					goto out;
4630aeb6601e77c348064513052bf90a11952a190d0plougher				}
4640aeb6601e77c348064513052bf90a11952a190d0plougher
4650aeb6601e77c348064513052bf90a11952a190d0plougher			msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
4660aeb6601e77c348064513052bf90a11952a190d0plougher			msblk->fragment[i].locked = 1;
4670aeb6601e77c348064513052bf90a11952a190d0plougher			up(&msblk->fragment_mutex);
4680aeb6601e77c348064513052bf90a11952a190d0plougher
4690aeb6601e77c348064513052bf90a11952a190d0plougher			if (!(msblk->fragment[i].length = squashfs_read_data(s,
4700aeb6601e77c348064513052bf90a11952a190d0plougher						msblk->fragment[i].data,
4710aeb6601e77c348064513052bf90a11952a190d0plougher						start_block, length, NULL))) {
4720aeb6601e77c348064513052bf90a11952a190d0plougher				ERROR("Unable to read fragment cache block "
4730aeb6601e77c348064513052bf90a11952a190d0plougher							"[%llx]\n", start_block);
4740aeb6601e77c348064513052bf90a11952a190d0plougher				msblk->fragment[i].locked = 0;
4750aeb6601e77c348064513052bf90a11952a190d0plougher				goto out;
4760aeb6601e77c348064513052bf90a11952a190d0plougher			}
4770aeb6601e77c348064513052bf90a11952a190d0plougher
4780aeb6601e77c348064513052bf90a11952a190d0plougher			msblk->fragment[i].block = start_block;
4790aeb6601e77c348064513052bf90a11952a190d0plougher			TRACE("New fragment %d, start block %lld, locked %d\n",
4800aeb6601e77c348064513052bf90a11952a190d0plougher						i, msblk->fragment[i].block,
4810aeb6601e77c348064513052bf90a11952a190d0plougher						msblk->fragment[i].locked);
4820aeb6601e77c348064513052bf90a11952a190d0plougher			break;
4830aeb6601e77c348064513052bf90a11952a190d0plougher		}
4840aeb6601e77c348064513052bf90a11952a190d0plougher
4850aeb6601e77c348064513052bf90a11952a190d0plougher		msblk->fragment[i].locked++;
4860aeb6601e77c348064513052bf90a11952a190d0plougher		up(&msblk->fragment_mutex);
4870aeb6601e77c348064513052bf90a11952a190d0plougher		TRACE("Got fragment %d, start block %lld, locked %d\n", i,
4880aeb6601e77c348064513052bf90a11952a190d0plougher						msblk->fragment[i].block,
4890aeb6601e77c348064513052bf90a11952a190d0plougher						msblk->fragment[i].locked);
4900aeb6601e77c348064513052bf90a11952a190d0plougher		break;
4910aeb6601e77c348064513052bf90a11952a190d0plougher	}
4920aeb6601e77c348064513052bf90a11952a190d0plougher
4930aeb6601e77c348064513052bf90a11952a190d0plougher	return &msblk->fragment[i];
4940aeb6601e77c348064513052bf90a11952a190d0plougher
4950aeb6601e77c348064513052bf90a11952a190d0plougherout:
4960aeb6601e77c348064513052bf90a11952a190d0plougher	return NULL;
4970aeb6601e77c348064513052bf90a11952a190d0plougher}
4980aeb6601e77c348064513052bf90a11952a190d0plougher
4990aeb6601e77c348064513052bf90a11952a190d0plougher
5000aeb6601e77c348064513052bf90a11952a190d0plougherstatic struct inode *squashfs_new_inode(struct super_block *s,
5010aeb6601e77c348064513052bf90a11952a190d0plougher		struct squashfs_base_inode_header *inodeb)
5020aeb6601e77c348064513052bf90a11952a190d0plougher{
5030aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
5040aeb6601e77c348064513052bf90a11952a190d0plougher	struct inode *i = new_inode(s);
5050aeb6601e77c348064513052bf90a11952a190d0plougher
5060aeb6601e77c348064513052bf90a11952a190d0plougher	if (i) {
5070aeb6601e77c348064513052bf90a11952a190d0plougher		i->i_ino = inodeb->inode_number;
5080aeb6601e77c348064513052bf90a11952a190d0plougher		i->i_mtime = inodeb->mtime;
5090aeb6601e77c348064513052bf90a11952a190d0plougher		i->i_atime = inodeb->mtime;
5100aeb6601e77c348064513052bf90a11952a190d0plougher		i->i_ctime = inodeb->mtime;
5110aeb6601e77c348064513052bf90a11952a190d0plougher		i->i_uid = msblk->uid[inodeb->uid];
5120aeb6601e77c348064513052bf90a11952a190d0plougher		i->i_mode = inodeb->mode;
5130aeb6601e77c348064513052bf90a11952a190d0plougher		i->i_size = 0;
5140aeb6601e77c348064513052bf90a11952a190d0plougher		if (inodeb->guid == SQUASHFS_GUIDS)
5150aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_gid = i->i_uid;
5160aeb6601e77c348064513052bf90a11952a190d0plougher		else
5170aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_gid = msblk->guid[inodeb->guid];
5180aeb6601e77c348064513052bf90a11952a190d0plougher	}
5190aeb6601e77c348064513052bf90a11952a190d0plougher
5200aeb6601e77c348064513052bf90a11952a190d0plougher	return i;
5210aeb6601e77c348064513052bf90a11952a190d0plougher}
5220aeb6601e77c348064513052bf90a11952a190d0plougher
5230aeb6601e77c348064513052bf90a11952a190d0plougher
5240aeb6601e77c348064513052bf90a11952a190d0plougherstatic struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode)
5250aeb6601e77c348064513052bf90a11952a190d0plougher{
5260aeb6601e77c348064513052bf90a11952a190d0plougher	struct inode *i;
5270aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
5280aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_super_block *sblk = &msblk->sblk;
5290aeb6601e77c348064513052bf90a11952a190d0plougher	long long block = SQUASHFS_INODE_BLK(inode) +
5300aeb6601e77c348064513052bf90a11952a190d0plougher		sblk->inode_table_start;
5310aeb6601e77c348064513052bf90a11952a190d0plougher	unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
5320aeb6601e77c348064513052bf90a11952a190d0plougher	long long next_block;
5330aeb6601e77c348064513052bf90a11952a190d0plougher	unsigned int next_offset;
5340aeb6601e77c348064513052bf90a11952a190d0plougher	union squashfs_inode_header id, sid;
5350aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_base_inode_header *inodeb = &id.base,
5360aeb6601e77c348064513052bf90a11952a190d0plougher					  *sinodeb = &sid.base;
5370aeb6601e77c348064513052bf90a11952a190d0plougher
5380aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Entered squashfs_iget\n");
5390aeb6601e77c348064513052bf90a11952a190d0plougher
5400aeb6601e77c348064513052bf90a11952a190d0plougher	if (msblk->swap) {
5410aeb6601e77c348064513052bf90a11952a190d0plougher		if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
5420aeb6601e77c348064513052bf90a11952a190d0plougher					offset, sizeof(*sinodeb), &next_block,
5430aeb6601e77c348064513052bf90a11952a190d0plougher					&next_offset))
5440aeb6601e77c348064513052bf90a11952a190d0plougher			goto failed_read;
5450aeb6601e77c348064513052bf90a11952a190d0plougher		SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb,
5460aeb6601e77c348064513052bf90a11952a190d0plougher					sizeof(*sinodeb));
5470aeb6601e77c348064513052bf90a11952a190d0plougher	} else
5480aeb6601e77c348064513052bf90a11952a190d0plougher		if (!squashfs_get_cached_block(s, (char *) inodeb, block,
5490aeb6601e77c348064513052bf90a11952a190d0plougher					offset, sizeof(*inodeb), &next_block,
5500aeb6601e77c348064513052bf90a11952a190d0plougher					&next_offset))
5510aeb6601e77c348064513052bf90a11952a190d0plougher			goto failed_read;
5520aeb6601e77c348064513052bf90a11952a190d0plougher
5530aeb6601e77c348064513052bf90a11952a190d0plougher	switch(inodeb->inode_type) {
5540aeb6601e77c348064513052bf90a11952a190d0plougher		case SQUASHFS_FILE_TYPE: {
5550aeb6601e77c348064513052bf90a11952a190d0plougher			unsigned int frag_size;
5560aeb6601e77c348064513052bf90a11952a190d0plougher			long long frag_blk;
5570aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_reg_inode_header *inodep = &id.reg;
5580aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_reg_inode_header *sinodep = &sid.reg;
5590aeb6601e77c348064513052bf90a11952a190d0plougher
5600aeb6601e77c348064513052bf90a11952a190d0plougher			if (msblk->swap) {
5610aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(s, (char *)
5620aeb6601e77c348064513052bf90a11952a190d0plougher						sinodep, block, offset,
5630aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(*sinodep), &next_block,
5640aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
5650aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
5660aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);
5670aeb6601e77c348064513052bf90a11952a190d0plougher			} else
5680aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(s, (char *)
5690aeb6601e77c348064513052bf90a11952a190d0plougher						inodep, block, offset,
5700aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(*inodep), &next_block,
5710aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
5720aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
5730aeb6601e77c348064513052bf90a11952a190d0plougher
5740aeb6601e77c348064513052bf90a11952a190d0plougher			frag_blk = SQUASHFS_INVALID_BLK;
5750aeb6601e77c348064513052bf90a11952a190d0plougher			if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
5760aeb6601e77c348064513052bf90a11952a190d0plougher					!get_fragment_location(s,
5770aeb6601e77c348064513052bf90a11952a190d0plougher					inodep->fragment, &frag_blk, &frag_size))
5780aeb6601e77c348064513052bf90a11952a190d0plougher				goto failed_read;
5790aeb6601e77c348064513052bf90a11952a190d0plougher
5800aeb6601e77c348064513052bf90a11952a190d0plougher			if((i = squashfs_new_inode(s, inodeb)) == NULL)
5810aeb6601e77c348064513052bf90a11952a190d0plougher				goto failed_read1;
5820aeb6601e77c348064513052bf90a11952a190d0plougher
5830aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_nlink = 1;
5840aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_size = inodep->file_size;
5850aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_fop = &generic_ro_fops;
5860aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_mode |= S_IFREG;
5870aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_blocks = ((i->i_size - 1) >> 9) + 1;
5880aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_blksize = PAGE_CACHE_SIZE;
5890aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
5900aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
5910aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
5920aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->start_block = inodep->start_block;
5930aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->u.s1.block_list_start = next_block;
5940aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->offset = next_offset;
5950aeb6601e77c348064513052bf90a11952a190d0plougher			if (sblk->block_size > 4096)
5960aeb6601e77c348064513052bf90a11952a190d0plougher				i->i_data.a_ops = &squashfs_aops;
5970aeb6601e77c348064513052bf90a11952a190d0plougher			else
5980aeb6601e77c348064513052bf90a11952a190d0plougher				i->i_data.a_ops = &squashfs_aops_4K;
5990aeb6601e77c348064513052bf90a11952a190d0plougher
6000aeb6601e77c348064513052bf90a11952a190d0plougher			TRACE("File inode %x:%x, start_block %llx, "
6010aeb6601e77c348064513052bf90a11952a190d0plougher					"block_list_start %llx, offset %x\n",
6020aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_INODE_BLK(inode), offset,
6030aeb6601e77c348064513052bf90a11952a190d0plougher					inodep->start_block, next_block,
6040aeb6601e77c348064513052bf90a11952a190d0plougher					next_offset);
6050aeb6601e77c348064513052bf90a11952a190d0plougher			break;
6060aeb6601e77c348064513052bf90a11952a190d0plougher		}
6070aeb6601e77c348064513052bf90a11952a190d0plougher		case SQUASHFS_LREG_TYPE: {
6080aeb6601e77c348064513052bf90a11952a190d0plougher			unsigned int frag_size;
6090aeb6601e77c348064513052bf90a11952a190d0plougher			long long frag_blk;
6100aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_lreg_inode_header *inodep = &id.lreg;
6110aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_lreg_inode_header *sinodep = &sid.lreg;
6120aeb6601e77c348064513052bf90a11952a190d0plougher
6130aeb6601e77c348064513052bf90a11952a190d0plougher			if (msblk->swap) {
6140aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(s, (char *)
6150aeb6601e77c348064513052bf90a11952a190d0plougher						sinodep, block, offset,
6160aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(*sinodep), &next_block,
6170aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
6180aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
6190aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);
6200aeb6601e77c348064513052bf90a11952a190d0plougher			} else
6210aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(s, (char *)
6220aeb6601e77c348064513052bf90a11952a190d0plougher						inodep, block, offset,
6230aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(*inodep), &next_block,
6240aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
6250aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
6260aeb6601e77c348064513052bf90a11952a190d0plougher
6270aeb6601e77c348064513052bf90a11952a190d0plougher			frag_blk = SQUASHFS_INVALID_BLK;
6280aeb6601e77c348064513052bf90a11952a190d0plougher			if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
6290aeb6601e77c348064513052bf90a11952a190d0plougher					!get_fragment_location(s,
6300aeb6601e77c348064513052bf90a11952a190d0plougher					inodep->fragment, &frag_blk, &frag_size))
6310aeb6601e77c348064513052bf90a11952a190d0plougher				goto failed_read;
6320aeb6601e77c348064513052bf90a11952a190d0plougher
6330aeb6601e77c348064513052bf90a11952a190d0plougher			if((i = squashfs_new_inode(s, inodeb)) == NULL)
6340aeb6601e77c348064513052bf90a11952a190d0plougher				goto failed_read1;
6350aeb6601e77c348064513052bf90a11952a190d0plougher
6360aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_nlink = inodep->nlink;
6370aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_size = inodep->file_size;
6380aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_fop = &generic_ro_fops;
6390aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_mode |= S_IFREG;
6400aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_blocks = ((i->i_size - 1) >> 9) + 1;
6410aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_blksize = PAGE_CACHE_SIZE;
6420aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
6430aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
6440aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
6450aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->start_block = inodep->start_block;
6460aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->u.s1.block_list_start = next_block;
6470aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->offset = next_offset;
6480aeb6601e77c348064513052bf90a11952a190d0plougher			if (sblk->block_size > 4096)
6490aeb6601e77c348064513052bf90a11952a190d0plougher				i->i_data.a_ops = &squashfs_aops;
6500aeb6601e77c348064513052bf90a11952a190d0plougher			else
6510aeb6601e77c348064513052bf90a11952a190d0plougher				i->i_data.a_ops = &squashfs_aops_4K;
6520aeb6601e77c348064513052bf90a11952a190d0plougher
6530aeb6601e77c348064513052bf90a11952a190d0plougher			TRACE("File inode %x:%x, start_block %llx, "
6540aeb6601e77c348064513052bf90a11952a190d0plougher					"block_list_start %llx, offset %x\n",
6550aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_INODE_BLK(inode), offset,
6560aeb6601e77c348064513052bf90a11952a190d0plougher					inodep->start_block, next_block,
6570aeb6601e77c348064513052bf90a11952a190d0plougher					next_offset);
6580aeb6601e77c348064513052bf90a11952a190d0plougher			break;
6590aeb6601e77c348064513052bf90a11952a190d0plougher		}
6600aeb6601e77c348064513052bf90a11952a190d0plougher		case SQUASHFS_DIR_TYPE: {
6610aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_dir_inode_header *inodep = &id.dir;
6620aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_dir_inode_header *sinodep = &sid.dir;
6630aeb6601e77c348064513052bf90a11952a190d0plougher
6640aeb6601e77c348064513052bf90a11952a190d0plougher			if (msblk->swap) {
6650aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(s, (char *)
6660aeb6601e77c348064513052bf90a11952a190d0plougher						sinodep, block, offset,
6670aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(*sinodep), &next_block,
6680aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
6690aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
6700aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);
6710aeb6601e77c348064513052bf90a11952a190d0plougher			} else
6720aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(s, (char *)
6730aeb6601e77c348064513052bf90a11952a190d0plougher						inodep, block, offset,
6740aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(*inodep), &next_block,
6750aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
6760aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
6770aeb6601e77c348064513052bf90a11952a190d0plougher
6780aeb6601e77c348064513052bf90a11952a190d0plougher			if((i = squashfs_new_inode(s, inodeb)) == NULL)
6790aeb6601e77c348064513052bf90a11952a190d0plougher				goto failed_read1;
6800aeb6601e77c348064513052bf90a11952a190d0plougher
6810aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_nlink = inodep->nlink;
6820aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_size = inodep->file_size;
6830aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_op = &squashfs_dir_inode_ops;
6840aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_fop = &squashfs_dir_ops;
6850aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_mode |= S_IFDIR;
6860aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->start_block = inodep->start_block;
6870aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->offset = inodep->offset;
6880aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->u.s2.directory_index_count = 0;
6890aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
6900aeb6601e77c348064513052bf90a11952a190d0plougher
6910aeb6601e77c348064513052bf90a11952a190d0plougher			TRACE("Directory inode %x:%x, start_block %x, offset "
6920aeb6601e77c348064513052bf90a11952a190d0plougher					"%x\n", SQUASHFS_INODE_BLK(inode),
6930aeb6601e77c348064513052bf90a11952a190d0plougher					offset, inodep->start_block,
6940aeb6601e77c348064513052bf90a11952a190d0plougher					inodep->offset);
6950aeb6601e77c348064513052bf90a11952a190d0plougher			break;
6960aeb6601e77c348064513052bf90a11952a190d0plougher		}
6970aeb6601e77c348064513052bf90a11952a190d0plougher		case SQUASHFS_LDIR_TYPE: {
6980aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_ldir_inode_header *inodep = &id.ldir;
6990aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_ldir_inode_header *sinodep = &sid.ldir;
7000aeb6601e77c348064513052bf90a11952a190d0plougher
7010aeb6601e77c348064513052bf90a11952a190d0plougher			if (msblk->swap) {
7020aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(s, (char *)
7030aeb6601e77c348064513052bf90a11952a190d0plougher						sinodep, block, offset,
7040aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(*sinodep), &next_block,
7050aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
7060aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
7070aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep,
7080aeb6601e77c348064513052bf90a11952a190d0plougher						sinodep);
7090aeb6601e77c348064513052bf90a11952a190d0plougher			} else
7100aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(s, (char *)
7110aeb6601e77c348064513052bf90a11952a190d0plougher						inodep, block, offset,
7120aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(*inodep), &next_block,
7130aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
7140aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
7150aeb6601e77c348064513052bf90a11952a190d0plougher
7160aeb6601e77c348064513052bf90a11952a190d0plougher			if((i = squashfs_new_inode(s, inodeb)) == NULL)
7170aeb6601e77c348064513052bf90a11952a190d0plougher				goto failed_read1;
7180aeb6601e77c348064513052bf90a11952a190d0plougher
7190aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_nlink = inodep->nlink;
7200aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_size = inodep->file_size;
7210aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_op = &squashfs_dir_inode_ops;
7220aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_fop = &squashfs_dir_ops;
7230aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_mode |= S_IFDIR;
7240aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->start_block = inodep->start_block;
7250aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->offset = inodep->offset;
7260aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
7270aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->u.s2.directory_index_offset =
7280aeb6601e77c348064513052bf90a11952a190d0plougher								next_offset;
7290aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->u.s2.directory_index_count =
7300aeb6601e77c348064513052bf90a11952a190d0plougher								inodep->i_count;
7310aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
7320aeb6601e77c348064513052bf90a11952a190d0plougher
7330aeb6601e77c348064513052bf90a11952a190d0plougher			TRACE("Long directory inode %x:%x, start_block %x, "
7340aeb6601e77c348064513052bf90a11952a190d0plougher					"offset %x\n",
7350aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_INODE_BLK(inode), offset,
7360aeb6601e77c348064513052bf90a11952a190d0plougher					inodep->start_block, inodep->offset);
7370aeb6601e77c348064513052bf90a11952a190d0plougher			break;
7380aeb6601e77c348064513052bf90a11952a190d0plougher		}
7390aeb6601e77c348064513052bf90a11952a190d0plougher		case SQUASHFS_SYMLINK_TYPE: {
7400aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_symlink_inode_header *inodep =
7410aeb6601e77c348064513052bf90a11952a190d0plougher								&id.symlink;
7420aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_symlink_inode_header *sinodep =
7430aeb6601e77c348064513052bf90a11952a190d0plougher								&sid.symlink;
7440aeb6601e77c348064513052bf90a11952a190d0plougher
7450aeb6601e77c348064513052bf90a11952a190d0plougher			if (msblk->swap) {
7460aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(s, (char *)
7470aeb6601e77c348064513052bf90a11952a190d0plougher						sinodep, block, offset,
7480aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(*sinodep), &next_block,
7490aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
7500aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
7510aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep,
7520aeb6601e77c348064513052bf90a11952a190d0plougher								sinodep);
7530aeb6601e77c348064513052bf90a11952a190d0plougher			} else
7540aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(s, (char *)
7550aeb6601e77c348064513052bf90a11952a190d0plougher						inodep, block, offset,
7560aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(*inodep), &next_block,
7570aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
7580aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
7590aeb6601e77c348064513052bf90a11952a190d0plougher
7600aeb6601e77c348064513052bf90a11952a190d0plougher			if((i = squashfs_new_inode(s, inodeb)) == NULL)
7610aeb6601e77c348064513052bf90a11952a190d0plougher				goto failed_read1;
7620aeb6601e77c348064513052bf90a11952a190d0plougher
7630aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_nlink = inodep->nlink;
7640aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_size = inodep->symlink_size;
7650aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_op = &page_symlink_inode_operations;
7660aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_data.a_ops = &squashfs_symlink_aops;
7670aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_mode |= S_IFLNK;
7680aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->start_block = next_block;
7690aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_I(i)->offset = next_offset;
7700aeb6601e77c348064513052bf90a11952a190d0plougher
7710aeb6601e77c348064513052bf90a11952a190d0plougher			TRACE("Symbolic link inode %x:%x, start_block %llx, "
7720aeb6601e77c348064513052bf90a11952a190d0plougher					"offset %x\n",
7730aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_INODE_BLK(inode), offset,
7740aeb6601e77c348064513052bf90a11952a190d0plougher					next_block, next_offset);
7750aeb6601e77c348064513052bf90a11952a190d0plougher			break;
7760aeb6601e77c348064513052bf90a11952a190d0plougher		 }
7770aeb6601e77c348064513052bf90a11952a190d0plougher		 case SQUASHFS_BLKDEV_TYPE:
7780aeb6601e77c348064513052bf90a11952a190d0plougher		 case SQUASHFS_CHRDEV_TYPE: {
7790aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_dev_inode_header *inodep = &id.dev;
7800aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_dev_inode_header *sinodep = &sid.dev;
7810aeb6601e77c348064513052bf90a11952a190d0plougher
7820aeb6601e77c348064513052bf90a11952a190d0plougher			if (msblk->swap) {
7830aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(s, (char *)
7840aeb6601e77c348064513052bf90a11952a190d0plougher						sinodep, block, offset,
7850aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(*sinodep), &next_block,
7860aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
7870aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
7880aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);
7890aeb6601e77c348064513052bf90a11952a190d0plougher			} else
7900aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(s, (char *)
7910aeb6601e77c348064513052bf90a11952a190d0plougher						inodep, block, offset,
7920aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(*inodep), &next_block,
7930aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
7940aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
7950aeb6601e77c348064513052bf90a11952a190d0plougher
7960aeb6601e77c348064513052bf90a11952a190d0plougher			if ((i = squashfs_new_inode(s, inodeb)) == NULL)
7970aeb6601e77c348064513052bf90a11952a190d0plougher				goto failed_read1;
7980aeb6601e77c348064513052bf90a11952a190d0plougher
7990aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_nlink = inodep->nlink;
8000aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_mode |= (inodeb->inode_type ==
8010aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_CHRDEV_TYPE) ?  S_IFCHR :
8020aeb6601e77c348064513052bf90a11952a190d0plougher					S_IFBLK;
803244f83fd9ba894f8aafbc409b3ea97a492c67ca2plougher			init_special_inode(i, i->i_mode, inodep->rdev);
8040aeb6601e77c348064513052bf90a11952a190d0plougher
8050aeb6601e77c348064513052bf90a11952a190d0plougher			TRACE("Device inode %x:%x, rdev %x\n",
8060aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_INODE_BLK(inode), offset,
8070aeb6601e77c348064513052bf90a11952a190d0plougher					inodep->rdev);
8080aeb6601e77c348064513052bf90a11952a190d0plougher			break;
8090aeb6601e77c348064513052bf90a11952a190d0plougher		 }
8100aeb6601e77c348064513052bf90a11952a190d0plougher		 case SQUASHFS_FIFO_TYPE:
8110aeb6601e77c348064513052bf90a11952a190d0plougher		 case SQUASHFS_SOCKET_TYPE: {
8120aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_ipc_inode_header *inodep = &id.ipc;
8130aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_ipc_inode_header *sinodep = &sid.ipc;
8140aeb6601e77c348064513052bf90a11952a190d0plougher
8150aeb6601e77c348064513052bf90a11952a190d0plougher			if (msblk->swap) {
8160aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(s, (char *)
8170aeb6601e77c348064513052bf90a11952a190d0plougher						sinodep, block, offset,
8180aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(*sinodep), &next_block,
8190aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
8200aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
8210aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);
8220aeb6601e77c348064513052bf90a11952a190d0plougher			} else
8230aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(s, (char *)
8240aeb6601e77c348064513052bf90a11952a190d0plougher						inodep, block, offset,
8250aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(*inodep), &next_block,
8260aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
8270aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
8280aeb6601e77c348064513052bf90a11952a190d0plougher
8290aeb6601e77c348064513052bf90a11952a190d0plougher			if ((i = squashfs_new_inode(s, inodeb)) == NULL)
8300aeb6601e77c348064513052bf90a11952a190d0plougher				goto failed_read1;
8310aeb6601e77c348064513052bf90a11952a190d0plougher
8320aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_nlink = inodep->nlink;
8330aeb6601e77c348064513052bf90a11952a190d0plougher			i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
8340aeb6601e77c348064513052bf90a11952a190d0plougher							? S_IFIFO : S_IFSOCK;
8350aeb6601e77c348064513052bf90a11952a190d0plougher			init_special_inode(i, i->i_mode, 0);
8360aeb6601e77c348064513052bf90a11952a190d0plougher			break;
8370aeb6601e77c348064513052bf90a11952a190d0plougher		 }
8380aeb6601e77c348064513052bf90a11952a190d0plougher		 default:
8390aeb6601e77c348064513052bf90a11952a190d0plougher			ERROR("Unknown inode type %d in squashfs_iget!\n",
8400aeb6601e77c348064513052bf90a11952a190d0plougher					inodeb->inode_type);
8410aeb6601e77c348064513052bf90a11952a190d0plougher			goto failed_read1;
8420aeb6601e77c348064513052bf90a11952a190d0plougher	}
8430aeb6601e77c348064513052bf90a11952a190d0plougher
8440aeb6601e77c348064513052bf90a11952a190d0plougher	insert_inode_hash(i);
8450aeb6601e77c348064513052bf90a11952a190d0plougher	return i;
8460aeb6601e77c348064513052bf90a11952a190d0plougher
8470aeb6601e77c348064513052bf90a11952a190d0plougherfailed_read:
8480aeb6601e77c348064513052bf90a11952a190d0plougher	ERROR("Unable to read inode [%llx:%x]\n", block, offset);
8490aeb6601e77c348064513052bf90a11952a190d0plougher
8500aeb6601e77c348064513052bf90a11952a190d0plougherfailed_read1:
8510aeb6601e77c348064513052bf90a11952a190d0plougher	return NULL;
8520aeb6601e77c348064513052bf90a11952a190d0plougher}
8530aeb6601e77c348064513052bf90a11952a190d0plougher
8540aeb6601e77c348064513052bf90a11952a190d0plougher
8550aeb6601e77c348064513052bf90a11952a190d0plougherint read_fragment_index_table(struct super_block *s)
8560aeb6601e77c348064513052bf90a11952a190d0plougher{
8570aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
8580aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_super_block *sblk = &msblk->sblk;
8590aeb6601e77c348064513052bf90a11952a190d0plougher
8600aeb6601e77c348064513052bf90a11952a190d0plougher	if (!(msblk->fragment_index = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES
8610aeb6601e77c348064513052bf90a11952a190d0plougher					(sblk->fragments), GFP_KERNEL))) {
8620aeb6601e77c348064513052bf90a11952a190d0plougher		ERROR("Failed to allocate uid/gid table\n");
8630aeb6601e77c348064513052bf90a11952a190d0plougher		return 0;
8640aeb6601e77c348064513052bf90a11952a190d0plougher	}
8650aeb6601e77c348064513052bf90a11952a190d0plougher
8660aeb6601e77c348064513052bf90a11952a190d0plougher	if (SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments) &&
8670aeb6601e77c348064513052bf90a11952a190d0plougher					!squashfs_read_data(s, (char *)
8680aeb6601e77c348064513052bf90a11952a190d0plougher					msblk->fragment_index,
8690aeb6601e77c348064513052bf90a11952a190d0plougher					sblk->fragment_table_start,
8700aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_FRAGMENT_INDEX_BYTES
8710aeb6601e77c348064513052bf90a11952a190d0plougher					(sblk->fragments) |
8720aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
8730aeb6601e77c348064513052bf90a11952a190d0plougher		ERROR("unable to read fragment index table\n");
8740aeb6601e77c348064513052bf90a11952a190d0plougher		return 0;
8750aeb6601e77c348064513052bf90a11952a190d0plougher	}
8760aeb6601e77c348064513052bf90a11952a190d0plougher
8770aeb6601e77c348064513052bf90a11952a190d0plougher	if (msblk->swap) {
8780aeb6601e77c348064513052bf90a11952a190d0plougher		int i;
8790aeb6601e77c348064513052bf90a11952a190d0plougher		long long fragment;
8800aeb6601e77c348064513052bf90a11952a190d0plougher
8810aeb6601e77c348064513052bf90a11952a190d0plougher		for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments);
8820aeb6601e77c348064513052bf90a11952a190d0plougher									i++) {
8830aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
8840aeb6601e77c348064513052bf90a11952a190d0plougher						&msblk->fragment_index[i], 1);
8850aeb6601e77c348064513052bf90a11952a190d0plougher			msblk->fragment_index[i] = fragment;
8860aeb6601e77c348064513052bf90a11952a190d0plougher		}
8870aeb6601e77c348064513052bf90a11952a190d0plougher	}
8880aeb6601e77c348064513052bf90a11952a190d0plougher
8890aeb6601e77c348064513052bf90a11952a190d0plougher	return 1;
8900aeb6601e77c348064513052bf90a11952a190d0plougher}
8910aeb6601e77c348064513052bf90a11952a190d0plougher
8920aeb6601e77c348064513052bf90a11952a190d0plougher
8930aeb6601e77c348064513052bf90a11952a190d0plougherstatic int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
8940aeb6601e77c348064513052bf90a11952a190d0plougher{
8950aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_super_block *sblk = &msblk->sblk;
8960aeb6601e77c348064513052bf90a11952a190d0plougher
8970aeb6601e77c348064513052bf90a11952a190d0plougher	msblk->iget = squashfs_iget;
8980aeb6601e77c348064513052bf90a11952a190d0plougher	msblk->read_blocklist = read_blocklist;
8990aeb6601e77c348064513052bf90a11952a190d0plougher	msblk->read_fragment_index_table = read_fragment_index_table;
9000aeb6601e77c348064513052bf90a11952a190d0plougher
9010aeb6601e77c348064513052bf90a11952a190d0plougher	if (sblk->s_major == 1) {
9020aeb6601e77c348064513052bf90a11952a190d0plougher		if (!squashfs_1_0_supported(msblk)) {
9030aeb6601e77c348064513052bf90a11952a190d0plougher			SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "
9040aeb6601e77c348064513052bf90a11952a190d0plougher				"are unsupported\n");
9050aeb6601e77c348064513052bf90a11952a190d0plougher			SERROR("Please recompile with "
9060aeb6601e77c348064513052bf90a11952a190d0plougher				"Squashfs 1.0 support enabled\n");
9070aeb6601e77c348064513052bf90a11952a190d0plougher			return 0;
9080aeb6601e77c348064513052bf90a11952a190d0plougher		}
9090aeb6601e77c348064513052bf90a11952a190d0plougher	} else if (sblk->s_major == 2) {
9100aeb6601e77c348064513052bf90a11952a190d0plougher		if (!squashfs_2_0_supported(msblk)) {
9110aeb6601e77c348064513052bf90a11952a190d0plougher			SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "
9120aeb6601e77c348064513052bf90a11952a190d0plougher				"are unsupported\n");
9130aeb6601e77c348064513052bf90a11952a190d0plougher			SERROR("Please recompile with "
9140aeb6601e77c348064513052bf90a11952a190d0plougher				"Squashfs 2.0 support enabled\n");
9150aeb6601e77c348064513052bf90a11952a190d0plougher			return 0;
9160aeb6601e77c348064513052bf90a11952a190d0plougher		}
9170aeb6601e77c348064513052bf90a11952a190d0plougher	} else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
9180aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_MINOR) {
9190aeb6601e77c348064513052bf90a11952a190d0plougher		SERROR("Major/Minor mismatch, trying to mount newer %d.%d "
9200aeb6601e77c348064513052bf90a11952a190d0plougher				"filesystem\n", sblk->s_major, sblk->s_minor);
9210aeb6601e77c348064513052bf90a11952a190d0plougher		SERROR("Please update your kernel\n");
9220aeb6601e77c348064513052bf90a11952a190d0plougher		return 0;
9230aeb6601e77c348064513052bf90a11952a190d0plougher	}
9240aeb6601e77c348064513052bf90a11952a190d0plougher
9250aeb6601e77c348064513052bf90a11952a190d0plougher	return 1;
9260aeb6601e77c348064513052bf90a11952a190d0plougher}
9270aeb6601e77c348064513052bf90a11952a190d0plougher
9280aeb6601e77c348064513052bf90a11952a190d0plougher
9290aeb6601e77c348064513052bf90a11952a190d0plougherstatic struct super_block *squashfs_read_super(struct super_block *s,
9300aeb6601e77c348064513052bf90a11952a190d0plougher		void *data, int silent)
9310aeb6601e77c348064513052bf90a11952a190d0plougher{
9320aeb6601e77c348064513052bf90a11952a190d0plougher	kdev_t dev = s->s_dev;
9330aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
9340aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_super_block *sblk = &msblk->sblk;
9350aeb6601e77c348064513052bf90a11952a190d0plougher	int i;
9360aeb6601e77c348064513052bf90a11952a190d0plougher	struct inode *root;
937410dd958c15c73d91e877a0afe085bfaee37d9ffplougher
938410dd958c15c73d91e877a0afe085bfaee37d9ffplougher	if (!(msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize()))) {
939410dd958c15c73d91e877a0afe085bfaee37d9ffplougher		ERROR("Failed to allocate zlib workspace\n");
940410dd958c15c73d91e877a0afe085bfaee37d9ffplougher		goto failed_mount;
941410dd958c15c73d91e877a0afe085bfaee37d9ffplougher	}
942410dd958c15c73d91e877a0afe085bfaee37d9ffplougher
9430aeb6601e77c348064513052bf90a11952a190d0plougher	msblk->devblksize = get_hardsect_size(dev);
9440aeb6601e77c348064513052bf90a11952a190d0plougher	if(msblk->devblksize < BLOCK_SIZE)
9450aeb6601e77c348064513052bf90a11952a190d0plougher		msblk->devblksize = BLOCK_SIZE;
9460aeb6601e77c348064513052bf90a11952a190d0plougher	msblk->devblksize_log2 = ffz(~msblk->devblksize);
9470aeb6601e77c348064513052bf90a11952a190d0plougher        set_blocksize(dev, msblk->devblksize);
9480aeb6601e77c348064513052bf90a11952a190d0plougher	s->s_blocksize = msblk->devblksize;
9490aeb6601e77c348064513052bf90a11952a190d0plougher	s->s_blocksize_bits = msblk->devblksize_log2;
9500aeb6601e77c348064513052bf90a11952a190d0plougher
9510aeb6601e77c348064513052bf90a11952a190d0plougher	init_MUTEX(&msblk->read_data_mutex);
9520aeb6601e77c348064513052bf90a11952a190d0plougher	init_MUTEX(&msblk->read_page_mutex);
9530aeb6601e77c348064513052bf90a11952a190d0plougher	init_MUTEX(&msblk->block_cache_mutex);
9540aeb6601e77c348064513052bf90a11952a190d0plougher	init_MUTEX(&msblk->fragment_mutex);
9550aeb6601e77c348064513052bf90a11952a190d0plougher
9560aeb6601e77c348064513052bf90a11952a190d0plougher	init_waitqueue_head(&msblk->waitq);
9570aeb6601e77c348064513052bf90a11952a190d0plougher	init_waitqueue_head(&msblk->fragment_wait_queue);
9580aeb6601e77c348064513052bf90a11952a190d0plougher
9590aeb6601e77c348064513052bf90a11952a190d0plougher	if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
9600aeb6601e77c348064513052bf90a11952a190d0plougher					sizeof(struct squashfs_super_block) |
9610aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
9620aeb6601e77c348064513052bf90a11952a190d0plougher		SERROR("unable to read superblock\n");
9630aeb6601e77c348064513052bf90a11952a190d0plougher		goto failed_mount;
9640aeb6601e77c348064513052bf90a11952a190d0plougher	}
9650aeb6601e77c348064513052bf90a11952a190d0plougher
9660aeb6601e77c348064513052bf90a11952a190d0plougher	/* Check it is a SQUASHFS superblock */
9670aeb6601e77c348064513052bf90a11952a190d0plougher	msblk->swap = 0;
9680aeb6601e77c348064513052bf90a11952a190d0plougher	if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) {
9690aeb6601e77c348064513052bf90a11952a190d0plougher		if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) {
9700aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_super_block ssblk;
9710aeb6601e77c348064513052bf90a11952a190d0plougher
9720aeb6601e77c348064513052bf90a11952a190d0plougher			WARNING("Mounting a different endian SQUASHFS "
9730aeb6601e77c348064513052bf90a11952a190d0plougher				"filesystem on %s\n", bdevname(dev));
9740aeb6601e77c348064513052bf90a11952a190d0plougher
9750aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);
9760aeb6601e77c348064513052bf90a11952a190d0plougher			memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));
9770aeb6601e77c348064513052bf90a11952a190d0plougher			msblk->swap = 1;
9780aeb6601e77c348064513052bf90a11952a190d0plougher		} else  {
9790aeb6601e77c348064513052bf90a11952a190d0plougher			SERROR("Can't find a SQUASHFS superblock on %s\n",
9800aeb6601e77c348064513052bf90a11952a190d0plougher							bdevname(dev));
9810aeb6601e77c348064513052bf90a11952a190d0plougher			goto failed_mount;
9820aeb6601e77c348064513052bf90a11952a190d0plougher		}
9830aeb6601e77c348064513052bf90a11952a190d0plougher	}
9840aeb6601e77c348064513052bf90a11952a190d0plougher
9850aeb6601e77c348064513052bf90a11952a190d0plougher	/* Check the MAJOR & MINOR versions */
9860aeb6601e77c348064513052bf90a11952a190d0plougher	if(!supported_squashfs_filesystem(msblk, silent))
9870aeb6601e77c348064513052bf90a11952a190d0plougher		goto failed_mount;
9880aeb6601e77c348064513052bf90a11952a190d0plougher
9890aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Found valid superblock on %s\n", bdevname(dev));
9900aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Inodes are %scompressed\n",
9910aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_UNCOMPRESSED_INODES
9920aeb6601e77c348064513052bf90a11952a190d0plougher					(sblk->flags) ? "un" : "");
9930aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Data is %scompressed\n",
9940aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
9950aeb6601e77c348064513052bf90a11952a190d0plougher					? "un" : "");
9960aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Check data is %s present in the filesystem\n",
9970aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_CHECK_DATA(sblk->flags) ?
9980aeb6601e77c348064513052bf90a11952a190d0plougher					"" : "not");
9990aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);
10000aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Block size %d\n", sblk->block_size);
10010aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Number of inodes %d\n", sblk->inodes);
10020aeb6601e77c348064513052bf90a11952a190d0plougher	if (sblk->s_major > 1)
10030aeb6601e77c348064513052bf90a11952a190d0plougher		TRACE("Number of fragments %d\n", sblk->fragments);
10040aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Number of uids %d\n", sblk->no_uids);
10050aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Number of gids %d\n", sblk->no_guids);
10060aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);
10070aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);
10080aeb6601e77c348064513052bf90a11952a190d0plougher	if (sblk->s_major > 1)
10090aeb6601e77c348064513052bf90a11952a190d0plougher		TRACE("sblk->fragment_table_start %llx\n",
10100aeb6601e77c348064513052bf90a11952a190d0plougher					sblk->fragment_table_start);
10110aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("sblk->uid_start %llx\n", sblk->uid_start);
10120aeb6601e77c348064513052bf90a11952a190d0plougher
10130aeb6601e77c348064513052bf90a11952a190d0plougher	s->s_flags |= MS_RDONLY;
10140aeb6601e77c348064513052bf90a11952a190d0plougher	s->s_op = &squashfs_ops;
10150aeb6601e77c348064513052bf90a11952a190d0plougher
10160aeb6601e77c348064513052bf90a11952a190d0plougher	/* Init inode_table block pointer array */
10170aeb6601e77c348064513052bf90a11952a190d0plougher	if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
10180aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_CACHED_BLKS, GFP_KERNEL))) {
10190aeb6601e77c348064513052bf90a11952a190d0plougher		ERROR("Failed to allocate block cache\n");
10200aeb6601e77c348064513052bf90a11952a190d0plougher		goto failed_mount;
10210aeb6601e77c348064513052bf90a11952a190d0plougher	}
10220aeb6601e77c348064513052bf90a11952a190d0plougher
10230aeb6601e77c348064513052bf90a11952a190d0plougher	for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
10240aeb6601e77c348064513052bf90a11952a190d0plougher		msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
10250aeb6601e77c348064513052bf90a11952a190d0plougher
10260aeb6601e77c348064513052bf90a11952a190d0plougher	msblk->next_cache = 0;
10270aeb6601e77c348064513052bf90a11952a190d0plougher
10280aeb6601e77c348064513052bf90a11952a190d0plougher	/* Allocate read_data block */
10290aeb6601e77c348064513052bf90a11952a190d0plougher	msblk->read_size = (sblk->block_size < SQUASHFS_METADATA_SIZE) ?
10300aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_METADATA_SIZE :
10310aeb6601e77c348064513052bf90a11952a190d0plougher					sblk->block_size;
10320aeb6601e77c348064513052bf90a11952a190d0plougher
10330aeb6601e77c348064513052bf90a11952a190d0plougher	if (!(msblk->read_data = kmalloc(msblk->read_size, GFP_KERNEL))) {
10340aeb6601e77c348064513052bf90a11952a190d0plougher		ERROR("Failed to allocate read_data block\n");
10350aeb6601e77c348064513052bf90a11952a190d0plougher		goto failed_mount;
10360aeb6601e77c348064513052bf90a11952a190d0plougher	}
10370aeb6601e77c348064513052bf90a11952a190d0plougher
10380aeb6601e77c348064513052bf90a11952a190d0plougher	/* Allocate read_page block */
10390aeb6601e77c348064513052bf90a11952a190d0plougher	if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) {
10400aeb6601e77c348064513052bf90a11952a190d0plougher		ERROR("Failed to allocate read_page block\n");
10410aeb6601e77c348064513052bf90a11952a190d0plougher		goto failed_mount;
10420aeb6601e77c348064513052bf90a11952a190d0plougher	}
10430aeb6601e77c348064513052bf90a11952a190d0plougher
10440aeb6601e77c348064513052bf90a11952a190d0plougher	/* Allocate uid and gid tables */
10450aeb6601e77c348064513052bf90a11952a190d0plougher	if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
10460aeb6601e77c348064513052bf90a11952a190d0plougher					sizeof(unsigned int), GFP_KERNEL))) {
10470aeb6601e77c348064513052bf90a11952a190d0plougher		ERROR("Failed to allocate uid/gid table\n");
10480aeb6601e77c348064513052bf90a11952a190d0plougher		goto failed_mount;
10490aeb6601e77c348064513052bf90a11952a190d0plougher	}
10500aeb6601e77c348064513052bf90a11952a190d0plougher	msblk->guid = msblk->uid + sblk->no_uids;
10510aeb6601e77c348064513052bf90a11952a190d0plougher
10520aeb6601e77c348064513052bf90a11952a190d0plougher	if (msblk->swap) {
10530aeb6601e77c348064513052bf90a11952a190d0plougher		unsigned int suid[sblk->no_uids + sblk->no_guids];
10540aeb6601e77c348064513052bf90a11952a190d0plougher
10550aeb6601e77c348064513052bf90a11952a190d0plougher		if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,
10560aeb6601e77c348064513052bf90a11952a190d0plougher					((sblk->no_uids + sblk->no_guids) *
10570aeb6601e77c348064513052bf90a11952a190d0plougher					 sizeof(unsigned int)) |
10580aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
10590aeb6601e77c348064513052bf90a11952a190d0plougher			ERROR("unable to read uid/gid table\n");
10600aeb6601e77c348064513052bf90a11952a190d0plougher			goto failed_mount;
10610aeb6601e77c348064513052bf90a11952a190d0plougher		}
10620aeb6601e77c348064513052bf90a11952a190d0plougher
10630aeb6601e77c348064513052bf90a11952a190d0plougher		SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids +
10640aeb6601e77c348064513052bf90a11952a190d0plougher			sblk->no_guids), (sizeof(unsigned int) * 8));
10650aeb6601e77c348064513052bf90a11952a190d0plougher	} else
10660aeb6601e77c348064513052bf90a11952a190d0plougher		if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,
10670aeb6601e77c348064513052bf90a11952a190d0plougher					((sblk->no_uids + sblk->no_guids) *
10680aeb6601e77c348064513052bf90a11952a190d0plougher					 sizeof(unsigned int)) |
10690aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
10700aeb6601e77c348064513052bf90a11952a190d0plougher			ERROR("unable to read uid/gid table\n");
10710aeb6601e77c348064513052bf90a11952a190d0plougher			goto failed_mount;
10720aeb6601e77c348064513052bf90a11952a190d0plougher		}
10730aeb6601e77c348064513052bf90a11952a190d0plougher
10740aeb6601e77c348064513052bf90a11952a190d0plougher
10750aeb6601e77c348064513052bf90a11952a190d0plougher	if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))
10760aeb6601e77c348064513052bf90a11952a190d0plougher		goto allocate_root;
10770aeb6601e77c348064513052bf90a11952a190d0plougher
10780aeb6601e77c348064513052bf90a11952a190d0plougher	if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) *
10790aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) {
10800aeb6601e77c348064513052bf90a11952a190d0plougher		ERROR("Failed to allocate fragment block cache\n");
10810aeb6601e77c348064513052bf90a11952a190d0plougher		goto failed_mount;
10820aeb6601e77c348064513052bf90a11952a190d0plougher	}
10830aeb6601e77c348064513052bf90a11952a190d0plougher
10840aeb6601e77c348064513052bf90a11952a190d0plougher	for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {
10850aeb6601e77c348064513052bf90a11952a190d0plougher		msblk->fragment[i].locked = 0;
10860aeb6601e77c348064513052bf90a11952a190d0plougher		msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
10870aeb6601e77c348064513052bf90a11952a190d0plougher		msblk->fragment[i].data = NULL;
10880aeb6601e77c348064513052bf90a11952a190d0plougher	}
10890aeb6601e77c348064513052bf90a11952a190d0plougher
10900aeb6601e77c348064513052bf90a11952a190d0plougher	msblk->next_fragment = 0;
10910aeb6601e77c348064513052bf90a11952a190d0plougher
10920aeb6601e77c348064513052bf90a11952a190d0plougher	/* Allocate fragment index table */
10930aeb6601e77c348064513052bf90a11952a190d0plougher	if(msblk->read_fragment_index_table(s) == 0)
10940aeb6601e77c348064513052bf90a11952a190d0plougher		goto failed_mount;
10950aeb6601e77c348064513052bf90a11952a190d0plougher
10960aeb6601e77c348064513052bf90a11952a190d0plougherallocate_root:
10970aeb6601e77c348064513052bf90a11952a190d0plougher	if ((root = (msblk->iget)(s, sblk->root_inode)) == NULL)
10980aeb6601e77c348064513052bf90a11952a190d0plougher		goto failed_mount;
10990aeb6601e77c348064513052bf90a11952a190d0plougher
11000aeb6601e77c348064513052bf90a11952a190d0plougher	if ((s->s_root = d_alloc_root(root)) == NULL) {
11010aeb6601e77c348064513052bf90a11952a190d0plougher		ERROR("Root inode create failed\n");
11020aeb6601e77c348064513052bf90a11952a190d0plougher		iput(root);
11030aeb6601e77c348064513052bf90a11952a190d0plougher		goto failed_mount;
11040aeb6601e77c348064513052bf90a11952a190d0plougher	}
11050aeb6601e77c348064513052bf90a11952a190d0plougher
11060aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Leaving squashfs_read_super\n");
11070aeb6601e77c348064513052bf90a11952a190d0plougher	return s;
11080aeb6601e77c348064513052bf90a11952a190d0plougher
11090aeb6601e77c348064513052bf90a11952a190d0plougherfailed_mount:
11100aeb6601e77c348064513052bf90a11952a190d0plougher	kfree(msblk->fragment_index);
11110aeb6601e77c348064513052bf90a11952a190d0plougher	kfree(msblk->fragment);
11120aeb6601e77c348064513052bf90a11952a190d0plougher	kfree(msblk->uid);
11130aeb6601e77c348064513052bf90a11952a190d0plougher	kfree(msblk->read_page);
11140aeb6601e77c348064513052bf90a11952a190d0plougher	kfree(msblk->read_data);
11150aeb6601e77c348064513052bf90a11952a190d0plougher	kfree(msblk->block_cache);
11160aeb6601e77c348064513052bf90a11952a190d0plougher	kfree(msblk->fragment_index_2);
1117410dd958c15c73d91e877a0afe085bfaee37d9ffplougher	vfree(msblk->stream.workspace);
11180aeb6601e77c348064513052bf90a11952a190d0plougher	return NULL;
11190aeb6601e77c348064513052bf90a11952a190d0plougher}
11200aeb6601e77c348064513052bf90a11952a190d0plougher
11210aeb6601e77c348064513052bf90a11952a190d0plougher
11220aeb6601e77c348064513052bf90a11952a190d0plougherstatic int squashfs_statfs(struct super_block *s, struct statfs *buf)
11230aeb6601e77c348064513052bf90a11952a190d0plougher{
11240aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
11250aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_super_block *sblk = &msblk->sblk;
11260aeb6601e77c348064513052bf90a11952a190d0plougher
11270aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Entered squashfs_statfs\n");
11280aeb6601e77c348064513052bf90a11952a190d0plougher
11290aeb6601e77c348064513052bf90a11952a190d0plougher	buf->f_type = SQUASHFS_MAGIC;
11300aeb6601e77c348064513052bf90a11952a190d0plougher	buf->f_bsize = sblk->block_size;
11310aeb6601e77c348064513052bf90a11952a190d0plougher	buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1;
11320aeb6601e77c348064513052bf90a11952a190d0plougher	buf->f_bfree = buf->f_bavail = 0;
11330aeb6601e77c348064513052bf90a11952a190d0plougher	buf->f_files = sblk->inodes;
11340aeb6601e77c348064513052bf90a11952a190d0plougher	buf->f_ffree = 0;
11350aeb6601e77c348064513052bf90a11952a190d0plougher	buf->f_namelen = SQUASHFS_NAME_LEN;
11360aeb6601e77c348064513052bf90a11952a190d0plougher
11370aeb6601e77c348064513052bf90a11952a190d0plougher	return 0;
11380aeb6601e77c348064513052bf90a11952a190d0plougher}
11390aeb6601e77c348064513052bf90a11952a190d0plougher
11400aeb6601e77c348064513052bf90a11952a190d0plougher
11410aeb6601e77c348064513052bf90a11952a190d0plougherstatic int squashfs_symlink_readpage(struct file *file, struct page *page)
11420aeb6601e77c348064513052bf90a11952a190d0plougher{
11430aeb6601e77c348064513052bf90a11952a190d0plougher	struct inode *inode = page->mapping->host;
11440aeb6601e77c348064513052bf90a11952a190d0plougher	int index = page->index << PAGE_CACHE_SHIFT, length, bytes;
11450aeb6601e77c348064513052bf90a11952a190d0plougher	long long block = SQUASHFS_I(inode)->start_block;
11460aeb6601e77c348064513052bf90a11952a190d0plougher	int offset = SQUASHFS_I(inode)->offset;
11470aeb6601e77c348064513052bf90a11952a190d0plougher	void *pageaddr = kmap(page);
11480aeb6601e77c348064513052bf90a11952a190d0plougher
11490aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
11500aeb6601e77c348064513052bf90a11952a190d0plougher				"%llx, offset %x\n", page->index,
11510aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_I(inode)->start_block,
11520aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_I(inode)->offset);
11530aeb6601e77c348064513052bf90a11952a190d0plougher
11540aeb6601e77c348064513052bf90a11952a190d0plougher	for (length = 0; length < index; length += bytes) {
11550aeb6601e77c348064513052bf90a11952a190d0plougher		if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL,
11560aeb6601e77c348064513052bf90a11952a190d0plougher				block, offset, PAGE_CACHE_SIZE, &block,
11570aeb6601e77c348064513052bf90a11952a190d0plougher				&offset))) {
11580aeb6601e77c348064513052bf90a11952a190d0plougher			ERROR("Unable to read symbolic link [%llx:%x]\n", block,
11590aeb6601e77c348064513052bf90a11952a190d0plougher					offset);
11600aeb6601e77c348064513052bf90a11952a190d0plougher			goto skip_read;
11610aeb6601e77c348064513052bf90a11952a190d0plougher		}
11620aeb6601e77c348064513052bf90a11952a190d0plougher	}
11630aeb6601e77c348064513052bf90a11952a190d0plougher
11640aeb6601e77c348064513052bf90a11952a190d0plougher	if (length != index) {
11650aeb6601e77c348064513052bf90a11952a190d0plougher		ERROR("(squashfs_symlink_readpage) length != index\n");
11660aeb6601e77c348064513052bf90a11952a190d0plougher		bytes = 0;
11670aeb6601e77c348064513052bf90a11952a190d0plougher		goto skip_read;
11680aeb6601e77c348064513052bf90a11952a190d0plougher	}
11690aeb6601e77c348064513052bf90a11952a190d0plougher
11700aeb6601e77c348064513052bf90a11952a190d0plougher	bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE :
11710aeb6601e77c348064513052bf90a11952a190d0plougher					i_size_read(inode) - length;
11720aeb6601e77c348064513052bf90a11952a190d0plougher
11730aeb6601e77c348064513052bf90a11952a190d0plougher	if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block,
11740aeb6601e77c348064513052bf90a11952a190d0plougher					offset, bytes, &block, &offset)))
11750aeb6601e77c348064513052bf90a11952a190d0plougher		ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
11760aeb6601e77c348064513052bf90a11952a190d0plougher
11770aeb6601e77c348064513052bf90a11952a190d0plougherskip_read:
11780aeb6601e77c348064513052bf90a11952a190d0plougher	memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
11790aeb6601e77c348064513052bf90a11952a190d0plougher	kunmap(page);
11800aeb6601e77c348064513052bf90a11952a190d0plougher	SetPageUptodate(page);
11810aeb6601e77c348064513052bf90a11952a190d0plougher	UnlockPage(page);
11820aeb6601e77c348064513052bf90a11952a190d0plougher
11830aeb6601e77c348064513052bf90a11952a190d0plougher	return 0;
11840aeb6601e77c348064513052bf90a11952a190d0plougher}
11850aeb6601e77c348064513052bf90a11952a190d0plougher
11860aeb6601e77c348064513052bf90a11952a190d0plougher
11870aeb6601e77c348064513052bf90a11952a190d0plougherstruct meta_index *locate_meta_index(struct inode *inode, int index, int offset)
11880aeb6601e77c348064513052bf90a11952a190d0plougher{
11890aeb6601e77c348064513052bf90a11952a190d0plougher	struct meta_index *meta = NULL;
11900aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
11910aeb6601e77c348064513052bf90a11952a190d0plougher	int i;
11920aeb6601e77c348064513052bf90a11952a190d0plougher
11930aeb6601e77c348064513052bf90a11952a190d0plougher	down(&msblk->meta_index_mutex);
11940aeb6601e77c348064513052bf90a11952a190d0plougher
11950aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
11960aeb6601e77c348064513052bf90a11952a190d0plougher
11970aeb6601e77c348064513052bf90a11952a190d0plougher	if(msblk->meta_index == NULL)
11980aeb6601e77c348064513052bf90a11952a190d0plougher		goto not_allocated;
11990aeb6601e77c348064513052bf90a11952a190d0plougher
12000aeb6601e77c348064513052bf90a11952a190d0plougher	for (i = 0; i < SQUASHFS_META_NUMBER; i ++)
12010aeb6601e77c348064513052bf90a11952a190d0plougher		if (msblk->meta_index[i].inode_number == inode->i_ino &&
12020aeb6601e77c348064513052bf90a11952a190d0plougher				msblk->meta_index[i].offset >= offset &&
12030aeb6601e77c348064513052bf90a11952a190d0plougher				msblk->meta_index[i].offset <= index &&
12040aeb6601e77c348064513052bf90a11952a190d0plougher				msblk->meta_index[i].locked == 0) {
12050aeb6601e77c348064513052bf90a11952a190d0plougher			TRACE("locate_meta_index: entry %d, offset %d\n", i,
12060aeb6601e77c348064513052bf90a11952a190d0plougher					msblk->meta_index[i].offset);
12070aeb6601e77c348064513052bf90a11952a190d0plougher			meta = &msblk->meta_index[i];
12080aeb6601e77c348064513052bf90a11952a190d0plougher			offset = meta->offset;
12090aeb6601e77c348064513052bf90a11952a190d0plougher		}
12100aeb6601e77c348064513052bf90a11952a190d0plougher
12110aeb6601e77c348064513052bf90a11952a190d0plougher	if (meta)
12120aeb6601e77c348064513052bf90a11952a190d0plougher		meta->locked = 1;
12130aeb6601e77c348064513052bf90a11952a190d0plougher
12140aeb6601e77c348064513052bf90a11952a190d0ploughernot_allocated:
12150aeb6601e77c348064513052bf90a11952a190d0plougher	up(&msblk->meta_index_mutex);
12160aeb6601e77c348064513052bf90a11952a190d0plougher
12170aeb6601e77c348064513052bf90a11952a190d0plougher	return meta;
12180aeb6601e77c348064513052bf90a11952a190d0plougher}
12190aeb6601e77c348064513052bf90a11952a190d0plougher
12200aeb6601e77c348064513052bf90a11952a190d0plougher
12210aeb6601e77c348064513052bf90a11952a190d0plougherstruct meta_index *empty_meta_index(struct inode *inode, int offset, int skip)
12220aeb6601e77c348064513052bf90a11952a190d0plougher{
12230aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
12240aeb6601e77c348064513052bf90a11952a190d0plougher	struct meta_index *meta = NULL;
12250aeb6601e77c348064513052bf90a11952a190d0plougher	int i;
12260aeb6601e77c348064513052bf90a11952a190d0plougher
12270aeb6601e77c348064513052bf90a11952a190d0plougher	down(&msblk->meta_index_mutex);
12280aeb6601e77c348064513052bf90a11952a190d0plougher
12290aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
12300aeb6601e77c348064513052bf90a11952a190d0plougher
12310aeb6601e77c348064513052bf90a11952a190d0plougher	if(msblk->meta_index == NULL) {
12320aeb6601e77c348064513052bf90a11952a190d0plougher		if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) *
12330aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_META_NUMBER, GFP_KERNEL))) {
12340aeb6601e77c348064513052bf90a11952a190d0plougher			ERROR("Failed to allocate meta_index\n");
12350aeb6601e77c348064513052bf90a11952a190d0plougher			goto failed;
12360aeb6601e77c348064513052bf90a11952a190d0plougher		}
12370aeb6601e77c348064513052bf90a11952a190d0plougher		for(i = 0; i < SQUASHFS_META_NUMBER; i++) {
12380aeb6601e77c348064513052bf90a11952a190d0plougher			msblk->meta_index[i].inode_number = 0;
12390aeb6601e77c348064513052bf90a11952a190d0plougher			msblk->meta_index[i].locked = 0;
12400aeb6601e77c348064513052bf90a11952a190d0plougher		}
12410aeb6601e77c348064513052bf90a11952a190d0plougher		msblk->next_meta_index = 0;
12420aeb6601e77c348064513052bf90a11952a190d0plougher	}
12430aeb6601e77c348064513052bf90a11952a190d0plougher
12440aeb6601e77c348064513052bf90a11952a190d0plougher	for(i = SQUASHFS_META_NUMBER; i &&
12450aeb6601e77c348064513052bf90a11952a190d0plougher			msblk->meta_index[msblk->next_meta_index].locked; i --)
12460aeb6601e77c348064513052bf90a11952a190d0plougher		msblk->next_meta_index = (msblk->next_meta_index + 1) %
12470aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_META_NUMBER;
12480aeb6601e77c348064513052bf90a11952a190d0plougher
12490aeb6601e77c348064513052bf90a11952a190d0plougher	if(i == 0) {
12500aeb6601e77c348064513052bf90a11952a190d0plougher		TRACE("empty_meta_index: failed!\n");
12510aeb6601e77c348064513052bf90a11952a190d0plougher		goto failed;
12520aeb6601e77c348064513052bf90a11952a190d0plougher	}
12530aeb6601e77c348064513052bf90a11952a190d0plougher
12540aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("empty_meta_index: returned meta entry %d, %p\n",
12550aeb6601e77c348064513052bf90a11952a190d0plougher			msblk->next_meta_index,
12560aeb6601e77c348064513052bf90a11952a190d0plougher			&msblk->meta_index[msblk->next_meta_index]);
12570aeb6601e77c348064513052bf90a11952a190d0plougher
12580aeb6601e77c348064513052bf90a11952a190d0plougher	meta = &msblk->meta_index[msblk->next_meta_index];
12590aeb6601e77c348064513052bf90a11952a190d0plougher	msblk->next_meta_index = (msblk->next_meta_index + 1) %
12600aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_META_NUMBER;
12610aeb6601e77c348064513052bf90a11952a190d0plougher
12620aeb6601e77c348064513052bf90a11952a190d0plougher	meta->inode_number = inode->i_ino;
12630aeb6601e77c348064513052bf90a11952a190d0plougher	meta->offset = offset;
12640aeb6601e77c348064513052bf90a11952a190d0plougher	meta->skip = skip;
12650aeb6601e77c348064513052bf90a11952a190d0plougher	meta->entries = 0;
12660aeb6601e77c348064513052bf90a11952a190d0plougher	meta->locked = 1;
12670aeb6601e77c348064513052bf90a11952a190d0plougher
12680aeb6601e77c348064513052bf90a11952a190d0plougherfailed:
12690aeb6601e77c348064513052bf90a11952a190d0plougher	up(&msblk->meta_index_mutex);
12700aeb6601e77c348064513052bf90a11952a190d0plougher	return meta;
12710aeb6601e77c348064513052bf90a11952a190d0plougher}
12720aeb6601e77c348064513052bf90a11952a190d0plougher
12730aeb6601e77c348064513052bf90a11952a190d0plougher
12740aeb6601e77c348064513052bf90a11952a190d0ploughervoid release_meta_index(struct inode *inode, struct meta_index *meta)
12750aeb6601e77c348064513052bf90a11952a190d0plougher{
12760aeb6601e77c348064513052bf90a11952a190d0plougher	meta->locked = 0;
12770aeb6601e77c348064513052bf90a11952a190d0plougher}
12780aeb6601e77c348064513052bf90a11952a190d0plougher
12790aeb6601e77c348064513052bf90a11952a190d0plougher
12800aeb6601e77c348064513052bf90a11952a190d0plougherstatic int read_block_index(struct super_block *s, int blocks, char *block_list,
12810aeb6601e77c348064513052bf90a11952a190d0plougher		long long *start_block, int *offset)
12820aeb6601e77c348064513052bf90a11952a190d0plougher{
12830aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
12840aeb6601e77c348064513052bf90a11952a190d0plougher	unsigned int *block_listp;
12850aeb6601e77c348064513052bf90a11952a190d0plougher	int block = 0;
12860aeb6601e77c348064513052bf90a11952a190d0plougher
12870aeb6601e77c348064513052bf90a11952a190d0plougher	if (msblk->swap) {
12880aeb6601e77c348064513052bf90a11952a190d0plougher		char sblock_list[blocks << 2];
12890aeb6601e77c348064513052bf90a11952a190d0plougher
12900aeb6601e77c348064513052bf90a11952a190d0plougher		if (!squashfs_get_cached_block(s, sblock_list, *start_block,
12910aeb6601e77c348064513052bf90a11952a190d0plougher				*offset, blocks << 2, start_block, offset)) {
12920aeb6601e77c348064513052bf90a11952a190d0plougher			ERROR("Unable to read block list [%llx:%x]\n",
12930aeb6601e77c348064513052bf90a11952a190d0plougher				*start_block, *offset);
12940aeb6601e77c348064513052bf90a11952a190d0plougher			goto failure;
12950aeb6601e77c348064513052bf90a11952a190d0plougher		}
12960aeb6601e77c348064513052bf90a11952a190d0plougher		SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
12970aeb6601e77c348064513052bf90a11952a190d0plougher				((unsigned int *)sblock_list), blocks);
12980aeb6601e77c348064513052bf90a11952a190d0plougher	} else
12990aeb6601e77c348064513052bf90a11952a190d0plougher		if (!squashfs_get_cached_block(s, block_list, *start_block,
13000aeb6601e77c348064513052bf90a11952a190d0plougher				*offset, blocks << 2, start_block, offset)) {
13010aeb6601e77c348064513052bf90a11952a190d0plougher			ERROR("Unable to read block list [%llx:%x]\n",
13020aeb6601e77c348064513052bf90a11952a190d0plougher				*start_block, *offset);
13030aeb6601e77c348064513052bf90a11952a190d0plougher			goto failure;
13040aeb6601e77c348064513052bf90a11952a190d0plougher		}
13050aeb6601e77c348064513052bf90a11952a190d0plougher
13060aeb6601e77c348064513052bf90a11952a190d0plougher	for (block_listp = (unsigned int *) block_list; blocks;
13070aeb6601e77c348064513052bf90a11952a190d0plougher				block_listp++, blocks --)
13080aeb6601e77c348064513052bf90a11952a190d0plougher		block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);
13090aeb6601e77c348064513052bf90a11952a190d0plougher
13100aeb6601e77c348064513052bf90a11952a190d0plougher	return block;
13110aeb6601e77c348064513052bf90a11952a190d0plougher
13120aeb6601e77c348064513052bf90a11952a190d0plougherfailure:
13130aeb6601e77c348064513052bf90a11952a190d0plougher	return -1;
13140aeb6601e77c348064513052bf90a11952a190d0plougher}
13150aeb6601e77c348064513052bf90a11952a190d0plougher
13160aeb6601e77c348064513052bf90a11952a190d0plougher
13170aeb6601e77c348064513052bf90a11952a190d0plougher#define SIZE 256
13180aeb6601e77c348064513052bf90a11952a190d0plougher
13190aeb6601e77c348064513052bf90a11952a190d0plougherstatic inline int calculate_skip(int blocks) {
13200aeb6601e77c348064513052bf90a11952a190d0plougher	int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES);
13210aeb6601e77c348064513052bf90a11952a190d0plougher	return skip >= 7 ? 7 : skip + 1;
13220aeb6601e77c348064513052bf90a11952a190d0plougher}
13230aeb6601e77c348064513052bf90a11952a190d0plougher
13240aeb6601e77c348064513052bf90a11952a190d0plougher
13250aeb6601e77c348064513052bf90a11952a190d0plougherstatic int get_meta_index(struct inode *inode, int index,
13260aeb6601e77c348064513052bf90a11952a190d0plougher		long long *index_block, int *index_offset,
13270aeb6601e77c348064513052bf90a11952a190d0plougher		long long *data_block, char *block_list)
13280aeb6601e77c348064513052bf90a11952a190d0plougher{
13290aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
13300aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_super_block *sblk = &msblk->sblk;
13310aeb6601e77c348064513052bf90a11952a190d0plougher	int skip = calculate_skip(i_size_read(inode) >> sblk->block_log);
13320aeb6601e77c348064513052bf90a11952a190d0plougher	int offset = 0;
13330aeb6601e77c348064513052bf90a11952a190d0plougher	struct meta_index *meta;
13340aeb6601e77c348064513052bf90a11952a190d0plougher	struct meta_entry *meta_entry;
13350aeb6601e77c348064513052bf90a11952a190d0plougher	long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start;
13360aeb6601e77c348064513052bf90a11952a190d0plougher	int cur_offset = SQUASHFS_I(inode)->offset;
13370aeb6601e77c348064513052bf90a11952a190d0plougher	long long cur_data_block = SQUASHFS_I(inode)->start_block;
13380aeb6601e77c348064513052bf90a11952a190d0plougher	int i;
13390aeb6601e77c348064513052bf90a11952a190d0plougher
13400aeb6601e77c348064513052bf90a11952a190d0plougher	index /= SQUASHFS_META_INDEXES * skip;
13410aeb6601e77c348064513052bf90a11952a190d0plougher
13420aeb6601e77c348064513052bf90a11952a190d0plougher	while ( offset < index ) {
13430aeb6601e77c348064513052bf90a11952a190d0plougher		meta = locate_meta_index(inode, index, offset + 1);
13440aeb6601e77c348064513052bf90a11952a190d0plougher
13450aeb6601e77c348064513052bf90a11952a190d0plougher		if (meta == NULL) {
13460aeb6601e77c348064513052bf90a11952a190d0plougher			if ((meta = empty_meta_index(inode, offset + 1,
13470aeb6601e77c348064513052bf90a11952a190d0plougher							skip)) == NULL)
13480aeb6601e77c348064513052bf90a11952a190d0plougher				goto all_done;
13490aeb6601e77c348064513052bf90a11952a190d0plougher		} else {
13500aeb6601e77c348064513052bf90a11952a190d0plougher			offset = index < meta->offset + meta->entries ? index :
13510aeb6601e77c348064513052bf90a11952a190d0plougher				meta->offset + meta->entries - 1;
13520aeb6601e77c348064513052bf90a11952a190d0plougher			meta_entry = &meta->meta_entry[offset - meta->offset];
13530aeb6601e77c348064513052bf90a11952a190d0plougher			cur_index_block = meta_entry->index_block + sblk->inode_table_start;
13540aeb6601e77c348064513052bf90a11952a190d0plougher			cur_offset = meta_entry->offset;
13550aeb6601e77c348064513052bf90a11952a190d0plougher			cur_data_block = meta_entry->data_block;
13560aeb6601e77c348064513052bf90a11952a190d0plougher			TRACE("get_meta_index: offset %d, meta->offset %d, "
13570aeb6601e77c348064513052bf90a11952a190d0plougher				"meta->entries %d\n", offset, meta->offset,
13580aeb6601e77c348064513052bf90a11952a190d0plougher				meta->entries);
13590aeb6601e77c348064513052bf90a11952a190d0plougher			TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
13600aeb6601e77c348064513052bf90a11952a190d0plougher				" data_block 0x%llx\n", cur_index_block,
13610aeb6601e77c348064513052bf90a11952a190d0plougher				cur_offset, cur_data_block);
13620aeb6601e77c348064513052bf90a11952a190d0plougher		}
13630aeb6601e77c348064513052bf90a11952a190d0plougher
13640aeb6601e77c348064513052bf90a11952a190d0plougher		for (i = meta->offset + meta->entries; i <= index &&
13650aeb6601e77c348064513052bf90a11952a190d0plougher				i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
13660aeb6601e77c348064513052bf90a11952a190d0plougher			int blocks = skip * SQUASHFS_META_INDEXES;
13670aeb6601e77c348064513052bf90a11952a190d0plougher
13680aeb6601e77c348064513052bf90a11952a190d0plougher			while (blocks) {
13690aeb6601e77c348064513052bf90a11952a190d0plougher				int block = blocks > (SIZE >> 2) ? (SIZE >> 2) :
13700aeb6601e77c348064513052bf90a11952a190d0plougher					blocks;
13710aeb6601e77c348064513052bf90a11952a190d0plougher				int res = read_block_index(inode->i_sb, block,
13720aeb6601e77c348064513052bf90a11952a190d0plougher					block_list, &cur_index_block,
13730aeb6601e77c348064513052bf90a11952a190d0plougher					&cur_offset);
13740aeb6601e77c348064513052bf90a11952a190d0plougher
13750aeb6601e77c348064513052bf90a11952a190d0plougher				if (res == -1)
13760aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed;
13770aeb6601e77c348064513052bf90a11952a190d0plougher
13780aeb6601e77c348064513052bf90a11952a190d0plougher				cur_data_block += res;
13790aeb6601e77c348064513052bf90a11952a190d0plougher				blocks -= block;
13800aeb6601e77c348064513052bf90a11952a190d0plougher			}
13810aeb6601e77c348064513052bf90a11952a190d0plougher
13820aeb6601e77c348064513052bf90a11952a190d0plougher			meta_entry = &meta->meta_entry[i - meta->offset];
13830aeb6601e77c348064513052bf90a11952a190d0plougher			meta_entry->index_block = cur_index_block - sblk->inode_table_start;
13840aeb6601e77c348064513052bf90a11952a190d0plougher			meta_entry->offset = cur_offset;
13850aeb6601e77c348064513052bf90a11952a190d0plougher			meta_entry->data_block = cur_data_block;
13860aeb6601e77c348064513052bf90a11952a190d0plougher			meta->entries ++;
13870aeb6601e77c348064513052bf90a11952a190d0plougher			offset ++;
13880aeb6601e77c348064513052bf90a11952a190d0plougher		}
13890aeb6601e77c348064513052bf90a11952a190d0plougher
13900aeb6601e77c348064513052bf90a11952a190d0plougher		TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
13910aeb6601e77c348064513052bf90a11952a190d0plougher				meta->offset, meta->entries);
13920aeb6601e77c348064513052bf90a11952a190d0plougher
13930aeb6601e77c348064513052bf90a11952a190d0plougher		release_meta_index(inode, meta);
13940aeb6601e77c348064513052bf90a11952a190d0plougher	}
13950aeb6601e77c348064513052bf90a11952a190d0plougher
13960aeb6601e77c348064513052bf90a11952a190d0plougherall_done:
13970aeb6601e77c348064513052bf90a11952a190d0plougher	*index_block = cur_index_block;
13980aeb6601e77c348064513052bf90a11952a190d0plougher	*index_offset = cur_offset;
13990aeb6601e77c348064513052bf90a11952a190d0plougher	*data_block = cur_data_block;
14000aeb6601e77c348064513052bf90a11952a190d0plougher
14010aeb6601e77c348064513052bf90a11952a190d0plougher	return offset * SQUASHFS_META_INDEXES * skip;
14020aeb6601e77c348064513052bf90a11952a190d0plougher
14030aeb6601e77c348064513052bf90a11952a190d0plougherfailed:
14040aeb6601e77c348064513052bf90a11952a190d0plougher	release_meta_index(inode, meta);
14050aeb6601e77c348064513052bf90a11952a190d0plougher	return -1;
14060aeb6601e77c348064513052bf90a11952a190d0plougher}
14070aeb6601e77c348064513052bf90a11952a190d0plougher
14080aeb6601e77c348064513052bf90a11952a190d0plougher
14090aeb6601e77c348064513052bf90a11952a190d0plougherstatic long long read_blocklist(struct inode *inode, int index,
14100aeb6601e77c348064513052bf90a11952a190d0plougher				int readahead_blks, char *block_list,
14110aeb6601e77c348064513052bf90a11952a190d0plougher				unsigned short **block_p, unsigned int *bsize)
14120aeb6601e77c348064513052bf90a11952a190d0plougher{
14130aeb6601e77c348064513052bf90a11952a190d0plougher	long long block_ptr;
14140aeb6601e77c348064513052bf90a11952a190d0plougher	int offset;
14150aeb6601e77c348064513052bf90a11952a190d0plougher	long long block;
14160aeb6601e77c348064513052bf90a11952a190d0plougher	int res = get_meta_index(inode, index, &block_ptr, &offset, &block,
14170aeb6601e77c348064513052bf90a11952a190d0plougher		block_list);
14180aeb6601e77c348064513052bf90a11952a190d0plougher
14190aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"
14200aeb6601e77c348064513052bf90a11952a190d0plougher		       " 0x%x, block 0x%llx\n", res, index, block_ptr, offset,
14210aeb6601e77c348064513052bf90a11952a190d0plougher		       block);
14220aeb6601e77c348064513052bf90a11952a190d0plougher
14230aeb6601e77c348064513052bf90a11952a190d0plougher	if(res == -1)
14240aeb6601e77c348064513052bf90a11952a190d0plougher		goto failure;
14250aeb6601e77c348064513052bf90a11952a190d0plougher
14260aeb6601e77c348064513052bf90a11952a190d0plougher	index -= res;
14270aeb6601e77c348064513052bf90a11952a190d0plougher
14280aeb6601e77c348064513052bf90a11952a190d0plougher	while ( index ) {
14290aeb6601e77c348064513052bf90a11952a190d0plougher		int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
14300aeb6601e77c348064513052bf90a11952a190d0plougher		int res = read_block_index(inode->i_sb, blocks, block_list,
14310aeb6601e77c348064513052bf90a11952a190d0plougher			&block_ptr, &offset);
14320aeb6601e77c348064513052bf90a11952a190d0plougher		if (res == -1)
14330aeb6601e77c348064513052bf90a11952a190d0plougher			goto failure;
14340aeb6601e77c348064513052bf90a11952a190d0plougher		block += res;
14350aeb6601e77c348064513052bf90a11952a190d0plougher		index -= blocks;
14360aeb6601e77c348064513052bf90a11952a190d0plougher	}
14370aeb6601e77c348064513052bf90a11952a190d0plougher
14380aeb6601e77c348064513052bf90a11952a190d0plougher	if (read_block_index(inode->i_sb, 1, block_list,
14390aeb6601e77c348064513052bf90a11952a190d0plougher			&block_ptr, &offset) == -1)
14400aeb6601e77c348064513052bf90a11952a190d0plougher		goto failure;
14410aeb6601e77c348064513052bf90a11952a190d0plougher	*bsize = *((unsigned int *) block_list);
14420aeb6601e77c348064513052bf90a11952a190d0plougher
14430aeb6601e77c348064513052bf90a11952a190d0plougher	return block;
14440aeb6601e77c348064513052bf90a11952a190d0plougher
14450aeb6601e77c348064513052bf90a11952a190d0plougherfailure:
14460aeb6601e77c348064513052bf90a11952a190d0plougher	return 0;
14470aeb6601e77c348064513052bf90a11952a190d0plougher}
14480aeb6601e77c348064513052bf90a11952a190d0plougher
14490aeb6601e77c348064513052bf90a11952a190d0plougher
14500aeb6601e77c348064513052bf90a11952a190d0plougherstatic int squashfs_readpage(struct file *file, struct page *page)
14510aeb6601e77c348064513052bf90a11952a190d0plougher{
14520aeb6601e77c348064513052bf90a11952a190d0plougher	struct inode *inode = page->mapping->host;
14530aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
14540aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_super_block *sblk = &msblk->sblk;
14550aeb6601e77c348064513052bf90a11952a190d0plougher	unsigned char block_list[SIZE];
14560aeb6601e77c348064513052bf90a11952a190d0plougher	long long block;
14570aeb6601e77c348064513052bf90a11952a190d0plougher	unsigned int bsize, i = 0, bytes = 0, byte_offset = 0;
14580aeb6601e77c348064513052bf90a11952a190d0plougher	int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
14590aeb6601e77c348064513052bf90a11952a190d0plougher 	void *pageaddr;
14600aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_fragment_cache *fragment = NULL;
14610aeb6601e77c348064513052bf90a11952a190d0plougher	char *data_ptr = msblk->read_page;
14620aeb6601e77c348064513052bf90a11952a190d0plougher
14630aeb6601e77c348064513052bf90a11952a190d0plougher	int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
14640aeb6601e77c348064513052bf90a11952a190d0plougher	int start_index = page->index & ~mask;
14650aeb6601e77c348064513052bf90a11952a190d0plougher	int end_index = start_index | mask;
14660aeb6601e77c348064513052bf90a11952a190d0plougher
14670aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
14680aeb6601e77c348064513052bf90a11952a190d0plougher					page->index,
14690aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_I(inode)->start_block);
14700aeb6601e77c348064513052bf90a11952a190d0plougher
14710aeb6601e77c348064513052bf90a11952a190d0plougher	if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
14720aeb6601e77c348064513052bf90a11952a190d0plougher					PAGE_CACHE_SHIFT))
14730aeb6601e77c348064513052bf90a11952a190d0plougher		goto skip_read;
14740aeb6601e77c348064513052bf90a11952a190d0plougher
14750aeb6601e77c348064513052bf90a11952a190d0plougher	if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
14760aeb6601e77c348064513052bf90a11952a190d0plougher					|| index < (i_size_read(inode) >>
14770aeb6601e77c348064513052bf90a11952a190d0plougher					sblk->block_log)) {
14780aeb6601e77c348064513052bf90a11952a190d0plougher		if ((block = (msblk->read_blocklist)(inode, index, 1,
14790aeb6601e77c348064513052bf90a11952a190d0plougher					block_list, NULL, &bsize)) == 0)
14800aeb6601e77c348064513052bf90a11952a190d0plougher			goto skip_read;
14810aeb6601e77c348064513052bf90a11952a190d0plougher
14820aeb6601e77c348064513052bf90a11952a190d0plougher		down(&msblk->read_page_mutex);
14830aeb6601e77c348064513052bf90a11952a190d0plougher
14840aeb6601e77c348064513052bf90a11952a190d0plougher		if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page,
14850aeb6601e77c348064513052bf90a11952a190d0plougher					block, bsize, NULL))) {
14860aeb6601e77c348064513052bf90a11952a190d0plougher			ERROR("Unable to read page, block %llx, size %x\n", block,
14870aeb6601e77c348064513052bf90a11952a190d0plougher					bsize);
14880aeb6601e77c348064513052bf90a11952a190d0plougher			up(&msblk->read_page_mutex);
14890aeb6601e77c348064513052bf90a11952a190d0plougher			goto skip_read;
14900aeb6601e77c348064513052bf90a11952a190d0plougher		}
14910aeb6601e77c348064513052bf90a11952a190d0plougher	} else {
14920aeb6601e77c348064513052bf90a11952a190d0plougher		if ((fragment = get_cached_fragment(inode->i_sb,
14930aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_I(inode)->
14940aeb6601e77c348064513052bf90a11952a190d0plougher					u.s1.fragment_start_block,
14950aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_I(inode)->u.s1.fragment_size))
14960aeb6601e77c348064513052bf90a11952a190d0plougher					== NULL) {
14970aeb6601e77c348064513052bf90a11952a190d0plougher			ERROR("Unable to read page, block %llx, size %x\n",
14980aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_I(inode)->
14990aeb6601e77c348064513052bf90a11952a190d0plougher					u.s1.fragment_start_block,
15000aeb6601e77c348064513052bf90a11952a190d0plougher					(int) SQUASHFS_I(inode)->
15010aeb6601e77c348064513052bf90a11952a190d0plougher					u.s1.fragment_size);
15020aeb6601e77c348064513052bf90a11952a190d0plougher			goto skip_read;
15030aeb6601e77c348064513052bf90a11952a190d0plougher		}
15040aeb6601e77c348064513052bf90a11952a190d0plougher		bytes = SQUASHFS_I(inode)->u.s1.fragment_offset +
15050aeb6601e77c348064513052bf90a11952a190d0plougher					(i_size_read(inode) & (sblk->block_size
15060aeb6601e77c348064513052bf90a11952a190d0plougher					- 1));
15070aeb6601e77c348064513052bf90a11952a190d0plougher		byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset;
15080aeb6601e77c348064513052bf90a11952a190d0plougher		data_ptr = fragment->data;
15090aeb6601e77c348064513052bf90a11952a190d0plougher	}
15100aeb6601e77c348064513052bf90a11952a190d0plougher
15110aeb6601e77c348064513052bf90a11952a190d0plougher	for (i = start_index; i <= end_index && byte_offset < bytes;
15120aeb6601e77c348064513052bf90a11952a190d0plougher					i++, byte_offset += PAGE_CACHE_SIZE) {
15130aeb6601e77c348064513052bf90a11952a190d0plougher		struct page *push_page;
15140aeb6601e77c348064513052bf90a11952a190d0plougher		int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ?
15150aeb6601e77c348064513052bf90a11952a190d0plougher					PAGE_CACHE_SIZE : bytes - byte_offset;
15160aeb6601e77c348064513052bf90a11952a190d0plougher
15170aeb6601e77c348064513052bf90a11952a190d0plougher		TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n",
15180aeb6601e77c348064513052bf90a11952a190d0plougher					bytes, i, byte_offset, available_bytes);
15190aeb6601e77c348064513052bf90a11952a190d0plougher
15200aeb6601e77c348064513052bf90a11952a190d0plougher		if (i == page->index)  {
15210aeb6601e77c348064513052bf90a11952a190d0plougher			pageaddr = kmap_atomic(page, KM_USER0);
15220aeb6601e77c348064513052bf90a11952a190d0plougher			memcpy(pageaddr, data_ptr + byte_offset,
15230aeb6601e77c348064513052bf90a11952a190d0plougher					available_bytes);
15240aeb6601e77c348064513052bf90a11952a190d0plougher			memset(pageaddr + available_bytes, 0,
15250aeb6601e77c348064513052bf90a11952a190d0plougher					PAGE_CACHE_SIZE - available_bytes);
15260aeb6601e77c348064513052bf90a11952a190d0plougher			kunmap_atomic(pageaddr, KM_USER0);
15270aeb6601e77c348064513052bf90a11952a190d0plougher			flush_dcache_page(page);
15280aeb6601e77c348064513052bf90a11952a190d0plougher			SetPageUptodate(page);
15290aeb6601e77c348064513052bf90a11952a190d0plougher			UnlockPage(page);
15300aeb6601e77c348064513052bf90a11952a190d0plougher		} else if ((push_page =
15310aeb6601e77c348064513052bf90a11952a190d0plougher				grab_cache_page_nowait(page->mapping, i))) {
15320aeb6601e77c348064513052bf90a11952a190d0plougher 			pageaddr = kmap_atomic(push_page, KM_USER0);
15330aeb6601e77c348064513052bf90a11952a190d0plougher
15340aeb6601e77c348064513052bf90a11952a190d0plougher			memcpy(pageaddr, data_ptr + byte_offset,
15350aeb6601e77c348064513052bf90a11952a190d0plougher					available_bytes);
15360aeb6601e77c348064513052bf90a11952a190d0plougher			memset(pageaddr + available_bytes, 0,
15370aeb6601e77c348064513052bf90a11952a190d0plougher					PAGE_CACHE_SIZE - available_bytes);
15380aeb6601e77c348064513052bf90a11952a190d0plougher			kunmap_atomic(pageaddr, KM_USER0);
15390aeb6601e77c348064513052bf90a11952a190d0plougher			flush_dcache_page(push_page);
15400aeb6601e77c348064513052bf90a11952a190d0plougher			SetPageUptodate(push_page);
15410aeb6601e77c348064513052bf90a11952a190d0plougher			UnlockPage(push_page);
15420aeb6601e77c348064513052bf90a11952a190d0plougher			page_cache_release(push_page);
15430aeb6601e77c348064513052bf90a11952a190d0plougher		}
15440aeb6601e77c348064513052bf90a11952a190d0plougher	}
15450aeb6601e77c348064513052bf90a11952a190d0plougher
15460aeb6601e77c348064513052bf90a11952a190d0plougher	if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
15470aeb6601e77c348064513052bf90a11952a190d0plougher					|| index < (i_size_read(inode) >>
15480aeb6601e77c348064513052bf90a11952a190d0plougher					sblk->block_log))
15490aeb6601e77c348064513052bf90a11952a190d0plougher		up(&msblk->read_page_mutex);
15500aeb6601e77c348064513052bf90a11952a190d0plougher	else
15510aeb6601e77c348064513052bf90a11952a190d0plougher		release_cached_fragment(msblk, fragment);
15520aeb6601e77c348064513052bf90a11952a190d0plougher
15530aeb6601e77c348064513052bf90a11952a190d0plougher	return 0;
15540aeb6601e77c348064513052bf90a11952a190d0plougher
15550aeb6601e77c348064513052bf90a11952a190d0plougherskip_read:
15560aeb6601e77c348064513052bf90a11952a190d0plougher	pageaddr = kmap_atomic(page, KM_USER0);
15570aeb6601e77c348064513052bf90a11952a190d0plougher	memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
15580aeb6601e77c348064513052bf90a11952a190d0plougher	kunmap_atomic(pageaddr, KM_USER0);
15590aeb6601e77c348064513052bf90a11952a190d0plougher	flush_dcache_page(page);
15600aeb6601e77c348064513052bf90a11952a190d0plougher	SetPageUptodate(page);
15610aeb6601e77c348064513052bf90a11952a190d0plougher	UnlockPage(page);
15620aeb6601e77c348064513052bf90a11952a190d0plougher
15630aeb6601e77c348064513052bf90a11952a190d0plougher	return 0;
15640aeb6601e77c348064513052bf90a11952a190d0plougher}
15650aeb6601e77c348064513052bf90a11952a190d0plougher
15660aeb6601e77c348064513052bf90a11952a190d0plougher
15670aeb6601e77c348064513052bf90a11952a190d0plougherstatic int squashfs_readpage4K(struct file *file, struct page *page)
15680aeb6601e77c348064513052bf90a11952a190d0plougher{
15690aeb6601e77c348064513052bf90a11952a190d0plougher	struct inode *inode = page->mapping->host;
15700aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &inode->i_sb->u.squashfs_sb;
15710aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_super_block *sblk = &msblk->sblk;
15720aeb6601e77c348064513052bf90a11952a190d0plougher	unsigned char block_list[SIZE];
15730aeb6601e77c348064513052bf90a11952a190d0plougher	long long block;
15740aeb6601e77c348064513052bf90a11952a190d0plougher	unsigned int bsize, bytes = 0;
15750aeb6601e77c348064513052bf90a11952a190d0plougher 	void *pageaddr;
15760aeb6601e77c348064513052bf90a11952a190d0plougher
15770aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n",
15780aeb6601e77c348064513052bf90a11952a190d0plougher					page->index,
15790aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_I(inode)->start_block);
15800aeb6601e77c348064513052bf90a11952a190d0plougher
15810aeb6601e77c348064513052bf90a11952a190d0plougher	if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
15820aeb6601e77c348064513052bf90a11952a190d0plougher					PAGE_CACHE_SHIFT)) {
15830aeb6601e77c348064513052bf90a11952a190d0plougher		pageaddr = kmap_atomic(page, KM_USER0);
15840aeb6601e77c348064513052bf90a11952a190d0plougher		goto skip_read;
15850aeb6601e77c348064513052bf90a11952a190d0plougher	}
15860aeb6601e77c348064513052bf90a11952a190d0plougher
15870aeb6601e77c348064513052bf90a11952a190d0plougher	if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
15880aeb6601e77c348064513052bf90a11952a190d0plougher					|| page->index < (i_size_read(inode) >>
15890aeb6601e77c348064513052bf90a11952a190d0plougher					sblk->block_log)) {
15900aeb6601e77c348064513052bf90a11952a190d0plougher		block = (msblk->read_blocklist)(inode, page->index, 1,
15910aeb6601e77c348064513052bf90a11952a190d0plougher					block_list, NULL, &bsize);
15920aeb6601e77c348064513052bf90a11952a190d0plougher
15930aeb6601e77c348064513052bf90a11952a190d0plougher		down(&msblk->read_page_mutex);
15940aeb6601e77c348064513052bf90a11952a190d0plougher		bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
15950aeb6601e77c348064513052bf90a11952a190d0plougher					bsize, NULL);
15960aeb6601e77c348064513052bf90a11952a190d0plougher		pageaddr = kmap_atomic(page, KM_USER0);
15970aeb6601e77c348064513052bf90a11952a190d0plougher		if (bytes)
15980aeb6601e77c348064513052bf90a11952a190d0plougher			memcpy(pageaddr, msblk->read_page, bytes);
15990aeb6601e77c348064513052bf90a11952a190d0plougher		else
16000aeb6601e77c348064513052bf90a11952a190d0plougher			ERROR("Unable to read page, block %llx, size %x\n",
16010aeb6601e77c348064513052bf90a11952a190d0plougher					block, bsize);
16020aeb6601e77c348064513052bf90a11952a190d0plougher		up(&msblk->read_page_mutex);
16030aeb6601e77c348064513052bf90a11952a190d0plougher	} else {
16040aeb6601e77c348064513052bf90a11952a190d0plougher		struct squashfs_fragment_cache *fragment =
16050aeb6601e77c348064513052bf90a11952a190d0plougher			get_cached_fragment(inode->i_sb,
16060aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_I(inode)->
16070aeb6601e77c348064513052bf90a11952a190d0plougher					u.s1.fragment_start_block,
16080aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_I(inode)-> u.s1.fragment_size);
16090aeb6601e77c348064513052bf90a11952a190d0plougher		pageaddr = kmap_atomic(page, KM_USER0);
16100aeb6601e77c348064513052bf90a11952a190d0plougher		if (fragment) {
16110aeb6601e77c348064513052bf90a11952a190d0plougher			bytes = i_size_read(inode) & (sblk->block_size - 1);
16120aeb6601e77c348064513052bf90a11952a190d0plougher			memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->
16130aeb6601e77c348064513052bf90a11952a190d0plougher					u.s1.fragment_offset, bytes);
16140aeb6601e77c348064513052bf90a11952a190d0plougher			release_cached_fragment(msblk, fragment);
16150aeb6601e77c348064513052bf90a11952a190d0plougher		} else
16160aeb6601e77c348064513052bf90a11952a190d0plougher			ERROR("Unable to read page, block %llx, size %x\n",
16170aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_I(inode)->
16180aeb6601e77c348064513052bf90a11952a190d0plougher					u.s1.fragment_start_block, (int)
16190aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_I(inode)-> u.s1.fragment_size);
16200aeb6601e77c348064513052bf90a11952a190d0plougher	}
16210aeb6601e77c348064513052bf90a11952a190d0plougher
16220aeb6601e77c348064513052bf90a11952a190d0plougherskip_read:
16230aeb6601e77c348064513052bf90a11952a190d0plougher	memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
16240aeb6601e77c348064513052bf90a11952a190d0plougher	kunmap_atomic(pageaddr, KM_USER0);
16250aeb6601e77c348064513052bf90a11952a190d0plougher	flush_dcache_page(page);
16260aeb6601e77c348064513052bf90a11952a190d0plougher	SetPageUptodate(page);
16270aeb6601e77c348064513052bf90a11952a190d0plougher	UnlockPage(page);
16280aeb6601e77c348064513052bf90a11952a190d0plougher
16290aeb6601e77c348064513052bf90a11952a190d0plougher	return 0;
16300aeb6601e77c348064513052bf90a11952a190d0plougher}
16310aeb6601e77c348064513052bf90a11952a190d0plougher
16320aeb6601e77c348064513052bf90a11952a190d0plougher
16330aeb6601e77c348064513052bf90a11952a190d0plougherstatic int get_dir_index_using_offset(struct super_block *s, long long
16340aeb6601e77c348064513052bf90a11952a190d0plougher				*next_block, unsigned int *next_offset,
16350aeb6601e77c348064513052bf90a11952a190d0plougher				long long index_start,
16360aeb6601e77c348064513052bf90a11952a190d0plougher				unsigned int index_offset, int i_count,
16370aeb6601e77c348064513052bf90a11952a190d0plougher				long long f_pos)
16380aeb6601e77c348064513052bf90a11952a190d0plougher{
16390aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
16400aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_super_block *sblk = &msblk->sblk;
16410aeb6601e77c348064513052bf90a11952a190d0plougher	int i, length = 0;
16420aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_dir_index index;
16430aeb6601e77c348064513052bf90a11952a190d0plougher
16440aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
16450aeb6601e77c348064513052bf90a11952a190d0plougher					i_count, (unsigned int) f_pos);
16460aeb6601e77c348064513052bf90a11952a190d0plougher
16470aeb6601e77c348064513052bf90a11952a190d0plougher	f_pos -= 3;
16480aeb6601e77c348064513052bf90a11952a190d0plougher	if (f_pos == 0)
16490aeb6601e77c348064513052bf90a11952a190d0plougher		goto finish;
16500aeb6601e77c348064513052bf90a11952a190d0plougher
16510aeb6601e77c348064513052bf90a11952a190d0plougher	for (i = 0; i < i_count; i++) {
16520aeb6601e77c348064513052bf90a11952a190d0plougher		if (msblk->swap) {
16530aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_dir_index sindex;
16540aeb6601e77c348064513052bf90a11952a190d0plougher			squashfs_get_cached_block(s, (char *) &sindex,
16550aeb6601e77c348064513052bf90a11952a190d0plougher					index_start, index_offset,
16560aeb6601e77c348064513052bf90a11952a190d0plougher					sizeof(sindex), &index_start,
16570aeb6601e77c348064513052bf90a11952a190d0plougher					&index_offset);
16580aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
16590aeb6601e77c348064513052bf90a11952a190d0plougher		} else
16600aeb6601e77c348064513052bf90a11952a190d0plougher			squashfs_get_cached_block(s, (char *) &index,
16610aeb6601e77c348064513052bf90a11952a190d0plougher					index_start, index_offset,
16620aeb6601e77c348064513052bf90a11952a190d0plougher					sizeof(index), &index_start,
16630aeb6601e77c348064513052bf90a11952a190d0plougher					&index_offset);
16640aeb6601e77c348064513052bf90a11952a190d0plougher
16650aeb6601e77c348064513052bf90a11952a190d0plougher		if (index.index > f_pos)
16660aeb6601e77c348064513052bf90a11952a190d0plougher			break;
16670aeb6601e77c348064513052bf90a11952a190d0plougher
16680aeb6601e77c348064513052bf90a11952a190d0plougher		squashfs_get_cached_block(s, NULL, index_start, index_offset,
16690aeb6601e77c348064513052bf90a11952a190d0plougher					index.size + 1, &index_start,
16700aeb6601e77c348064513052bf90a11952a190d0plougher					&index_offset);
16710aeb6601e77c348064513052bf90a11952a190d0plougher
16720aeb6601e77c348064513052bf90a11952a190d0plougher		length = index.index;
16730aeb6601e77c348064513052bf90a11952a190d0plougher		*next_block = index.start_block + sblk->directory_table_start;
16740aeb6601e77c348064513052bf90a11952a190d0plougher	}
16750aeb6601e77c348064513052bf90a11952a190d0plougher
16760aeb6601e77c348064513052bf90a11952a190d0plougher	*next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
16770aeb6601e77c348064513052bf90a11952a190d0plougher
16780aeb6601e77c348064513052bf90a11952a190d0plougherfinish:
16790aeb6601e77c348064513052bf90a11952a190d0plougher	return length + 3;
16800aeb6601e77c348064513052bf90a11952a190d0plougher}
16810aeb6601e77c348064513052bf90a11952a190d0plougher
16820aeb6601e77c348064513052bf90a11952a190d0plougher
16830aeb6601e77c348064513052bf90a11952a190d0plougherstatic int get_dir_index_using_name(struct super_block *s, long long
16840aeb6601e77c348064513052bf90a11952a190d0plougher				*next_block, unsigned int *next_offset,
16850aeb6601e77c348064513052bf90a11952a190d0plougher				long long index_start,
16860aeb6601e77c348064513052bf90a11952a190d0plougher				unsigned int index_offset, int i_count,
16870aeb6601e77c348064513052bf90a11952a190d0plougher				const char *name, int size)
16880aeb6601e77c348064513052bf90a11952a190d0plougher{
16890aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &s->u.squashfs_sb;
16900aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_super_block *sblk = &msblk->sblk;
16910aeb6601e77c348064513052bf90a11952a190d0plougher	int i, length = 0;
16920aeb6601e77c348064513052bf90a11952a190d0plougher	char buffer[sizeof(struct squashfs_dir_index) + SQUASHFS_NAME_LEN + 1];
16930aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_dir_index *index = (struct squashfs_dir_index *) buffer;
16940aeb6601e77c348064513052bf90a11952a190d0plougher	char str[SQUASHFS_NAME_LEN + 1];
16950aeb6601e77c348064513052bf90a11952a190d0plougher
16960aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
16970aeb6601e77c348064513052bf90a11952a190d0plougher
16980aeb6601e77c348064513052bf90a11952a190d0plougher	strncpy(str, name, size);
16990aeb6601e77c348064513052bf90a11952a190d0plougher	str[size] = '\0';
17000aeb6601e77c348064513052bf90a11952a190d0plougher
17010aeb6601e77c348064513052bf90a11952a190d0plougher	for (i = 0; i < i_count; i++) {
17020aeb6601e77c348064513052bf90a11952a190d0plougher		if (msblk->swap) {
17030aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_dir_index sindex;
17040aeb6601e77c348064513052bf90a11952a190d0plougher			squashfs_get_cached_block(s, (char *) &sindex,
17050aeb6601e77c348064513052bf90a11952a190d0plougher					index_start, index_offset,
17060aeb6601e77c348064513052bf90a11952a190d0plougher					sizeof(sindex), &index_start,
17070aeb6601e77c348064513052bf90a11952a190d0plougher					&index_offset);
17080aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_SWAP_DIR_INDEX(index, &sindex);
17090aeb6601e77c348064513052bf90a11952a190d0plougher		} else
17100aeb6601e77c348064513052bf90a11952a190d0plougher			squashfs_get_cached_block(s, (char *) index,
17110aeb6601e77c348064513052bf90a11952a190d0plougher					index_start, index_offset,
17120aeb6601e77c348064513052bf90a11952a190d0plougher					sizeof(struct squashfs_dir_index),
17130aeb6601e77c348064513052bf90a11952a190d0plougher					&index_start, &index_offset);
17140aeb6601e77c348064513052bf90a11952a190d0plougher
17150aeb6601e77c348064513052bf90a11952a190d0plougher		squashfs_get_cached_block(s, index->name, index_start,
17160aeb6601e77c348064513052bf90a11952a190d0plougher					index_offset, index->size + 1,
17170aeb6601e77c348064513052bf90a11952a190d0plougher					&index_start, &index_offset);
17180aeb6601e77c348064513052bf90a11952a190d0plougher
17190aeb6601e77c348064513052bf90a11952a190d0plougher		index->name[index->size + 1] = '\0';
17200aeb6601e77c348064513052bf90a11952a190d0plougher
17210aeb6601e77c348064513052bf90a11952a190d0plougher		if (strcmp(index->name, str) > 0)
17220aeb6601e77c348064513052bf90a11952a190d0plougher			break;
17230aeb6601e77c348064513052bf90a11952a190d0plougher
17240aeb6601e77c348064513052bf90a11952a190d0plougher		length = index->index;
17250aeb6601e77c348064513052bf90a11952a190d0plougher		*next_block = index->start_block + sblk->directory_table_start;
17260aeb6601e77c348064513052bf90a11952a190d0plougher	}
17270aeb6601e77c348064513052bf90a11952a190d0plougher
17280aeb6601e77c348064513052bf90a11952a190d0plougher	*next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
17290aeb6601e77c348064513052bf90a11952a190d0plougher	return length + 3;
17300aeb6601e77c348064513052bf90a11952a190d0plougher}
17310aeb6601e77c348064513052bf90a11952a190d0plougher
17320aeb6601e77c348064513052bf90a11952a190d0plougher
17330aeb6601e77c348064513052bf90a11952a190d0plougherstatic int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
17340aeb6601e77c348064513052bf90a11952a190d0plougher{
17350aeb6601e77c348064513052bf90a11952a190d0plougher	struct inode *i = file->f_dentry->d_inode;
17360aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
17370aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_super_block *sblk = &msblk->sblk;
17380aeb6601e77c348064513052bf90a11952a190d0plougher	long long next_block = SQUASHFS_I(i)->start_block +
17390aeb6601e77c348064513052bf90a11952a190d0plougher		sblk->directory_table_start;
174067bd5ed1112f4240f5ec66cbbc169bd802abe52cplougher	int next_offset = SQUASHFS_I(i)->offset, length = 0,
17410aeb6601e77c348064513052bf90a11952a190d0plougher		dir_count;
17420aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_dir_header dirh;
17430aeb6601e77c348064513052bf90a11952a190d0plougher	char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1];
17440aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
17450aeb6601e77c348064513052bf90a11952a190d0plougher
17460aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
17470aeb6601e77c348064513052bf90a11952a190d0plougher
17480aeb6601e77c348064513052bf90a11952a190d0plougher	while(file->f_pos < 3) {
17490aeb6601e77c348064513052bf90a11952a190d0plougher		char *name;
17500aeb6601e77c348064513052bf90a11952a190d0plougher		int size, i_ino;
17510aeb6601e77c348064513052bf90a11952a190d0plougher
17520aeb6601e77c348064513052bf90a11952a190d0plougher		if(file->f_pos == 0) {
17530aeb6601e77c348064513052bf90a11952a190d0plougher			name = ".";
17540aeb6601e77c348064513052bf90a11952a190d0plougher			size = 1;
17550aeb6601e77c348064513052bf90a11952a190d0plougher			i_ino = i->i_ino;
17560aeb6601e77c348064513052bf90a11952a190d0plougher		} else {
17570aeb6601e77c348064513052bf90a11952a190d0plougher			name = "..";
17580aeb6601e77c348064513052bf90a11952a190d0plougher			size = 2;
17590aeb6601e77c348064513052bf90a11952a190d0plougher			i_ino = SQUASHFS_I(i)->u.s2.parent_inode;
17600aeb6601e77c348064513052bf90a11952a190d0plougher		}
17610aeb6601e77c348064513052bf90a11952a190d0plougher		TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n",
17620aeb6601e77c348064513052bf90a11952a190d0plougher				(unsigned int) dirent, name, size, (int)
17630aeb6601e77c348064513052bf90a11952a190d0plougher				file->f_pos, i_ino,
17640aeb6601e77c348064513052bf90a11952a190d0plougher				squashfs_filetype_table[1]);
17650aeb6601e77c348064513052bf90a11952a190d0plougher
17660aeb6601e77c348064513052bf90a11952a190d0plougher		if (filldir(dirent, name, size,
17670aeb6601e77c348064513052bf90a11952a190d0plougher				file->f_pos, i_ino,
17680aeb6601e77c348064513052bf90a11952a190d0plougher				squashfs_filetype_table[1]) < 0) {
17690aeb6601e77c348064513052bf90a11952a190d0plougher				TRACE("Filldir returned less than 0\n");
17700aeb6601e77c348064513052bf90a11952a190d0plougher				goto finish;
17710aeb6601e77c348064513052bf90a11952a190d0plougher		}
17720aeb6601e77c348064513052bf90a11952a190d0plougher		file->f_pos += size;
17730aeb6601e77c348064513052bf90a11952a190d0plougher	}
17740aeb6601e77c348064513052bf90a11952a190d0plougher
17750aeb6601e77c348064513052bf90a11952a190d0plougher	length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
17760aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_I(i)->u.s2.directory_index_start,
17770aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_I(i)->u.s2.directory_index_offset,
17780aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_I(i)->u.s2.directory_index_count,
17790aeb6601e77c348064513052bf90a11952a190d0plougher				file->f_pos);
17800aeb6601e77c348064513052bf90a11952a190d0plougher
17810aeb6601e77c348064513052bf90a11952a190d0plougher	while (length < i_size_read(i)) {
17820aeb6601e77c348064513052bf90a11952a190d0plougher		/* read directory header */
17830aeb6601e77c348064513052bf90a11952a190d0plougher		if (msblk->swap) {
17840aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_dir_header sdirh;
17850aeb6601e77c348064513052bf90a11952a190d0plougher
17860aeb6601e77c348064513052bf90a11952a190d0plougher			if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
17870aeb6601e77c348064513052bf90a11952a190d0plougher					next_block, next_offset, sizeof(sdirh),
17880aeb6601e77c348064513052bf90a11952a190d0plougher					&next_block, &next_offset))
17890aeb6601e77c348064513052bf90a11952a190d0plougher				goto failed_read;
17900aeb6601e77c348064513052bf90a11952a190d0plougher
17910aeb6601e77c348064513052bf90a11952a190d0plougher			length += sizeof(sdirh);
17920aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
17930aeb6601e77c348064513052bf90a11952a190d0plougher		} else {
17940aeb6601e77c348064513052bf90a11952a190d0plougher			if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
17950aeb6601e77c348064513052bf90a11952a190d0plougher					next_block, next_offset, sizeof(dirh),
17960aeb6601e77c348064513052bf90a11952a190d0plougher					&next_block, &next_offset))
17970aeb6601e77c348064513052bf90a11952a190d0plougher				goto failed_read;
17980aeb6601e77c348064513052bf90a11952a190d0plougher
17990aeb6601e77c348064513052bf90a11952a190d0plougher			length += sizeof(dirh);
18000aeb6601e77c348064513052bf90a11952a190d0plougher		}
18010aeb6601e77c348064513052bf90a11952a190d0plougher
18020aeb6601e77c348064513052bf90a11952a190d0plougher		dir_count = dirh.count + 1;
18030aeb6601e77c348064513052bf90a11952a190d0plougher		while (dir_count--) {
18040aeb6601e77c348064513052bf90a11952a190d0plougher			if (msblk->swap) {
18050aeb6601e77c348064513052bf90a11952a190d0plougher				struct squashfs_dir_entry sdire;
18060aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(i->i_sb, (char *)
18070aeb6601e77c348064513052bf90a11952a190d0plougher						&sdire, next_block, next_offset,
18080aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(sdire), &next_block,
18090aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
18100aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
18110aeb6601e77c348064513052bf90a11952a190d0plougher
18120aeb6601e77c348064513052bf90a11952a190d0plougher				length += sizeof(sdire);
18130aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
18140aeb6601e77c348064513052bf90a11952a190d0plougher			} else {
18150aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(i->i_sb, (char *)
18160aeb6601e77c348064513052bf90a11952a190d0plougher						dire, next_block, next_offset,
18170aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(*dire), &next_block,
18180aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
18190aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
18200aeb6601e77c348064513052bf90a11952a190d0plougher
18210aeb6601e77c348064513052bf90a11952a190d0plougher				length += sizeof(*dire);
18220aeb6601e77c348064513052bf90a11952a190d0plougher			}
18230aeb6601e77c348064513052bf90a11952a190d0plougher
18240aeb6601e77c348064513052bf90a11952a190d0plougher			if (!squashfs_get_cached_block(i->i_sb, dire->name,
18250aeb6601e77c348064513052bf90a11952a190d0plougher						next_block, next_offset,
18260aeb6601e77c348064513052bf90a11952a190d0plougher						dire->size + 1, &next_block,
18270aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
18280aeb6601e77c348064513052bf90a11952a190d0plougher				goto failed_read;
18290aeb6601e77c348064513052bf90a11952a190d0plougher
18300aeb6601e77c348064513052bf90a11952a190d0plougher			length += dire->size + 1;
18310aeb6601e77c348064513052bf90a11952a190d0plougher
18320aeb6601e77c348064513052bf90a11952a190d0plougher			if (file->f_pos >= length)
18330aeb6601e77c348064513052bf90a11952a190d0plougher				continue;
18340aeb6601e77c348064513052bf90a11952a190d0plougher
18350aeb6601e77c348064513052bf90a11952a190d0plougher			dire->name[dire->size + 1] = '\0';
18360aeb6601e77c348064513052bf90a11952a190d0plougher
18370aeb6601e77c348064513052bf90a11952a190d0plougher			TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n",
18380aeb6601e77c348064513052bf90a11952a190d0plougher					(unsigned int) dirent, dire->name,
18390aeb6601e77c348064513052bf90a11952a190d0plougher					dire->size + 1, (int) file->f_pos,
18400aeb6601e77c348064513052bf90a11952a190d0plougher					dirh.start_block, dire->offset,
18410aeb6601e77c348064513052bf90a11952a190d0plougher					dirh.inode_number + dire->inode_number,
18420aeb6601e77c348064513052bf90a11952a190d0plougher					squashfs_filetype_table[dire->type]);
18430aeb6601e77c348064513052bf90a11952a190d0plougher
18440aeb6601e77c348064513052bf90a11952a190d0plougher			if (filldir(dirent, dire->name, dire->size + 1,
18450aeb6601e77c348064513052bf90a11952a190d0plougher					file->f_pos,
18460aeb6601e77c348064513052bf90a11952a190d0plougher					dirh.inode_number + dire->inode_number,
18470aeb6601e77c348064513052bf90a11952a190d0plougher					squashfs_filetype_table[dire->type])
18480aeb6601e77c348064513052bf90a11952a190d0plougher					< 0) {
18490aeb6601e77c348064513052bf90a11952a190d0plougher				TRACE("Filldir returned less than 0\n");
18500aeb6601e77c348064513052bf90a11952a190d0plougher				goto finish;
18510aeb6601e77c348064513052bf90a11952a190d0plougher			}
18520aeb6601e77c348064513052bf90a11952a190d0plougher			file->f_pos = length;
18530aeb6601e77c348064513052bf90a11952a190d0plougher		}
18540aeb6601e77c348064513052bf90a11952a190d0plougher	}
18550aeb6601e77c348064513052bf90a11952a190d0plougher
18560aeb6601e77c348064513052bf90a11952a190d0plougherfinish:
185767bd5ed1112f4240f5ec66cbbc169bd802abe52cplougher	return 0;
18580aeb6601e77c348064513052bf90a11952a190d0plougher
18590aeb6601e77c348064513052bf90a11952a190d0plougherfailed_read:
18600aeb6601e77c348064513052bf90a11952a190d0plougher	ERROR("Unable to read directory block [%llx:%x]\n", next_block,
18610aeb6601e77c348064513052bf90a11952a190d0plougher		next_offset);
18620aeb6601e77c348064513052bf90a11952a190d0plougher	return 0;
18630aeb6601e77c348064513052bf90a11952a190d0plougher}
18640aeb6601e77c348064513052bf90a11952a190d0plougher
18650aeb6601e77c348064513052bf90a11952a190d0plougher
18660aeb6601e77c348064513052bf90a11952a190d0plougherstatic struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry)
18670aeb6601e77c348064513052bf90a11952a190d0plougher{
18680aeb6601e77c348064513052bf90a11952a190d0plougher	const unsigned char *name = dentry->d_name.name;
18690aeb6601e77c348064513052bf90a11952a190d0plougher	int len = dentry->d_name.len;
18700aeb6601e77c348064513052bf90a11952a190d0plougher	struct inode *inode = NULL;
18710aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_sb_info *msblk = &i->i_sb->u.squashfs_sb;
18720aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_super_block *sblk = &msblk->sblk;
18730aeb6601e77c348064513052bf90a11952a190d0plougher	long long next_block = SQUASHFS_I(i)->start_block +
18740aeb6601e77c348064513052bf90a11952a190d0plougher				sblk->directory_table_start;
18750aeb6601e77c348064513052bf90a11952a190d0plougher	int next_offset = SQUASHFS_I(i)->offset, length = 0,
18760aeb6601e77c348064513052bf90a11952a190d0plougher				dir_count;
18770aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_dir_header dirh;
18780aeb6601e77c348064513052bf90a11952a190d0plougher	char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN];
18790aeb6601e77c348064513052bf90a11952a190d0plougher	struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
18800aeb6601e77c348064513052bf90a11952a190d0plougher
18810aeb6601e77c348064513052bf90a11952a190d0plougher	TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
18820aeb6601e77c348064513052bf90a11952a190d0plougher
18830aeb6601e77c348064513052bf90a11952a190d0plougher	if (len > SQUASHFS_NAME_LEN)
18840aeb6601e77c348064513052bf90a11952a190d0plougher		goto exit_loop;
18850aeb6601e77c348064513052bf90a11952a190d0plougher
18860aeb6601e77c348064513052bf90a11952a190d0plougher	length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
18870aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_I(i)->u.s2.directory_index_start,
18880aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_I(i)->u.s2.directory_index_offset,
18890aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_I(i)->u.s2.directory_index_count, name,
18900aeb6601e77c348064513052bf90a11952a190d0plougher				len);
18910aeb6601e77c348064513052bf90a11952a190d0plougher
18920aeb6601e77c348064513052bf90a11952a190d0plougher	while (length < i_size_read(i)) {
18930aeb6601e77c348064513052bf90a11952a190d0plougher		/* read directory header */
18940aeb6601e77c348064513052bf90a11952a190d0plougher		if (msblk->swap) {
18950aeb6601e77c348064513052bf90a11952a190d0plougher			struct squashfs_dir_header sdirh;
18960aeb6601e77c348064513052bf90a11952a190d0plougher			if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
18970aeb6601e77c348064513052bf90a11952a190d0plougher					next_block, next_offset, sizeof(sdirh),
18980aeb6601e77c348064513052bf90a11952a190d0plougher					&next_block, &next_offset))
18990aeb6601e77c348064513052bf90a11952a190d0plougher				goto failed_read;
19000aeb6601e77c348064513052bf90a11952a190d0plougher
19010aeb6601e77c348064513052bf90a11952a190d0plougher			length += sizeof(sdirh);
19020aeb6601e77c348064513052bf90a11952a190d0plougher			SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
19030aeb6601e77c348064513052bf90a11952a190d0plougher		} else {
19040aeb6601e77c348064513052bf90a11952a190d0plougher			if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
19050aeb6601e77c348064513052bf90a11952a190d0plougher					next_block, next_offset, sizeof(dirh),
19060aeb6601e77c348064513052bf90a11952a190d0plougher					&next_block, &next_offset))
19070aeb6601e77c348064513052bf90a11952a190d0plougher				goto failed_read;
19080aeb6601e77c348064513052bf90a11952a190d0plougher
19090aeb6601e77c348064513052bf90a11952a190d0plougher			length += sizeof(dirh);
19100aeb6601e77c348064513052bf90a11952a190d0plougher		}
19110aeb6601e77c348064513052bf90a11952a190d0plougher
19120aeb6601e77c348064513052bf90a11952a190d0plougher		dir_count = dirh.count + 1;
19130aeb6601e77c348064513052bf90a11952a190d0plougher		while (dir_count--) {
19140aeb6601e77c348064513052bf90a11952a190d0plougher			if (msblk->swap) {
19150aeb6601e77c348064513052bf90a11952a190d0plougher				struct squashfs_dir_entry sdire;
19160aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(i->i_sb, (char *)
19170aeb6601e77c348064513052bf90a11952a190d0plougher						&sdire, next_block,next_offset,
19180aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(sdire), &next_block,
19190aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
19200aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
19210aeb6601e77c348064513052bf90a11952a190d0plougher
19220aeb6601e77c348064513052bf90a11952a190d0plougher				length += sizeof(sdire);
19230aeb6601e77c348064513052bf90a11952a190d0plougher				SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
19240aeb6601e77c348064513052bf90a11952a190d0plougher			} else {
19250aeb6601e77c348064513052bf90a11952a190d0plougher				if (!squashfs_get_cached_block(i->i_sb, (char *)
19260aeb6601e77c348064513052bf90a11952a190d0plougher						dire, next_block,next_offset,
19270aeb6601e77c348064513052bf90a11952a190d0plougher						sizeof(*dire), &next_block,
19280aeb6601e77c348064513052bf90a11952a190d0plougher						&next_offset))
19290aeb6601e77c348064513052bf90a11952a190d0plougher					goto failed_read;
19300aeb6601e77c348064513052bf90a11952a190d0plougher
19310aeb6601e77c348064513052bf90a11952a190d0plougher				length += sizeof(*dire);
19320aeb6601e77c348064513052bf90a11952a190d0plougher			}
19330aeb6601e77c348064513052bf90a11952a190d0plougher
19340aeb6601e77c348064513052bf90a11952a190d0plougher			if (!squashfs_get_cached_block(i->i_sb, dire->name,
19350aeb6601e77c348064513052bf90a11952a190d0plougher					next_block, next_offset, dire->size + 1,
19360aeb6601e77c348064513052bf90a11952a190d0plougher					&next_block, &next_offset))
19370aeb6601e77c348064513052bf90a11952a190d0plougher				goto failed_read;
19380aeb6601e77c348064513052bf90a11952a190d0plougher
19390aeb6601e77c348064513052bf90a11952a190d0plougher			length += dire->size + 1;
19400aeb6601e77c348064513052bf90a11952a190d0plougher
19410aeb6601e77c348064513052bf90a11952a190d0plougher			if (name[0] < dire->name[0])
19420aeb6601e77c348064513052bf90a11952a190d0plougher				goto exit_loop;
19430aeb6601e77c348064513052bf90a11952a190d0plougher
19440aeb6601e77c348064513052bf90a11952a190d0plougher			if ((len == dire->size + 1) && !strncmp(name,
19450aeb6601e77c348064513052bf90a11952a190d0plougher						dire->name, len)) {
19460aeb6601e77c348064513052bf90a11952a190d0plougher				squashfs_inode_t ino =
19470aeb6601e77c348064513052bf90a11952a190d0plougher					SQUASHFS_MKINODE(dirh.start_block,
19480aeb6601e77c348064513052bf90a11952a190d0plougher					dire->offset);
19490aeb6601e77c348064513052bf90a11952a190d0plougher
19500aeb6601e77c348064513052bf90a11952a190d0plougher				TRACE("calling squashfs_iget for directory "
19510aeb6601e77c348064513052bf90a11952a190d0plougher					"entry %s, inode %x:%x, %d\n", name,
19520aeb6601e77c348064513052bf90a11952a190d0plougher					dirh.start_block, dire->offset,
19530aeb6601e77c348064513052bf90a11952a190d0plougher					dirh.inode_number + dire->inode_number);
19540aeb6601e77c348064513052bf90a11952a190d0plougher
19550aeb6601e77c348064513052bf90a11952a190d0plougher				inode = (msblk->iget)(i->i_sb, ino);
19560aeb6601e77c348064513052bf90a11952a190d0plougher
19570aeb6601e77c348064513052bf90a11952a190d0plougher				goto exit_loop;
19580aeb6601e77c348064513052bf90a11952a190d0plougher			}
19590aeb6601e77c348064513052bf90a11952a190d0plougher		}
19600aeb6601e77c348064513052bf90a11952a190d0plougher	}
19610aeb6601e77c348064513052bf90a11952a190d0plougher
19620aeb6601e77c348064513052bf90a11952a190d0plougherexit_loop:
19630aeb6601e77c348064513052bf90a11952a190d0plougher	d_add(dentry, inode);
19640aeb6601e77c348064513052bf90a11952a190d0plougher	return ERR_PTR(0);
19650aeb6601e77c348064513052bf90a11952a190d0plougher
19660aeb6601e77c348064513052bf90a11952a190d0plougherfailed_read:
19670aeb6601e77c348064513052bf90a11952a190d0plougher	ERROR("Unable to read directory block [%llx:%x]\n", next_block,
19680aeb6601e77c348064513052bf90a11952a190d0plougher		next_offset);
19690aeb6601e77c348064513052bf90a11952a190d0plougher	goto exit_loop;
19700aeb6601e77c348064513052bf90a11952a190d0plougher}
19710aeb6601e77c348064513052bf90a11952a190d0plougher
19720aeb6601e77c348064513052bf90a11952a190d0plougher
19730aeb6601e77c348064513052bf90a11952a190d0plougherstatic void squashfs_put_super(struct super_block *s)
19740aeb6601e77c348064513052bf90a11952a190d0plougher{
19750aeb6601e77c348064513052bf90a11952a190d0plougher	int i;
19760aeb6601e77c348064513052bf90a11952a190d0plougher
19770aeb6601e77c348064513052bf90a11952a190d0plougher		struct squashfs_sb_info *sbi = &s->u.squashfs_sb;
19780aeb6601e77c348064513052bf90a11952a190d0plougher		if (sbi->block_cache)
19790aeb6601e77c348064513052bf90a11952a190d0plougher			for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
19800aeb6601e77c348064513052bf90a11952a190d0plougher				if (sbi->block_cache[i].block !=
19810aeb6601e77c348064513052bf90a11952a190d0plougher							SQUASHFS_INVALID_BLK)
19820aeb6601e77c348064513052bf90a11952a190d0plougher					kfree(sbi->block_cache[i].data);
19830aeb6601e77c348064513052bf90a11952a190d0plougher		if (sbi->fragment)
19840aeb6601e77c348064513052bf90a11952a190d0plougher			for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++)
1985af371d91a8865df5ab3079887b86c76a48b6e405plougher				SQUASHFS_FREE(sbi->fragment[i].data);
19860aeb6601e77c348064513052bf90a11952a190d0plougher		kfree(sbi->fragment);
19870aeb6601e77c348064513052bf90a11952a190d0plougher		kfree(sbi->block_cache);
19880aeb6601e77c348064513052bf90a11952a190d0plougher		kfree(sbi->read_data);
19890aeb6601e77c348064513052bf90a11952a190d0plougher		kfree(sbi->read_page);
19900aeb6601e77c348064513052bf90a11952a190d0plougher		kfree(sbi->uid);
19910aeb6601e77c348064513052bf90a11952a190d0plougher		kfree(sbi->fragment_index);
19920aeb6601e77c348064513052bf90a11952a190d0plougher		kfree(sbi->fragment_index_2);
1993410dd958c15c73d91e877a0afe085bfaee37d9ffplougher		kfree(sbi->meta_index);
1994410dd958c15c73d91e877a0afe085bfaee37d9ffplougher		vfree(sbi->stream.workspace);
19950aeb6601e77c348064513052bf90a11952a190d0plougher		sbi->block_cache = NULL;
19960aeb6601e77c348064513052bf90a11952a190d0plougher		sbi->uid = NULL;
19970aeb6601e77c348064513052bf90a11952a190d0plougher		sbi->read_data = NULL;
19980aeb6601e77c348064513052bf90a11952a190d0plougher		sbi->read_page = NULL;
19990aeb6601e77c348064513052bf90a11952a190d0plougher		sbi->fragment = NULL;
20000aeb6601e77c348064513052bf90a11952a190d0plougher		sbi->fragment_index = NULL;
20010aeb6601e77c348064513052bf90a11952a190d0plougher		sbi->fragment_index_2 = NULL;
2002410dd958c15c73d91e877a0afe085bfaee37d9ffplougher		sbi->meta_index = NULL;
2003410dd958c15c73d91e877a0afe085bfaee37d9ffplougher		sbi->stream.workspace = NULL;
20040aeb6601e77c348064513052bf90a11952a190d0plougher}
20050aeb6601e77c348064513052bf90a11952a190d0plougher
20060aeb6601e77c348064513052bf90a11952a190d0plougher
20070aeb6601e77c348064513052bf90a11952a190d0plougherstatic int __init init_squashfs_fs(void)
20080aeb6601e77c348064513052bf90a11952a190d0plougher{
20090aeb6601e77c348064513052bf90a11952a190d0plougher
2010d09dc28507a55fa82ba904224caea5da2f432360plougher	printk(KERN_INFO "squashfs: version 3.1 (2006/08/15) "
20110aeb6601e77c348064513052bf90a11952a190d0plougher		"Phillip Lougher\n");
20120aeb6601e77c348064513052bf90a11952a190d0plougher
20130aeb6601e77c348064513052bf90a11952a190d0plougher	return register_filesystem(&squashfs_fs_type);
20140aeb6601e77c348064513052bf90a11952a190d0plougher}
20150aeb6601e77c348064513052bf90a11952a190d0plougher
20160aeb6601e77c348064513052bf90a11952a190d0plougher
20170aeb6601e77c348064513052bf90a11952a190d0plougherstatic void __exit exit_squashfs_fs(void)
20180aeb6601e77c348064513052bf90a11952a190d0plougher{
20190aeb6601e77c348064513052bf90a11952a190d0plougher	unregister_filesystem(&squashfs_fs_type);
20200aeb6601e77c348064513052bf90a11952a190d0plougher}
20210aeb6601e77c348064513052bf90a11952a190d0plougher
20220aeb6601e77c348064513052bf90a11952a190d0plougher
20230aeb6601e77c348064513052bf90a11952a190d0plougherEXPORT_NO_SYMBOLS;
20240aeb6601e77c348064513052bf90a11952a190d0plougher
20250aeb6601e77c348064513052bf90a11952a190d0ploughermodule_init(init_squashfs_fs);
20260aeb6601e77c348064513052bf90a11952a190d0ploughermodule_exit(exit_squashfs_fs);
2027aa8954128ab96f6cb57193e6943c61f1bc6cd631plougherMODULE_DESCRIPTION("squashfs 3.1, a compressed read-only filesystem");
2028f6cd337f8de328e2b448b9f29c00d9132748f7feplougherMODULE_AUTHOR("Phillip Lougher <phillip@lougher.demon.co.uk>");
20290aeb6601e77c348064513052bf90a11952a190d0plougherMODULE_LICENSE("GPL");
2030