Gentoo Archives: gentoo-commits

From: "Mike Pagano (mpagano)" <mpagano@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] linux-patches r1354 - genpatches-2.6/trunk/2.6.27
Date: Sun, 12 Oct 2008 18:19:58
Message-Id: E1Kp5XX-0000hY-5g@stork.gentoo.org
1 Author: mpagano
2 Date: 2008-10-12 18:19:38 +0000 (Sun, 12 Oct 2008)
3 New Revision: 1354
4
5 Added:
6 genpatches-2.6/trunk/2.6.27/4100_dm-bbr.patch
7 genpatches-2.6/trunk/2.6.27/4300_squashfs-3.4.patch
8 genpatches-2.6/trunk/2.6.27/4400_alpha-sysctl-uac.patch
9 Removed:
10 genpatches-2.6/trunk/2.6.27/4105_dm-bbr.patch
11 genpatches-2.6/trunk/2.6.27/4300_squashfs-3.3.patch
12 genpatches-2.6/trunk/2.6.27/4405_alpha-sysctl-uac.patch
13 Modified:
14 genpatches-2.6/trunk/2.6.27/0000_README
15 genpatches-2.6/trunk/2.6.27/4200_fbcondecor-0.9.4.patch
16 Log:
17 Patch cleanup for 2.6.27 release.
18
19 Modified: genpatches-2.6/trunk/2.6.27/0000_README
20 ===================================================================
21 --- genpatches-2.6/trunk/2.6.27/0000_README 2008-10-11 01:09:49 UTC (rev 1353)
22 +++ genpatches-2.6/trunk/2.6.27/0000_README 2008-10-12 18:19:38 UTC (rev 1354)
23 @@ -39,7 +39,7 @@
24 Individual Patch Descriptions:
25 --------------------------------------------------------------------------
26
27 -Patch: 4105_dm-bbr.patch
28 +Patch: 4100_dm-bbr.patch
29 From: EVMS 2.5.2
30 Desc: Bad block relocation support for LiveCD users
31
32 @@ -51,7 +51,7 @@
33 From: http://squashfs.sourceforge.net/
34 Desc: driver to support squashfs filesystems.
35
36 -Patch: 4405_alpha-sysctl-uac.patch
37 +Patch: 4400_alpha-sysctl-uac.patch
38 From: Tavis Ormandy <taviso@g.o> and http://bugs.gentoo.org/show_bug.cgi?id=217323
39 Desc: enable control of the unaligned access control policy from sysctl
40
41
42 Added: genpatches-2.6/trunk/2.6.27/4100_dm-bbr.patch
43 ===================================================================
44 --- genpatches-2.6/trunk/2.6.27/4100_dm-bbr.patch (rev 0)
45 +++ genpatches-2.6/trunk/2.6.27/4100_dm-bbr.patch 2008-10-12 18:19:38 UTC (rev 1354)
46 @@ -0,0 +1,1190 @@
47 +BBR Target, updated by dsd@g.o
48 +
49 +Incomplete changelog:
50 + 2008/06/16: updated for new API in 2.6.26
51 + 2007/07/08: updated for new API in 2.6.22
52 +
53 +Index: linux-2.6.26-gentoo/drivers/md/Kconfig
54 +===================================================================
55 +--- linux-2.6.26-gentoo.orig/drivers/md/Kconfig
56 ++++ linux-2.6.26-gentoo/drivers/md/Kconfig
57 +@@ -288,4 +288,15 @@ config DM_UEVENT
58 + ---help---
59 + Generate udev events for DM events.
60 +
61 ++config BLK_DEV_DM_BBR
62 ++ tristate "Bad Block Relocation Device Target (EXPERIMENTAL)"
63 ++ depends on BLK_DEV_DM && EXPERIMENTAL
64 ++ ---help---
65 ++ Support for devices with software-based bad-block-relocation.
66 ++
67 ++ To compile this as a module, choose M here: the module will be
68 ++ called dm-bbr.
69 ++
70 ++ If unsure, say N.
71 ++
72 + endif # MD
73 +Index: linux-2.6.26-gentoo/drivers/md/Makefile
74 +===================================================================
75 +--- linux-2.6.26-gentoo.orig/drivers/md/Makefile
76 ++++ linux-2.6.26-gentoo/drivers/md/Makefile
77 +@@ -41,6 +41,7 @@ obj-$(CONFIG_DM_MULTIPATH_RDAC) += dm-rd
78 + obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o
79 + obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o
80 + obj-$(CONFIG_DM_ZERO) += dm-zero.o
81 ++obj-$(CONFIG_BLK_DEV_DM_BBR) += dm-bbr.o
82 +
83 + quiet_cmd_unroll = UNROLL $@
84 + cmd_unroll = $(PERL) $(srctree)/$(src)/unroll.pl $(UNROLL) \
85 +Index: linux-2.6.26-gentoo/drivers/md/dm-bbr.c
86 +===================================================================
87 +--- /dev/null
88 ++++ linux-2.6.26-gentoo/drivers/md/dm-bbr.c
89 +@@ -0,0 +1,1012 @@
90 ++/*
91 ++ * (C) Copyright IBM Corp. 2002, 2004
92 ++ *
93 ++ * This program is free software; you can redistribute it and/or modify
94 ++ * it under the terms of the GNU General Public License as published by
95 ++ * the Free Software Foundation; either version 2 of the License, or
96 ++ * (at your option) any later version.
97 ++ *
98 ++ * This program is distributed in the hope that it will be useful,
99 ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
100 ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
101 ++ * the GNU General Public License for more details.
102 ++ *
103 ++ * You should have received a copy of the GNU General Public License
104 ++ * along with this program; if not, write to the Free Software
105 ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
106 ++ *
107 ++ * linux/drivers/md/dm-bbr.c
108 ++ *
109 ++ * Bad-block-relocation (BBR) target for device-mapper.
110 ++ *
111 ++ * The BBR target is designed to remap I/O write failures to another safe
112 ++ * location on disk. Note that most disk drives have BBR built into them,
113 ++ * this means that our software BBR will be only activated when all hardware
114 ++ * BBR replacement sectors have been used.
115 ++ */
116 ++
117 ++#include <linux/module.h>
118 ++#include <linux/init.h>
119 ++#include <linux/bio.h>
120 ++#include <linux/spinlock.h>
121 ++#include <linux/slab.h>
122 ++#include <linux/mempool.h>
123 ++#include <linux/workqueue.h>
124 ++#include <linux/vmalloc.h>
125 ++#include <linux/dm-io.h>
126 ++
127 ++#include "dm.h"
128 ++#include "dm-bio-list.h"
129 ++#include "dm-bio-record.h"
130 ++#include "dm-bbr.h"
131 ++
132 ++#define DM_MSG_PREFIX "bbr"
133 ++#define SECTOR_SIZE (1 << SECTOR_SHIFT)
134 ++
135 ++static struct workqueue_struct *dm_bbr_wq = NULL;
136 ++static void bbr_remap_handler(struct work_struct *work);
137 ++static struct kmem_cache *bbr_remap_cache;
138 ++static struct kmem_cache *bbr_io_cache;
139 ++static mempool_t *bbr_io_pool;
140 ++
141 ++/**
142 ++ * bbr_binary_tree_destroy
143 ++ *
144 ++ * Destroy the binary tree.
145 ++ **/
146 ++static void bbr_binary_tree_destroy(struct bbr_runtime_remap *root)
147 ++{
148 ++ struct bbr_runtime_remap **link = NULL;
149 ++ struct bbr_runtime_remap *node = root;
150 ++
151 ++ while (node) {
152 ++ if (node->left) {
153 ++ link = &node->left;
154 ++ node = node->left;
155 ++ continue;
156 ++ }
157 ++ if (node->right) {
158 ++ link = &node->right;
159 ++ node = node->right;
160 ++ continue;
161 ++ }
162 ++
163 ++ kmem_cache_free(bbr_remap_cache, node);
164 ++ if (node == root) {
165 ++ /* If root is deleted, we're done. */
166 ++ break;
167 ++ }
168 ++
169 ++ /* Back to root. */
170 ++ node = root;
171 ++ *link = NULL;
172 ++ }
173 ++}
174 ++
175 ++static void bbr_free_remap(struct bbr_private *bbr_id)
176 ++{
177 ++ spin_lock_irq(&bbr_id->remap_root_lock);
178 ++ bbr_binary_tree_destroy(bbr_id->remap_root);
179 ++ bbr_id->remap_root = NULL;
180 ++ spin_unlock_irq(&bbr_id->remap_root_lock);
181 ++}
182 ++
183 ++static struct bbr_private *bbr_alloc_private(void)
184 ++{
185 ++ struct bbr_private *bbr_id;
186 ++
187 ++ bbr_id = kzalloc(sizeof(*bbr_id), GFP_KERNEL);
188 ++ if (bbr_id == NULL)
189 ++ return NULL;
190 ++
191 ++ INIT_WORK(&bbr_id->remap_work, bbr_remap_handler);
192 ++ spin_lock_init(&bbr_id->remap_root_lock);
193 ++ spin_lock_init(&bbr_id->remap_ios_lock);
194 ++ bbr_id->in_use_replacement_blks = (atomic_t) ATOMIC_INIT(0);
195 ++
196 ++ return bbr_id;
197 ++}
198 ++
199 ++static void bbr_free_private(struct bbr_private *bbr_id)
200 ++{
201 ++ vfree(bbr_id->bbr_table);
202 ++ bbr_free_remap(bbr_id);
203 ++ kfree(bbr_id);
204 ++}
205 ++
206 ++static u32 crc_table[256];
207 ++static u32 crc_table_built = 0;
208 ++
209 ++static void build_crc_table(void)
210 ++{
211 ++ u32 i, j, crc;
212 ++
213 ++ for (i = 0; i <= 255; i++) {
214 ++ crc = i;
215 ++ for (j = 8; j > 0; j--) {
216 ++ if (crc & 1)
217 ++ crc = (crc >> 1) ^ CRC_POLYNOMIAL;
218 ++ else
219 ++ crc >>= 1;
220 ++ }
221 ++ crc_table[i] = crc;
222 ++ }
223 ++ crc_table_built = 1;
224 ++}
225 ++
226 ++static u32 calculate_crc(u32 crc, void *buffer, u32 buffersize)
227 ++{
228 ++ unsigned char *current_byte;
229 ++ u32 temp1, temp2, i;
230 ++
231 ++ current_byte = (unsigned char *) buffer;
232 ++ /* Make sure the crc table is available */
233 ++ if (!crc_table_built)
234 ++ build_crc_table();
235 ++ /* Process each byte in the buffer. */
236 ++ for (i = 0; i < buffersize; i++) {
237 ++ temp1 = (crc >> 8) & 0x00FFFFFF;
238 ++ temp2 = crc_table[(crc ^ (u32) * current_byte) &
239 ++ (u32) 0xff];
240 ++ current_byte++;
241 ++ crc = temp1 ^ temp2;
242 ++ }
243 ++ return crc;
244 ++}
245 ++
246 ++/**
247 ++ * le_bbr_table_sector_to_cpu
248 ++ *
249 ++ * Convert bbr meta data from on-disk (LE) format
250 ++ * to the native cpu endian format.
251 ++ **/
252 ++static void le_bbr_table_sector_to_cpu(struct bbr_table *p)
253 ++{
254 ++ int i;
255 ++ p->signature = le32_to_cpup(&p->signature);
256 ++ p->crc = le32_to_cpup(&p->crc);
257 ++ p->sequence_number = le32_to_cpup(&p->sequence_number);
258 ++ p->in_use_cnt = le32_to_cpup(&p->in_use_cnt);
259 ++ for (i = 0; i < BBR_ENTRIES_PER_SECT; i++) {
260 ++ p->entries[i].bad_sect =
261 ++ le64_to_cpup(&p->entries[i].bad_sect);
262 ++ p->entries[i].replacement_sect =
263 ++ le64_to_cpup(&p->entries[i].replacement_sect);
264 ++ }
265 ++}
266 ++
267 ++/**
268 ++ * cpu_bbr_table_sector_to_le
269 ++ *
270 ++ * Convert bbr meta data from cpu endian format to on-disk (LE) format
271 ++ **/
272 ++static void cpu_bbr_table_sector_to_le(struct bbr_table *p,
273 ++ struct bbr_table *le)
274 ++{
275 ++ int i;
276 ++ le->signature = cpu_to_le32p(&p->signature);
277 ++ le->crc = cpu_to_le32p(&p->crc);
278 ++ le->sequence_number = cpu_to_le32p(&p->sequence_number);
279 ++ le->in_use_cnt = cpu_to_le32p(&p->in_use_cnt);
280 ++ for (i = 0; i < BBR_ENTRIES_PER_SECT; i++) {
281 ++ le->entries[i].bad_sect =
282 ++ cpu_to_le64p(&p->entries[i].bad_sect);
283 ++ le->entries[i].replacement_sect =
284 ++ cpu_to_le64p(&p->entries[i].replacement_sect);
285 ++ }
286 ++}
287 ++
288 ++/**
289 ++ * validate_bbr_table_sector
290 ++ *
291 ++ * Check the specified BBR table sector for a valid signature and CRC. If it's
292 ++ * valid, endian-convert the table sector.
293 ++ **/
294 ++static int validate_bbr_table_sector(struct bbr_table *p)
295 ++{
296 ++ int org_crc, final_crc;
297 ++
298 ++ if (le32_to_cpup(&p->signature) != BBR_TABLE_SIGNATURE) {
299 ++ DMERR("BBR table signature doesn't match!");
300 ++ DMERR("Found 0x%x. Expecting 0x%x",
301 ++ le32_to_cpup(&p->signature), BBR_TABLE_SIGNATURE);
302 ++ return -EINVAL;
303 ++ }
304 ++
305 ++ if (!p->crc) {
306 ++ DMERR("BBR table sector has no CRC!");
307 ++ return -EINVAL;
308 ++ }
309 ++
310 ++ org_crc = le32_to_cpup(&p->crc);
311 ++ p->crc = 0;
312 ++ final_crc = calculate_crc(INITIAL_CRC, (void *)p, sizeof(*p));
313 ++ if (final_crc != org_crc) {
314 ++ DMERR("CRC failed!");
315 ++ DMERR("Found 0x%x. Expecting 0x%x",
316 ++ org_crc, final_crc);
317 ++ return -EINVAL;
318 ++ }
319 ++
320 ++ p->crc = cpu_to_le32p(&org_crc);
321 ++ le_bbr_table_sector_to_cpu(p);
322 ++
323 ++ return 0;
324 ++}
325 ++
326 ++/**
327 ++ * bbr_binary_tree_insert
328 ++ *
329 ++ * Insert a node into the binary tree.
330 ++ **/
331 ++static void bbr_binary_tree_insert(struct bbr_runtime_remap **root,
332 ++ struct bbr_runtime_remap *newnode)
333 ++{
334 ++ struct bbr_runtime_remap **node = root;
335 ++ while (node && *node) {
336 ++ node = (newnode->remap.bad_sect > (*node)->remap.bad_sect) ?
337 ++ &(*node)->right : &(*node)->left;
338 ++ }
339 ++
340 ++ newnode->left = newnode->right = NULL;
341 ++ *node = newnode;
342 ++}
343 ++
344 ++/**
345 ++ * bbr_binary_search
346 ++ *
347 ++ * Search for a node that contains bad_sect == lsn.
348 ++ **/
349 ++static struct bbr_runtime_remap *bbr_binary_search(
350 ++ struct bbr_runtime_remap *root,
351 ++ u64 lsn)
352 ++{
353 ++ struct bbr_runtime_remap *node = root;
354 ++ while (node) {
355 ++ if (node->remap.bad_sect == lsn)
356 ++ break;
357 ++
358 ++ node = (lsn > node->remap.bad_sect) ? node->right : node->left;
359 ++ }
360 ++ return node;
361 ++}
362 ++
363 ++/**
364 ++ * bbr_insert_remap_entry
365 ++ *
366 ++ * Create a new remap entry and add it to the binary tree for this node.
367 ++ **/
368 ++static int bbr_insert_remap_entry(struct bbr_private *bbr_id,
369 ++ struct bbr_table_entry *new_bbr_entry)
370 ++{
371 ++ struct bbr_runtime_remap *newnode;
372 ++
373 ++ newnode = kmem_cache_alloc(bbr_remap_cache, GFP_NOIO);
374 ++ if (!newnode) {
375 ++ DMERR("Could not allocate from remap cache!");
376 ++ return -ENOMEM;
377 ++ }
378 ++ newnode->remap.bad_sect = new_bbr_entry->bad_sect;
379 ++ newnode->remap.replacement_sect = new_bbr_entry->replacement_sect;
380 ++ spin_lock_irq(&bbr_id->remap_root_lock);
381 ++ bbr_binary_tree_insert(&bbr_id->remap_root, newnode);
382 ++ spin_unlock_irq(&bbr_id->remap_root_lock);
383 ++ return 0;
384 ++}
385 ++
386 ++/**
387 ++ * bbr_table_to_remap_list
388 ++ *
389 ++ * The on-disk bbr table is sorted by the replacement sector LBA. In order to
390 ++ * improve run time performance, the in memory remap list must be sorted by
391 ++ * the bad sector LBA. This function is called at discovery time to initialize
392 ++ * the remap list. This function assumes that at least one copy of meta data
393 ++ * is valid.
394 ++ **/
395 ++static u32 bbr_table_to_remap_list(struct bbr_private *bbr_id)
396 ++{
397 ++ u32 in_use_blks = 0;
398 ++ int i, j;
399 ++ struct bbr_table *p;
400 ++
401 ++ for (i = 0, p = bbr_id->bbr_table;
402 ++ i < bbr_id->nr_sects_bbr_table;
403 ++ i++, p++) {
404 ++ if (!p->in_use_cnt)
405 ++ break;
406 ++
407 ++ in_use_blks += p->in_use_cnt;
408 ++ for (j = 0; j < p->in_use_cnt; j++)
409 ++ bbr_insert_remap_entry(bbr_id, &p->entries[j]);
410 ++ }
411 ++ if (in_use_blks) {
412 ++ char b[32];
413 ++ DMWARN("There are %u BBR entries for device %s",
414 ++ in_use_blks, format_dev_t(b, bbr_id->dev->bdev->bd_dev));
415 ++ }
416 ++
417 ++ return in_use_blks;
418 ++}
419 ++
420 ++/**
421 ++ * bbr_search_remap_entry
422 ++ *
423 ++ * Search remap entry for the specified sector. If found, return a pointer to
424 ++ * the table entry. Otherwise, return NULL.
425 ++ **/
426 ++static struct bbr_table_entry *bbr_search_remap_entry(
427 ++ struct bbr_private *bbr_id,
428 ++ u64 lsn)
429 ++{
430 ++ struct bbr_runtime_remap *p;
431 ++
432 ++ spin_lock_irq(&bbr_id->remap_root_lock);
433 ++ p = bbr_binary_search(bbr_id->remap_root, lsn);
434 ++ spin_unlock_irq(&bbr_id->remap_root_lock);
435 ++ return (p) ? &p->remap : NULL;
436 ++}
437 ++
438 ++/**
439 ++ * bbr_remap
440 ++ *
441 ++ * If *lsn is in the remap table, return TRUE and modify *lsn,
442 ++ * else, return FALSE.
443 ++ **/
444 ++static int bbr_remap(struct bbr_private *bbr_id,
445 ++ u64 *lsn)
446 ++{
447 ++ struct bbr_table_entry *e;
448 ++
449 ++ if (atomic_read(&bbr_id->in_use_replacement_blks)) {
450 ++ e = bbr_search_remap_entry(bbr_id, *lsn);
451 ++ if (e) {
452 ++ *lsn = e->replacement_sect;
453 ++ return 1;
454 ++ }
455 ++ }
456 ++ return 0;
457 ++}
458 ++
459 ++/**
460 ++ * bbr_remap_probe
461 ++ *
462 ++ * If any of the sectors in the range [lsn, lsn+nr_sects] are in the remap
463 ++ * table return TRUE, Else, return FALSE.
464 ++ **/
465 ++static int bbr_remap_probe(struct bbr_private *bbr_id,
466 ++ u64 lsn, u64 nr_sects)
467 ++{
468 ++ u64 tmp, cnt;
469 ++
470 ++ if (atomic_read(&bbr_id->in_use_replacement_blks)) {
471 ++ for (cnt = 0, tmp = lsn;
472 ++ cnt < nr_sects;
473 ++ cnt += bbr_id->blksize_in_sects, tmp = lsn + cnt) {
474 ++ if (bbr_remap(bbr_id,&tmp))
475 ++ return 1;
476 ++ }
477 ++ }
478 ++ return 0;
479 ++}
480 ++
481 ++static int rw_table(struct bbr_private *bbr_id, void *vma,
482 ++ struct dm_io_region *ptr, int rw)
483 ++{
484 ++ bbr_id->vma_io_req.bi_rw = rw;
485 ++ bbr_id->vma_io_req.mem.ptr.vma = vma;
486 ++ bbr_id->vma_io_req.notify.fn = NULL;
487 ++
488 ++ return dm_io(&bbr_id->vma_io_req, 1, ptr, NULL);
489 ++}
490 ++
491 ++static int io_sync(struct bbr_private *bbr_id, struct page_list *pl,
492 ++ unsigned offset, struct dm_io_region *ptr, int rw)
493 ++{
494 ++ bbr_id->page_io_req.bi_rw = rw;
495 ++ bbr_id->page_io_req.mem.ptr.pl = pl;
496 ++ bbr_id->page_io_req.mem.offset = offset;
497 ++ bbr_id->page_io_req.notify.fn = NULL;
498 ++
499 ++ return dm_io(&bbr_id->page_io_req, 1, ptr, NULL);
500 ++}
501 ++
502 ++/**
503 ++ * bbr_setup
504 ++ *
505 ++ * Read the remap tables from disk and set up the initial remap tree.
506 ++ **/
507 ++static int bbr_setup(struct bbr_private *bbr_id)
508 ++{
509 ++ struct bbr_table *table = bbr_id->bbr_table;
510 ++ struct dm_io_region job;
511 ++ int i, rc = 0;
512 ++
513 ++ job.bdev = bbr_id->dev->bdev;
514 ++ job.count = 1;
515 ++
516 ++ /* Read and verify each BBR table sector individually. */
517 ++ for (i = 0; i < bbr_id->nr_sects_bbr_table; i++, table++) {
518 ++ job.sector = bbr_id->lba_table1 + i;
519 ++ rc = rw_table(bbr_id, table, &job, READ);
520 ++ if (rc && bbr_id->lba_table2) {
521 ++ job.sector = bbr_id->lba_table2 + i;
522 ++ rc = rw_table(bbr_id, table, &job, READ);
523 ++ }
524 ++ if (rc)
525 ++ goto out;
526 ++
527 ++ rc = validate_bbr_table_sector(table);
528 ++ if (rc)
529 ++ goto out;
530 ++ }
531 ++ atomic_set(&bbr_id->in_use_replacement_blks,
532 ++ bbr_table_to_remap_list(bbr_id));
533 ++
534 ++out:
535 ++ if (rc)
536 ++ DMERR("error during device setup: %d", rc);
537 ++ return rc;
538 ++}
539 ++
540 ++/**
541 ++ * bbr_io_remap_error
542 ++ * @bbr_id: Private data for the BBR node.
543 ++ * @rw: READ or WRITE.
544 ++ * @starting_lsn: Starting sector of request to remap.
545 ++ * @count: Number of sectors in the request.
546 ++ * @page: Page containing the data for the request.
547 ++ * @offset: Byte-offset of the data within the page.
548 ++ *
549 ++ * For the requested range, try to write each sector individually. For each
550 ++ * sector that fails, find the next available remap location and write the
551 ++ * data to that new location. Then update the table and write both copies
552 ++ * of the table to disk. Finally, update the in-memory mapping and do any
553 ++ * other necessary bookkeeping.
554 ++ **/
555 ++static int bbr_io_remap_error(struct bbr_private *bbr_id,
556 ++ int rw,
557 ++ u64 starting_lsn,
558 ++ u64 count,
559 ++ struct page *page,
560 ++ unsigned int offset)
561 ++{
562 ++ struct bbr_table *bbr_table;
563 ++ struct dm_io_region job;
564 ++ struct page_list pl;
565 ++ unsigned long table_sector_index;
566 ++ unsigned long table_sector_offset;
567 ++ unsigned long index;
568 ++ u64 lsn, new_lsn;
569 ++ char b[32];
570 ++ int rc;
571 ++
572 ++ job.bdev = bbr_id->dev->bdev;
573 ++ job.count = 1;
574 ++ pl.page = page;
575 ++ pl.next = NULL;
576 ++
577 ++ /* For each sector in the request. */
578 ++ for (lsn = 0; lsn < count; lsn++, offset += SECTOR_SIZE) {
579 ++ job.sector = starting_lsn + lsn;
580 ++ rc = io_sync(bbr_id, &pl, offset, &job, rw);
581 ++ while (rc) {
582 ++ /* Find the next available relocation sector. */
583 ++ new_lsn = atomic_read(&bbr_id->in_use_replacement_blks);
584 ++ if (new_lsn >= bbr_id->nr_replacement_blks) {
585 ++ /* No more replacement sectors available. */
586 ++ return -EIO;
587 ++ }
588 ++ new_lsn += bbr_id->start_replacement_sect;
589 ++
590 ++ /* Write the data to its new location. */
591 ++ DMWARN("device %s: Trying to remap bad sector "PFU64" to sector "PFU64,
592 ++ format_dev_t(b, bbr_id->dev->bdev->bd_dev),
593 ++ starting_lsn + lsn, new_lsn);
594 ++ job.sector = new_lsn;
595 ++ rc = io_sync(bbr_id, &pl, offset, &job, rw);
596 ++ if (rc) {
597 ++ /* This replacement sector is bad.
598 ++ * Try the next one.
599 ++ */
600 ++ DMERR("device %s: replacement sector "PFU64" is bad. Skipping.",
601 ++ format_dev_t(b, bbr_id->dev->bdev->bd_dev), new_lsn);
602 ++ atomic_inc(&bbr_id->in_use_replacement_blks);
603 ++ continue;
604 ++ }
605 ++
606 ++ /* Add this new entry to the on-disk table. */
607 ++ table_sector_index = new_lsn -
608 ++ bbr_id->start_replacement_sect;
609 ++ table_sector_offset = table_sector_index /
610 ++ BBR_ENTRIES_PER_SECT;
611 ++ index = table_sector_index % BBR_ENTRIES_PER_SECT;
612 ++
613 ++ bbr_table = &bbr_id->bbr_table[table_sector_offset];
614 ++ bbr_table->entries[index].bad_sect = starting_lsn + lsn;
615 ++ bbr_table->entries[index].replacement_sect = new_lsn;
616 ++ bbr_table->in_use_cnt++;
617 ++ bbr_table->sequence_number++;
618 ++ bbr_table->crc = 0;
619 ++ bbr_table->crc = calculate_crc(INITIAL_CRC,
620 ++ bbr_table,
621 ++ sizeof(struct bbr_table));
622 ++
623 ++ /* Write the table to disk. */
624 ++ cpu_bbr_table_sector_to_le(bbr_table, bbr_table);
625 ++ if (bbr_id->lba_table1) {
626 ++ job.sector = bbr_id->lba_table1 + table_sector_offset;
627 ++ rc = rw_table(bbr_id, bbr_table, &job, WRITE);
628 ++ }
629 ++ if (bbr_id->lba_table2) {
630 ++ job.sector = bbr_id->lba_table2 + table_sector_offset;
631 ++ rc |= rw_table(bbr_id, bbr_table, &job, WRITE);
632 ++ }
633 ++ le_bbr_table_sector_to_cpu(bbr_table);
634 ++
635 ++ if (rc) {
636 ++ /* Error writing one of the tables to disk. */
637 ++ DMERR("device %s: error updating BBR tables on disk.",
638 ++ format_dev_t(b, bbr_id->dev->bdev->bd_dev));
639 ++ return rc;
640 ++ }
641 ++
642 ++ /* Insert a new entry in the remapping binary-tree. */
643 ++ rc = bbr_insert_remap_entry(bbr_id,
644 ++ &bbr_table->entries[index]);
645 ++ if (rc) {
646 ++ DMERR("device %s: error adding new entry to remap tree.",
647 ++ format_dev_t(b, bbr_id->dev->bdev->bd_dev));
648 ++ return rc;
649 ++ }
650 ++
651 ++ atomic_inc(&bbr_id->in_use_replacement_blks);
652 ++ }
653 ++ }
654 ++
655 ++ return 0;
656 ++}
657 ++
658 ++/**
659 ++ * bbr_io_process_request
660 ++ *
661 ++ * For each sector in this request, check if the sector has already
662 ++ * been remapped. If so, process all previous sectors in the request,
663 ++ * followed by the remapped sector. Then reset the starting lsn and
664 ++ * count, and keep going with the rest of the request as if it were
665 ++ * a whole new request. If any of the sync_io's return an error,
666 ++ * call the remapper to relocate the bad sector(s).
667 ++ *
668 ++ * 2.5 Note: When switching over to bio's for the I/O path, we have made
669 ++ * the assumption that the I/O request described by the bio is one
670 ++ * virtually contiguous piece of memory (even though the bio vector
671 ++ * describes it using a series of physical page addresses).
672 ++ **/
673 ++static int bbr_io_process_request(struct bbr_private *bbr_id,
674 ++ struct bio *bio)
675 ++{
676 ++ struct dm_io_region job;
677 ++ u64 starting_lsn = bio->bi_sector;
678 ++ u64 count, lsn, remapped_lsn;
679 ++ struct page_list pl;
680 ++ unsigned int offset;
681 ++ int i, rw = bio_data_dir(bio);
682 ++ int rc = 0;
683 ++
684 ++ job.bdev = bbr_id->dev->bdev;
685 ++ pl.next = NULL;
686 ++
687 ++ /* Each bio can contain multiple vectors, each with a different page.
688 ++ * Treat each vector as a separate request.
689 ++ */
690 ++ /* KMC: Is this the right way to walk the bvec list? */
691 ++ for (i = 0;
692 ++ i < bio->bi_vcnt;
693 ++ i++, bio->bi_idx++, starting_lsn += count) {
694 ++
695 ++ /* Bvec info: number of sectors, page,
696 ++ * and byte-offset within page.
697 ++ */
698 ++ count = bio_iovec(bio)->bv_len >> SECTOR_SHIFT;
699 ++ pl.page = bio_iovec(bio)->bv_page;
700 ++ offset = bio_iovec(bio)->bv_offset;
701 ++
702 ++ /* For each sector in this bvec, check if the sector has
703 ++ * already been remapped. If so, process all previous sectors
704 ++ * in this request, followed by the remapped sector. Then reset
705 ++ * the starting lsn and count and keep going with the rest of
706 ++ * the request as if it were a whole new request.
707 ++ */
708 ++ for (lsn = 0; lsn < count; lsn++) {
709 ++ remapped_lsn = starting_lsn + lsn;
710 ++ rc = bbr_remap(bbr_id, &remapped_lsn);
711 ++ if (!rc) {
712 ++ /* This sector is fine. */
713 ++ continue;
714 ++ }
715 ++
716 ++ /* Process all sectors in the request up to this one. */
717 ++ if (lsn > 0) {
718 ++ job.sector = starting_lsn;
719 ++ job.count = lsn;
720 ++ rc = io_sync(bbr_id, &pl, offset, &job, rw);
721 ++ if (rc) {
722 ++ /* If this I/O failed, then one of the
723 ++ * sectors in this request needs to be
724 ++ * relocated.
725 ++ */
726 ++ rc = bbr_io_remap_error(bbr_id, rw,
727 ++ starting_lsn,
728 ++ lsn, pl.page,
729 ++ offset);
730 ++ if (rc) {
731 ++ /* KMC: Return? Or continue to next bvec? */
732 ++ return rc;
733 ++ }
734 ++ }
735 ++ offset += (lsn << SECTOR_SHIFT);
736 ++ }
737 ++
738 ++ /* Process the remapped sector. */
739 ++ job.sector = remapped_lsn;
740 ++ job.count = 1;
741 ++ rc = io_sync(bbr_id, &pl, offset, &job, rw);
742 ++ if (rc) {
743 ++ /* BUGBUG - Need more processing if this caused
744 ++ * an error. If this I/O failed, then the
745 ++ * existing remap is now bad, and we need to
746 ++ * find a new remap. Can't use
747 ++ * bbr_io_remap_error(), because the existing
748 ++ * map entry needs to be changed, not added
749 ++ * again, and the original table entry also
750 ++ * needs to be changed.
751 ++ */
752 ++ return rc;
753 ++ }
754 ++
755 ++ starting_lsn += (lsn + 1);
756 ++ count -= (lsn + 1);
757 ++ lsn = -1;
758 ++ offset += SECTOR_SIZE;
759 ++ }
760 ++
761 ++ /* Check for any remaining sectors after the last split. This
762 ++ * could potentially be the whole request, but that should be a
763 ++ * rare case because requests should only be processed by the
764 ++ * thread if we know an error occurred or they contained one or
765 ++ * more remapped sectors.
766 ++ */
767 ++ if (count) {
768 ++ job.sector = starting_lsn;
769 ++ job.count = count;
770 ++ rc = io_sync(bbr_id, &pl, offset, &job, rw);
771 ++ if (rc) {
772 ++ /* If this I/O failed, then one of the sectors
773 ++ * in this request needs to be relocated.
774 ++ */
775 ++ rc = bbr_io_remap_error(bbr_id, rw, starting_lsn,
776 ++ count, pl.page, offset);
777 ++ if (rc) {
778 ++ /* KMC: Return? Or continue to next bvec? */
779 ++ return rc;
780 ++ }
781 ++ }
782 ++ }
783 ++ }
784 ++
785 ++ return 0;
786 ++}
787 ++
788 ++static void bbr_io_process_requests(struct bbr_private *bbr_id,
789 ++ struct bio *bio)
790 ++{
791 ++ struct bio *next;
792 ++ int rc;
793 ++
794 ++ while (bio) {
795 ++ next = bio->bi_next;
796 ++ bio->bi_next = NULL;
797 ++
798 ++ rc = bbr_io_process_request(bbr_id, bio);
799 ++
800 ++ bio_endio(bio, rc);
801 ++
802 ++ bio = next;
803 ++ }
804 ++}
805 ++
806 ++/**
807 ++ * bbr_remap_handler
808 ++ *
809 ++ * This is the handler for the bbr work-queue.
810 ++ *
811 ++ * I/O requests should only be sent to this handler if we know that:
812 ++ * a) the request contains at least one remapped sector.
813 ++ * or
814 ++ * b) the request caused an error on the normal I/O path.
815 ++ *
816 ++ * This function uses synchronous I/O, so sending a request to this
817 ++ * thread that doesn't need special processing will cause severe
818 ++ * performance degredation.
819 ++ **/
820 ++static void bbr_remap_handler(struct work_struct *work)
821 ++{
822 ++ struct bbr_private *bbr_id =
823 ++ container_of(work, struct bbr_private, remap_work);
824 ++ struct bio *bio;
825 ++ unsigned long flags;
826 ++
827 ++ spin_lock_irqsave(&bbr_id->remap_ios_lock, flags);
828 ++ bio = bio_list_get(&bbr_id->remap_ios);
829 ++ spin_unlock_irqrestore(&bbr_id->remap_ios_lock, flags);
830 ++
831 ++ bbr_io_process_requests(bbr_id, bio);
832 ++}
833 ++
834 ++/**
835 ++ * bbr_endio
836 ++ *
837 ++ * This is the callback for normal write requests. Check for an error
838 ++ * during the I/O, and send to the thread for processing if necessary.
839 ++ **/
840 ++static int bbr_endio(struct dm_target *ti, struct bio *bio,
841 ++ int error, union map_info *map_context)
842 ++{
843 ++ struct bbr_private *bbr_id = ti->private;
844 ++ struct dm_bio_details *bbr_io = map_context->ptr;
845 ++
846 ++ if (error && bbr_io) {
847 ++ unsigned long flags;
848 ++ char b[32];
849 ++
850 ++ dm_bio_restore(bbr_io, bio);
851 ++ map_context->ptr = NULL;
852 ++
853 ++ DMERR("device %s: I/O failure on sector %lu. "
854 ++ "Scheduling for retry.",
855 ++ format_dev_t(b, bbr_id->dev->bdev->bd_dev),
856 ++ (unsigned long)bio->bi_sector);
857 ++
858 ++ spin_lock_irqsave(&bbr_id->remap_ios_lock, flags);
859 ++ bio_list_add(&bbr_id->remap_ios, bio);
860 ++ spin_unlock_irqrestore(&bbr_id->remap_ios_lock, flags);
861 ++
862 ++ queue_work(dm_bbr_wq, &bbr_id->remap_work);
863 ++
864 ++ error = 1;
865 ++ }
866 ++
867 ++ if (bbr_io)
868 ++ mempool_free(bbr_io, bbr_io_pool);
869 ++
870 ++ return error;
871 ++}
872 ++
873 ++/**
874 ++ * Construct a bbr mapping
875 ++ **/
876 ++static int bbr_ctr(struct dm_target *ti, unsigned int argc, char **argv)
877 ++{
878 ++ struct bbr_private *bbr_id;
879 ++ unsigned long block_size;
880 ++ char *end;
881 ++ int rc = -EINVAL;
882 ++
883 ++ if (argc != 8) {
884 ++ ti->error = "dm-bbr requires exactly 8 arguments: "
885 ++ "device offset table1_lsn table2_lsn table_size start_replacement nr_replacement_blks block_size";
886 ++ goto out1;
887 ++ }
888 ++
889 ++ bbr_id = bbr_alloc_private();
890 ++ if (!bbr_id) {
891 ++ ti->error = "dm-bbr: Error allocating bbr private data.";
892 ++ goto out1;
893 ++ }
894 ++
895 ++ bbr_id->offset = simple_strtoull(argv[1], &end, 10);
896 ++ bbr_id->lba_table1 = simple_strtoull(argv[2], &end, 10);
897 ++ bbr_id->lba_table2 = simple_strtoull(argv[3], &end, 10);
898 ++ bbr_id->nr_sects_bbr_table = simple_strtoull(argv[4], &end, 10);
899 ++ bbr_id->start_replacement_sect = simple_strtoull(argv[5], &end, 10);
900 ++ bbr_id->nr_replacement_blks = simple_strtoull(argv[6], &end, 10);
901 ++ block_size = simple_strtoul(argv[7], &end, 10);
902 ++ bbr_id->blksize_in_sects = (block_size >> SECTOR_SHIFT);
903 ++
904 ++ bbr_id->vma_io_req.mem.type = DM_IO_VMA;
905 ++ bbr_id->vma_io_req.client = dm_io_client_create(1);
906 ++ if (IS_ERR(bbr_id->vma_io_req.client)) {
907 ++ rc = PTR_ERR(bbr_id->vma_io_req.client);
908 ++ DMWARN("couldn't allocate disk VMA io client");
909 ++ goto out2;
910 ++ }
911 ++
912 ++ bbr_id->page_io_req.mem.type = DM_IO_PAGE_LIST;
913 ++ bbr_id->page_io_req.client = dm_io_client_create(1);
914 ++ if (IS_ERR(bbr_id->page_io_req.client)) {
915 ++ rc = PTR_ERR(bbr_id->page_io_req.client);
916 ++ DMWARN("couldn't allocate pagelist io client");
917 ++ goto out3;
918 ++ }
919 ++
920 ++ bbr_id->bbr_table = vmalloc(bbr_id->nr_sects_bbr_table << SECTOR_SHIFT);
921 ++ if (!bbr_id->bbr_table) {
922 ++ ti->error = "dm-bbr: Error allocating bbr table.";
923 ++ goto out4;
924 ++ }
925 ++
926 ++ if (dm_get_device(ti, argv[0], 0, ti->len,
927 ++ dm_table_get_mode(ti->table), &bbr_id->dev)) {
928 ++ ti->error = "dm-bbr: Device lookup failed";
929 ++ goto out4;
930 ++ }
931 ++
932 ++ rc = bbr_setup(bbr_id);
933 ++ if (rc) {
934 ++ ti->error = "dm-bbr: Device setup failed";
935 ++ goto out5;
936 ++ }
937 ++
938 ++ ti->private = bbr_id;
939 ++ return 0;
940 ++
941 ++out5:
942 ++ dm_put_device(ti, bbr_id->dev);
943 ++out4:
944 ++ dm_io_client_destroy(bbr_id->page_io_req.client);
945 ++out3:
946 ++ dm_io_client_destroy(bbr_id->vma_io_req.client);
947 ++out2:
948 ++ bbr_free_private(bbr_id);
949 ++out1:
950 ++ return rc;
951 ++}
952 ++
953 ++static void bbr_dtr(struct dm_target *ti)
954 ++{
955 ++ struct bbr_private *bbr_id = ti->private;
956 ++
957 ++ dm_put_device(ti, bbr_id->dev);
958 ++ dm_io_client_destroy(bbr_id->page_io_req.client);
959 ++ dm_io_client_destroy(bbr_id->vma_io_req.client);
960 ++ bbr_free_private(bbr_id);
961 ++}
962 ++
963 ++static int bbr_map(struct dm_target *ti, struct bio *bio,
964 ++ union map_info *map_context)
965 ++{
966 ++ struct bbr_private *bbr_id = ti->private;
967 ++ struct dm_bio_details *bbr_io;
968 ++ unsigned long flags;
969 ++ int rc = 1;
970 ++
971 ++ bio->bi_sector += bbr_id->offset;
972 ++
973 ++ if (atomic_read(&bbr_id->in_use_replacement_blks) == 0 ||
974 ++ !bbr_remap_probe(bbr_id, bio->bi_sector, bio_sectors(bio))) {
975 ++ /* No existing remaps or this request doesn't
976 ++ * contain any remapped sectors.
977 ++ */
978 ++ bio->bi_bdev = bbr_id->dev->bdev;
979 ++
980 ++ bbr_io = mempool_alloc(bbr_io_pool, GFP_NOIO);
981 ++ dm_bio_record(bbr_io, bio);
982 ++ map_context->ptr = bbr_io;
983 ++ } else {
984 ++ /* This request has at least one remapped sector.
985 ++ * Give it to the work-queue for processing.
986 ++ */
987 ++ map_context->ptr = NULL;
988 ++ spin_lock_irqsave(&bbr_id->remap_ios_lock, flags);
989 ++ bio_list_add(&bbr_id->remap_ios, bio);
990 ++ spin_unlock_irqrestore(&bbr_id->remap_ios_lock, flags);
991 ++
992 ++ queue_work(dm_bbr_wq, &bbr_id->remap_work);
993 ++ rc = 0;
994 ++ }
995 ++
996 ++ return rc;
997 ++}
998 ++
999 ++static int bbr_status(struct dm_target *ti, status_type_t type,
1000 ++ char *result, unsigned int maxlen)
1001 ++{
1002 ++ struct bbr_private *bbr_id = ti->private;
1003 ++ char b[BDEVNAME_SIZE];
1004 ++
1005 ++ switch (type) {
1006 ++ case STATUSTYPE_INFO:
1007 ++ result[0] = '\0';
1008 ++ break;
1009 ++
1010 ++ case STATUSTYPE_TABLE:
1011 ++ snprintf(result, maxlen, "%s "PFU64" "PFU64" "PFU64" "PFU64" "PFU64" "PFU64" %u",
1012 ++ format_dev_t(b, bbr_id->dev->bdev->bd_dev),
1013 ++ bbr_id->offset, bbr_id->lba_table1, bbr_id->lba_table2,
1014 ++ bbr_id->nr_sects_bbr_table,
1015 ++ bbr_id->start_replacement_sect,
1016 ++ bbr_id->nr_replacement_blks,
1017 ++ bbr_id->blksize_in_sects << SECTOR_SHIFT);
1018 ++ break;
1019 ++ }
1020 ++ return 0;
1021 ++}
1022 ++
1023 ++static struct target_type bbr_target = {
1024 ++ .name = "bbr",
1025 ++ .version= {1, 0, 1},
1026 ++ .module = THIS_MODULE,
1027 ++ .ctr = bbr_ctr,
1028 ++ .dtr = bbr_dtr,
1029 ++ .map = bbr_map,
1030 ++ .end_io = bbr_endio,
1031 ++ .status = bbr_status,
1032 ++};
1033 ++
1034 ++int __init dm_bbr_init(void)
1035 ++{
1036 ++ int rc;
1037 ++
1038 ++ rc = dm_register_target(&bbr_target);
1039 ++ if (rc) {
1040 ++ DMERR("error registering target.");
1041 ++ goto err1;
1042 ++ }
1043 ++
1044 ++ bbr_remap_cache = kmem_cache_create("bbr-remap",
1045 ++ sizeof(struct bbr_runtime_remap),
1046 ++ 0, SLAB_HWCACHE_ALIGN, NULL);
1047 ++ if (!bbr_remap_cache) {
1048 ++ DMERR("error creating remap cache.");
1049 ++ rc = ENOMEM;
1050 ++ goto err2;
1051 ++ }
1052 ++
1053 ++ bbr_io_cache = kmem_cache_create("bbr-io", sizeof(struct dm_bio_details),
1054 ++ 0, SLAB_HWCACHE_ALIGN, NULL);
1055 ++ if (!bbr_io_cache) {
1056 ++ DMERR("error creating io cache.");
1057 ++ rc = ENOMEM;
1058 ++ goto err3;
1059 ++ }
1060 ++
1061 ++ bbr_io_pool = mempool_create(256, mempool_alloc_slab,
1062 ++ mempool_free_slab, bbr_io_cache);
1063 ++ if (!bbr_io_pool) {
1064 ++ DMERR("error creating io mempool.");
1065 ++ rc = ENOMEM;
1066 ++ goto err4;
1067 ++ }
1068 ++
1069 ++ dm_bbr_wq = create_workqueue("dm-bbr");
1070 ++ if (!dm_bbr_wq) {
1071 ++ DMERR("error creating work-queue.");
1072 ++ rc = ENOMEM;
1073 ++ goto err5;
1074 ++ }
1075 ++
1076 ++ return 0;
1077 ++
1078 ++err5:
1079 ++ mempool_destroy(bbr_io_pool);
1080 ++err4:
1081 ++ kmem_cache_destroy(bbr_io_cache);
1082 ++err3:
1083 ++ kmem_cache_destroy(bbr_remap_cache);
1084 ++err2:
1085 ++ dm_unregister_target(&bbr_target);
1086 ++err1:
1087 ++ return rc;
1088 ++}
1089 ++
1090 ++void __exit dm_bbr_exit(void)
1091 ++{
1092 ++ destroy_workqueue(dm_bbr_wq);
1093 ++ mempool_destroy(bbr_io_pool);
1094 ++ kmem_cache_destroy(bbr_io_cache);
1095 ++ kmem_cache_destroy(bbr_remap_cache);
1096 ++ dm_unregister_target(&bbr_target);
1097 ++}
1098 ++
1099 ++module_init(dm_bbr_init);
1100 ++module_exit(dm_bbr_exit);
1101 ++MODULE_LICENSE("GPL");
1102 +Index: linux-2.6.26-gentoo/drivers/md/dm-bbr.h
1103 +===================================================================
1104 +--- /dev/null
1105 ++++ linux-2.6.26-gentoo/drivers/md/dm-bbr.h
1106 +@@ -0,0 +1,130 @@
1107 ++/*
1108 ++ * (C) Copyright IBM Corp. 2002, 2004
1109 ++ *
1110 ++ * This program is free software; you can redistribute it and/or modify
1111 ++ * it under the terms of the GNU General Public License as published by
1112 ++ * the Free Software Foundation; either version 2 of the License, or
1113 ++ * (at your option) any later version.
1114 ++ *
1115 ++ * This program is distributed in the hope that it will be useful,
1116 ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1117 ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
1118 ++ * the GNU General Public License for more details.
1119 ++ *
1120 ++ * You should have received a copy of the GNU General Public License
1121 ++ * along with this program; if not, write to the Free Software
1122 ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1123 ++ *
1124 ++ * linux/drivers/md/dm-bbr.h
1125 ++ *
1126 ++ * Bad-block-relocation (BBR) target for device-mapper.
1127 ++ *
1128 ++ * The BBR target is designed to remap I/O write failures to another safe
1129 ++ * location on disk. Note that most disk drives have BBR built into them,
1130 ++ * this means that our software BBR will be only activated when all hardware
1131 ++ * BBR replacement sectors have been used.
1132 ++ */
1133 ++
1134 ++#include <linux/dm-io.h>
1135 ++
1136 ++#define BBR_TABLE_SIGNATURE 0x42627254 /* BbrT */
1137 ++#define BBR_ENTRIES_PER_SECT 31
1138 ++#define INITIAL_CRC 0xFFFFFFFF
1139 ++#define CRC_POLYNOMIAL 0xEDB88320L
1140 ++
1141 ++/**
1142 ++ * Macros to cleanly print 64-bit numbers on both 32-bit and 64-bit machines.
1143 ++ * Use these in place of %Ld, %Lu, and %Lx.
1144 ++ **/
1145 ++#if BITS_PER_LONG > 32
1146 ++#define PFU64 "%llu"
1147 ++#else
1148 ++#define PFU64 "%Lu"
1149 ++#endif
1150 ++
1151 ++/**
1152 ++ * struct bbr_table_entry
1153 ++ * @bad_sect: LBA of bad location.
1154 ++ * @replacement_sect: LBA of new location.
1155 ++ *
1156 ++ * Structure to describe one BBR remap.
1157 ++ **/
1158 ++struct bbr_table_entry {
1159 ++ u64 bad_sect;
1160 ++ u64 replacement_sect;
1161 ++};
1162 ++
1163 ++/**
1164 ++ * struct bbr_table
1165 ++ * @signature: Signature on each BBR table sector.
1166 ++ * @crc: CRC for this table sector.
1167 ++ * @sequence_number: Used to resolve conflicts when primary and secondary
1168 ++ * tables do not match.
1169 ++ * @in_use_cnt: Number of in-use table entries.
1170 ++ * @entries: Actual table of remaps.
1171 ++ *
1172 ++ * Structure to describe each sector of the metadata table. Each sector in this
1173 ++ * table can describe 31 remapped sectors.
1174 ++ **/
1175 ++struct bbr_table {
1176 ++ u32 signature;
1177 ++ u32 crc;
1178 ++ u32 sequence_number;
1179 ++ u32 in_use_cnt;
1180 ++ struct bbr_table_entry entries[BBR_ENTRIES_PER_SECT];
1181 ++};
1182 ++
1183 ++/**
1184 ++ * struct bbr_runtime_remap
1185 ++ *
1186 ++ * Node in the binary tree used to keep track of remaps.
1187 ++ **/
1188 ++struct bbr_runtime_remap {
1189 ++ struct bbr_table_entry remap;
1190 ++ struct bbr_runtime_remap *left;
1191 ++ struct bbr_runtime_remap *right;
1192 ++};
1193 ++
1194 ++/**
1195 ++ * struct bbr_private
1196 ++ * @dev: Info about underlying device.
1197 ++ * @bbr_table: Copy of metadata table.
1198 ++ * @remap_root: Binary tree containing all remaps.
1199 ++ * @remap_root_lock: Lock for the binary tree.
1200 ++ * @remap_work: For adding work items to the work-queue.
1201 ++ * @remap_ios: List of I/Os for the work-queue to handle.
1202 ++ * @remap_ios_lock: Lock for the remap_ios list.
1203 ++ * @offset: LBA of data area.
1204 ++ * @lba_table1: LBA of primary BBR table.
1205 ++ * @lba_table2: LBA of secondary BBR table.
1206 ++ * @nr_sects_bbr_table: Size of each BBR table.
1207 ++ * @nr_replacement_blks: Number of replacement blocks.
1208 ++ * @start_replacement_sect: LBA of start of replacement blocks.
1209 ++ * @blksize_in_sects: Size of each block.
1210 ++ * @in_use_replacement_blks: Current number of remapped blocks.
1211 ++ *
1212 ++ * Private data for each BBR target.
1213 ++ **/
1214 ++struct bbr_private {
1215 ++ struct dm_dev *dev;
1216 ++ struct bbr_table *bbr_table;
1217 ++ struct bbr_runtime_remap *remap_root;
1218 ++ spinlock_t remap_root_lock;
1219 ++
1220 ++ struct dm_io_request vma_io_req;
1221 ++ struct dm_io_request page_io_req;
1222 ++
1223 ++ struct work_struct remap_work;
1224 ++ struct bio_list remap_ios;
1225 ++ spinlock_t remap_ios_lock;
1226 ++
1227 ++ u64 offset;
1228 ++ u64 lba_table1;
1229 ++ u64 lba_table2;
1230 ++ u64 nr_sects_bbr_table;
1231 ++ u64 start_replacement_sect;
1232 ++ u64 nr_replacement_blks;
1233 ++ u32 blksize_in_sects;
1234 ++ atomic_t in_use_replacement_blks;
1235 ++};
1236 ++
1237
1238 Deleted: genpatches-2.6/trunk/2.6.27/4105_dm-bbr.patch
1239 ===================================================================
1240 --- genpatches-2.6/trunk/2.6.27/4105_dm-bbr.patch 2008-10-11 01:09:49 UTC (rev 1353)
1241 +++ genpatches-2.6/trunk/2.6.27/4105_dm-bbr.patch 2008-10-12 18:19:38 UTC (rev 1354)
1242 @@ -1,1190 +0,0 @@
1243 -BBR Target, updated by dsd@g.o
1244 -
1245 -Incomplete changelog:
1246 - 2008/06/16: updated for new API in 2.6.26
1247 - 2007/07/08: updated for new API in 2.6.22
1248 -
1249 -Index: linux-2.6.26-gentoo/drivers/md/Kconfig
1250 -===================================================================
1251 ---- linux-2.6.26-gentoo.orig/drivers/md/Kconfig
1252 -+++ linux-2.6.26-gentoo/drivers/md/Kconfig
1253 -@@ -288,4 +288,15 @@ config DM_UEVENT
1254 - ---help---
1255 - Generate udev events for DM events.
1256 -
1257 -+config BLK_DEV_DM_BBR
1258 -+ tristate "Bad Block Relocation Device Target (EXPERIMENTAL)"
1259 -+ depends on BLK_DEV_DM && EXPERIMENTAL
1260 -+ ---help---
1261 -+ Support for devices with software-based bad-block-relocation.
1262 -+
1263 -+ To compile this as a module, choose M here: the module will be
1264 -+ called dm-bbr.
1265 -+
1266 -+ If unsure, say N.
1267 -+
1268 - endif # MD
1269 -Index: linux-2.6.26-gentoo/drivers/md/Makefile
1270 -===================================================================
1271 ---- linux-2.6.26-gentoo.orig/drivers/md/Makefile
1272 -+++ linux-2.6.26-gentoo/drivers/md/Makefile
1273 -@@ -41,6 +41,7 @@ obj-$(CONFIG_DM_MULTIPATH_RDAC) += dm-rd
1274 - obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o
1275 - obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o
1276 - obj-$(CONFIG_DM_ZERO) += dm-zero.o
1277 -+obj-$(CONFIG_BLK_DEV_DM_BBR) += dm-bbr.o
1278 -
1279 - quiet_cmd_unroll = UNROLL $@
1280 - cmd_unroll = $(PERL) $(srctree)/$(src)/unroll.pl $(UNROLL) \
1281 -Index: linux-2.6.26-gentoo/drivers/md/dm-bbr.c
1282 -===================================================================
1283 ---- /dev/null
1284 -+++ linux-2.6.26-gentoo/drivers/md/dm-bbr.c
1285 -@@ -0,0 +1,1012 @@
1286 -+/*
1287 -+ * (C) Copyright IBM Corp. 2002, 2004
1288 -+ *
1289 -+ * This program is free software; you can redistribute it and/or modify
1290 -+ * it under the terms of the GNU General Public License as published by
1291 -+ * the Free Software Foundation; either version 2 of the License, or
1292 -+ * (at your option) any later version.
1293 -+ *
1294 -+ * This program is distributed in the hope that it will be useful,
1295 -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1296 -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
1297 -+ * the GNU General Public License for more details.
1298 -+ *
1299 -+ * You should have received a copy of the GNU General Public License
1300 -+ * along with this program; if not, write to the Free Software
1301 -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1302 -+ *
1303 -+ * linux/drivers/md/dm-bbr.c
1304 -+ *
1305 -+ * Bad-block-relocation (BBR) target for device-mapper.
1306 -+ *
1307 -+ * The BBR target is designed to remap I/O write failures to another safe
1308 -+ * location on disk. Note that most disk drives have BBR built into them,
1309 -+ * this means that our software BBR will be only activated when all hardware
1310 -+ * BBR replacement sectors have been used.
1311 -+ */
1312 -+
1313 -+#include <linux/module.h>
1314 -+#include <linux/init.h>
1315 -+#include <linux/bio.h>
1316 -+#include <linux/spinlock.h>
1317 -+#include <linux/slab.h>
1318 -+#include <linux/mempool.h>
1319 -+#include <linux/workqueue.h>
1320 -+#include <linux/vmalloc.h>
1321 -+#include <linux/dm-io.h>
1322 -+
1323 -+#include "dm.h"
1324 -+#include "dm-bio-list.h"
1325 -+#include "dm-bio-record.h"
1326 -+#include "dm-bbr.h"
1327 -+
1328 -+#define DM_MSG_PREFIX "bbr"
1329 -+#define SECTOR_SIZE (1 << SECTOR_SHIFT)
1330 -+
1331 -+static struct workqueue_struct *dm_bbr_wq = NULL;
1332 -+static void bbr_remap_handler(struct work_struct *work);
1333 -+static struct kmem_cache *bbr_remap_cache;
1334 -+static struct kmem_cache *bbr_io_cache;
1335 -+static mempool_t *bbr_io_pool;
1336 -+
1337 -+/**
1338 -+ * bbr_binary_tree_destroy
1339 -+ *
1340 -+ * Destroy the binary tree.
1341 -+ **/
1342 -+static void bbr_binary_tree_destroy(struct bbr_runtime_remap *root)
1343 -+{
1344 -+ struct bbr_runtime_remap **link = NULL;
1345 -+ struct bbr_runtime_remap *node = root;
1346 -+
1347 -+ while (node) {
1348 -+ if (node->left) {
1349 -+ link = &node->left;
1350 -+ node = node->left;
1351 -+ continue;
1352 -+ }
1353 -+ if (node->right) {
1354 -+ link = &node->right;
1355 -+ node = node->right;
1356 -+ continue;
1357 -+ }
1358 -+
1359 -+ kmem_cache_free(bbr_remap_cache, node);
1360 -+ if (node == root) {
1361 -+ /* If root is deleted, we're done. */
1362 -+ break;
1363 -+ }
1364 -+
1365 -+ /* Back to root. */
1366 -+ node = root;
1367 -+ *link = NULL;
1368 -+ }
1369 -+}
1370 -+
1371 -+static void bbr_free_remap(struct bbr_private *bbr_id)
1372 -+{
1373 -+ spin_lock_irq(&bbr_id->remap_root_lock);
1374 -+ bbr_binary_tree_destroy(bbr_id->remap_root);
1375 -+ bbr_id->remap_root = NULL;
1376 -+ spin_unlock_irq(&bbr_id->remap_root_lock);
1377 -+}
1378 -+
1379 -+static struct bbr_private *bbr_alloc_private(void)
1380 -+{
1381 -+ struct bbr_private *bbr_id;
1382 -+
1383 -+ bbr_id = kzalloc(sizeof(*bbr_id), GFP_KERNEL);
1384 -+ if (bbr_id == NULL)
1385 -+ return NULL;
1386 -+
1387 -+ INIT_WORK(&bbr_id->remap_work, bbr_remap_handler);
1388 -+ spin_lock_init(&bbr_id->remap_root_lock);
1389 -+ spin_lock_init(&bbr_id->remap_ios_lock);
1390 -+ bbr_id->in_use_replacement_blks = (atomic_t) ATOMIC_INIT(0);
1391 -+
1392 -+ return bbr_id;
1393 -+}
1394 -+
1395 -+static void bbr_free_private(struct bbr_private *bbr_id)
1396 -+{
1397 -+ vfree(bbr_id->bbr_table);
1398 -+ bbr_free_remap(bbr_id);
1399 -+ kfree(bbr_id);
1400 -+}
1401 -+
1402 -+static u32 crc_table[256];
1403 -+static u32 crc_table_built = 0;
1404 -+
1405 -+static void build_crc_table(void)
1406 -+{
1407 -+ u32 i, j, crc;
1408 -+
1409 -+ for (i = 0; i <= 255; i++) {
1410 -+ crc = i;
1411 -+ for (j = 8; j > 0; j--) {
1412 -+ if (crc & 1)
1413 -+ crc = (crc >> 1) ^ CRC_POLYNOMIAL;
1414 -+ else
1415 -+ crc >>= 1;
1416 -+ }
1417 -+ crc_table[i] = crc;
1418 -+ }
1419 -+ crc_table_built = 1;
1420 -+}
1421 -+
1422 -+static u32 calculate_crc(u32 crc, void *buffer, u32 buffersize)
1423 -+{
1424 -+ unsigned char *current_byte;
1425 -+ u32 temp1, temp2, i;
1426 -+
1427 -+ current_byte = (unsigned char *) buffer;
1428 -+ /* Make sure the crc table is available */
1429 -+ if (!crc_table_built)
1430 -+ build_crc_table();
1431 -+ /* Process each byte in the buffer. */
1432 -+ for (i = 0; i < buffersize; i++) {
1433 -+ temp1 = (crc >> 8) & 0x00FFFFFF;
1434 -+ temp2 = crc_table[(crc ^ (u32) * current_byte) &
1435 -+ (u32) 0xff];
1436 -+ current_byte++;
1437 -+ crc = temp1 ^ temp2;
1438 -+ }
1439 -+ return crc;
1440 -+}
1441 -+
1442 -+/**
1443 -+ * le_bbr_table_sector_to_cpu
1444 -+ *
1445 -+ * Convert bbr meta data from on-disk (LE) format
1446 -+ * to the native cpu endian format.
1447 -+ **/
1448 -+static void le_bbr_table_sector_to_cpu(struct bbr_table *p)
1449 -+{
1450 -+ int i;
1451 -+ p->signature = le32_to_cpup(&p->signature);
1452 -+ p->crc = le32_to_cpup(&p->crc);
1453 -+ p->sequence_number = le32_to_cpup(&p->sequence_number);
1454 -+ p->in_use_cnt = le32_to_cpup(&p->in_use_cnt);
1455 -+ for (i = 0; i < BBR_ENTRIES_PER_SECT; i++) {
1456 -+ p->entries[i].bad_sect =
1457 -+ le64_to_cpup(&p->entries[i].bad_sect);
1458 -+ p->entries[i].replacement_sect =
1459 -+ le64_to_cpup(&p->entries[i].replacement_sect);
1460 -+ }
1461 -+}
1462 -+
1463 -+/**
1464 -+ * cpu_bbr_table_sector_to_le
1465 -+ *
1466 -+ * Convert bbr meta data from cpu endian format to on-disk (LE) format
1467 -+ **/
1468 -+static void cpu_bbr_table_sector_to_le(struct bbr_table *p,
1469 -+ struct bbr_table *le)
1470 -+{
1471 -+ int i;
1472 -+ le->signature = cpu_to_le32p(&p->signature);
1473 -+ le->crc = cpu_to_le32p(&p->crc);
1474 -+ le->sequence_number = cpu_to_le32p(&p->sequence_number);
1475 -+ le->in_use_cnt = cpu_to_le32p(&p->in_use_cnt);
1476 -+ for (i = 0; i < BBR_ENTRIES_PER_SECT; i++) {
1477 -+ le->entries[i].bad_sect =
1478 -+ cpu_to_le64p(&p->entries[i].bad_sect);
1479 -+ le->entries[i].replacement_sect =
1480 -+ cpu_to_le64p(&p->entries[i].replacement_sect);
1481 -+ }
1482 -+}
1483 -+
1484 -+/**
1485 -+ * validate_bbr_table_sector
1486 -+ *
1487 -+ * Check the specified BBR table sector for a valid signature and CRC. If it's
1488 -+ * valid, endian-convert the table sector.
1489 -+ **/
1490 -+static int validate_bbr_table_sector(struct bbr_table *p)
1491 -+{
1492 -+ int org_crc, final_crc;
1493 -+
1494 -+ if (le32_to_cpup(&p->signature) != BBR_TABLE_SIGNATURE) {
1495 -+ DMERR("BBR table signature doesn't match!");
1496 -+ DMERR("Found 0x%x. Expecting 0x%x",
1497 -+ le32_to_cpup(&p->signature), BBR_TABLE_SIGNATURE);
1498 -+ return -EINVAL;
1499 -+ }
1500 -+
1501 -+ if (!p->crc) {
1502 -+ DMERR("BBR table sector has no CRC!");
1503 -+ return -EINVAL;
1504 -+ }
1505 -+
1506 -+ org_crc = le32_to_cpup(&p->crc);
1507 -+ p->crc = 0;
1508 -+ final_crc = calculate_crc(INITIAL_CRC, (void *)p, sizeof(*p));
1509 -+ if (final_crc != org_crc) {
1510 -+ DMERR("CRC failed!");
1511 -+ DMERR("Found 0x%x. Expecting 0x%x",
1512 -+ org_crc, final_crc);
1513 -+ return -EINVAL;
1514 -+ }
1515 -+
1516 -+ p->crc = cpu_to_le32p(&org_crc);
1517 -+ le_bbr_table_sector_to_cpu(p);
1518 -+
1519 -+ return 0;
1520 -+}
1521 -+
1522 -+/**
1523 -+ * bbr_binary_tree_insert
1524 -+ *
1525 -+ * Insert a node into the binary tree.
1526 -+ **/
1527 -+static void bbr_binary_tree_insert(struct bbr_runtime_remap **root,
1528 -+ struct bbr_runtime_remap *newnode)
1529 -+{
1530 -+ struct bbr_runtime_remap **node = root;
1531 -+ while (node && *node) {
1532 -+ node = (newnode->remap.bad_sect > (*node)->remap.bad_sect) ?
1533 -+ &(*node)->right : &(*node)->left;
1534 -+ }
1535 -+
1536 -+ newnode->left = newnode->right = NULL;
1537 -+ *node = newnode;
1538 -+}
1539 -+
1540 -+/**
1541 -+ * bbr_binary_search
1542 -+ *
1543 -+ * Search for a node that contains bad_sect == lsn.
1544 -+ **/
1545 -+static struct bbr_runtime_remap *bbr_binary_search(
1546 -+ struct bbr_runtime_remap *root,
1547 -+ u64 lsn)
1548 -+{
1549 -+ struct bbr_runtime_remap *node = root;
1550 -+ while (node) {
1551 -+ if (node->remap.bad_sect == lsn)
1552 -+ break;
1553 -+
1554 -+ node = (lsn > node->remap.bad_sect) ? node->right : node->left;
1555 -+ }
1556 -+ return node;
1557 -+}
1558 -+
1559 -+/**
1560 -+ * bbr_insert_remap_entry
1561 -+ *
1562 -+ * Create a new remap entry and add it to the binary tree for this node.
1563 -+ **/
1564 -+static int bbr_insert_remap_entry(struct bbr_private *bbr_id,
1565 -+ struct bbr_table_entry *new_bbr_entry)
1566 -+{
1567 -+ struct bbr_runtime_remap *newnode;
1568 -+
1569 -+ newnode = kmem_cache_alloc(bbr_remap_cache, GFP_NOIO);
1570 -+ if (!newnode) {
1571 -+ DMERR("Could not allocate from remap cache!");
1572 -+ return -ENOMEM;
1573 -+ }
1574 -+ newnode->remap.bad_sect = new_bbr_entry->bad_sect;
1575 -+ newnode->remap.replacement_sect = new_bbr_entry->replacement_sect;
1576 -+ spin_lock_irq(&bbr_id->remap_root_lock);
1577 -+ bbr_binary_tree_insert(&bbr_id->remap_root, newnode);
1578 -+ spin_unlock_irq(&bbr_id->remap_root_lock);
1579 -+ return 0;
1580 -+}
1581 -+
1582 -+/**
1583 -+ * bbr_table_to_remap_list
1584 -+ *
1585 -+ * The on-disk bbr table is sorted by the replacement sector LBA. In order to
1586 -+ * improve run time performance, the in memory remap list must be sorted by
1587 -+ * the bad sector LBA. This function is called at discovery time to initialize
1588 -+ * the remap list. This function assumes that at least one copy of meta data
1589 -+ * is valid.
1590 -+ **/
1591 -+static u32 bbr_table_to_remap_list(struct bbr_private *bbr_id)
1592 -+{
1593 -+ u32 in_use_blks = 0;
1594 -+ int i, j;
1595 -+ struct bbr_table *p;
1596 -+
1597 -+ for (i = 0, p = bbr_id->bbr_table;
1598 -+ i < bbr_id->nr_sects_bbr_table;
1599 -+ i++, p++) {
1600 -+ if (!p->in_use_cnt)
1601 -+ break;
1602 -+
1603 -+ in_use_blks += p->in_use_cnt;
1604 -+ for (j = 0; j < p->in_use_cnt; j++)
1605 -+ bbr_insert_remap_entry(bbr_id, &p->entries[j]);
1606 -+ }
1607 -+ if (in_use_blks) {
1608 -+ char b[32];
1609 -+ DMWARN("There are %u BBR entries for device %s",
1610 -+ in_use_blks, format_dev_t(b, bbr_id->dev->bdev->bd_dev));
1611 -+ }
1612 -+
1613 -+ return in_use_blks;
1614 -+}
1615 -+
1616 -+/**
1617 -+ * bbr_search_remap_entry
1618 -+ *
1619 -+ * Search remap entry for the specified sector. If found, return a pointer to
1620 -+ * the table entry. Otherwise, return NULL.
1621 -+ **/
1622 -+static struct bbr_table_entry *bbr_search_remap_entry(
1623 -+ struct bbr_private *bbr_id,
1624 -+ u64 lsn)
1625 -+{
1626 -+ struct bbr_runtime_remap *p;
1627 -+
1628 -+ spin_lock_irq(&bbr_id->remap_root_lock);
1629 -+ p = bbr_binary_search(bbr_id->remap_root, lsn);
1630 -+ spin_unlock_irq(&bbr_id->remap_root_lock);
1631 -+ return (p) ? &p->remap : NULL;
1632 -+}
1633 -+
1634 -+/**
1635 -+ * bbr_remap
1636 -+ *
1637 -+ * If *lsn is in the remap table, return TRUE and modify *lsn,
1638 -+ * else, return FALSE.
1639 -+ **/
1640 -+static int bbr_remap(struct bbr_private *bbr_id,
1641 -+ u64 *lsn)
1642 -+{
1643 -+ struct bbr_table_entry *e;
1644 -+
1645 -+ if (atomic_read(&bbr_id->in_use_replacement_blks)) {
1646 -+ e = bbr_search_remap_entry(bbr_id, *lsn);
1647 -+ if (e) {
1648 -+ *lsn = e->replacement_sect;
1649 -+ return 1;
1650 -+ }
1651 -+ }
1652 -+ return 0;
1653 -+}
1654 -+
1655 -+/**
1656 -+ * bbr_remap_probe
1657 -+ *
1658 -+ * If any of the sectors in the range [lsn, lsn+nr_sects] are in the remap
1659 -+ * table return TRUE, Else, return FALSE.
1660 -+ **/
1661 -+static int bbr_remap_probe(struct bbr_private *bbr_id,
1662 -+ u64 lsn, u64 nr_sects)
1663 -+{
1664 -+ u64 tmp, cnt;
1665 -+
1666 -+ if (atomic_read(&bbr_id->in_use_replacement_blks)) {
1667 -+ for (cnt = 0, tmp = lsn;
1668 -+ cnt < nr_sects;
1669 -+ cnt += bbr_id->blksize_in_sects, tmp = lsn + cnt) {
1670 -+ if (bbr_remap(bbr_id,&tmp))
1671 -+ return 1;
1672 -+ }
1673 -+ }
1674 -+ return 0;
1675 -+}
1676 -+
1677 -+static int rw_table(struct bbr_private *bbr_id, void *vma,
1678 -+ struct dm_io_region *ptr, int rw)
1679 -+{
1680 -+ bbr_id->vma_io_req.bi_rw = rw;
1681 -+ bbr_id->vma_io_req.mem.ptr.vma = vma;
1682 -+ bbr_id->vma_io_req.notify.fn = NULL;
1683 -+
1684 -+ return dm_io(&bbr_id->vma_io_req, 1, ptr, NULL);
1685 -+}
1686 -+
1687 -+static int io_sync(struct bbr_private *bbr_id, struct page_list *pl,
1688 -+ unsigned offset, struct dm_io_region *ptr, int rw)
1689 -+{
1690 -+ bbr_id->page_io_req.bi_rw = rw;
1691 -+ bbr_id->page_io_req.mem.ptr.pl = pl;
1692 -+ bbr_id->page_io_req.mem.offset = offset;
1693 -+ bbr_id->page_io_req.notify.fn = NULL;
1694 -+
1695 -+ return dm_io(&bbr_id->page_io_req, 1, ptr, NULL);
1696 -+}
1697 -+
1698 -+/**
1699 -+ * bbr_setup
1700 -+ *
1701 -+ * Read the remap tables from disk and set up the initial remap tree.
1702 -+ **/
1703 -+static int bbr_setup(struct bbr_private *bbr_id)
1704 -+{
1705 -+ struct bbr_table *table = bbr_id->bbr_table;
1706 -+ struct dm_io_region job;
1707 -+ int i, rc = 0;
1708 -+
1709 -+ job.bdev = bbr_id->dev->bdev;
1710 -+ job.count = 1;
1711 -+
1712 -+ /* Read and verify each BBR table sector individually. */
1713 -+ for (i = 0; i < bbr_id->nr_sects_bbr_table; i++, table++) {
1714 -+ job.sector = bbr_id->lba_table1 + i;
1715 -+ rc = rw_table(bbr_id, table, &job, READ);
1716 -+ if (rc && bbr_id->lba_table2) {
1717 -+ job.sector = bbr_id->lba_table2 + i;
1718 -+ rc = rw_table(bbr_id, table, &job, READ);
1719 -+ }
1720 -+ if (rc)
1721 -+ goto out;
1722 -+
1723 -+ rc = validate_bbr_table_sector(table);
1724 -+ if (rc)
1725 -+ goto out;
1726 -+ }
1727 -+ atomic_set(&bbr_id->in_use_replacement_blks,
1728 -+ bbr_table_to_remap_list(bbr_id));
1729 -+
1730 -+out:
1731 -+ if (rc)
1732 -+ DMERR("error during device setup: %d", rc);
1733 -+ return rc;
1734 -+}
1735 -+
1736 -+/**
1737 -+ * bbr_io_remap_error
1738 -+ * @bbr_id: Private data for the BBR node.
1739 -+ * @rw: READ or WRITE.
1740 -+ * @starting_lsn: Starting sector of request to remap.
1741 -+ * @count: Number of sectors in the request.
1742 -+ * @page: Page containing the data for the request.
1743 -+ * @offset: Byte-offset of the data within the page.
1744 -+ *
1745 -+ * For the requested range, try to write each sector individually. For each
1746 -+ * sector that fails, find the next available remap location and write the
1747 -+ * data to that new location. Then update the table and write both copies
1748 -+ * of the table to disk. Finally, update the in-memory mapping and do any
1749 -+ * other necessary bookkeeping.
1750 -+ **/
1751 -+static int bbr_io_remap_error(struct bbr_private *bbr_id,
1752 -+ int rw,
1753 -+ u64 starting_lsn,
1754 -+ u64 count,
1755 -+ struct page *page,
1756 -+ unsigned int offset)
1757 -+{
1758 -+ struct bbr_table *bbr_table;
1759 -+ struct dm_io_region job;
1760 -+ struct page_list pl;
1761 -+ unsigned long table_sector_index;
1762 -+ unsigned long table_sector_offset;
1763 -+ unsigned long index;
1764 -+ u64 lsn, new_lsn;
1765 -+ char b[32];
1766 -+ int rc;
1767 -+
1768 -+ job.bdev = bbr_id->dev->bdev;
1769 -+ job.count = 1;
1770 -+ pl.page = page;
1771 -+ pl.next = NULL;
1772 -+
1773 -+ /* For each sector in the request. */
1774 -+ for (lsn = 0; lsn < count; lsn++, offset += SECTOR_SIZE) {
1775 -+ job.sector = starting_lsn + lsn;
1776 -+ rc = io_sync(bbr_id, &pl, offset, &job, rw);
1777 -+ while (rc) {
1778 -+ /* Find the next available relocation sector. */
1779 -+ new_lsn = atomic_read(&bbr_id->in_use_replacement_blks);
1780 -+ if (new_lsn >= bbr_id->nr_replacement_blks) {
1781 -+ /* No more replacement sectors available. */
1782 -+ return -EIO;
1783 -+ }
1784 -+ new_lsn += bbr_id->start_replacement_sect;
1785 -+
1786 -+ /* Write the data to its new location. */
1787 -+ DMWARN("device %s: Trying to remap bad sector "PFU64" to sector "PFU64,
1788 -+ format_dev_t(b, bbr_id->dev->bdev->bd_dev),
1789 -+ starting_lsn + lsn, new_lsn);
1790 -+ job.sector = new_lsn;
1791 -+ rc = io_sync(bbr_id, &pl, offset, &job, rw);
1792 -+ if (rc) {
1793 -+ /* This replacement sector is bad.
1794 -+ * Try the next one.
1795 -+ */
1796 -+ DMERR("device %s: replacement sector "PFU64" is bad. Skipping.",
1797 -+ format_dev_t(b, bbr_id->dev->bdev->bd_dev), new_lsn);
1798 -+ atomic_inc(&bbr_id->in_use_replacement_blks);
1799 -+ continue;
1800 -+ }
1801 -+
1802 -+ /* Add this new entry to the on-disk table. */
1803 -+ table_sector_index = new_lsn -
1804 -+ bbr_id->start_replacement_sect;
1805 -+ table_sector_offset = table_sector_index /
1806 -+ BBR_ENTRIES_PER_SECT;
1807 -+ index = table_sector_index % BBR_ENTRIES_PER_SECT;
1808 -+
1809 -+ bbr_table = &bbr_id->bbr_table[table_sector_offset];
1810 -+ bbr_table->entries[index].bad_sect = starting_lsn + lsn;
1811 -+ bbr_table->entries[index].replacement_sect = new_lsn;
1812 -+ bbr_table->in_use_cnt++;
1813 -+ bbr_table->sequence_number++;
1814 -+ bbr_table->crc = 0;
1815 -+ bbr_table->crc = calculate_crc(INITIAL_CRC,
1816 -+ bbr_table,
1817 -+ sizeof(struct bbr_table));
1818 -+
1819 -+ /* Write the table to disk. */
1820 -+ cpu_bbr_table_sector_to_le(bbr_table, bbr_table);
1821 -+ if (bbr_id->lba_table1) {
1822 -+ job.sector = bbr_id->lba_table1 + table_sector_offset;
1823 -+ rc = rw_table(bbr_id, bbr_table, &job, WRITE);
1824 -+ }
1825 -+ if (bbr_id->lba_table2) {
1826 -+ job.sector = bbr_id->lba_table2 + table_sector_offset;
1827 -+ rc |= rw_table(bbr_id, bbr_table, &job, WRITE);
1828 -+ }
1829 -+ le_bbr_table_sector_to_cpu(bbr_table);
1830 -+
1831 -+ if (rc) {
1832 -+ /* Error writing one of the tables to disk. */
1833 -+ DMERR("device %s: error updating BBR tables on disk.",
1834 -+ format_dev_t(b, bbr_id->dev->bdev->bd_dev));
1835 -+ return rc;
1836 -+ }
1837 -+
1838 -+ /* Insert a new entry in the remapping binary-tree. */
1839 -+ rc = bbr_insert_remap_entry(bbr_id,
1840 -+ &bbr_table->entries[index]);
1841 -+ if (rc) {
1842 -+ DMERR("device %s: error adding new entry to remap tree.",
1843 -+ format_dev_t(b, bbr_id->dev->bdev->bd_dev));
1844 -+ return rc;
1845 -+ }
1846 -+
1847 -+ atomic_inc(&bbr_id->in_use_replacement_blks);
1848 -+ }
1849 -+ }
1850 -+
1851 -+ return 0;
1852 -+}
1853 -+
1854 -+/**
1855 -+ * bbr_io_process_request
1856 -+ *
1857 -+ * For each sector in this request, check if the sector has already
1858 -+ * been remapped. If so, process all previous sectors in the request,
1859 -+ * followed by the remapped sector. Then reset the starting lsn and
1860 -+ * count, and keep going with the rest of the request as if it were
1861 -+ * a whole new request. If any of the sync_io's return an error,
1862 -+ * call the remapper to relocate the bad sector(s).
1863 -+ *
1864 -+ * 2.5 Note: When switching over to bio's for the I/O path, we have made
1865 -+ * the assumption that the I/O request described by the bio is one
1866 -+ * virtually contiguous piece of memory (even though the bio vector
1867 -+ * describes it using a series of physical page addresses).
1868 -+ **/
1869 -+static int bbr_io_process_request(struct bbr_private *bbr_id,
1870 -+ struct bio *bio)
1871 -+{
1872 -+ struct dm_io_region job;
1873 -+ u64 starting_lsn = bio->bi_sector;
1874 -+ u64 count, lsn, remapped_lsn;
1875 -+ struct page_list pl;
1876 -+ unsigned int offset;
1877 -+ int i, rw = bio_data_dir(bio);
1878 -+ int rc = 0;
1879 -+
1880 -+ job.bdev = bbr_id->dev->bdev;
1881 -+ pl.next = NULL;
1882 -+
1883 -+ /* Each bio can contain multiple vectors, each with a different page.
1884 -+ * Treat each vector as a separate request.
1885 -+ */
1886 -+ /* KMC: Is this the right way to walk the bvec list? */
1887 -+ for (i = 0;
1888 -+ i < bio->bi_vcnt;
1889 -+ i++, bio->bi_idx++, starting_lsn += count) {
1890 -+
1891 -+ /* Bvec info: number of sectors, page,
1892 -+ * and byte-offset within page.
1893 -+ */
1894 -+ count = bio_iovec(bio)->bv_len >> SECTOR_SHIFT;
1895 -+ pl.page = bio_iovec(bio)->bv_page;
1896 -+ offset = bio_iovec(bio)->bv_offset;
1897 -+
1898 -+ /* For each sector in this bvec, check if the sector has
1899 -+ * already been remapped. If so, process all previous sectors
1900 -+ * in this request, followed by the remapped sector. Then reset
1901 -+ * the starting lsn and count and keep going with the rest of
1902 -+ * the request as if it were a whole new request.
1903 -+ */
1904 -+ for (lsn = 0; lsn < count; lsn++) {
1905 -+ remapped_lsn = starting_lsn + lsn;
1906 -+ rc = bbr_remap(bbr_id, &remapped_lsn);
1907 -+ if (!rc) {
1908 -+ /* This sector is fine. */
1909 -+ continue;
1910 -+ }
1911 -+
1912 -+ /* Process all sectors in the request up to this one. */
1913 -+ if (lsn > 0) {
1914 -+ job.sector = starting_lsn;
1915 -+ job.count = lsn;
1916 -+ rc = io_sync(bbr_id, &pl, offset, &job, rw);
1917 -+ if (rc) {
1918 -+ /* If this I/O failed, then one of the
1919 -+ * sectors in this request needs to be
1920 -+ * relocated.
1921 -+ */
1922 -+ rc = bbr_io_remap_error(bbr_id, rw,
1923 -+ starting_lsn,
1924 -+ lsn, pl.page,
1925 -+ offset);
1926 -+ if (rc) {
1927 -+ /* KMC: Return? Or continue to next bvec? */
1928 -+ return rc;
1929 -+ }
1930 -+ }
1931 -+ offset += (lsn << SECTOR_SHIFT);
1932 -+ }
1933 -+
1934 -+ /* Process the remapped sector. */
1935 -+ job.sector = remapped_lsn;
1936 -+ job.count = 1;
1937 -+ rc = io_sync(bbr_id, &pl, offset, &job, rw);
1938 -+ if (rc) {
1939 -+ /* BUGBUG - Need more processing if this caused
1940 -+ * an error. If this I/O failed, then the
1941 -+ * existing remap is now bad, and we need to
1942 -+ * find a new remap. Can't use
1943 -+ * bbr_io_remap_error(), because the existing
1944 -+ * map entry needs to be changed, not added
1945 -+ * again, and the original table entry also
1946 -+ * needs to be changed.
1947 -+ */
1948 -+ return rc;
1949 -+ }
1950 -+
1951 -+ starting_lsn += (lsn + 1);
1952 -+ count -= (lsn + 1);
1953 -+ lsn = -1;
1954 -+ offset += SECTOR_SIZE;
1955 -+ }
1956 -+
1957 -+ /* Check for any remaining sectors after the last split. This
1958 -+ * could potentially be the whole request, but that should be a
1959 -+ * rare case because requests should only be processed by the
1960 -+ * thread if we know an error occurred or they contained one or
1961 -+ * more remapped sectors.
1962 -+ */
1963 -+ if (count) {
1964 -+ job.sector = starting_lsn;
1965 -+ job.count = count;
1966 -+ rc = io_sync(bbr_id, &pl, offset, &job, rw);
1967 -+ if (rc) {
1968 -+ /* If this I/O failed, then one of the sectors
1969 -+ * in this request needs to be relocated.
1970 -+ */
1971 -+ rc = bbr_io_remap_error(bbr_id, rw, starting_lsn,
1972 -+ count, pl.page, offset);
1973 -+ if (rc) {
1974 -+ /* KMC: Return? Or continue to next bvec? */
1975 -+ return rc;
1976 -+ }
1977 -+ }
1978 -+ }
1979 -+ }
1980 -+
1981 -+ return 0;
1982 -+}
1983 -+
1984 -+static void bbr_io_process_requests(struct bbr_private *bbr_id,
1985 -+ struct bio *bio)
1986 -+{
1987 -+ struct bio *next;
1988 -+ int rc;
1989 -+
1990 -+ while (bio) {
1991 -+ next = bio->bi_next;
1992 -+ bio->bi_next = NULL;
1993 -+
1994 -+ rc = bbr_io_process_request(bbr_id, bio);
1995 -+
1996 -+ bio_endio(bio, rc);
1997 -+
1998 -+ bio = next;
1999 -+ }
2000 -+}
2001 -+
2002 -+/**
2003 -+ * bbr_remap_handler
2004 -+ *
2005 -+ * This is the handler for the bbr work-queue.
2006 -+ *
2007 -+ * I/O requests should only be sent to this handler if we know that:
2008 -+ * a) the request contains at least one remapped sector.
2009 -+ * or
2010 -+ * b) the request caused an error on the normal I/O path.
2011 -+ *
2012 -+ * This function uses synchronous I/O, so sending a request to this
2013 -+ * thread that doesn't need special processing will cause severe
2014 -+ * performance degredation.
2015 -+ **/
2016 -+static void bbr_remap_handler(struct work_struct *work)
2017 -+{
2018 -+ struct bbr_private *bbr_id =
2019 -+ container_of(work, struct bbr_private, remap_work);
2020 -+ struct bio *bio;
2021 -+ unsigned long flags;
2022 -+
2023 -+ spin_lock_irqsave(&bbr_id->remap_ios_lock, flags);
2024 -+ bio = bio_list_get(&bbr_id->remap_ios);
2025 -+ spin_unlock_irqrestore(&bbr_id->remap_ios_lock, flags);
2026 -+
2027 -+ bbr_io_process_requests(bbr_id, bio);
2028 -+}
2029 -+
2030 -+/**
2031 -+ * bbr_endio
2032 -+ *
2033 -+ * This is the callback for normal write requests. Check for an error
2034 -+ * during the I/O, and send to the thread for processing if necessary.
2035 -+ **/
2036 -+static int bbr_endio(struct dm_target *ti, struct bio *bio,
2037 -+ int error, union map_info *map_context)
2038 -+{
2039 -+ struct bbr_private *bbr_id = ti->private;
2040 -+ struct dm_bio_details *bbr_io = map_context->ptr;
2041 -+
2042 -+ if (error && bbr_io) {
2043 -+ unsigned long flags;
2044 -+ char b[32];
2045 -+
2046 -+ dm_bio_restore(bbr_io, bio);
2047 -+ map_context->ptr = NULL;
2048 -+
2049 -+ DMERR("device %s: I/O failure on sector %lu. "
2050 -+ "Scheduling for retry.",
2051 -+ format_dev_t(b, bbr_id->dev->bdev->bd_dev),
2052 -+ (unsigned long)bio->bi_sector);
2053 -+
2054 -+ spin_lock_irqsave(&bbr_id->remap_ios_lock, flags);
2055 -+ bio_list_add(&bbr_id->remap_ios, bio);
2056 -+ spin_unlock_irqrestore(&bbr_id->remap_ios_lock, flags);
2057 -+
2058 -+ queue_work(dm_bbr_wq, &bbr_id->remap_work);
2059 -+
2060 -+ error = 1;
2061 -+ }
2062 -+
2063 -+ if (bbr_io)
2064 -+ mempool_free(bbr_io, bbr_io_pool);
2065 -+
2066 -+ return error;
2067 -+}
2068 -+
2069 -+/**
2070 -+ * Construct a bbr mapping
2071 -+ **/
2072 -+static int bbr_ctr(struct dm_target *ti, unsigned int argc, char **argv)
2073 -+{
2074 -+ struct bbr_private *bbr_id;
2075 -+ unsigned long block_size;
2076 -+ char *end;
2077 -+ int rc = -EINVAL;
2078 -+
2079 -+ if (argc != 8) {
2080 -+ ti->error = "dm-bbr requires exactly 8 arguments: "
2081 -+ "device offset table1_lsn table2_lsn table_size start_replacement nr_replacement_blks block_size";
2082 -+ goto out1;
2083 -+ }
2084 -+
2085 -+ bbr_id = bbr_alloc_private();
2086 -+ if (!bbr_id) {
2087 -+ ti->error = "dm-bbr: Error allocating bbr private data.";
2088 -+ goto out1;
2089 -+ }
2090 -+
2091 -+ bbr_id->offset = simple_strtoull(argv[1], &end, 10);
2092 -+ bbr_id->lba_table1 = simple_strtoull(argv[2], &end, 10);
2093 -+ bbr_id->lba_table2 = simple_strtoull(argv[3], &end, 10);
2094 -+ bbr_id->nr_sects_bbr_table = simple_strtoull(argv[4], &end, 10);
2095 -+ bbr_id->start_replacement_sect = simple_strtoull(argv[5], &end, 10);
2096 -+ bbr_id->nr_replacement_blks = simple_strtoull(argv[6], &end, 10);
2097 -+ block_size = simple_strtoul(argv[7], &end, 10);
2098 -+ bbr_id->blksize_in_sects = (block_size >> SECTOR_SHIFT);
2099 -+
2100 -+ bbr_id->vma_io_req.mem.type = DM_IO_VMA;
2101 -+ bbr_id->vma_io_req.client = dm_io_client_create(1);
2102 -+ if (IS_ERR(bbr_id->vma_io_req.client)) {
2103 -+ rc = PTR_ERR(bbr_id->vma_io_req.client);
2104 -+ DMWARN("couldn't allocate disk VMA io client");
2105 -+ goto out2;
2106 -+ }
2107 -+
2108 -+ bbr_id->page_io_req.mem.type = DM_IO_PAGE_LIST;
2109 -+ bbr_id->page_io_req.client = dm_io_client_create(1);
2110 -+ if (IS_ERR(bbr_id->page_io_req.client)) {
2111 -+ rc = PTR_ERR(bbr_id->page_io_req.client);
2112 -+ DMWARN("couldn't allocate pagelist io client");
2113 -+ goto out3;
2114 -+ }
2115 -+
2116 -+ bbr_id->bbr_table = vmalloc(bbr_id->nr_sects_bbr_table << SECTOR_SHIFT);
2117 -+ if (!bbr_id->bbr_table) {
2118 -+ ti->error = "dm-bbr: Error allocating bbr table.";
2119 -+ goto out4;
2120 -+ }
2121 -+
2122 -+ if (dm_get_device(ti, argv[0], 0, ti->len,
2123 -+ dm_table_get_mode(ti->table), &bbr_id->dev)) {
2124 -+ ti->error = "dm-bbr: Device lookup failed";
2125 -+ goto out4;
2126 -+ }
2127 -+
2128 -+ rc = bbr_setup(bbr_id);
2129 -+ if (rc) {
2130 -+ ti->error = "dm-bbr: Device setup failed";
2131 -+ goto out5;
2132 -+ }
2133 -+
2134 -+ ti->private = bbr_id;
2135 -+ return 0;
2136 -+
2137 -+out5:
2138 -+ dm_put_device(ti, bbr_id->dev);
2139 -+out4:
2140 -+ dm_io_client_destroy(bbr_id->page_io_req.client);
2141 -+out3:
2142 -+ dm_io_client_destroy(bbr_id->vma_io_req.client);
2143 -+out2:
2144 -+ bbr_free_private(bbr_id);
2145 -+out1:
2146 -+ return rc;
2147 -+}
2148 -+
2149 -+static void bbr_dtr(struct dm_target *ti)
2150 -+{
2151 -+ struct bbr_private *bbr_id = ti->private;
2152 -+
2153 -+ dm_put_device(ti, bbr_id->dev);
2154 -+ dm_io_client_destroy(bbr_id->page_io_req.client);
2155 -+ dm_io_client_destroy(bbr_id->vma_io_req.client);
2156 -+ bbr_free_private(bbr_id);
2157 -+}
2158 -+
2159 -+static int bbr_map(struct dm_target *ti, struct bio *bio,
2160 -+ union map_info *map_context)
2161 -+{
2162 -+ struct bbr_private *bbr_id = ti->private;
2163 -+ struct dm_bio_details *bbr_io;
2164 -+ unsigned long flags;
2165 -+ int rc = 1;
2166 -+
2167 -+ bio->bi_sector += bbr_id->offset;
2168 -+
2169 -+ if (atomic_read(&bbr_id->in_use_replacement_blks) == 0 ||
2170 -+ !bbr_remap_probe(bbr_id, bio->bi_sector, bio_sectors(bio))) {
2171 -+ /* No existing remaps or this request doesn't
2172 -+ * contain any remapped sectors.
2173 -+ */
2174 -+ bio->bi_bdev = bbr_id->dev->bdev;
2175 -+
2176 -+ bbr_io = mempool_alloc(bbr_io_pool, GFP_NOIO);
2177 -+ dm_bio_record(bbr_io, bio);
2178 -+ map_context->ptr = bbr_io;
2179 -+ } else {
2180 -+ /* This request has at least one remapped sector.
2181 -+ * Give it to the work-queue for processing.
2182 -+ */
2183 -+ map_context->ptr = NULL;
2184 -+ spin_lock_irqsave(&bbr_id->remap_ios_lock, flags);
2185 -+ bio_list_add(&bbr_id->remap_ios, bio);
2186 -+ spin_unlock_irqrestore(&bbr_id->remap_ios_lock, flags);
2187 -+
2188 -+ queue_work(dm_bbr_wq, &bbr_id->remap_work);
2189 -+ rc = 0;
2190 -+ }
2191 -+
2192 -+ return rc;
2193 -+}
2194 -+
2195 -+static int bbr_status(struct dm_target *ti, status_type_t type,
2196 -+ char *result, unsigned int maxlen)
2197 -+{
2198 -+ struct bbr_private *bbr_id = ti->private;
2199 -+ char b[BDEVNAME_SIZE];
2200 -+
2201 -+ switch (type) {
2202 -+ case STATUSTYPE_INFO:
2203 -+ result[0] = '\0';
2204 -+ break;
2205 -+
2206 -+ case STATUSTYPE_TABLE:
2207 -+ snprintf(result, maxlen, "%s "PFU64" "PFU64" "PFU64" "PFU64" "PFU64" "PFU64" %u",
2208 -+ format_dev_t(b, bbr_id->dev->bdev->bd_dev),
2209 -+ bbr_id->offset, bbr_id->lba_table1, bbr_id->lba_table2,
2210 -+ bbr_id->nr_sects_bbr_table,
2211 -+ bbr_id->start_replacement_sect,
2212 -+ bbr_id->nr_replacement_blks,
2213 -+ bbr_id->blksize_in_sects << SECTOR_SHIFT);
2214 -+ break;
2215 -+ }
2216 -+ return 0;
2217 -+}
2218 -+
2219 -+static struct target_type bbr_target = {
2220 -+ .name = "bbr",
2221 -+ .version= {1, 0, 1},
2222 -+ .module = THIS_MODULE,
2223 -+ .ctr = bbr_ctr,
2224 -+ .dtr = bbr_dtr,
2225 -+ .map = bbr_map,
2226 -+ .end_io = bbr_endio,
2227 -+ .status = bbr_status,
2228 -+};
2229 -+
2230 -+int __init dm_bbr_init(void)
2231 -+{
2232 -+ int rc;
2233 -+
2234 -+ rc = dm_register_target(&bbr_target);
2235 -+ if (rc) {
2236 -+ DMERR("error registering target.");
2237 -+ goto err1;
2238 -+ }
2239 -+
2240 -+ bbr_remap_cache = kmem_cache_create("bbr-remap",
2241 -+ sizeof(struct bbr_runtime_remap),
2242 -+ 0, SLAB_HWCACHE_ALIGN, NULL);
2243 -+ if (!bbr_remap_cache) {
2244 -+ DMERR("error creating remap cache.");
2245 -+ rc = ENOMEM;
2246 -+ goto err2;
2247 -+ }
2248 -+
2249 -+ bbr_io_cache = kmem_cache_create("bbr-io", sizeof(struct dm_bio_details),
2250 -+ 0, SLAB_HWCACHE_ALIGN, NULL);
2251 -+ if (!bbr_io_cache) {
2252 -+ DMERR("error creating io cache.");
2253 -+ rc = ENOMEM;
2254 -+ goto err3;
2255 -+ }
2256 -+
2257 -+ bbr_io_pool = mempool_create(256, mempool_alloc_slab,
2258 -+ mempool_free_slab, bbr_io_cache);
2259 -+ if (!bbr_io_pool) {
2260 -+ DMERR("error creating io mempool.");
2261 -+ rc = ENOMEM;
2262 -+ goto err4;
2263 -+ }
2264 -+
2265 -+ dm_bbr_wq = create_workqueue("dm-bbr");
2266 -+ if (!dm_bbr_wq) {
2267 -+ DMERR("error creating work-queue.");
2268 -+ rc = ENOMEM;
2269 -+ goto err5;
2270 -+ }
2271 -+
2272 -+ return 0;
2273 -+
2274 -+err5:
2275 -+ mempool_destroy(bbr_io_pool);
2276 -+err4:
2277 -+ kmem_cache_destroy(bbr_io_cache);
2278 -+err3:
2279 -+ kmem_cache_destroy(bbr_remap_cache);
2280 -+err2:
2281 -+ dm_unregister_target(&bbr_target);
2282 -+err1:
2283 -+ return rc;
2284 -+}
2285 -+
2286 -+void __exit dm_bbr_exit(void)
2287 -+{
2288 -+ destroy_workqueue(dm_bbr_wq);
2289 -+ mempool_destroy(bbr_io_pool);
2290 -+ kmem_cache_destroy(bbr_io_cache);
2291 -+ kmem_cache_destroy(bbr_remap_cache);
2292 -+ dm_unregister_target(&bbr_target);
2293 -+}
2294 -+
2295 -+module_init(dm_bbr_init);
2296 -+module_exit(dm_bbr_exit);
2297 -+MODULE_LICENSE("GPL");
2298 -Index: linux-2.6.26-gentoo/drivers/md/dm-bbr.h
2299 -===================================================================
2300 ---- /dev/null
2301 -+++ linux-2.6.26-gentoo/drivers/md/dm-bbr.h
2302 -@@ -0,0 +1,130 @@
2303 -+/*
2304 -+ * (C) Copyright IBM Corp. 2002, 2004
2305 -+ *
2306 -+ * This program is free software; you can redistribute it and/or modify
2307 -+ * it under the terms of the GNU General Public License as published by
2308 -+ * the Free Software Foundation; either version 2 of the License, or
2309 -+ * (at your option) any later version.
2310 -+ *
2311 -+ * This program is distributed in the hope that it will be useful,
2312 -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2313 -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
2314 -+ * the GNU General Public License for more details.
2315 -+ *
2316 -+ * You should have received a copy of the GNU General Public License
2317 -+ * along with this program; if not, write to the Free Software
2318 -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2319 -+ *
2320 -+ * linux/drivers/md/dm-bbr.h
2321 -+ *
2322 -+ * Bad-block-relocation (BBR) target for device-mapper.
2323 -+ *
2324 -+ * The BBR target is designed to remap I/O write failures to another safe
2325 -+ * location on disk. Note that most disk drives have BBR built into them,
2326 -+ * this means that our software BBR will be only activated when all hardware
2327 -+ * BBR replacement sectors have been used.
2328 -+ */
2329 -+
2330 -+#include <linux/dm-io.h>
2331 -+
2332 -+#define BBR_TABLE_SIGNATURE 0x42627254 /* BbrT */
2333 -+#define BBR_ENTRIES_PER_SECT 31
2334 -+#define INITIAL_CRC 0xFFFFFFFF
2335 -+#define CRC_POLYNOMIAL 0xEDB88320L
2336 -+
2337 -+/**
2338 -+ * Macros to cleanly print 64-bit numbers on both 32-bit and 64-bit machines.
2339 -+ * Use these in place of %Ld, %Lu, and %Lx.
2340 -+ **/
2341 -+#if BITS_PER_LONG > 32
2342 -+#define PFU64 "%llu"
2343 -+#else
2344 -+#define PFU64 "%Lu"
2345 -+#endif
2346 -+
2347 -+/**
2348 -+ * struct bbr_table_entry
2349 -+ * @bad_sect: LBA of bad location.
2350 -+ * @replacement_sect: LBA of new location.
2351 -+ *
2352 -+ * Structure to describe one BBR remap.
2353 -+ **/
2354 -+struct bbr_table_entry {
2355 -+ u64 bad_sect;
2356 -+ u64 replacement_sect;
2357 -+};
2358 -+
2359 -+/**
2360 -+ * struct bbr_table
2361 -+ * @signature: Signature on each BBR table sector.
2362 -+ * @crc: CRC for this table sector.
2363 -+ * @sequence_number: Used to resolve conflicts when primary and secondary
2364 -+ * tables do not match.
2365 -+ * @in_use_cnt: Number of in-use table entries.
2366 -+ * @entries: Actual table of remaps.
2367 -+ *
2368 -+ * Structure to describe each sector of the metadata table. Each sector in this
2369 -+ * table can describe 31 remapped sectors.
2370 -+ **/
2371 -+struct bbr_table {
2372 -+ u32 signature;
2373 -+ u32 crc;
2374 -+ u32 sequence_number;
2375 -+ u32 in_use_cnt;
2376 -+ struct bbr_table_entry entries[BBR_ENTRIES_PER_SECT];
2377 -+};
2378 -+
2379 -+/**
2380 -+ * struct bbr_runtime_remap
2381 -+ *
2382 -+ * Node in the binary tree used to keep track of remaps.
2383 -+ **/
2384 -+struct bbr_runtime_remap {
2385 -+ struct bbr_table_entry remap;
2386 -+ struct bbr_runtime_remap *left;
2387 -+ struct bbr_runtime_remap *right;
2388 -+};
2389 -+
2390 -+/**
2391 -+ * struct bbr_private
2392 -+ * @dev: Info about underlying device.
2393 -+ * @bbr_table: Copy of metadata table.
2394 -+ * @remap_root: Binary tree containing all remaps.
2395 -+ * @remap_root_lock: Lock for the binary tree.
2396 -+ * @remap_work: For adding work items to the work-queue.
2397 -+ * @remap_ios: List of I/Os for the work-queue to handle.
2398 -+ * @remap_ios_lock: Lock for the remap_ios list.
2399 -+ * @offset: LBA of data area.
2400 -+ * @lba_table1: LBA of primary BBR table.
2401 -+ * @lba_table2: LBA of secondary BBR table.
2402 -+ * @nr_sects_bbr_table: Size of each BBR table.
2403 -+ * @nr_replacement_blks: Number of replacement blocks.
2404 -+ * @start_replacement_sect: LBA of start of replacement blocks.
2405 -+ * @blksize_in_sects: Size of each block.
2406 -+ * @in_use_replacement_blks: Current number of remapped blocks.
2407 -+ *
2408 -+ * Private data for each BBR target.
2409 -+ **/
2410 -+struct bbr_private {
2411 -+ struct dm_dev *dev;
2412 -+ struct bbr_table *bbr_table;
2413 -+ struct bbr_runtime_remap *remap_root;
2414 -+ spinlock_t remap_root_lock;
2415 -+
2416 -+ struct dm_io_request vma_io_req;
2417 -+ struct dm_io_request page_io_req;
2418 -+
2419 -+ struct work_struct remap_work;
2420 -+ struct bio_list remap_ios;
2421 -+ spinlock_t remap_ios_lock;
2422 -+
2423 -+ u64 offset;
2424 -+ u64 lba_table1;
2425 -+ u64 lba_table2;
2426 -+ u64 nr_sects_bbr_table;
2427 -+ u64 start_replacement_sect;
2428 -+ u64 nr_replacement_blks;
2429 -+ u32 blksize_in_sects;
2430 -+ atomic_t in_use_replacement_blks;
2431 -+};
2432 -+
2433
2434 Modified: genpatches-2.6/trunk/2.6.27/4200_fbcondecor-0.9.4.patch
2435 ===================================================================
2436 --- genpatches-2.6/trunk/2.6.27/4200_fbcondecor-0.9.4.patch 2008-10-11 01:09:49 UTC (rev 1353)
2437 +++ genpatches-2.6/trunk/2.6.27/4200_fbcondecor-0.9.4.patch 2008-10-12 18:19:38 UTC (rev 1354)
2438 @@ -221,10 +221,9 @@
2439 +Fbcondecor, fbcondecor protocol design, current implementation & docs by:
2440 + Michal Januszewski <spock@g.o>
2441 +
2442 -diff -Naurp -x .git /tmp/linux/drivers/Makefile ./drivers/Makefile
2443 ---- /tmp/linux/drivers/Makefile 2008-03-25 07:24:16.000000000 +0100
2444 -+++ ./drivers/Makefile 2008-03-25 23:04:10.000000000 +0100
2445 -@@ -9,6 +9,9 @@ obj-$(CONFIG_HAVE_GPIO_LIB) += gpio/
2446 +--- a/drivers/Makefile 2008-10-12 13:30:08.000000000 -0400
2447 ++++ b/drivers/Makefile 2008-10-12 13:30:51.000000000 -0400
2448 +@@ -9,6 +9,9 @@ obj-y += gpio/
2449 obj-$(CONFIG_PCI) += pci/
2450 obj-$(CONFIG_PARISC) += parisc/
2451 obj-$(CONFIG_RAPIDIO) += rapidio/
2452 @@ -234,17 +233,16 @@
2453 obj-y += video/
2454 obj-$(CONFIG_ACPI) += acpi/
2455 # PnP must come after ACPI since it will eventually need to check if acpi
2456 -@@ -18,10 +21,6 @@ obj-$(CONFIG_ARM_AMBA) += amba/
2457 +@@ -18,9 +21,6 @@ obj-$(CONFIG_ARM_AMBA) += amba/
2458
2459 obj-$(CONFIG_XEN) += xen/
2460
2461 -# char/ comes before serial/ etc so that the VT console is the boot-time
2462 -# default.
2463 -obj-y += char/
2464 --
2465 - obj-$(CONFIG_CONNECTOR) += connector/
2466
2467 - # i810fb and intelfb depend on char/agp/
2468 + # gpu/ comes after char for AGP vs DRM startup
2469 + obj-y += gpu/
2470 diff -Naurp -x .git /tmp/linux/drivers/video/console/bitblit.c ./drivers/video/console/bitblit.c
2471 --- /tmp/linux/drivers/video/console/bitblit.c 2008-03-25 07:24:16.000000000 +0100
2472 +++ ./drivers/video/console/bitblit.c 2008-03-25 23:04:10.000000000 +0100
2473 @@ -973,21 +971,6 @@
2474 if (fbcon_is_inactive(vc, info) ||
2475 ops->blank_state != FB_BLANK_UNBLANK)
2476 fbcon_del_cursor_timer(info);
2477 -@@ -2394,8 +2450,12 @@ static int fbcon_blank(struct vc_data *v
2478 - fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
2479 - ops->cursor_flash = (!blank);
2480 -
2481 -- if (fb_blank(info, blank))
2482 -- fbcon_generic_blank(vc, info, blank);
2483 -+ if (fb_blank(info, blank)) {
2484 -+ if (fbcon_decor_active(info, vc))
2485 -+ fbcon_decor_blank(vc, info, blank);
2486 -+ else
2487 -+ fbcon_generic_blank(vc, info, blank);
2488 -+ }
2489 - }
2490 -
2491 - if (!blank)
2492 @@ -2546,13 +2606,22 @@ static int fbcon_do_set_font(struct vc_d
2493 }
2494
2495
2496 Deleted: genpatches-2.6/trunk/2.6.27/4300_squashfs-3.3.patch
2497 ===================================================================
2498 --- genpatches-2.6/trunk/2.6.27/4300_squashfs-3.3.patch 2008-10-11 01:09:49 UTC (rev 1353)
2499 +++ genpatches-2.6/trunk/2.6.27/4300_squashfs-3.3.patch 2008-10-12 18:19:38 UTC (rev 1354)
2500 @@ -1,4242 +0,0 @@
2501 -
2502 -iget changes for 2.6.25 by Daniel Drake <dsd@g.o>
2503 -https://bugs.gentoo.org/show_bug.cgi?id=218169
2504 -
2505 -Index: linux-2.6.25-gentoo/fs/Kconfig
2506 -===================================================================
2507 ---- linux-2.6.25-gentoo.orig/fs/Kconfig
2508 -+++ linux-2.6.25-gentoo/fs/Kconfig
2509 -@@ -1367,6 +1367,56 @@ config CRAMFS
2510 -
2511 - If unsure, say N.
2512 -
2513 -+config SQUASHFS
2514 -+ tristate "SquashFS 3.3 - Squashed file system support"
2515 -+ select ZLIB_INFLATE
2516 -+ help
2517 -+ Saying Y here includes support for SquashFS 3.3 (a Compressed
2518 -+ Read-Only File System). Squashfs is a highly compressed read-only
2519 -+ filesystem for Linux. It uses zlib compression to compress both
2520 -+ files, inodes and directories. Inodes in the system are very small
2521 -+ and all blocks are packed to minimise data overhead. Block sizes
2522 -+ greater than 4K are supported up to a maximum of 1 Mbytes (default
2523 -+ block size 128K). SquashFS 3.3 supports 64 bit filesystems and files
2524 -+ (larger than 4GB), full uid/gid information, hard links and timestamps.
2525 -+
2526 -+ Squashfs is intended for general read-only filesystem use, for
2527 -+ archival use (i.e. in cases where a .tar.gz file may be used), and in
2528 -+ embedded systems where low overhead is needed. Further information
2529 -+ and filesystem tools are available from http://squashfs.sourceforge.net.
2530 -+
2531 -+ If you want to compile this as a module ( = code which can be
2532 -+ inserted in and removed from the running kernel whenever you want),
2533 -+ say M here and read <file:Documentation/modules.txt>. The module
2534 -+ will be called squashfs. Note that the root file system (the one
2535 -+ containing the directory /) cannot be compiled as a module.
2536 -+
2537 -+ If unsure, say N.
2538 -+
2539 -+config SQUASHFS_EMBEDDED
2540 -+
2541 -+ bool "Additional option for memory-constrained systems"
2542 -+ depends on SQUASHFS
2543 -+ default n
2544 -+ help
2545 -+ Saying Y here allows you to specify cache size.
2546 -+
2547 -+ If unsure, say N.
2548 -+
2549 -+config SQUASHFS_FRAGMENT_CACHE_SIZE
2550 -+ int "Number of fragments cached" if SQUASHFS_EMBEDDED
2551 -+ depends on SQUASHFS
2552 -+ default "3"
2553 -+ help
2554 -+ By default SquashFS caches the last 3 fragments read from
2555 -+ the filesystem. Increasing this amount may mean SquashFS
2556 -+ has to re-read fragments less often from disk, at the expense
2557 -+ of extra system memory. Decreasing this amount will mean
2558 -+ SquashFS uses less memory at the expense of extra reads from disk.
2559 -+
2560 -+ Note there must be at least one cached fragment. Anything
2561 -+ much more than three will probably not make much difference.
2562 -+
2563 - config VXFS_FS
2564 - tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"
2565 - depends on BLOCK
2566 -Index: linux-2.6.25-gentoo/fs/Makefile
2567 -===================================================================
2568 ---- linux-2.6.25-gentoo.orig/fs/Makefile
2569 -+++ linux-2.6.25-gentoo/fs/Makefile
2570 -@@ -73,6 +73,7 @@ obj-$(CONFIG_JBD) += jbd/
2571 - obj-$(CONFIG_JBD2) += jbd2/
2572 - obj-$(CONFIG_EXT2_FS) += ext2/
2573 - obj-$(CONFIG_CRAMFS) += cramfs/
2574 -+obj-$(CONFIG_SQUASHFS) += squashfs/
2575 - obj-y += ramfs/
2576 - obj-$(CONFIG_HUGETLBFS) += hugetlbfs/
2577 - obj-$(CONFIG_CODA_FS) += coda/
2578 -Index: linux-2.6.25-gentoo/fs/squashfs/inode.c
2579 -===================================================================
2580 ---- /dev/null
2581 -+++ linux-2.6.25-gentoo/fs/squashfs/inode.c
2582 -@@ -0,0 +1,2186 @@
2583 -+/*
2584 -+ * Squashfs - a compressed read only filesystem for Linux
2585 -+ *
2586 -+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
2587 -+ * Phillip Lougher <phillip@××××××××××××××××.uk>
2588 -+ *
2589 -+ * This program is free software; you can redistribute it and/or
2590 -+ * modify it under the terms of the GNU General Public License
2591 -+ * as published by the Free Software Foundation; either version 2,
2592 -+ * or (at your option) any later version.
2593 -+ *
2594 -+ * This program is distributed in the hope that it will be useful,
2595 -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2596 -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2597 -+ * GNU General Public License for more details.
2598 -+ *
2599 -+ * You should have received a copy of the GNU General Public License
2600 -+ * along with this program; if not, write to the Free Software
2601 -+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
2602 -+ *
2603 -+ * inode.c
2604 -+ */
2605 -+
2606 -+#include <linux/squashfs_fs.h>
2607 -+#include <linux/module.h>
2608 -+#include <linux/zlib.h>
2609 -+#include <linux/fs.h>
2610 -+#include <linux/squashfs_fs_sb.h>
2611 -+#include <linux/squashfs_fs_i.h>
2612 -+#include <linux/buffer_head.h>
2613 -+#include <linux/vfs.h>
2614 -+#include <linux/vmalloc.h>
2615 -+#include <linux/smp_lock.h>
2616 -+#include <linux/exportfs.h>
2617 -+#include <linux/sched.h>
2618 -+
2619 -+#include "squashfs.h"
2620 -+
2621 -+int squashfs_cached_blks;
2622 -+
2623 -+static struct dentry *squashfs_get_parent(struct dentry *child);
2624 -+static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode);
2625 -+static int squashfs_statfs(struct dentry *, struct kstatfs *);
2626 -+static int squashfs_symlink_readpage(struct file *file, struct page *page);
2627 -+static long long read_blocklist(struct inode *inode, int index,
2628 -+ int readahead_blks, char *block_list,
2629 -+ unsigned short **block_p, unsigned int *bsize);
2630 -+static int squashfs_readpage(struct file *file, struct page *page);
2631 -+static int squashfs_readdir(struct file *, void *, filldir_t);
2632 -+static struct dentry *squashfs_lookup(struct inode *, struct dentry *,
2633 -+ struct nameidata *);
2634 -+static int squashfs_remount(struct super_block *s, int *flags, char *data);
2635 -+static void squashfs_put_super(struct super_block *);
2636 -+static int squashfs_get_sb(struct file_system_type *,int, const char *, void *,
2637 -+ struct vfsmount *);
2638 -+static struct inode *squashfs_alloc_inode(struct super_block *sb);
2639 -+static void squashfs_destroy_inode(struct inode *inode);
2640 -+static int init_inodecache(void);
2641 -+static void destroy_inodecache(void);
2642 -+
2643 -+static struct file_system_type squashfs_fs_type = {
2644 -+ .owner = THIS_MODULE,
2645 -+ .name = "squashfs",
2646 -+ .get_sb = squashfs_get_sb,
2647 -+ .kill_sb = kill_block_super,
2648 -+ .fs_flags = FS_REQUIRES_DEV
2649 -+};
2650 -+
2651 -+static const unsigned char squashfs_filetype_table[] = {
2652 -+ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
2653 -+};
2654 -+
2655 -+static struct super_operations squashfs_super_ops = {
2656 -+ .alloc_inode = squashfs_alloc_inode,
2657 -+ .destroy_inode = squashfs_destroy_inode,
2658 -+ .statfs = squashfs_statfs,
2659 -+ .put_super = squashfs_put_super,
2660 -+ .remount_fs = squashfs_remount
2661 -+};
2662 -+
2663 -+static struct super_operations squashfs_export_super_ops = {
2664 -+ .alloc_inode = squashfs_alloc_inode,
2665 -+ .destroy_inode = squashfs_destroy_inode,
2666 -+ .statfs = squashfs_statfs,
2667 -+ .put_super = squashfs_put_super,
2668 -+};
2669 -+
2670 -+static struct export_operations squashfs_export_ops = {
2671 -+ .get_parent = squashfs_get_parent
2672 -+};
2673 -+
2674 -+SQSH_EXTERN const struct address_space_operations squashfs_symlink_aops = {
2675 -+ .readpage = squashfs_symlink_readpage
2676 -+};
2677 -+
2678 -+SQSH_EXTERN const struct address_space_operations squashfs_aops = {
2679 -+ .readpage = squashfs_readpage
2680 -+};
2681 -+
2682 -+static const struct file_operations squashfs_dir_ops = {
2683 -+ .read = generic_read_dir,
2684 -+ .readdir = squashfs_readdir
2685 -+};
2686 -+
2687 -+SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = {
2688 -+ .lookup = squashfs_lookup
2689 -+};
2690 -+
2691 -+
2692 -+static struct buffer_head *get_block_length(struct super_block *s,
2693 -+ int *cur_index, int *offset, int *c_byte)
2694 -+{
2695 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
2696 -+ unsigned short temp;
2697 -+ struct buffer_head *bh;
2698 -+
2699 -+ if (!(bh = sb_bread(s, *cur_index)))
2700 -+ goto out;
2701 -+
2702 -+ if (msblk->devblksize - *offset == 1) {
2703 -+ if (msblk->swap)
2704 -+ ((unsigned char *) &temp)[1] = *((unsigned char *)
2705 -+ (bh->b_data + *offset));
2706 -+ else
2707 -+ ((unsigned char *) &temp)[0] = *((unsigned char *)
2708 -+ (bh->b_data + *offset));
2709 -+ brelse(bh);
2710 -+ if (!(bh = sb_bread(s, ++(*cur_index))))
2711 -+ goto out;
2712 -+ if (msblk->swap)
2713 -+ ((unsigned char *) &temp)[0] = *((unsigned char *)
2714 -+ bh->b_data);
2715 -+ else
2716 -+ ((unsigned char *) &temp)[1] = *((unsigned char *)
2717 -+ bh->b_data);
2718 -+ *c_byte = temp;
2719 -+ *offset = 1;
2720 -+ } else {
2721 -+ if (msblk->swap) {
2722 -+ ((unsigned char *) &temp)[1] = *((unsigned char *)
2723 -+ (bh->b_data + *offset));
2724 -+ ((unsigned char *) &temp)[0] = *((unsigned char *)
2725 -+ (bh->b_data + *offset + 1));
2726 -+ } else {
2727 -+ ((unsigned char *) &temp)[0] = *((unsigned char *)
2728 -+ (bh->b_data + *offset));
2729 -+ ((unsigned char *) &temp)[1] = *((unsigned char *)
2730 -+ (bh->b_data + *offset + 1));
2731 -+ }
2732 -+ *c_byte = temp;
2733 -+ *offset += 2;
2734 -+ }
2735 -+
2736 -+ if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) {
2737 -+ if (*offset == msblk->devblksize) {
2738 -+ brelse(bh);
2739 -+ if (!(bh = sb_bread(s, ++(*cur_index))))
2740 -+ goto out;
2741 -+ *offset = 0;
2742 -+ }
2743 -+ if (*((unsigned char *) (bh->b_data + *offset)) !=
2744 -+ SQUASHFS_MARKER_BYTE) {
2745 -+ ERROR("Metadata block marker corrupt @ %x\n",
2746 -+ *cur_index);
2747 -+ brelse(bh);
2748 -+ goto out;
2749 -+ }
2750 -+ (*offset)++;
2751 -+ }
2752 -+ return bh;
2753 -+
2754 -+out:
2755 -+ return NULL;
2756 -+}
2757 -+
2758 -+
2759 -+SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
2760 -+ long long index, unsigned int length,
2761 -+ long long *next_index, int srclength)
2762 -+{
2763 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
2764 -+ struct squashfs_super_block *sblk = &msblk->sblk;
2765 -+ struct buffer_head **bh;
2766 -+ unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
2767 -+ unsigned int cur_index = index >> msblk->devblksize_log2;
2768 -+ int bytes, avail_bytes, b = 0, k = 0;
2769 -+ unsigned int compressed;
2770 -+ unsigned int c_byte = length;
2771 -+
2772 -+ bh = kmalloc(((sblk->block_size >> msblk->devblksize_log2) + 1) *
2773 -+ sizeof(struct buffer_head *), GFP_KERNEL);
2774 -+ if (bh == NULL)
2775 -+ goto read_failure;
2776 -+
2777 -+ if (c_byte) {
2778 -+ bytes = msblk->devblksize - offset;
2779 -+ compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
2780 -+ c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
2781 -+
2782 -+ TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index,
2783 -+ compressed ? "" : "un", (unsigned int) c_byte, srclength);
2784 -+
2785 -+ if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used)
2786 -+ goto read_failure;
2787 -+
2788 -+ bh[0] = sb_getblk(s, cur_index);
2789 -+ if (bh[0] == NULL)
2790 -+ goto block_release;
2791 -+
2792 -+ for (b = 1; bytes < c_byte; b++) {
2793 -+ bh[b] = sb_getblk(s, ++cur_index);
2794 -+ if (bh[b] == NULL)
2795 -+ goto block_release;
2796 -+ bytes += msblk->devblksize;
2797 -+ }
2798 -+ ll_rw_block(READ, b, bh);
2799 -+ } else {
2800 -+ if (index < 0 || (index + 2) > sblk->bytes_used)
2801 -+ goto read_failure;
2802 -+
2803 -+ bh[0] = get_block_length(s, &cur_index, &offset, &c_byte);
2804 -+ if (bh[0] == NULL)
2805 -+ goto read_failure;
2806 -+
2807 -+ bytes = msblk->devblksize - offset;
2808 -+ compressed = SQUASHFS_COMPRESSED(c_byte);
2809 -+ c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
2810 -+
2811 -+ TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
2812 -+ ? "" : "un", (unsigned int) c_byte);
2813 -+
2814 -+ if (c_byte > srclength || (index + c_byte) > sblk->bytes_used)
2815 -+ goto read_failure;
2816 -+
2817 -+ for (b = 1; bytes < c_byte; b++) {
2818 -+ bh[b] = sb_getblk(s, ++cur_index);
2819 -+ if (bh[b] == NULL)
2820 -+ goto block_release;
2821 -+ bytes += msblk->devblksize;
2822 -+ }
2823 -+ ll_rw_block(READ, b - 1, bh + 1);
2824 -+ }
2825 -+
2826 -+ if (compressed) {
2827 -+ int zlib_err = 0;
2828 -+
2829 -+ /*
2830 -+ * uncompress block
2831 -+ */
2832 -+
2833 -+ mutex_lock(&msblk->read_data_mutex);
2834 -+
2835 -+ msblk->stream.next_out = buffer;
2836 -+ msblk->stream.avail_out = srclength;
2837 -+
2838 -+ for (bytes = 0; k < b; k++) {
2839 -+ avail_bytes = min(c_byte - bytes, msblk->devblksize - offset);
2840 -+
2841 -+ wait_on_buffer(bh[k]);
2842 -+ if (!buffer_uptodate(bh[k]))
2843 -+ goto release_mutex;
2844 -+
2845 -+ msblk->stream.next_in = bh[k]->b_data + offset;
2846 -+ msblk->stream.avail_in = avail_bytes;
2847 -+
2848 -+ if (k == 0) {
2849 -+ zlib_err = zlib_inflateInit(&msblk->stream);
2850 -+ if (zlib_err != Z_OK) {
2851 -+ ERROR("zlib_inflateInit returned unexpected result 0x%x,"
2852 -+ " srclength %d\n", zlib_err, srclength);
2853 -+ goto release_mutex;
2854 -+ }
2855 -+
2856 -+ if (avail_bytes == 0) {
2857 -+ offset = 0;
2858 -+ brelse(bh[k]);
2859 -+ continue;
2860 -+ }
2861 -+ }
2862 -+
2863 -+ zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH);
2864 -+ if (zlib_err != Z_OK && zlib_err != Z_STREAM_END) {
2865 -+ ERROR("zlib_inflate returned unexpected result 0x%x,"
2866 -+ " srclength %d, avail_in %d, avail_out %d\n", zlib_err,
2867 -+ srclength, msblk->stream.avail_in, msblk->stream.avail_out);
2868 -+ goto release_mutex;
2869 -+ }
2870 -+
2871 -+ bytes += avail_bytes;
2872 -+ offset = 0;
2873 -+ brelse(bh[k]);
2874 -+ }
2875 -+
2876 -+ if (zlib_err != Z_STREAM_END)
2877 -+ goto release_mutex;
2878 -+
2879 -+ zlib_err = zlib_inflateEnd(&msblk->stream);
2880 -+ if (zlib_err != Z_OK) {
2881 -+ ERROR("zlib_inflateEnd returned unexpected result 0x%x,"
2882 -+ " srclength %d\n", zlib_err, srclength);
2883 -+ goto release_mutex;
2884 -+ }
2885 -+ bytes = msblk->stream.total_out;
2886 -+ mutex_unlock(&msblk->read_data_mutex);
2887 -+ } else {
2888 -+ int i;
2889 -+
2890 -+ for(i = 0; i < b; i++) {
2891 -+ wait_on_buffer(bh[i]);
2892 -+ if (!buffer_uptodate(bh[i]))
2893 -+ goto block_release;
2894 -+ }
2895 -+
2896 -+ for (bytes = 0; k < b; k++) {
2897 -+ avail_bytes = min(c_byte - bytes, msblk->devblksize - offset);
2898 -+
2899 -+ memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes);
2900 -+ bytes += avail_bytes;
2901 -+ offset = 0;
2902 -+ brelse(bh[k]);
2903 -+ }
2904 -+ }
2905 -+
2906 -+ if (next_index)
2907 -+ *next_index = index + c_byte + (length ? 0 :
2908 -+ (SQUASHFS_CHECK_DATA(msblk->sblk.flags) ? 3 : 2));
2909 -+
2910 -+ kfree(bh);
2911 -+ return bytes;
2912 -+
2913 -+release_mutex:
2914 -+ mutex_unlock(&msblk->read_data_mutex);
2915 -+
2916 -+block_release:
2917 -+ for (; k < b; k++)
2918 -+ brelse(bh[k]);
2919 -+
2920 -+read_failure:
2921 -+ ERROR("sb_bread failed reading block 0x%x\n", cur_index);
2922 -+ kfree(bh);
2923 -+ return 0;
2924 -+}
2925 -+
2926 -+
2927 -+SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, void *buffer,
2928 -+ long long block, unsigned int offset,
2929 -+ int length, long long *next_block,
2930 -+ unsigned int *next_offset)
2931 -+{
2932 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
2933 -+ int n, i, bytes, return_length = length;
2934 -+ long long next_index;
2935 -+
2936 -+ TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
2937 -+
2938 -+ while (1) {
2939 -+ for (i = 0; i < squashfs_cached_blks; i++)
2940 -+ if (msblk->block_cache[i].block == block)
2941 -+ break;
2942 -+
2943 -+ mutex_lock(&msblk->block_cache_mutex);
2944 -+
2945 -+ if (i == squashfs_cached_blks) {
2946 -+ /* read inode header block */
2947 -+ if (msblk->unused_cache_blks == 0) {
2948 -+ mutex_unlock(&msblk->block_cache_mutex);
2949 -+ wait_event(msblk->waitq, msblk->unused_cache_blks);
2950 -+ continue;
2951 -+ }
2952 -+
2953 -+ i = msblk->next_cache;
2954 -+ for (n = 0; n < squashfs_cached_blks; n++) {
2955 -+ if (msblk->block_cache[i].block != SQUASHFS_USED_BLK)
2956 -+ break;
2957 -+ i = (i + 1) % squashfs_cached_blks;
2958 -+ }
2959 -+
2960 -+ msblk->next_cache = (i + 1) % squashfs_cached_blks;
2961 -+
2962 -+ if (msblk->block_cache[i].block == SQUASHFS_INVALID_BLK) {
2963 -+ msblk->block_cache[i].data = vmalloc(SQUASHFS_METADATA_SIZE);
2964 -+ if (msblk->block_cache[i].data == NULL) {
2965 -+ ERROR("Failed to allocate cache block\n");
2966 -+ mutex_unlock(&msblk->block_cache_mutex);
2967 -+ goto out;
2968 -+ }
2969 -+ }
2970 -+
2971 -+ msblk->block_cache[i].block = SQUASHFS_USED_BLK;
2972 -+ msblk->unused_cache_blks --;
2973 -+ mutex_unlock(&msblk->block_cache_mutex);
2974 -+
2975 -+ msblk->block_cache[i].length = squashfs_read_data(s,
2976 -+ msblk->block_cache[i].data, block, 0, &next_index,
2977 -+ SQUASHFS_METADATA_SIZE);
2978 -+
2979 -+ if (msblk->block_cache[i].length == 0) {
2980 -+ ERROR("Unable to read cache block [%llx:%x]\n", block, offset);
2981 -+ mutex_lock(&msblk->block_cache_mutex);
2982 -+ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
2983 -+ msblk->unused_cache_blks ++;
2984 -+ smp_mb();
2985 -+ vfree(msblk->block_cache[i].data);
2986 -+ wake_up(&msblk->waitq);
2987 -+ mutex_unlock(&msblk->block_cache_mutex);
2988 -+ goto out;
2989 -+ }
2990 -+
2991 -+ mutex_lock(&msblk->block_cache_mutex);
2992 -+ msblk->block_cache[i].block = block;
2993 -+ msblk->block_cache[i].next_index = next_index;
2994 -+ msblk->unused_cache_blks ++;
2995 -+ smp_mb();
2996 -+ wake_up(&msblk->waitq);
2997 -+ TRACE("Read cache block [%llx:%x]\n", block, offset);
2998 -+ }
2999 -+
3000 -+ if (msblk->block_cache[i].block != block) {
3001 -+ mutex_unlock(&msblk->block_cache_mutex);
3002 -+ continue;
3003 -+ }
3004 -+
3005 -+ bytes = msblk->block_cache[i].length - offset;
3006 -+
3007 -+ if (bytes < 1) {
3008 -+ mutex_unlock(&msblk->block_cache_mutex);
3009 -+ goto out;
3010 -+ } else if (bytes >= length) {
3011 -+ if (buffer)
3012 -+ memcpy(buffer, msblk->block_cache[i].data + offset, length);
3013 -+ if (msblk->block_cache[i].length - offset == length) {
3014 -+ *next_block = msblk->block_cache[i].next_index;
3015 -+ *next_offset = 0;
3016 -+ } else {
3017 -+ *next_block = block;
3018 -+ *next_offset = offset + length;
3019 -+ }
3020 -+ mutex_unlock(&msblk->block_cache_mutex);
3021 -+ goto finish;
3022 -+ } else {
3023 -+ if (buffer) {
3024 -+ memcpy(buffer, msblk->block_cache[i].data + offset, bytes);
3025 -+ buffer = (char *) buffer + bytes;
3026 -+ }
3027 -+ block = msblk->block_cache[i].next_index;
3028 -+ mutex_unlock(&msblk->block_cache_mutex);
3029 -+ length -= bytes;
3030 -+ offset = 0;
3031 -+ }
3032 -+ }
3033 -+
3034 -+finish:
3035 -+ return return_length;
3036 -+out:
3037 -+ return 0;
3038 -+}
3039 -+
3040 -+
3041 -+static int get_fragment_location(struct super_block *s, unsigned int fragment,
3042 -+ long long *fragment_start_block,
3043 -+ unsigned int *fragment_size)
3044 -+{
3045 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
3046 -+ long long start_block =
3047 -+ msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];
3048 -+ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
3049 -+ struct squashfs_fragment_entry fragment_entry;
3050 -+
3051 -+ if (msblk->swap) {
3052 -+ struct squashfs_fragment_entry sfragment_entry;
3053 -+
3054 -+ if (!squashfs_get_cached_block(s, &sfragment_entry, start_block, offset,
3055 -+ sizeof(sfragment_entry), &start_block, &offset))
3056 -+ goto out;
3057 -+ SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);
3058 -+ } else
3059 -+ if (!squashfs_get_cached_block(s, &fragment_entry, start_block, offset,
3060 -+ sizeof(fragment_entry), &start_block, &offset))
3061 -+ goto out;
3062 -+
3063 -+ *fragment_start_block = fragment_entry.start_block;
3064 -+ *fragment_size = fragment_entry.size;
3065 -+
3066 -+ return 1;
3067 -+
3068 -+out:
3069 -+ return 0;
3070 -+}
3071 -+
3072 -+
3073 -+SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk,
3074 -+ struct squashfs_fragment_cache *fragment)
3075 -+{
3076 -+ mutex_lock(&msblk->fragment_mutex);
3077 -+ fragment->locked --;
3078 -+ if (fragment->locked == 0) {
3079 -+ msblk->unused_frag_blks ++;
3080 -+ smp_mb();
3081 -+ wake_up(&msblk->fragment_wait_queue);
3082 -+ }
3083 -+ mutex_unlock(&msblk->fragment_mutex);
3084 -+}
3085 -+
3086 -+
3087 -+SQSH_EXTERN
3088 -+struct squashfs_fragment_cache *get_cached_fragment(struct super_block *s,
3089 -+ long long start_block, int length)
3090 -+{
3091 -+ int i, n;
3092 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
3093 -+ struct squashfs_super_block *sblk = &msblk->sblk;
3094 -+
3095 -+ while (1) {
3096 -+ mutex_lock(&msblk->fragment_mutex);
3097 -+
3098 -+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&
3099 -+ msblk->fragment[i].block != start_block; i++);
3100 -+
3101 -+ if (i == SQUASHFS_CACHED_FRAGMENTS) {
3102 -+ if (msblk->unused_frag_blks == 0) {
3103 -+ mutex_unlock(&msblk->fragment_mutex);
3104 -+ wait_event(msblk->fragment_wait_queue, msblk->unused_frag_blks);
3105 -+ continue;
3106 -+ }
3107 -+
3108 -+ i = msblk->next_fragment;
3109 -+ for (n = 0; n < SQUASHFS_CACHED_FRAGMENTS; n++) {
3110 -+ if (msblk->fragment[i].locked == 0)
3111 -+ break;
3112 -+ i = (i + 1) % SQUASHFS_CACHED_FRAGMENTS;
3113 -+ }
3114 -+
3115 -+ msblk->next_fragment = (msblk->next_fragment + 1) %
3116 -+ SQUASHFS_CACHED_FRAGMENTS;
3117 -+
3118 -+ if (msblk->fragment[i].data == NULL) {
3119 -+ msblk->fragment[i].data = vmalloc(sblk->block_size);
3120 -+ if (msblk->fragment[i].data == NULL) {
3121 -+ ERROR("Failed to allocate fragment cache block\n");
3122 -+ mutex_unlock(&msblk->fragment_mutex);
3123 -+ goto out;
3124 -+ }
3125 -+ }
3126 -+
3127 -+ msblk->unused_frag_blks --;
3128 -+ msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
3129 -+ msblk->fragment[i].locked = 1;
3130 -+ mutex_unlock(&msblk->fragment_mutex);
3131 -+
3132 -+ msblk->fragment[i].length = squashfs_read_data(s,
3133 -+ msblk->fragment[i].data, start_block, length, NULL,
3134 -+ sblk->block_size);
3135 -+
3136 -+ if (msblk->fragment[i].length == 0) {
3137 -+ ERROR("Unable to read fragment cache block [%llx]\n", start_block);
3138 -+ msblk->fragment[i].locked = 0;
3139 -+ msblk->unused_frag_blks ++;
3140 -+ smp_mb();
3141 -+ wake_up(&msblk->fragment_wait_queue);
3142 -+ goto out;
3143 -+ }
3144 -+
3145 -+ mutex_lock(&msblk->fragment_mutex);
3146 -+ msblk->fragment[i].block = start_block;
3147 -+ TRACE("New fragment %d, start block %lld, locked %d\n",
3148 -+ i, msblk->fragment[i].block, msblk->fragment[i].locked);
3149 -+ mutex_unlock(&msblk->fragment_mutex);
3150 -+ break;
3151 -+ }
3152 -+
3153 -+ if (msblk->fragment[i].locked == 0)
3154 -+ msblk->unused_frag_blks --;
3155 -+ msblk->fragment[i].locked++;
3156 -+ mutex_unlock(&msblk->fragment_mutex);
3157 -+ TRACE("Got fragment %d, start block %lld, locked %d\n", i,
3158 -+ msblk->fragment[i].block, msblk->fragment[i].locked);
3159 -+ break;
3160 -+ }
3161 -+
3162 -+ return &msblk->fragment[i];
3163 -+
3164 -+out:
3165 -+ return NULL;
3166 -+}
3167 -+
3168 -+
3169 -+static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i,
3170 -+ struct squashfs_base_inode_header *inodeb)
3171 -+{
3172 -+ i->i_ino = inodeb->inode_number;
3173 -+ i->i_mtime.tv_sec = inodeb->mtime;
3174 -+ i->i_atime.tv_sec = inodeb->mtime;
3175 -+ i->i_ctime.tv_sec = inodeb->mtime;
3176 -+ i->i_uid = msblk->uid[inodeb->uid];
3177 -+ i->i_mode = inodeb->mode;
3178 -+ i->i_size = 0;
3179 -+
3180 -+ if (inodeb->guid == SQUASHFS_GUIDS)
3181 -+ i->i_gid = i->i_uid;
3182 -+ else
3183 -+ i->i_gid = msblk->guid[inodeb->guid];
3184 -+}
3185 -+
3186 -+
3187 -+static squashfs_inode_t squashfs_inode_lookup(struct super_block *s, int ino)
3188 -+{
3189 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
3190 -+ long long start = msblk->inode_lookup_table[SQUASHFS_LOOKUP_BLOCK(ino - 1)];
3191 -+ int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino - 1);
3192 -+ squashfs_inode_t inode;
3193 -+
3194 -+ TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino);
3195 -+
3196 -+ if (msblk->swap) {
3197 -+ squashfs_inode_t sinode;
3198 -+
3199 -+ if (!squashfs_get_cached_block(s, &sinode, start, offset,
3200 -+ sizeof(sinode), &start, &offset))
3201 -+ goto out;
3202 -+ SQUASHFS_SWAP_INODE_T((&inode), &sinode);
3203 -+ } else if (!squashfs_get_cached_block(s, &inode, start, offset,
3204 -+ sizeof(inode), &start, &offset))
3205 -+ goto out;
3206 -+
3207 -+ TRACE("squashfs_inode_lookup, inode = 0x%llx\n", inode);
3208 -+
3209 -+ return inode;
3210 -+
3211 -+out:
3212 -+ return SQUASHFS_INVALID_BLK;
3213 -+}
3214 -+
3215 -+static struct dentry *squashfs_get_parent(struct dentry *child)
3216 -+{
3217 -+ struct inode *i = child->d_inode;
3218 -+ unsigned long ino = SQUASHFS_I(i)->u.s2.parent_inode;
3219 -+ squashfs_inode_t inode = squashfs_inode_lookup(i->i_sb, ino);
3220 -+ struct inode *parent;
3221 -+ struct dentry *rv;
3222 -+
3223 -+ TRACE("Entered squashfs_get_parent\n");
3224 -+
3225 -+ if (inode == SQUASHFS_INVALID_BLK)
3226 -+ return ERR_PTR(-EINVAL);
3227 -+
3228 -+ parent = squashfs_iget(i->i_sb, inode, ino);
3229 -+ if (IS_ERR(parent)) {
3230 -+ rv = ERR_PTR(-EACCES);
3231 -+ goto out;
3232 -+ }
3233 -+
3234 -+ rv = d_alloc_anon(parent);
3235 -+ if(rv == NULL)
3236 -+ rv = ERR_PTR(-ENOMEM);
3237 -+
3238 -+out:
3239 -+ return rv;
3240 -+}
3241 -+
3242 -+
3243 -+SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s,
3244 -+ squashfs_inode_t inode, unsigned int inode_number)
3245 -+{
3246 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
3247 -+ struct inode *i = iget_locked(s, inode_number);
3248 -+
3249 -+ TRACE("Entered squashfs_iget\n");
3250 -+ if (!i)
3251 -+ return ERR_PTR(-ENOMEM);
3252 -+
3253 -+ if (i->i_state & I_NEW) {
3254 -+ (msblk->read_inode)(i, inode);
3255 -+ unlock_new_inode(i);
3256 -+ }
3257 -+
3258 -+ return i;
3259 -+}
3260 -+
3261 -+
3262 -+static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode)
3263 -+{
3264 -+ struct super_block *s = i->i_sb;
3265 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
3266 -+ struct squashfs_super_block *sblk = &msblk->sblk;
3267 -+ long long block = SQUASHFS_INODE_BLK(inode) + sblk->inode_table_start;
3268 -+ unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
3269 -+ long long next_block;
3270 -+ unsigned int next_offset;
3271 -+ union squashfs_inode_header id, sid;
3272 -+ struct squashfs_base_inode_header *inodeb = &id.base, *sinodeb = &sid.base;
3273 -+
3274 -+ TRACE("Entered squashfs_read_inode\n");
3275 -+
3276 -+ if (msblk->swap) {
3277 -+ if (!squashfs_get_cached_block(s, sinodeb, block, offset,
3278 -+ sizeof(*sinodeb), &next_block, &next_offset))
3279 -+ goto failed_read;
3280 -+ SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb, sizeof(*sinodeb));
3281 -+ } else
3282 -+ if (!squashfs_get_cached_block(s, inodeb, block, offset,
3283 -+ sizeof(*inodeb), &next_block, &next_offset))
3284 -+ goto failed_read;
3285 -+
3286 -+ squashfs_new_inode(msblk, i, inodeb);
3287 -+
3288 -+ switch(inodeb->inode_type) {
3289 -+ case SQUASHFS_FILE_TYPE: {
3290 -+ unsigned int frag_size;
3291 -+ long long frag_blk;
3292 -+ struct squashfs_reg_inode_header *inodep = &id.reg;
3293 -+ struct squashfs_reg_inode_header *sinodep = &sid.reg;
3294 -+
3295 -+ if (msblk->swap) {
3296 -+ if (!squashfs_get_cached_block(s, sinodep, block, offset,
3297 -+ sizeof(*sinodep), &next_block, &next_offset))
3298 -+ goto failed_read;
3299 -+ SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);
3300 -+ } else
3301 -+ if (!squashfs_get_cached_block(s, inodep, block, offset,
3302 -+ sizeof(*inodep), &next_block, &next_offset))
3303 -+ goto failed_read;
3304 -+
3305 -+ frag_blk = SQUASHFS_INVALID_BLK;
3306 -+
3307 -+ if (inodep->fragment != SQUASHFS_INVALID_FRAG)
3308 -+ if(!get_fragment_location(s, inodep->fragment, &frag_blk,
3309 -+ &frag_size))
3310 -+ goto failed_read;
3311 -+
3312 -+ i->i_nlink = 1;
3313 -+ i->i_size = inodep->file_size;
3314 -+ i->i_fop = &generic_ro_fops;
3315 -+ i->i_mode |= S_IFREG;
3316 -+ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
3317 -+ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
3318 -+ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
3319 -+ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
3320 -+ SQUASHFS_I(i)->start_block = inodep->start_block;
3321 -+ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
3322 -+ SQUASHFS_I(i)->offset = next_offset;
3323 -+ i->i_data.a_ops = &squashfs_aops;
3324 -+
3325 -+ TRACE("File inode %x:%x, start_block %llx, "
3326 -+ "block_list_start %llx, offset %x\n",
3327 -+ SQUASHFS_INODE_BLK(inode), offset,
3328 -+ inodep->start_block, next_block,
3329 -+ next_offset);
3330 -+ break;
3331 -+ }
3332 -+ case SQUASHFS_LREG_TYPE: {
3333 -+ unsigned int frag_size;
3334 -+ long long frag_blk;
3335 -+ struct squashfs_lreg_inode_header *inodep = &id.lreg;
3336 -+ struct squashfs_lreg_inode_header *sinodep = &sid.lreg;
3337 -+
3338 -+ if (msblk->swap) {
3339 -+ if (!squashfs_get_cached_block(s, sinodep, block, offset,
3340 -+ sizeof(*sinodep), &next_block, &next_offset))
3341 -+ goto failed_read;
3342 -+ SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);
3343 -+ } else
3344 -+ if (!squashfs_get_cached_block(s, inodep, block, offset,
3345 -+ sizeof(*inodep), &next_block, &next_offset))
3346 -+ goto failed_read;
3347 -+
3348 -+ frag_blk = SQUASHFS_INVALID_BLK;
3349 -+
3350 -+ if (inodep->fragment != SQUASHFS_INVALID_FRAG)
3351 -+ if (!get_fragment_location(s, inodep->fragment, &frag_blk,
3352 -+ &frag_size))
3353 -+ goto failed_read;
3354 -+
3355 -+ i->i_nlink = inodep->nlink;
3356 -+ i->i_size = inodep->file_size;
3357 -+ i->i_fop = &generic_ro_fops;
3358 -+ i->i_mode |= S_IFREG;
3359 -+ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
3360 -+ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
3361 -+ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
3362 -+ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
3363 -+ SQUASHFS_I(i)->start_block = inodep->start_block;
3364 -+ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
3365 -+ SQUASHFS_I(i)->offset = next_offset;
3366 -+ i->i_data.a_ops = &squashfs_aops;
3367 -+
3368 -+ TRACE("File inode %x:%x, start_block %llx, "
3369 -+ "block_list_start %llx, offset %x\n",
3370 -+ SQUASHFS_INODE_BLK(inode), offset,
3371 -+ inodep->start_block, next_block,
3372 -+ next_offset);
3373 -+ break;
3374 -+ }
3375 -+ case SQUASHFS_DIR_TYPE: {
3376 -+ struct squashfs_dir_inode_header *inodep = &id.dir;
3377 -+ struct squashfs_dir_inode_header *sinodep = &sid.dir;
3378 -+
3379 -+ if (msblk->swap) {
3380 -+ if (!squashfs_get_cached_block(s, sinodep, block, offset,
3381 -+ sizeof(*sinodep), &next_block, &next_offset))
3382 -+ goto failed_read;
3383 -+ SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);
3384 -+ } else
3385 -+ if (!squashfs_get_cached_block(s, inodep, block, offset,
3386 -+ sizeof(*inodep), &next_block, &next_offset))
3387 -+ goto failed_read;
3388 -+
3389 -+ i->i_nlink = inodep->nlink;
3390 -+ i->i_size = inodep->file_size;
3391 -+ i->i_op = &squashfs_dir_inode_ops;
3392 -+ i->i_fop = &squashfs_dir_ops;
3393 -+ i->i_mode |= S_IFDIR;
3394 -+ SQUASHFS_I(i)->start_block = inodep->start_block;
3395 -+ SQUASHFS_I(i)->offset = inodep->offset;
3396 -+ SQUASHFS_I(i)->u.s2.directory_index_count = 0;
3397 -+ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
3398 -+
3399 -+ TRACE("Directory inode %x:%x, start_block %x, offset "
3400 -+ "%x\n", SQUASHFS_INODE_BLK(inode),
3401 -+ offset, inodep->start_block,
3402 -+ inodep->offset);
3403 -+ break;
3404 -+ }
3405 -+ case SQUASHFS_LDIR_TYPE: {
3406 -+ struct squashfs_ldir_inode_header *inodep = &id.ldir;
3407 -+ struct squashfs_ldir_inode_header *sinodep = &sid.ldir;
3408 -+
3409 -+ if (msblk->swap) {
3410 -+ if (!squashfs_get_cached_block(s, sinodep, block, offset,
3411 -+ sizeof(*sinodep), &next_block, &next_offset))
3412 -+ goto failed_read;
3413 -+ SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep, sinodep);
3414 -+ } else
3415 -+ if (!squashfs_get_cached_block(s, inodep, block, offset,
3416 -+ sizeof(*inodep), &next_block, &next_offset))
3417 -+ goto failed_read;
3418 -+
3419 -+ i->i_nlink = inodep->nlink;
3420 -+ i->i_size = inodep->file_size;
3421 -+ i->i_op = &squashfs_dir_inode_ops;
3422 -+ i->i_fop = &squashfs_dir_ops;
3423 -+ i->i_mode |= S_IFDIR;
3424 -+ SQUASHFS_I(i)->start_block = inodep->start_block;
3425 -+ SQUASHFS_I(i)->offset = inodep->offset;
3426 -+ SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
3427 -+ SQUASHFS_I(i)->u.s2.directory_index_offset = next_offset;
3428 -+ SQUASHFS_I(i)->u.s2.directory_index_count = inodep->i_count;
3429 -+ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
3430 -+
3431 -+ TRACE("Long directory inode %x:%x, start_block %x, offset %x\n",
3432 -+ SQUASHFS_INODE_BLK(inode), offset,
3433 -+ inodep->start_block, inodep->offset);
3434 -+ break;
3435 -+ }
3436 -+ case SQUASHFS_SYMLINK_TYPE: {
3437 -+ struct squashfs_symlink_inode_header *inodep = &id.symlink;
3438 -+ struct squashfs_symlink_inode_header *sinodep = &sid.symlink;
3439 -+
3440 -+ if (msblk->swap) {
3441 -+ if (!squashfs_get_cached_block(s, sinodep, block, offset,
3442 -+ sizeof(*sinodep), &next_block, &next_offset))
3443 -+ goto failed_read;
3444 -+ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, sinodep);
3445 -+ } else
3446 -+ if (!squashfs_get_cached_block(s, inodep, block, offset,
3447 -+ sizeof(*inodep), &next_block, &next_offset))
3448 -+ goto failed_read;
3449 -+
3450 -+ i->i_nlink = inodep->nlink;
3451 -+ i->i_size = inodep->symlink_size;
3452 -+ i->i_op = &page_symlink_inode_operations;
3453 -+ i->i_data.a_ops = &squashfs_symlink_aops;
3454 -+ i->i_mode |= S_IFLNK;
3455 -+ SQUASHFS_I(i)->start_block = next_block;
3456 -+ SQUASHFS_I(i)->offset = next_offset;
3457 -+
3458 -+ TRACE("Symbolic link inode %x:%x, start_block %llx, offset %x\n",
3459 -+ SQUASHFS_INODE_BLK(inode), offset,
3460 -+ next_block, next_offset);
3461 -+ break;
3462 -+ }
3463 -+ case SQUASHFS_BLKDEV_TYPE:
3464 -+ case SQUASHFS_CHRDEV_TYPE: {
3465 -+ struct squashfs_dev_inode_header *inodep = &id.dev;
3466 -+ struct squashfs_dev_inode_header *sinodep = &sid.dev;
3467 -+
3468 -+ if (msblk->swap) {
3469 -+ if (!squashfs_get_cached_block(s, sinodep, block, offset,
3470 -+ sizeof(*sinodep), &next_block, &next_offset))
3471 -+ goto failed_read;
3472 -+ SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);
3473 -+ } else
3474 -+ if (!squashfs_get_cached_block(s, inodep, block, offset,
3475 -+ sizeof(*inodep), &next_block, &next_offset))
3476 -+ goto failed_read;
3477 -+
3478 -+ i->i_nlink = inodep->nlink;
3479 -+ i->i_mode |= (inodeb->inode_type == SQUASHFS_CHRDEV_TYPE) ?
3480 -+ S_IFCHR : S_IFBLK;
3481 -+ init_special_inode(i, i->i_mode, old_decode_dev(inodep->rdev));
3482 -+
3483 -+ TRACE("Device inode %x:%x, rdev %x\n",
3484 -+ SQUASHFS_INODE_BLK(inode), offset, inodep->rdev);
3485 -+ break;
3486 -+ }
3487 -+ case SQUASHFS_FIFO_TYPE:
3488 -+ case SQUASHFS_SOCKET_TYPE: {
3489 -+ struct squashfs_ipc_inode_header *inodep = &id.ipc;
3490 -+ struct squashfs_ipc_inode_header *sinodep = &sid.ipc;
3491 -+
3492 -+ if (msblk->swap) {
3493 -+ if (!squashfs_get_cached_block(s, sinodep, block, offset,
3494 -+ sizeof(*sinodep), &next_block, &next_offset))
3495 -+ goto failed_read;
3496 -+ SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);
3497 -+ } else
3498 -+ if (!squashfs_get_cached_block(s, inodep, block, offset,
3499 -+ sizeof(*inodep), &next_block, &next_offset))
3500 -+ goto failed_read;
3501 -+
3502 -+ i->i_nlink = inodep->nlink;
3503 -+ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
3504 -+ ? S_IFIFO : S_IFSOCK;
3505 -+ init_special_inode(i, i->i_mode, 0);
3506 -+ break;
3507 -+ }
3508 -+ default:
3509 -+ ERROR("Unknown inode type %d in squashfs_iget!\n",
3510 -+ inodeb->inode_type);
3511 -+ goto failed_read1;
3512 -+ }
3513 -+
3514 -+ return 1;
3515 -+
3516 -+failed_read:
3517 -+ ERROR("Unable to read inode [%llx:%x]\n", block, offset);
3518 -+
3519 -+failed_read1:
3520 -+ make_bad_inode(i);
3521 -+ return 0;
3522 -+}
3523 -+
3524 -+
3525 -+static int read_inode_lookup_table(struct super_block *s)
3526 -+{
3527 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
3528 -+ struct squashfs_super_block *sblk = &msblk->sblk;
3529 -+ unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(sblk->inodes);
3530 -+
3531 -+ TRACE("In read_inode_lookup_table, length %d\n", length);
3532 -+
3533 -+ /* Allocate inode lookup table */
3534 -+ msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL);
3535 -+ if (msblk->inode_lookup_table == NULL) {
3536 -+ ERROR("Failed to allocate inode lookup table\n");
3537 -+ return 0;
3538 -+ }
3539 -+
3540 -+ if (!squashfs_read_data(s, (char *) msblk->inode_lookup_table,
3541 -+ sblk->lookup_table_start, length |
3542 -+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) {
3543 -+ ERROR("unable to read inode lookup table\n");
3544 -+ return 0;
3545 -+ }
3546 -+
3547 -+ if (msblk->swap) {
3548 -+ int i;
3549 -+ long long block;
3550 -+
3551 -+ for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) {
3552 -+ /* XXX */
3553 -+ SQUASHFS_SWAP_LOOKUP_BLOCKS((&block),
3554 -+ &msblk->inode_lookup_table[i], 1);
3555 -+ msblk->inode_lookup_table[i] = block;
3556 -+ }
3557 -+ }
3558 -+
3559 -+ return 1;
3560 -+}
3561 -+
3562 -+
3563 -+static int read_fragment_index_table(struct super_block *s)
3564 -+{
3565 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
3566 -+ struct squashfs_super_block *sblk = &msblk->sblk;
3567 -+ unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments);
3568 -+
3569 -+ if(length == 0)
3570 -+ return 1;
3571 -+
3572 -+ /* Allocate fragment index table */
3573 -+ msblk->fragment_index = kmalloc(length, GFP_KERNEL);
3574 -+ if (msblk->fragment_index == NULL) {
3575 -+ ERROR("Failed to allocate fragment index table\n");
3576 -+ return 0;
3577 -+ }
3578 -+
3579 -+ if (!squashfs_read_data(s, (char *) msblk->fragment_index,
3580 -+ sblk->fragment_table_start, length |
3581 -+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) {
3582 -+ ERROR("unable to read fragment index table\n");
3583 -+ return 0;
3584 -+ }
3585 -+
3586 -+ if (msblk->swap) {
3587 -+ int i;
3588 -+ long long fragment;
3589 -+
3590 -+ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) {
3591 -+ /* XXX */
3592 -+ SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
3593 -+ &msblk->fragment_index[i], 1);
3594 -+ msblk->fragment_index[i] = fragment;
3595 -+ }
3596 -+ }
3597 -+
3598 -+ return 1;
3599 -+}
3600 -+
3601 -+
3602 -+static int readahead_metadata(struct super_block *s)
3603 -+{
3604 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
3605 -+ int i;
3606 -+
3607 -+ squashfs_cached_blks = SQUASHFS_CACHED_BLKS;
3608 -+
3609 -+ /* Init inode_table block pointer array */
3610 -+ msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
3611 -+ squashfs_cached_blks, GFP_KERNEL);
3612 -+ if (msblk->block_cache == NULL) {
3613 -+ ERROR("Failed to allocate block cache\n");
3614 -+ goto failed;
3615 -+ }
3616 -+
3617 -+ for (i = 0; i < squashfs_cached_blks; i++)
3618 -+ msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
3619 -+
3620 -+ msblk->next_cache = 0;
3621 -+ msblk->unused_cache_blks = squashfs_cached_blks;
3622 -+
3623 -+ return 1;
3624 -+
3625 -+failed:
3626 -+ return 0;
3627 -+}
3628 -+
3629 -+
3630 -+static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
3631 -+{
3632 -+ struct squashfs_super_block *sblk = &msblk->sblk;
3633 -+
3634 -+ msblk->read_inode = squashfs_read_inode;
3635 -+ msblk->read_blocklist = read_blocklist;
3636 -+ msblk->read_fragment_index_table = read_fragment_index_table;
3637 -+
3638 -+ if (sblk->s_major == 1) {
3639 -+ if (!squashfs_1_0_supported(msblk)) {
3640 -+ SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "
3641 -+ "are unsupported\n");
3642 -+ SERROR("Please recompile with Squashfs 1.0 support enabled\n");
3643 -+ return 0;
3644 -+ }
3645 -+ } else if (sblk->s_major == 2) {
3646 -+ if (!squashfs_2_0_supported(msblk)) {
3647 -+ SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "
3648 -+ "are unsupported\n");
3649 -+ SERROR("Please recompile with Squashfs 2.0 support enabled\n");
3650 -+ return 0;
3651 -+ }
3652 -+ } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
3653 -+ SQUASHFS_MINOR) {
3654 -+ SERROR("Major/Minor mismatch, trying to mount newer %d.%d "
3655 -+ "filesystem\n", sblk->s_major, sblk->s_minor);
3656 -+ SERROR("Please update your kernel\n");
3657 -+ return 0;
3658 -+ }
3659 -+
3660 -+ return 1;
3661 -+}
3662 -+
3663 -+
3664 -+static int squashfs_fill_super(struct super_block *s, void *data, int silent)
3665 -+{
3666 -+ struct squashfs_sb_info *msblk;
3667 -+ struct squashfs_super_block *sblk;
3668 -+ int i;
3669 -+ char b[BDEVNAME_SIZE];
3670 -+ struct inode *root;
3671 -+
3672 -+ TRACE("Entered squashfs_fill_superblock\n");
3673 -+
3674 -+ s->s_fs_info = kzalloc(sizeof(struct squashfs_sb_info), GFP_KERNEL);
3675 -+ if (s->s_fs_info == NULL) {
3676 -+ ERROR("Failed to allocate superblock\n");
3677 -+ goto failure;
3678 -+ }
3679 -+ msblk = s->s_fs_info;
3680 -+
3681 -+ msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize());
3682 -+ if (msblk->stream.workspace == NULL) {
3683 -+ ERROR("Failed to allocate zlib workspace\n");
3684 -+ goto failure;
3685 -+ }
3686 -+ sblk = &msblk->sblk;
3687 -+
3688 -+ msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE);
3689 -+ msblk->devblksize_log2 = ffz(~msblk->devblksize);
3690 -+
3691 -+ mutex_init(&msblk->read_data_mutex);
3692 -+ mutex_init(&msblk->read_page_mutex);
3693 -+ mutex_init(&msblk->block_cache_mutex);
3694 -+ mutex_init(&msblk->fragment_mutex);
3695 -+ mutex_init(&msblk->meta_index_mutex);
3696 -+
3697 -+ init_waitqueue_head(&msblk->waitq);
3698 -+ init_waitqueue_head(&msblk->fragment_wait_queue);
3699 -+
3700 -+ /* sblk->bytes_used is checked in squashfs_read_data to ensure reads are not
3701 -+ * beyond filesystem end. As we're using squashfs_read_data to read sblk here,
3702 -+ * first set sblk->bytes_used to a useful value */
3703 -+ sblk->bytes_used = sizeof(struct squashfs_super_block);
3704 -+ if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
3705 -+ sizeof(struct squashfs_super_block) |
3706 -+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, sizeof(struct squashfs_super_block))) {
3707 -+ SERROR("unable to read superblock\n");
3708 -+ goto failed_mount;
3709 -+ }
3710 -+
3711 -+ /* Check it is a SQUASHFS superblock */
3712 -+ if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) {
3713 -+ if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) {
3714 -+ struct squashfs_super_block ssblk;
3715 -+
3716 -+ WARNING("Mounting a different endian SQUASHFS filesystem on %s\n",
3717 -+ bdevname(s->s_bdev, b));
3718 -+
3719 -+ SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);
3720 -+ memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));
3721 -+ msblk->swap = 1;
3722 -+ } else {
3723 -+ SERROR("Can't find a SQUASHFS superblock on %s\n",
3724 -+ bdevname(s->s_bdev, b));
3725 -+ goto failed_mount;
3726 -+ }
3727 -+ }
3728 -+
3729 -+ /* Check the MAJOR & MINOR versions */
3730 -+ if(!supported_squashfs_filesystem(msblk, silent))
3731 -+ goto failed_mount;
3732 -+
3733 -+ /* Check the filesystem does not extend beyond the end of the
3734 -+ block device */
3735 -+ if(sblk->bytes_used < 0 || sblk->bytes_used > i_size_read(s->s_bdev->bd_inode))
3736 -+ goto failed_mount;
3737 -+
3738 -+ /* Check the root inode for sanity */
3739 -+ if (SQUASHFS_INODE_OFFSET(sblk->root_inode) > SQUASHFS_METADATA_SIZE)
3740 -+ goto failed_mount;
3741 -+
3742 -+ TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b));
3743 -+ TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sblk->flags)
3744 -+ ? "un" : "");
3745 -+ TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
3746 -+ ? "un" : "");
3747 -+ TRACE("Check data is %spresent in the filesystem\n",
3748 -+ SQUASHFS_CHECK_DATA(sblk->flags) ? "" : "not ");
3749 -+ TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);
3750 -+ TRACE("Block size %d\n", sblk->block_size);
3751 -+ TRACE("Number of inodes %d\n", sblk->inodes);
3752 -+ if (sblk->s_major > 1)
3753 -+ TRACE("Number of fragments %d\n", sblk->fragments);
3754 -+ TRACE("Number of uids %d\n", sblk->no_uids);
3755 -+ TRACE("Number of gids %d\n", sblk->no_guids);
3756 -+ TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);
3757 -+ TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);
3758 -+ if (sblk->s_major > 1)
3759 -+ TRACE("sblk->fragment_table_start %llx\n", sblk->fragment_table_start);
3760 -+ TRACE("sblk->uid_start %llx\n", sblk->uid_start);
3761 -+
3762 -+ s->s_maxbytes = MAX_LFS_FILESIZE;
3763 -+ s->s_flags |= MS_RDONLY;
3764 -+ s->s_op = &squashfs_super_ops;
3765 -+
3766 -+ if (readahead_metadata(s) == 0)
3767 -+ goto failed_mount;
3768 -+
3769 -+ /* Allocate read_page block */
3770 -+ msblk->read_page = vmalloc(sblk->block_size);
3771 -+ if (msblk->read_page == NULL) {
3772 -+ ERROR("Failed to allocate read_page block\n");
3773 -+ goto failed_mount;
3774 -+ }
3775 -+
3776 -+ /* Allocate uid and gid tables */
3777 -+ msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
3778 -+ sizeof(unsigned int), GFP_KERNEL);
3779 -+ if (msblk->uid == NULL) {
3780 -+ ERROR("Failed to allocate uid/gid table\n");
3781 -+ goto failed_mount;
3782 -+ }
3783 -+ msblk->guid = msblk->uid + sblk->no_uids;
3784 -+
3785 -+ if (msblk->swap) {
3786 -+ unsigned int suid[sblk->no_uids + sblk->no_guids];
3787 -+
3788 -+ if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,
3789 -+ ((sblk->no_uids + sblk->no_guids) *
3790 -+ sizeof(unsigned int)) |
3791 -+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) {
3792 -+ ERROR("unable to read uid/gid table\n");
3793 -+ goto failed_mount;
3794 -+ }
3795 -+
3796 -+ SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids +
3797 -+ sblk->no_guids), (sizeof(unsigned int) * 8));
3798 -+ } else
3799 -+ if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,
3800 -+ ((sblk->no_uids + sblk->no_guids) *
3801 -+ sizeof(unsigned int)) |
3802 -+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) {
3803 -+ ERROR("unable to read uid/gid table\n");
3804 -+ goto failed_mount;
3805 -+ }
3806 -+
3807 -+
3808 -+ if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))
3809 -+ goto allocate_root;
3810 -+
3811 -+ msblk->fragment = kzalloc(sizeof(struct squashfs_fragment_cache) *
3812 -+ SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL);
3813 -+ if (msblk->fragment == NULL) {
3814 -+ ERROR("Failed to allocate fragment block cache\n");
3815 -+ goto failed_mount;
3816 -+ }
3817 -+
3818 -+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {
3819 -+ msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
3820 -+ }
3821 -+
3822 -+ msblk->next_fragment = 0;
3823 -+ msblk->unused_frag_blks = SQUASHFS_CACHED_FRAGMENTS;
3824 -+
3825 -+ /* Allocate and read fragment index table */
3826 -+ if (msblk->read_fragment_index_table(s) == 0)
3827 -+ goto failed_mount;
3828 -+
3829 -+ if(sblk->s_major < 3 || sblk->lookup_table_start == SQUASHFS_INVALID_BLK)
3830 -+ goto allocate_root;
3831 -+
3832 -+ /* Allocate and read inode lookup table */
3833 -+ if (read_inode_lookup_table(s) == 0)
3834 -+ goto failed_mount;
3835 -+
3836 -+ s->s_op = &squashfs_export_super_ops;
3837 -+ s->s_export_op = &squashfs_export_ops;
3838 -+
3839 -+allocate_root:
3840 -+ root = new_inode(s);
3841 -+ if ((msblk->read_inode)(root, sblk->root_inode) == 0)
3842 -+ goto failed_mount;
3843 -+ insert_inode_hash(root);
3844 -+
3845 -+ s->s_root = d_alloc_root(root);
3846 -+ if (s->s_root == NULL) {
3847 -+ ERROR("Root inode create failed\n");
3848 -+ iput(root);
3849 -+ goto failed_mount;
3850 -+ }
3851 -+
3852 -+ TRACE("Leaving squashfs_fill_super\n");
3853 -+ return 0;
3854 -+
3855 -+failed_mount:
3856 -+ kfree(msblk->inode_lookup_table);
3857 -+ kfree(msblk->fragment_index);
3858 -+ kfree(msblk->fragment);
3859 -+ kfree(msblk->uid);
3860 -+ vfree(msblk->read_page);
3861 -+ kfree(msblk->block_cache);
3862 -+ kfree(msblk->fragment_index_2);
3863 -+ vfree(msblk->stream.workspace);
3864 -+ kfree(s->s_fs_info);
3865 -+ s->s_fs_info = NULL;
3866 -+ return -EINVAL;
3867 -+
3868 -+failure:
3869 -+ return -ENOMEM;
3870 -+}
3871 -+
3872 -+
3873 -+static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
3874 -+{
3875 -+ struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info;
3876 -+ struct squashfs_super_block *sblk = &msblk->sblk;
3877 -+
3878 -+ TRACE("Entered squashfs_statfs\n");
3879 -+
3880 -+ buf->f_type = SQUASHFS_MAGIC;
3881 -+ buf->f_bsize = sblk->block_size;
3882 -+ buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1;
3883 -+ buf->f_bfree = buf->f_bavail = 0;
3884 -+ buf->f_files = sblk->inodes;
3885 -+ buf->f_ffree = 0;
3886 -+ buf->f_namelen = SQUASHFS_NAME_LEN;
3887 -+
3888 -+ return 0;
3889 -+}
3890 -+
3891 -+
3892 -+static int squashfs_symlink_readpage(struct file *file, struct page *page)
3893 -+{
3894 -+ struct inode *inode = page->mapping->host;
3895 -+ int index = page->index << PAGE_CACHE_SHIFT, length, bytes, avail_bytes;
3896 -+ long long block = SQUASHFS_I(inode)->start_block;
3897 -+ int offset = SQUASHFS_I(inode)->offset;
3898 -+ void *pageaddr = kmap(page);
3899 -+
3900 -+ TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
3901 -+ "%llx, offset %x\n", page->index,
3902 -+ SQUASHFS_I(inode)->start_block,
3903 -+ SQUASHFS_I(inode)->offset);
3904 -+
3905 -+ for (length = 0; length < index; length += bytes) {
3906 -+ bytes = squashfs_get_cached_block(inode->i_sb, NULL, block,
3907 -+ offset, PAGE_CACHE_SIZE, &block, &offset);
3908 -+ if (bytes == 0) {
3909 -+ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
3910 -+ goto skip_read;
3911 -+ }
3912 -+ }
3913 -+
3914 -+ if (length != index) {
3915 -+ ERROR("(squashfs_symlink_readpage) length != index\n");
3916 -+ bytes = 0;
3917 -+ goto skip_read;
3918 -+ }
3919 -+
3920 -+ avail_bytes = min_t(int, i_size_read(inode) - length, PAGE_CACHE_SIZE);
3921 -+
3922 -+ bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset,
3923 -+ avail_bytes, &block, &offset);
3924 -+ if (bytes == 0)
3925 -+ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
3926 -+
3927 -+skip_read:
3928 -+ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
3929 -+ kunmap(page);
3930 -+ flush_dcache_page(page);
3931 -+ SetPageUptodate(page);
3932 -+ unlock_page(page);
3933 -+
3934 -+ return 0;
3935 -+}
3936 -+
3937 -+
3938 -+struct meta_index *locate_meta_index(struct inode *inode, int index, int offset)
3939 -+{
3940 -+ struct meta_index *meta = NULL;
3941 -+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
3942 -+ int i;
3943 -+
3944 -+ mutex_lock(&msblk->meta_index_mutex);
3945 -+
3946 -+ TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
3947 -+
3948 -+ if (msblk->meta_index == NULL)
3949 -+ goto not_allocated;
3950 -+
3951 -+ for (i = 0; i < SQUASHFS_META_NUMBER; i ++) {
3952 -+ if (msblk->meta_index[i].inode_number == inode->i_ino &&
3953 -+ msblk->meta_index[i].offset >= offset &&
3954 -+ msblk->meta_index[i].offset <= index &&
3955 -+ msblk->meta_index[i].locked == 0) {
3956 -+ TRACE("locate_meta_index: entry %d, offset %d\n", i,
3957 -+ msblk->meta_index[i].offset);
3958 -+ meta = &msblk->meta_index[i];
3959 -+ offset = meta->offset;
3960 -+ }
3961 -+ }
3962 -+
3963 -+ if (meta)
3964 -+ meta->locked = 1;
3965 -+
3966 -+not_allocated:
3967 -+ mutex_unlock(&msblk->meta_index_mutex);
3968 -+
3969 -+ return meta;
3970 -+}
3971 -+
3972 -+
3973 -+struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip)
3974 -+{
3975 -+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
3976 -+ struct meta_index *meta = NULL;
3977 -+ int i;
3978 -+
3979 -+ mutex_lock(&msblk->meta_index_mutex);
3980 -+
3981 -+ TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
3982 -+
3983 -+ if (msblk->meta_index == NULL) {
3984 -+ msblk->meta_index = kmalloc(sizeof(struct meta_index) *
3985 -+ SQUASHFS_META_NUMBER, GFP_KERNEL);
3986 -+ if (msblk->meta_index == NULL) {
3987 -+ ERROR("Failed to allocate meta_index\n");
3988 -+ goto failed;
3989 -+ }
3990 -+ for (i = 0; i < SQUASHFS_META_NUMBER; i++) {
3991 -+ msblk->meta_index[i].inode_number = 0;
3992 -+ msblk->meta_index[i].locked = 0;
3993 -+ }
3994 -+ msblk->next_meta_index = 0;
3995 -+ }
3996 -+
3997 -+ for (i = SQUASHFS_META_NUMBER; i &&
3998 -+ msblk->meta_index[msblk->next_meta_index].locked; i --)
3999 -+ msblk->next_meta_index = (msblk->next_meta_index + 1) %
4000 -+ SQUASHFS_META_NUMBER;
4001 -+
4002 -+ if (i == 0) {
4003 -+ TRACE("empty_meta_index: failed!\n");
4004 -+ goto failed;
4005 -+ }
4006 -+
4007 -+ TRACE("empty_meta_index: returned meta entry %d, %p\n",
4008 -+ msblk->next_meta_index,
4009 -+ &msblk->meta_index[msblk->next_meta_index]);
4010 -+
4011 -+ meta = &msblk->meta_index[msblk->next_meta_index];
4012 -+ msblk->next_meta_index = (msblk->next_meta_index + 1) %
4013 -+ SQUASHFS_META_NUMBER;
4014 -+
4015 -+ meta->inode_number = inode->i_ino;
4016 -+ meta->offset = offset;
4017 -+ meta->skip = skip;
4018 -+ meta->entries = 0;
4019 -+ meta->locked = 1;
4020 -+
4021 -+failed:
4022 -+ mutex_unlock(&msblk->meta_index_mutex);
4023 -+ return meta;
4024 -+}
4025 -+
4026 -+
4027 -+void release_meta_index(struct inode *inode, struct meta_index *meta)
4028 -+{
4029 -+ meta->locked = 0;
4030 -+ smp_mb();
4031 -+}
4032 -+
4033 -+
4034 -+static int read_block_index(struct super_block *s, int blocks, char *block_list,
4035 -+ long long *start_block, int *offset)
4036 -+{
4037 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
4038 -+ unsigned int *block_listp;
4039 -+ int block = 0;
4040 -+
4041 -+ if (msblk->swap) {
4042 -+ char sblock_list[blocks << 2];
4043 -+
4044 -+ if (!squashfs_get_cached_block(s, sblock_list, *start_block,
4045 -+ *offset, blocks << 2, start_block, offset)) {
4046 -+ ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset);
4047 -+ goto failure;
4048 -+ }
4049 -+ SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
4050 -+ ((unsigned int *)sblock_list), blocks);
4051 -+ } else {
4052 -+ if (!squashfs_get_cached_block(s, block_list, *start_block,
4053 -+ *offset, blocks << 2, start_block, offset)) {
4054 -+ ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset);
4055 -+ goto failure;
4056 -+ }
4057 -+ }
4058 -+
4059 -+ for (block_listp = (unsigned int *) block_list; blocks;
4060 -+ block_listp++, blocks --)
4061 -+ block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);
4062 -+
4063 -+ return block;
4064 -+
4065 -+failure:
4066 -+ return -1;
4067 -+}
4068 -+
4069 -+
4070 -+#define SIZE 256
4071 -+
4072 -+static inline int calculate_skip(int blocks) {
4073 -+ int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES);
4074 -+ return skip >= 7 ? 7 : skip + 1;
4075 -+}
4076 -+
4077 -+
4078 -+static int get_meta_index(struct inode *inode, int index,
4079 -+ long long *index_block, int *index_offset,
4080 -+ long long *data_block, char *block_list)
4081 -+{
4082 -+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
4083 -+ struct squashfs_super_block *sblk = &msblk->sblk;
4084 -+ int skip = calculate_skip(i_size_read(inode) >> sblk->block_log);
4085 -+ int offset = 0;
4086 -+ struct meta_index *meta;
4087 -+ struct meta_entry *meta_entry;
4088 -+ long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start;
4089 -+ int cur_offset = SQUASHFS_I(inode)->offset;
4090 -+ long long cur_data_block = SQUASHFS_I(inode)->start_block;
4091 -+ int i;
4092 -+
4093 -+ index /= SQUASHFS_META_INDEXES * skip;
4094 -+
4095 -+ while (offset < index) {
4096 -+ meta = locate_meta_index(inode, index, offset + 1);
4097 -+
4098 -+ if (meta == NULL) {
4099 -+ meta = empty_meta_index(inode, offset + 1, skip);
4100 -+ if (meta == NULL)
4101 -+ goto all_done;
4102 -+ } else {
4103 -+ if(meta->entries == 0)
4104 -+ goto failed;
4105 -+ /* XXX */
4106 -+ offset = index < meta->offset + meta->entries ? index :
4107 -+ meta->offset + meta->entries - 1;
4108 -+ /* XXX */
4109 -+ meta_entry = &meta->meta_entry[offset - meta->offset];
4110 -+ cur_index_block = meta_entry->index_block + sblk->inode_table_start;
4111 -+ cur_offset = meta_entry->offset;
4112 -+ cur_data_block = meta_entry->data_block;
4113 -+ TRACE("get_meta_index: offset %d, meta->offset %d, "
4114 -+ "meta->entries %d\n", offset, meta->offset, meta->entries);
4115 -+ TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
4116 -+ " data_block 0x%llx\n", cur_index_block,
4117 -+ cur_offset, cur_data_block);
4118 -+ }
4119 -+
4120 -+ for (i = meta->offset + meta->entries; i <= index &&
4121 -+ i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
4122 -+ int blocks = skip * SQUASHFS_META_INDEXES;
4123 -+
4124 -+ while (blocks) {
4125 -+ int block = blocks > (SIZE >> 2) ? (SIZE >> 2) : blocks;
4126 -+ int res = read_block_index(inode->i_sb, block, block_list,
4127 -+ &cur_index_block, &cur_offset);
4128 -+
4129 -+ if (res == -1)
4130 -+ goto failed;
4131 -+
4132 -+ cur_data_block += res;
4133 -+ blocks -= block;
4134 -+ }
4135 -+
4136 -+ meta_entry = &meta->meta_entry[i - meta->offset];
4137 -+ meta_entry->index_block = cur_index_block - sblk->inode_table_start;
4138 -+ meta_entry->offset = cur_offset;
4139 -+ meta_entry->data_block = cur_data_block;
4140 -+ meta->entries ++;
4141 -+ offset ++;
4142 -+ }
4143 -+
4144 -+ TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
4145 -+ meta->offset, meta->entries);
4146 -+
4147 -+ release_meta_index(inode, meta);
4148 -+ }
4149 -+
4150 -+all_done:
4151 -+ *index_block = cur_index_block;
4152 -+ *index_offset = cur_offset;
4153 -+ *data_block = cur_data_block;
4154 -+
4155 -+ return offset * SQUASHFS_META_INDEXES * skip;
4156 -+
4157 -+failed:
4158 -+ release_meta_index(inode, meta);
4159 -+ return -1;
4160 -+}
4161 -+
4162 -+
4163 -+static long long read_blocklist(struct inode *inode, int index,
4164 -+ int readahead_blks, char *block_list,
4165 -+ unsigned short **block_p, unsigned int *bsize)
4166 -+{
4167 -+ long long block_ptr;
4168 -+ int offset;
4169 -+ long long block;
4170 -+ int res = get_meta_index(inode, index, &block_ptr, &offset, &block,
4171 -+ block_list);
4172 -+
4173 -+ TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"
4174 -+ " 0x%x, block 0x%llx\n", res, index, block_ptr, offset, block);
4175 -+
4176 -+ if(res == -1)
4177 -+ goto failure;
4178 -+
4179 -+ index -= res;
4180 -+
4181 -+ while (index) {
4182 -+ int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
4183 -+ int res = read_block_index(inode->i_sb, blocks, block_list,
4184 -+ &block_ptr, &offset);
4185 -+ if (res == -1)
4186 -+ goto failure;
4187 -+ block += res;
4188 -+ index -= blocks;
4189 -+ }
4190 -+
4191 -+ if (read_block_index(inode->i_sb, 1, block_list, &block_ptr, &offset) == -1)
4192 -+ goto failure;
4193 -+ *bsize = *((unsigned int *) block_list);
4194 -+
4195 -+ return block;
4196 -+
4197 -+failure:
4198 -+ return 0;
4199 -+}
4200 -+
4201 -+
4202 -+static int squashfs_readpage(struct file *file, struct page *page)
4203 -+{
4204 -+ struct inode *inode = page->mapping->host;
4205 -+ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
4206 -+ struct squashfs_super_block *sblk = &msblk->sblk;
4207 -+ unsigned char *block_list = NULL;
4208 -+ long long block;
4209 -+ unsigned int bsize, i;
4210 -+ int bytes;
4211 -+ int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
4212 -+ void *pageaddr;
4213 -+ struct squashfs_fragment_cache *fragment = NULL;
4214 -+ char *data_ptr = msblk->read_page;
4215 -+
4216 -+ int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
4217 -+ int start_index = page->index & ~mask;
4218 -+ int end_index = start_index | mask;
4219 -+ int file_end = i_size_read(inode) >> sblk->block_log;
4220 -+ int sparse = 0;
4221 -+
4222 -+ TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
4223 -+ page->index, SQUASHFS_I(inode)->start_block);
4224 -+
4225 -+ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
4226 -+ PAGE_CACHE_SHIFT))
4227 -+ goto out;
4228 -+
4229 -+ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
4230 -+ || index < file_end) {
4231 -+ block_list = kmalloc(SIZE, GFP_KERNEL);
4232 -+ if (block_list == NULL) {
4233 -+ ERROR("Failed to allocate block_list\n");
4234 -+ goto error_out;
4235 -+ }
4236 -+
4237 -+ block = (msblk->read_blocklist)(inode, index, 1, block_list, NULL, &bsize);
4238 -+ if (block == 0)
4239 -+ goto error_out;
4240 -+
4241 -+ if (bsize == 0) { /* hole */
4242 -+ bytes = index == file_end ?
4243 -+ (i_size_read(inode) & (sblk->block_size - 1)) : sblk->block_size;
4244 -+ sparse = 1;
4245 -+ } else {
4246 -+ mutex_lock(&msblk->read_page_mutex);
4247 -+
4248 -+ bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
4249 -+ bsize, NULL, sblk->block_size);
4250 -+
4251 -+ if (bytes == 0) {
4252 -+ ERROR("Unable to read page, block %llx, size %x\n", block, bsize);
4253 -+ mutex_unlock(&msblk->read_page_mutex);
4254 -+ goto error_out;
4255 -+ }
4256 -+ }
4257 -+ } else {
4258 -+ fragment = get_cached_fragment(inode->i_sb,
4259 -+ SQUASHFS_I(inode)-> u.s1.fragment_start_block,
4260 -+ SQUASHFS_I(inode)->u.s1.fragment_size);
4261 -+
4262 -+ if (fragment == NULL) {
4263 -+ ERROR("Unable to read page, block %llx, size %x\n",
4264 -+ SQUASHFS_I(inode)->u.s1.fragment_start_block,
4265 -+ (int) SQUASHFS_I(inode)->u.s1.fragment_size);
4266 -+ goto error_out;
4267 -+ }
4268 -+ bytes = i_size_read(inode) & (sblk->block_size - 1);
4269 -+ data_ptr = fragment->data + SQUASHFS_I(inode)->u.s1.fragment_offset;
4270 -+ }
4271 -+
4272 -+ for (i = start_index; i <= end_index && bytes > 0; i++,
4273 -+ bytes -= PAGE_CACHE_SIZE, data_ptr += PAGE_CACHE_SIZE) {
4274 -+ struct page *push_page;
4275 -+ int avail = sparse ? 0 : min_t(unsigned int, bytes, PAGE_CACHE_SIZE);
4276 -+
4277 -+ TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail);
4278 -+
4279 -+ push_page = (i == page->index) ? page :
4280 -+ grab_cache_page_nowait(page->mapping, i);
4281 -+
4282 -+ if (!push_page)
4283 -+ continue;
4284 -+
4285 -+ if (PageUptodate(push_page))
4286 -+ goto skip_page;
4287 -+
4288 -+ pageaddr = kmap_atomic(push_page, KM_USER0);
4289 -+ memcpy(pageaddr, data_ptr, avail);
4290 -+ memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail);
4291 -+ kunmap_atomic(pageaddr, KM_USER0);
4292 -+ flush_dcache_page(push_page);
4293 -+ SetPageUptodate(push_page);
4294 -+skip_page:
4295 -+ unlock_page(push_page);
4296 -+ if(i != page->index)
4297 -+ page_cache_release(push_page);
4298 -+ }
4299 -+
4300 -+ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
4301 -+ || index < file_end) {
4302 -+ if (!sparse)
4303 -+ mutex_unlock(&msblk->read_page_mutex);
4304 -+ kfree(block_list);
4305 -+ } else
4306 -+ release_cached_fragment(msblk, fragment);
4307 -+
4308 -+ return 0;
4309 -+
4310 -+error_out:
4311 -+ SetPageError(page);
4312 -+out:
4313 -+ pageaddr = kmap_atomic(page, KM_USER0);
4314 -+ memset(pageaddr, 0, PAGE_CACHE_SIZE);
4315 -+ kunmap_atomic(pageaddr, KM_USER0);
4316 -+ flush_dcache_page(page);
4317 -+ if (!PageError(page))
4318 -+ SetPageUptodate(page);
4319 -+ unlock_page(page);
4320 -+
4321 -+ kfree(block_list);
4322 -+ return 0;
4323 -+}
4324 -+
4325 -+
4326 -+static int get_dir_index_using_offset(struct super_block *s,
4327 -+ long long *next_block, unsigned int *next_offset,
4328 -+ long long index_start, unsigned int index_offset, int i_count,
4329 -+ long long f_pos)
4330 -+{
4331 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
4332 -+ struct squashfs_super_block *sblk = &msblk->sblk;
4333 -+ int i, length = 0;
4334 -+ struct squashfs_dir_index index;
4335 -+
4336 -+ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
4337 -+ i_count, (unsigned int) f_pos);
4338 -+
4339 -+ f_pos =- 3;
4340 -+ if (f_pos == 0)
4341 -+ goto finish;
4342 -+
4343 -+ for (i = 0; i < i_count; i++) {
4344 -+ if (msblk->swap) {
4345 -+ struct squashfs_dir_index sindex;
4346 -+ squashfs_get_cached_block(s, &sindex, index_start, index_offset,
4347 -+ sizeof(sindex), &index_start, &index_offset);
4348 -+ SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
4349 -+ } else
4350 -+ squashfs_get_cached_block(s, &index, index_start, index_offset,
4351 -+ sizeof(index), &index_start, &index_offset);
4352 -+
4353 -+ if (index.index > f_pos)
4354 -+ break;
4355 -+
4356 -+ squashfs_get_cached_block(s, NULL, index_start, index_offset,
4357 -+ index.size + 1, &index_start, &index_offset);
4358 -+
4359 -+ length = index.index;
4360 -+ *next_block = index.start_block + sblk->directory_table_start;
4361 -+ }
4362 -+
4363 -+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
4364 -+
4365 -+finish:
4366 -+ return length + 3;
4367 -+}
4368 -+
4369 -+
4370 -+static int get_dir_index_using_name(struct super_block *s,
4371 -+ long long *next_block, unsigned int *next_offset,
4372 -+ long long index_start, unsigned int index_offset, int i_count,
4373 -+ const char *name, int size)
4374 -+{
4375 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
4376 -+ struct squashfs_super_block *sblk = &msblk->sblk;
4377 -+ int i, length = 0;
4378 -+ struct squashfs_dir_index *index;
4379 -+ char *str;
4380 -+
4381 -+ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
4382 -+
4383 -+ str = kmalloc(sizeof(struct squashfs_dir_index) +
4384 -+ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL);
4385 -+ if (str == NULL) {
4386 -+ ERROR("Failed to allocate squashfs_dir_index\n");
4387 -+ goto failure;
4388 -+ }
4389 -+
4390 -+ index = (struct squashfs_dir_index *) (str + SQUASHFS_NAME_LEN + 1);
4391 -+ strncpy(str, name, size);
4392 -+ str[size] = '\0';
4393 -+
4394 -+ for (i = 0; i < i_count; i++) {
4395 -+ if (msblk->swap) {
4396 -+ struct squashfs_dir_index sindex;
4397 -+ squashfs_get_cached_block(s, &sindex, index_start, index_offset,
4398 -+ sizeof(sindex), &index_start, &index_offset);
4399 -+ SQUASHFS_SWAP_DIR_INDEX(index, &sindex);
4400 -+ } else
4401 -+ squashfs_get_cached_block(s, index, index_start, index_offset,
4402 -+ sizeof(struct squashfs_dir_index), &index_start, &index_offset);
4403 -+
4404 -+ squashfs_get_cached_block(s, index->name, index_start, index_offset,
4405 -+ index->size + 1, &index_start, &index_offset);
4406 -+
4407 -+ index->name[index->size + 1] = '\0';
4408 -+
4409 -+ if (strcmp(index->name, str) > 0)
4410 -+ break;
4411 -+
4412 -+ length = index->index;
4413 -+ *next_block = index->start_block + sblk->directory_table_start;
4414 -+ }
4415 -+
4416 -+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
4417 -+ kfree(str);
4418 -+
4419 -+failure:
4420 -+ return length + 3;
4421 -+}
4422 -+
4423 -+
4424 -+static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
4425 -+{
4426 -+ struct inode *i = file->f_dentry->d_inode;
4427 -+ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
4428 -+ struct squashfs_super_block *sblk = &msblk->sblk;
4429 -+ long long next_block = SQUASHFS_I(i)->start_block +
4430 -+ sblk->directory_table_start;
4431 -+ int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count;
4432 -+ struct squashfs_dir_header dirh;
4433 -+ struct squashfs_dir_entry *dire;
4434 -+
4435 -+ TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
4436 -+
4437 -+ dire = kmalloc(sizeof(struct squashfs_dir_entry) +
4438 -+ SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
4439 -+ if (dire == NULL) {
4440 -+ ERROR("Failed to allocate squashfs_dir_entry\n");
4441 -+ goto finish;
4442 -+ }
4443 -+
4444 -+ while(file->f_pos < 3) {
4445 -+ char *name;
4446 -+ int size, i_ino;
4447 -+
4448 -+ if(file->f_pos == 0) {
4449 -+ name = ".";
4450 -+ size = 1;
4451 -+ i_ino = i->i_ino;
4452 -+ } else {
4453 -+ name = "..";
4454 -+ size = 2;
4455 -+ i_ino = SQUASHFS_I(i)->u.s2.parent_inode;
4456 -+ }
4457 -+ TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n",
4458 -+ (unsigned int) dirent, name, size, (int)
4459 -+ file->f_pos, i_ino, squashfs_filetype_table[1]);
4460 -+
4461 -+ if (filldir(dirent, name, size, file->f_pos, i_ino,
4462 -+ squashfs_filetype_table[1]) < 0) {
4463 -+ TRACE("Filldir returned less than 0\n");
4464 -+ goto finish;
4465 -+ }
4466 -+ file->f_pos += size;
4467 -+ }
4468 -+
4469 -+ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
4470 -+ SQUASHFS_I(i)->u.s2.directory_index_start,
4471 -+ SQUASHFS_I(i)->u.s2.directory_index_offset,
4472 -+ SQUASHFS_I(i)->u.s2.directory_index_count, file->f_pos);
4473 -+
4474 -+ while (length < i_size_read(i)) {
4475 -+ /* read directory header */
4476 -+ if (msblk->swap) {
4477 -+ struct squashfs_dir_header sdirh;
4478 -+
4479 -+ if (!squashfs_get_cached_block(i->i_sb, &sdirh, next_block,
4480 -+ next_offset, sizeof(sdirh), &next_block, &next_offset))
4481 -+ goto failed_read;
4482 -+
4483 -+ length += sizeof(sdirh);
4484 -+ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
4485 -+ } else {
4486 -+ if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block,
4487 -+ next_offset, sizeof(dirh), &next_block, &next_offset))
4488 -+ goto failed_read;
4489 -+
4490 -+ length += sizeof(dirh);
4491 -+ }
4492 -+
4493 -+ dir_count = dirh.count + 1;
4494 -+ while (dir_count--) {
4495 -+ if (msblk->swap) {
4496 -+ struct squashfs_dir_entry sdire;
4497 -+ if (!squashfs_get_cached_block(i->i_sb, &sdire, next_block,
4498 -+ next_offset, sizeof(sdire), &next_block, &next_offset))
4499 -+ goto failed_read;
4500 -+
4501 -+ length += sizeof(sdire);
4502 -+ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
4503 -+ } else {
4504 -+ if (!squashfs_get_cached_block(i->i_sb, dire, next_block,
4505 -+ next_offset, sizeof(*dire), &next_block, &next_offset))
4506 -+ goto failed_read;
4507 -+
4508 -+ length += sizeof(*dire);
4509 -+ }
4510 -+
4511 -+ if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block,
4512 -+ next_offset, dire->size + 1, &next_block, &next_offset))
4513 -+ goto failed_read;
4514 -+
4515 -+ length += dire->size + 1;
4516 -+
4517 -+ if (file->f_pos >= length)
4518 -+ continue;
4519 -+
4520 -+ dire->name[dire->size + 1] = '\0';
4521 -+
4522 -+ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n",
4523 -+ (unsigned int) dirent, dire->name, dire->size + 1,
4524 -+ (int) file->f_pos, dirh.start_block, dire->offset,
4525 -+ dirh.inode_number + dire->inode_number,
4526 -+ squashfs_filetype_table[dire->type]);
4527 -+
4528 -+ if (filldir(dirent, dire->name, dire->size + 1, file->f_pos,
4529 -+ dirh.inode_number + dire->inode_number,
4530 -+ squashfs_filetype_table[dire->type]) < 0) {
4531 -+ TRACE("Filldir returned less than 0\n");
4532 -+ goto finish;
4533 -+ }
4534 -+ file->f_pos = length;
4535 -+ }
4536 -+ }
4537 -+
4538 -+finish:
4539 -+ kfree(dire);
4540 -+ return 0;
4541 -+
4542 -+failed_read:
4543 -+ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
4544 -+ next_offset);
4545 -+ kfree(dire);
4546 -+ return 0;
4547 -+}
4548 -+
4549 -+
4550 -+static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry,
4551 -+ struct nameidata *nd)
4552 -+{
4553 -+ const unsigned char *name = dentry->d_name.name;
4554 -+ int len = dentry->d_name.len;
4555 -+ struct inode *inode = NULL;
4556 -+ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
4557 -+ struct squashfs_super_block *sblk = &msblk->sblk;
4558 -+ long long next_block = SQUASHFS_I(i)->start_block +
4559 -+ sblk->directory_table_start;
4560 -+ int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count;
4561 -+ struct squashfs_dir_header dirh;
4562 -+ struct squashfs_dir_entry *dire;
4563 -+
4564 -+ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
4565 -+
4566 -+ dire = kmalloc(sizeof(struct squashfs_dir_entry) +
4567 -+ SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
4568 -+ if (dire == NULL) {
4569 -+ ERROR("Failed to allocate squashfs_dir_entry\n");
4570 -+ goto exit_lookup;
4571 -+ }
4572 -+
4573 -+ if (len > SQUASHFS_NAME_LEN)
4574 -+ goto exit_lookup;
4575 -+
4576 -+ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
4577 -+ SQUASHFS_I(i)->u.s2.directory_index_start,
4578 -+ SQUASHFS_I(i)->u.s2.directory_index_offset,
4579 -+ SQUASHFS_I(i)->u.s2.directory_index_count, name, len);
4580 -+
4581 -+ while (length < i_size_read(i)) {
4582 -+ /* read directory header */
4583 -+ if (msblk->swap) {
4584 -+ struct squashfs_dir_header sdirh;
4585 -+ if (!squashfs_get_cached_block(i->i_sb, &sdirh, next_block,
4586 -+ next_offset, sizeof(sdirh), &next_block, &next_offset))
4587 -+ goto failed_read;
4588 -+
4589 -+ length += sizeof(sdirh);
4590 -+ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
4591 -+ } else {
4592 -+ if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block,
4593 -+ next_offset, sizeof(dirh), &next_block, &next_offset))
4594 -+ goto failed_read;
4595 -+
4596 -+ length += sizeof(dirh);
4597 -+ }
4598 -+
4599 -+ dir_count = dirh.count + 1;
4600 -+ while (dir_count--) {
4601 -+ if (msblk->swap) {
4602 -+ struct squashfs_dir_entry sdire;
4603 -+ if (!squashfs_get_cached_block(i->i_sb, &sdire, next_block,
4604 -+ next_offset, sizeof(sdire), &next_block, &next_offset))
4605 -+ goto failed_read;
4606 -+
4607 -+ length += sizeof(sdire);
4608 -+ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
4609 -+ } else {
4610 -+ if (!squashfs_get_cached_block(i->i_sb, dire, next_block,
4611 -+ next_offset, sizeof(*dire), &next_block, &next_offset))
4612 -+ goto failed_read;
4613 -+
4614 -+ length += sizeof(*dire);
4615 -+ }
4616 -+
4617 -+ if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block,
4618 -+ next_offset, dire->size + 1, &next_block, &next_offset))
4619 -+ goto failed_read;
4620 -+
4621 -+ length += dire->size + 1;
4622 -+
4623 -+ if (name[0] < dire->name[0])
4624 -+ goto exit_lookup;
4625 -+
4626 -+ if ((len == dire->size + 1) && !strncmp(name, dire->name, len)) {
4627 -+ squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block,
4628 -+ dire->offset);
4629 -+
4630 -+ TRACE("calling squashfs_iget for directory entry %s, inode"
4631 -+ " %x:%x, %d\n", name, dirh.start_block, dire->offset,
4632 -+ dirh.inode_number + dire->inode_number);
4633 -+
4634 -+ inode = squashfs_iget(i->i_sb, ino, dirh.inode_number + dire->inode_number);
4635 -+
4636 -+ goto exit_lookup;
4637 -+ }
4638 -+ }
4639 -+ }
4640 -+
4641 -+exit_lookup:
4642 -+ kfree(dire);
4643 -+ if (inode)
4644 -+ return d_splice_alias(inode, dentry);
4645 -+ d_add(dentry, inode);
4646 -+ return ERR_PTR(0);
4647 -+
4648 -+failed_read:
4649 -+ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
4650 -+ next_offset);
4651 -+ goto exit_lookup;
4652 -+}
4653 -+
4654 -+
4655 -+static int squashfs_remount(struct super_block *s, int *flags, char *data)
4656 -+{
4657 -+ *flags |= MS_RDONLY;
4658 -+ return 0;
4659 -+}
4660 -+
4661 -+
4662 -+static void squashfs_put_super(struct super_block *s)
4663 -+{
4664 -+ int i;
4665 -+
4666 -+ if (s->s_fs_info) {
4667 -+ struct squashfs_sb_info *sbi = s->s_fs_info;
4668 -+ if (sbi->block_cache)
4669 -+ for (i = 0; i < squashfs_cached_blks; i++)
4670 -+ if (sbi->block_cache[i].block != SQUASHFS_INVALID_BLK)
4671 -+ vfree(sbi->block_cache[i].data);
4672 -+ if (sbi->fragment)
4673 -+ for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++)
4674 -+ vfree(sbi->fragment[i].data);
4675 -+ kfree(sbi->fragment);
4676 -+ kfree(sbi->block_cache);
4677 -+ vfree(sbi->read_page);
4678 -+ kfree(sbi->uid);
4679 -+ kfree(sbi->fragment_index);
4680 -+ kfree(sbi->fragment_index_2);
4681 -+ kfree(sbi->meta_index);
4682 -+ vfree(sbi->stream.workspace);
4683 -+ kfree(s->s_fs_info);
4684 -+ s->s_fs_info = NULL;
4685 -+ }
4686 -+}
4687 -+
4688 -+
4689 -+static int squashfs_get_sb(struct file_system_type *fs_type, int flags,
4690 -+ const char *dev_name, void *data, struct vfsmount *mnt)
4691 -+{
4692 -+ return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super,
4693 -+ mnt);
4694 -+}
4695 -+
4696 -+
4697 -+static int __init init_squashfs_fs(void)
4698 -+{
4699 -+ int err = init_inodecache();
4700 -+ if (err)
4701 -+ goto out;
4702 -+
4703 -+ printk(KERN_INFO "squashfs: version 3.3 (2007/10/31) "
4704 -+ "Phillip Lougher\n");
4705 -+
4706 -+ err = register_filesystem(&squashfs_fs_type);
4707 -+ if (err)
4708 -+ destroy_inodecache();
4709 -+
4710 -+out:
4711 -+ return err;
4712 -+}
4713 -+
4714 -+
4715 -+static void __exit exit_squashfs_fs(void)
4716 -+{
4717 -+ unregister_filesystem(&squashfs_fs_type);
4718 -+ destroy_inodecache();
4719 -+}
4720 -+
4721 -+
4722 -+static struct kmem_cache * squashfs_inode_cachep;
4723 -+
4724 -+
4725 -+static struct inode *squashfs_alloc_inode(struct super_block *sb)
4726 -+{
4727 -+ struct squashfs_inode_info *ei;
4728 -+ ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL);
4729 -+ return ei ? &ei->vfs_inode : NULL;
4730 -+}
4731 -+
4732 -+
4733 -+static void squashfs_destroy_inode(struct inode *inode)
4734 -+{
4735 -+ kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode));
4736 -+}
4737 -+
4738 -+
4739 -+static void init_once(struct kmem_cache *cachep, void *foo)
4740 -+{
4741 -+ struct squashfs_inode_info *ei = foo;
4742 -+
4743 -+ inode_init_once(&ei->vfs_inode);
4744 -+}
4745 -+
4746 -+
4747 -+static int __init init_inodecache(void)
4748 -+{
4749 -+ squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache",
4750 -+ sizeof(struct squashfs_inode_info), 0,
4751 -+ SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, init_once);
4752 -+ if (squashfs_inode_cachep == NULL)
4753 -+ return -ENOMEM;
4754 -+ return 0;
4755 -+}
4756 -+
4757 -+
4758 -+static void destroy_inodecache(void)
4759 -+{
4760 -+ kmem_cache_destroy(squashfs_inode_cachep);
4761 -+}
4762 -+
4763 -+
4764 -+module_init(init_squashfs_fs);
4765 -+module_exit(exit_squashfs_fs);
4766 -+MODULE_DESCRIPTION("squashfs 3.2-r2-CVS, a compressed read-only filesystem");
4767 -+MODULE_AUTHOR("Phillip Lougher <phillip@××××××××××××××××.uk>");
4768 -+MODULE_LICENSE("GPL");
4769 -Index: linux-2.6.25-gentoo/fs/squashfs/Makefile
4770 -===================================================================
4771 ---- /dev/null
4772 -+++ linux-2.6.25-gentoo/fs/squashfs/Makefile
4773 -@@ -0,0 +1,7 @@
4774 -+#
4775 -+# Makefile for the linux squashfs routines.
4776 -+#
4777 -+
4778 -+obj-$(CONFIG_SQUASHFS) += squashfs.o
4779 -+squashfs-y += inode.o
4780 -+squashfs-y += squashfs2_0.o
4781 -Index: linux-2.6.25-gentoo/fs/squashfs/squashfs2_0.c
4782 -===================================================================
4783 ---- /dev/null
4784 -+++ linux-2.6.25-gentoo/fs/squashfs/squashfs2_0.c
4785 -@@ -0,0 +1,740 @@
4786 -+/*
4787 -+ * Squashfs - a compressed read only filesystem for Linux
4788 -+ *
4789 -+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
4790 -+ * Phillip Lougher <phillip@××××××××××××××××.uk>
4791 -+ *
4792 -+ * This program is free software; you can redistribute it and/or
4793 -+ * modify it under the terms of the GNU General Public License
4794 -+ * as published by the Free Software Foundation; either version 2,
4795 -+ * or (at your option) any later version.
4796 -+ *
4797 -+ * This program is distributed in the hope that it will be useful,
4798 -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4799 -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4800 -+ * GNU General Public License for more details.
4801 -+ *
4802 -+ * You should have received a copy of the GNU General Public License
4803 -+ * along with this program; if not, write to the Free Software
4804 -+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
4805 -+ *
4806 -+ * squashfs2_0.c
4807 -+ */
4808 -+
4809 -+#include <linux/squashfs_fs.h>
4810 -+#include <linux/module.h>
4811 -+#include <linux/zlib.h>
4812 -+#include <linux/fs.h>
4813 -+#include <linux/squashfs_fs_sb.h>
4814 -+#include <linux/squashfs_fs_i.h>
4815 -+
4816 -+#include "squashfs.h"
4817 -+static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir);
4818 -+static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *,
4819 -+ struct nameidata *);
4820 -+
4821 -+static struct file_operations squashfs_dir_ops_2 = {
4822 -+ .read = generic_read_dir,
4823 -+ .readdir = squashfs_readdir_2
4824 -+};
4825 -+
4826 -+static struct inode_operations squashfs_dir_inode_ops_2 = {
4827 -+ .lookup = squashfs_lookup_2
4828 -+};
4829 -+
4830 -+static unsigned char squashfs_filetype_table[] = {
4831 -+ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
4832 -+};
4833 -+
4834 -+static int read_fragment_index_table_2(struct super_block *s)
4835 -+{
4836 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
4837 -+ struct squashfs_super_block *sblk = &msblk->sblk;
4838 -+
4839 -+ if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2
4840 -+ (sblk->fragments), GFP_KERNEL))) {
4841 -+ ERROR("Failed to allocate uid/gid table\n");
4842 -+ return 0;
4843 -+ }
4844 -+
4845 -+ if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) &&
4846 -+ !squashfs_read_data(s, (char *)
4847 -+ msblk->fragment_index_2,
4848 -+ sblk->fragment_table_start,
4849 -+ SQUASHFS_FRAGMENT_INDEX_BYTES_2
4850 -+ (sblk->fragments) |
4851 -+ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) {
4852 -+ ERROR("unable to read fragment index table\n");
4853 -+ return 0;
4854 -+ }
4855 -+
4856 -+ if (msblk->swap) {
4857 -+ int i;
4858 -+ unsigned int fragment;
4859 -+
4860 -+ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments);
4861 -+ i++) {
4862 -+ SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment),
4863 -+ &msblk->fragment_index_2[i], 1);
4864 -+ msblk->fragment_index_2[i] = fragment;
4865 -+ }
4866 -+ }
4867 -+
4868 -+ return 1;
4869 -+}
4870 -+
4871 -+
4872 -+static int get_fragment_location_2(struct super_block *s, unsigned int fragment,
4873 -+ long long *fragment_start_block,
4874 -+ unsigned int *fragment_size)
4875 -+{
4876 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
4877 -+ long long start_block =
4878 -+ msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)];
4879 -+ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment);
4880 -+ struct squashfs_fragment_entry_2 fragment_entry;
4881 -+
4882 -+ if (msblk->swap) {
4883 -+ struct squashfs_fragment_entry_2 sfragment_entry;
4884 -+
4885 -+ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
4886 -+ start_block, offset,
4887 -+ sizeof(sfragment_entry), &start_block,
4888 -+ &offset))
4889 -+ goto out;
4890 -+ SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry);
4891 -+ } else
4892 -+ if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
4893 -+ start_block, offset,
4894 -+ sizeof(fragment_entry), &start_block,
4895 -+ &offset))
4896 -+ goto out;
4897 -+
4898 -+ *fragment_start_block = fragment_entry.start_block;
4899 -+ *fragment_size = fragment_entry.size;
4900 -+
4901 -+ return 1;
4902 -+
4903 -+out:
4904 -+ return 0;
4905 -+}
4906 -+
4907 -+
4908 -+static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i,
4909 -+ struct squashfs_base_inode_header_2 *inodeb, unsigned int ino)
4910 -+{
4911 -+ struct squashfs_super_block *sblk = &msblk->sblk;
4912 -+
4913 -+ i->i_ino = ino;
4914 -+ i->i_mtime.tv_sec = sblk->mkfs_time;
4915 -+ i->i_atime.tv_sec = sblk->mkfs_time;
4916 -+ i->i_ctime.tv_sec = sblk->mkfs_time;
4917 -+ i->i_uid = msblk->uid[inodeb->uid];
4918 -+ i->i_mode = inodeb->mode;
4919 -+ i->i_nlink = 1;
4920 -+ i->i_size = 0;
4921 -+ if (inodeb->guid == SQUASHFS_GUIDS)
4922 -+ i->i_gid = i->i_uid;
4923 -+ else
4924 -+ i->i_gid = msblk->guid[inodeb->guid];
4925 -+}
4926 -+
4927 -+
4928 -+static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode)
4929 -+{
4930 -+ struct super_block *s = i->i_sb;
4931 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
4932 -+ struct squashfs_super_block *sblk = &msblk->sblk;
4933 -+ unsigned int block = SQUASHFS_INODE_BLK(inode) +
4934 -+ sblk->inode_table_start;
4935 -+ unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
4936 -+ unsigned int ino = SQUASHFS_MK_VFS_INODE(block -
4937 -+ sblk->inode_table_start, offset);
4938 -+ long long next_block;
4939 -+ unsigned int next_offset;
4940 -+ union squashfs_inode_header_2 id, sid;
4941 -+ struct squashfs_base_inode_header_2 *inodeb = &id.base,
4942 -+ *sinodeb = &sid.base;
4943 -+
4944 -+ TRACE("Entered squashfs_read_inode_2\n");
4945 -+
4946 -+ if (msblk->swap) {
4947 -+ if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
4948 -+ offset, sizeof(*sinodeb), &next_block,
4949 -+ &next_offset))
4950 -+ goto failed_read;
4951 -+ SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb,
4952 -+ sizeof(*sinodeb));
4953 -+ } else
4954 -+ if (!squashfs_get_cached_block(s, (char *) inodeb, block,
4955 -+ offset, sizeof(*inodeb), &next_block,
4956 -+ &next_offset))
4957 -+ goto failed_read;
4958 -+
4959 -+ squashfs_new_inode(msblk, i, inodeb, ino);
4960 -+
4961 -+ switch(inodeb->inode_type) {
4962 -+ case SQUASHFS_FILE_TYPE: {
4963 -+ struct squashfs_reg_inode_header_2 *inodep = &id.reg;
4964 -+ struct squashfs_reg_inode_header_2 *sinodep = &sid.reg;
4965 -+ long long frag_blk;
4966 -+ unsigned int frag_size = 0;
4967 -+
4968 -+ if (msblk->swap) {
4969 -+ if (!squashfs_get_cached_block(s, (char *)
4970 -+ sinodep, block, offset,
4971 -+ sizeof(*sinodep), &next_block,
4972 -+ &next_offset))
4973 -+ goto failed_read;
4974 -+ SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep);
4975 -+ } else
4976 -+ if (!squashfs_get_cached_block(s, (char *)
4977 -+ inodep, block, offset,
4978 -+ sizeof(*inodep), &next_block,
4979 -+ &next_offset))
4980 -+ goto failed_read;
4981 -+
4982 -+ frag_blk = SQUASHFS_INVALID_BLK;
4983 -+ if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
4984 -+ !get_fragment_location_2(s,
4985 -+ inodep->fragment, &frag_blk, &frag_size))
4986 -+ goto failed_read;
4987 -+
4988 -+ i->i_size = inodep->file_size;
4989 -+ i->i_fop = &generic_ro_fops;
4990 -+ i->i_mode |= S_IFREG;
4991 -+ i->i_mtime.tv_sec = inodep->mtime;
4992 -+ i->i_atime.tv_sec = inodep->mtime;
4993 -+ i->i_ctime.tv_sec = inodep->mtime;
4994 -+ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
4995 -+ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
4996 -+ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
4997 -+ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
4998 -+ SQUASHFS_I(i)->start_block = inodep->start_block;
4999 -+ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
5000 -+ SQUASHFS_I(i)->offset = next_offset;
5001 -+ i->i_data.a_ops = &squashfs_aops;
5002 -+
5003 -+ TRACE("File inode %x:%x, start_block %x, "
5004 -+ "block_list_start %llx, offset %x\n",
5005 -+ SQUASHFS_INODE_BLK(inode), offset,
5006 -+ inodep->start_block, next_block,
5007 -+ next_offset);
5008 -+ break;
5009 -+ }
5010 -+ case SQUASHFS_DIR_TYPE: {
5011 -+ struct squashfs_dir_inode_header_2 *inodep = &id.dir;
5012 -+ struct squashfs_dir_inode_header_2 *sinodep = &sid.dir;
5013 -+
5014 -+ if (msblk->swap) {
5015 -+ if (!squashfs_get_cached_block(s, (char *)
5016 -+ sinodep, block, offset,
5017 -+ sizeof(*sinodep), &next_block,
5018 -+ &next_offset))
5019 -+ goto failed_read;
5020 -+ SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep);
5021 -+ } else
5022 -+ if (!squashfs_get_cached_block(s, (char *)
5023 -+ inodep, block, offset,
5024 -+ sizeof(*inodep), &next_block,
5025 -+ &next_offset))
5026 -+ goto failed_read;
5027 -+
5028 -+ i->i_size = inodep->file_size;
5029 -+ i->i_op = &squashfs_dir_inode_ops_2;
5030 -+ i->i_fop = &squashfs_dir_ops_2;
5031 -+ i->i_mode |= S_IFDIR;
5032 -+ i->i_mtime.tv_sec = inodep->mtime;
5033 -+ i->i_atime.tv_sec = inodep->mtime;
5034 -+ i->i_ctime.tv_sec = inodep->mtime;
5035 -+ SQUASHFS_I(i)->start_block = inodep->start_block;
5036 -+ SQUASHFS_I(i)->offset = inodep->offset;
5037 -+ SQUASHFS_I(i)->u.s2.directory_index_count = 0;
5038 -+ SQUASHFS_I(i)->u.s2.parent_inode = 0;
5039 -+
5040 -+ TRACE("Directory inode %x:%x, start_block %x, offset "
5041 -+ "%x\n", SQUASHFS_INODE_BLK(inode),
5042 -+ offset, inodep->start_block,
5043 -+ inodep->offset);
5044 -+ break;
5045 -+ }
5046 -+ case SQUASHFS_LDIR_TYPE: {
5047 -+ struct squashfs_ldir_inode_header_2 *inodep = &id.ldir;
5048 -+ struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir;
5049 -+
5050 -+ if (msblk->swap) {
5051 -+ if (!squashfs_get_cached_block(s, (char *)
5052 -+ sinodep, block, offset,
5053 -+ sizeof(*sinodep), &next_block,
5054 -+ &next_offset))
5055 -+ goto failed_read;
5056 -+ SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep,
5057 -+ sinodep);
5058 -+ } else
5059 -+ if (!squashfs_get_cached_block(s, (char *)
5060 -+ inodep, block, offset,
5061 -+ sizeof(*inodep), &next_block,
5062 -+ &next_offset))
5063 -+ goto failed_read;
5064 -+
5065 -+ i->i_size = inodep->file_size;
5066 -+ i->i_op = &squashfs_dir_inode_ops_2;
5067 -+ i->i_fop = &squashfs_dir_ops_2;
5068 -+ i->i_mode |= S_IFDIR;
5069 -+ i->i_mtime.tv_sec = inodep->mtime;
5070 -+ i->i_atime.tv_sec = inodep->mtime;
5071 -+ i->i_ctime.tv_sec = inodep->mtime;
5072 -+ SQUASHFS_I(i)->start_block = inodep->start_block;
5073 -+ SQUASHFS_I(i)->offset = inodep->offset;
5074 -+ SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
5075 -+ SQUASHFS_I(i)->u.s2.directory_index_offset =
5076 -+ next_offset;
5077 -+ SQUASHFS_I(i)->u.s2.directory_index_count =
5078 -+ inodep->i_count;
5079 -+ SQUASHFS_I(i)->u.s2.parent_inode = 0;
5080 -+
5081 -+ TRACE("Long directory inode %x:%x, start_block %x, "
5082 -+ "offset %x\n",
5083 -+ SQUASHFS_INODE_BLK(inode), offset,
5084 -+ inodep->start_block, inodep->offset);
5085 -+ break;
5086 -+ }
5087 -+ case SQUASHFS_SYMLINK_TYPE: {
5088 -+ struct squashfs_symlink_inode_header_2 *inodep =
5089 -+ &id.symlink;
5090 -+ struct squashfs_symlink_inode_header_2 *sinodep =
5091 -+ &sid.symlink;
5092 -+
5093 -+ if (msblk->swap) {
5094 -+ if (!squashfs_get_cached_block(s, (char *)
5095 -+ sinodep, block, offset,
5096 -+ sizeof(*sinodep), &next_block,
5097 -+ &next_offset))
5098 -+ goto failed_read;
5099 -+ SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
5100 -+ sinodep);
5101 -+ } else
5102 -+ if (!squashfs_get_cached_block(s, (char *)
5103 -+ inodep, block, offset,
5104 -+ sizeof(*inodep), &next_block,
5105 -+ &next_offset))
5106 -+ goto failed_read;
5107 -+
5108 -+ i->i_size = inodep->symlink_size;
5109 -+ i->i_op = &page_symlink_inode_operations;
5110 -+ i->i_data.a_ops = &squashfs_symlink_aops;
5111 -+ i->i_mode |= S_IFLNK;
5112 -+ SQUASHFS_I(i)->start_block = next_block;
5113 -+ SQUASHFS_I(i)->offset = next_offset;
5114 -+
5115 -+ TRACE("Symbolic link inode %x:%x, start_block %llx, "
5116 -+ "offset %x\n",
5117 -+ SQUASHFS_INODE_BLK(inode), offset,
5118 -+ next_block, next_offset);
5119 -+ break;
5120 -+ }
5121 -+ case SQUASHFS_BLKDEV_TYPE:
5122 -+ case SQUASHFS_CHRDEV_TYPE: {
5123 -+ struct squashfs_dev_inode_header_2 *inodep = &id.dev;
5124 -+ struct squashfs_dev_inode_header_2 *sinodep = &sid.dev;
5125 -+
5126 -+ if (msblk->swap) {
5127 -+ if (!squashfs_get_cached_block(s, (char *)
5128 -+ sinodep, block, offset,
5129 -+ sizeof(*sinodep), &next_block,
5130 -+ &next_offset))
5131 -+ goto failed_read;
5132 -+ SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep);
5133 -+ } else
5134 -+ if (!squashfs_get_cached_block(s, (char *)
5135 -+ inodep, block, offset,
5136 -+ sizeof(*inodep), &next_block,
5137 -+ &next_offset))
5138 -+ goto failed_read;
5139 -+
5140 -+ i->i_mode |= (inodeb->inode_type ==
5141 -+ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR :
5142 -+ S_IFBLK;
5143 -+ init_special_inode(i, i->i_mode,
5144 -+ old_decode_dev(inodep->rdev));
5145 -+
5146 -+ TRACE("Device inode %x:%x, rdev %x\n",
5147 -+ SQUASHFS_INODE_BLK(inode), offset,
5148 -+ inodep->rdev);
5149 -+ break;
5150 -+ }
5151 -+ case SQUASHFS_FIFO_TYPE:
5152 -+ case SQUASHFS_SOCKET_TYPE: {
5153 -+
5154 -+ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
5155 -+ ? S_IFIFO : S_IFSOCK;
5156 -+ init_special_inode(i, i->i_mode, 0);
5157 -+ break;
5158 -+ }
5159 -+ default:
5160 -+ ERROR("Unknown inode type %d in squashfs_iget!\n",
5161 -+ inodeb->inode_type);
5162 -+ goto failed_read1;
5163 -+ }
5164 -+
5165 -+ return 1;
5166 -+
5167 -+failed_read:
5168 -+ ERROR("Unable to read inode [%x:%x]\n", block, offset);
5169 -+
5170 -+failed_read1:
5171 -+ return 0;
5172 -+}
5173 -+
5174 -+
5175 -+static int get_dir_index_using_offset(struct super_block *s, long long
5176 -+ *next_block, unsigned int *next_offset,
5177 -+ long long index_start,
5178 -+ unsigned int index_offset, int i_count,
5179 -+ long long f_pos)
5180 -+{
5181 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
5182 -+ struct squashfs_super_block *sblk = &msblk->sblk;
5183 -+ int i, length = 0;
5184 -+ struct squashfs_dir_index_2 index;
5185 -+
5186 -+ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
5187 -+ i_count, (unsigned int) f_pos);
5188 -+
5189 -+ if (f_pos == 0)
5190 -+ goto finish;
5191 -+
5192 -+ for (i = 0; i < i_count; i++) {
5193 -+ if (msblk->swap) {
5194 -+ struct squashfs_dir_index_2 sindex;
5195 -+ squashfs_get_cached_block(s, (char *) &sindex,
5196 -+ index_start, index_offset,
5197 -+ sizeof(sindex), &index_start,
5198 -+ &index_offset);
5199 -+ SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex);
5200 -+ } else
5201 -+ squashfs_get_cached_block(s, (char *) &index,
5202 -+ index_start, index_offset,
5203 -+ sizeof(index), &index_start,
5204 -+ &index_offset);
5205 -+
5206 -+ if (index.index > f_pos)
5207 -+ break;
5208 -+
5209 -+ squashfs_get_cached_block(s, NULL, index_start, index_offset,
5210 -+ index.size + 1, &index_start,
5211 -+ &index_offset);
5212 -+
5213 -+ length = index.index;
5214 -+ *next_block = index.start_block + sblk->directory_table_start;
5215 -+ }
5216 -+
5217 -+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
5218 -+
5219 -+finish:
5220 -+ return length;
5221 -+}
5222 -+
5223 -+
5224 -+static int get_dir_index_using_name(struct super_block *s, long long
5225 -+ *next_block, unsigned int *next_offset,
5226 -+ long long index_start,
5227 -+ unsigned int index_offset, int i_count,
5228 -+ const char *name, int size)
5229 -+{
5230 -+ struct squashfs_sb_info *msblk = s->s_fs_info;
5231 -+ struct squashfs_super_block *sblk = &msblk->sblk;
5232 -+ int i, length = 0;
5233 -+ struct squashfs_dir_index_2 *index;
5234 -+ char *str;
5235 -+
5236 -+ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
5237 -+
5238 -+ if (!(str = kmalloc(sizeof(struct squashfs_dir_index) +
5239 -+ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) {
5240 -+ ERROR("Failed to allocate squashfs_dir_index\n");
5241 -+ goto failure;
5242 -+ }
5243 -+
5244 -+ index = (struct squashfs_dir_index_2 *) (str + SQUASHFS_NAME_LEN + 1);
5245 -+ strncpy(str, name, size);
5246 -+ str[size] = '\0';
5247 -+
5248 -+ for (i = 0; i < i_count; i++) {
5249 -+ if (msblk->swap) {
5250 -+ struct squashfs_dir_index_2 sindex;
5251 -+ squashfs_get_cached_block(s, (char *) &sindex,
5252 -+ index_start, index_offset,
5253 -+ sizeof(sindex), &index_start,
5254 -+ &index_offset);
5255 -+ SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex);
5256 -+ } else
5257 -+ squashfs_get_cached_block(s, (char *) index,
5258 -+ index_start, index_offset,
5259 -+ sizeof(struct squashfs_dir_index_2),
5260 -+ &index_start, &index_offset);
5261 -+
5262 -+ squashfs_get_cached_block(s, index->name, index_start,
5263 -+ index_offset, index->size + 1,
5264 -+ &index_start, &index_offset);
5265 -+
5266 -+ index->name[index->size + 1] = '\0';
5267 -+
5268 -+ if (strcmp(index->name, str) > 0)
5269 -+ break;
5270 -+
5271 -+ length = index->index;
5272 -+ *next_block = index->start_block + sblk->directory_table_start;
5273 -+ }
5274 -+
5275 -+ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
5276 -+ kfree(str);
5277 -+failure:
5278 -+ return length;
5279 -+}
5280 -+
5281 -+
5282 -+static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir)
5283 -+{
5284 -+ struct inode *i = file->f_dentry->d_inode;
5285 -+ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
5286 -+ struct squashfs_super_block *sblk = &msblk->sblk;
5287 -+ long long next_block = SQUASHFS_I(i)->start_block +
5288 -+ sblk->directory_table_start;
5289 -+ int next_offset = SQUASHFS_I(i)->offset, length = 0,
5290 -+ dir_count;
5291 -+ struct squashfs_dir_header_2 dirh;
5292 -+ struct squashfs_dir_entry_2 *dire;
5293 -+
5294 -+ TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset);
5295 -+
5296 -+ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
5297 -+ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
5298 -+ ERROR("Failed to allocate squashfs_dir_entry\n");
5299 -+ goto finish;
5300 -+ }
5301 -+
5302 -+ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
5303 -+ SQUASHFS_I(i)->u.s2.directory_index_start,
5304 -+ SQUASHFS_I(i)->u.s2.directory_index_offset,
5305 -+ SQUASHFS_I(i)->u.s2.directory_index_count,
5306 -+ file->f_pos);
5307 -+
5308 -+ while (length < i_size_read(i)) {
5309 -+ /* read directory header */
5310 -+ if (msblk->swap) {
5311 -+ struct squashfs_dir_header_2 sdirh;
5312 -+
5313 -+ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
5314 -+ next_block, next_offset, sizeof(sdirh),
5315 -+ &next_block, &next_offset))
5316 -+ goto failed_read;
5317 -+
5318 -+ length += sizeof(sdirh);
5319 -+ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
5320 -+ } else {
5321 -+ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
5322 -+ next_block, next_offset, sizeof(dirh),
5323 -+ &next_block, &next_offset))
5324 -+ goto failed_read;
5325 -+
5326 -+ length += sizeof(dirh);
5327 -+ }
5328 -+
5329 -+ dir_count = dirh.count + 1;
5330 -+ while (dir_count--) {
5331 -+ if (msblk->swap) {
5332 -+ struct squashfs_dir_entry_2 sdire;
5333 -+ if (!squashfs_get_cached_block(i->i_sb, (char *)
5334 -+ &sdire, next_block, next_offset,
5335 -+ sizeof(sdire), &next_block,
5336 -+ &next_offset))
5337 -+ goto failed_read;
5338 -+
5339 -+ length += sizeof(sdire);
5340 -+ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
5341 -+ } else {
5342 -+ if (!squashfs_get_cached_block(i->i_sb, (char *)
5343 -+ dire, next_block, next_offset,
5344 -+ sizeof(*dire), &next_block,
5345 -+ &next_offset))
5346 -+ goto failed_read;
5347 -+
5348 -+ length += sizeof(*dire);
5349 -+ }
5350 -+
5351 -+ if (!squashfs_get_cached_block(i->i_sb, dire->name,
5352 -+ next_block, next_offset,
5353 -+ dire->size + 1, &next_block,
5354 -+ &next_offset))
5355 -+ goto failed_read;
5356 -+
5357 -+ length += dire->size + 1;
5358 -+
5359 -+ if (file->f_pos >= length)
5360 -+ continue;
5361 -+
5362 -+ dire->name[dire->size + 1] = '\0';
5363 -+
5364 -+ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n",
5365 -+ (unsigned int) dirent, dire->name,
5366 -+ dire->size + 1, (int) file->f_pos,
5367 -+ dirh.start_block, dire->offset,
5368 -+ squashfs_filetype_table[dire->type]);
5369 -+
5370 -+ if (filldir(dirent, dire->name, dire->size + 1,
5371 -+ file->f_pos, SQUASHFS_MK_VFS_INODE(
5372 -+ dirh.start_block, dire->offset),
5373 -+ squashfs_filetype_table[dire->type])
5374 -+ < 0) {
5375 -+ TRACE("Filldir returned less than 0\n");
5376 -+ goto finish;
5377 -+ }
5378 -+ file->f_pos = length;
5379 -+ }
5380 -+ }
5381 -+
5382 -+finish:
5383 -+ kfree(dire);
5384 -+ return 0;
5385 -+
5386 -+failed_read:
5387 -+ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
5388 -+ next_offset);
5389 -+ kfree(dire);
5390 -+ return 0;
5391 -+}
5392 -+
5393 -+
5394 -+static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry,
5395 -+ struct nameidata *nd)
5396 -+{
5397 -+ const unsigned char *name = dentry->d_name.name;
5398 -+ int len = dentry->d_name.len;
5399 -+ struct inode *inode = NULL;
5400 -+ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
5401 -+ struct squashfs_super_block *sblk = &msblk->sblk;
5402 -+ long long next_block = SQUASHFS_I(i)->start_block +
5403 -+ sblk->directory_table_start;
5404 -+ int next_offset = SQUASHFS_I(i)->offset, length = 0,
5405 -+ dir_count;
5406 -+ struct squashfs_dir_header_2 dirh;
5407 -+ struct squashfs_dir_entry_2 *dire;
5408 -+ int sorted = sblk->s_major == 2 && sblk->s_minor >= 1;
5409 -+
5410 -+ TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset);
5411 -+
5412 -+ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
5413 -+ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
5414 -+ ERROR("Failed to allocate squashfs_dir_entry\n");
5415 -+ goto exit_loop;
5416 -+ }
5417 -+
5418 -+ if (len > SQUASHFS_NAME_LEN)
5419 -+ goto exit_loop;
5420 -+
5421 -+ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
5422 -+ SQUASHFS_I(i)->u.s2.directory_index_start,
5423 -+ SQUASHFS_I(i)->u.s2.directory_index_offset,
5424 -+ SQUASHFS_I(i)->u.s2.directory_index_count, name,
5425 -+ len);
5426 -+
5427 -+ while (length < i_size_read(i)) {
5428 -+ /* read directory header */
5429 -+ if (msblk->swap) {
5430 -+ struct squashfs_dir_header_2 sdirh;
5431 -+ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
5432 -+ next_block, next_offset, sizeof(sdirh),
5433 -+ &next_block, &next_offset))
5434 -+ goto failed_read;
5435 -+
5436 -+ length += sizeof(sdirh);
5437 -+ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
5438 -+ } else {
5439 -+ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
5440 -+ next_block, next_offset, sizeof(dirh),
5441 -+ &next_block, &next_offset))
5442 -+ goto failed_read;
5443 -+
5444 -+ length += sizeof(dirh);
5445 -+ }
5446 -+
5447 -+ dir_count = dirh.count + 1;
5448 -+ while (dir_count--) {
5449 -+ if (msblk->swap) {
5450 -+ struct squashfs_dir_entry_2 sdire;
5451 -+ if (!squashfs_get_cached_block(i->i_sb, (char *)
5452 -+ &sdire, next_block,next_offset,
5453 -+ sizeof(sdire), &next_block,
5454 -+ &next_offset))
5455 -+ goto failed_read;
5456 -+
5457 -+ length += sizeof(sdire);
5458 -+ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
5459 -+ } else {
5460 -+ if (!squashfs_get_cached_block(i->i_sb, (char *)
5461 -+ dire, next_block,next_offset,
5462 -+ sizeof(*dire), &next_block,
5463 -+ &next_offset))
5464 -+ goto failed_read;
5465 -+
5466 -+ length += sizeof(*dire);
5467 -+ }
5468 -+
5469 -+ if (!squashfs_get_cached_block(i->i_sb, dire->name,
5470 -+ next_block, next_offset, dire->size + 1,
5471 -+ &next_block, &next_offset))
5472 -+ goto failed_read;
5473 -+
5474 -+ length += dire->size + 1;
5475 -+
5476 -+ if (sorted && name[0] < dire->name[0])
5477 -+ goto exit_loop;
5478 -+
5479 -+ if ((len == dire->size + 1) && !strncmp(name,
5480 -+ dire->name, len)) {
5481 -+ squashfs_inode_t ino =
5482 -+ SQUASHFS_MKINODE(dirh.start_block,
5483 -+ dire->offset);
5484 -+ unsigned int inode_number = SQUASHFS_MK_VFS_INODE(dirh.start_block,
5485 -+ dire->offset);
5486 -+
5487 -+ TRACE("calling squashfs_iget for directory "
5488 -+ "entry %s, inode %x:%x, %lld\n", name,
5489 -+ dirh.start_block, dire->offset, ino);
5490 -+
5491 -+ inode = squashfs_iget(i->i_sb, ino, inode_number);
5492 -+
5493 -+ goto exit_loop;
5494 -+ }
5495 -+ }
5496 -+ }
5497 -+
5498 -+exit_loop:
5499 -+ kfree(dire);
5500 -+ d_add(dentry, inode);
5501 -+ return ERR_PTR(0);
5502 -+
5503 -+failed_read:
5504 -+ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
5505 -+ next_offset);
5506 -+ goto exit_loop;
5507 -+}
5508 -+
5509 -+
5510 -+int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
5511 -+{
5512 -+ struct squashfs_super_block *sblk = &msblk->sblk;
5513 -+
5514 -+ msblk->read_inode = squashfs_read_inode_2;
5515 -+ msblk->read_fragment_index_table = read_fragment_index_table_2;
5516 -+
5517 -+ sblk->bytes_used = sblk->bytes_used_2;
5518 -+ sblk->uid_start = sblk->uid_start_2;
5519 -+ sblk->guid_start = sblk->guid_start_2;
5520 -+ sblk->inode_table_start = sblk->inode_table_start_2;
5521 -+ sblk->directory_table_start = sblk->directory_table_start_2;
5522 -+ sblk->fragment_table_start = sblk->fragment_table_start_2;
5523 -+
5524 -+ return 1;
5525 -+}
5526 -Index: linux-2.6.25-gentoo/fs/squashfs/squashfs.h
5527 -===================================================================
5528 ---- /dev/null
5529 -+++ linux-2.6.25-gentoo/fs/squashfs/squashfs.h
5530 -@@ -0,0 +1,86 @@
5531 -+/*
5532 -+ * Squashfs - a compressed read only filesystem for Linux
5533 -+ *
5534 -+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
5535 -+ * Phillip Lougher <phillip@××××××××××××××××.uk>
5536 -+ *
5537 -+ * This program is free software; you can redistribute it and/or
5538 -+ * modify it under the terms of the GNU General Public License
5539 -+ * as published by the Free Software Foundation; either version 2,
5540 -+ * or (at your option) any later version.
5541 -+ *
5542 -+ * This program is distributed in the hope that it will be useful,
5543 -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
5544 -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5545 -+ * GNU General Public License for more details.
5546 -+ *
5547 -+ * You should have received a copy of the GNU General Public License
5548 -+ * along with this program; if not, write to the Free Software
5549 -+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
5550 -+ *
5551 -+ * squashfs.h
5552 -+ */
5553 -+
5554 -+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
5555 -+#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
5556 -+#endif
5557 -+
5558 -+#ifdef SQUASHFS_TRACE
5559 -+#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args)
5560 -+#else
5561 -+#define TRACE(s, args...) {}
5562 -+#endif
5563 -+
5564 -+#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args)
5565 -+
5566 -+#define SERROR(s, args...) do { \
5567 -+ if (!silent) \
5568 -+ printk(KERN_ERR "SQUASHFS error: "s, ## args);\
5569 -+ } while(0)
5570 -+
5571 -+#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args)
5572 -+
5573 -+static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode)
5574 -+{
5575 -+ return list_entry(inode, struct squashfs_inode_info, vfs_inode);
5576 -+}
5577 -+
5578 -+#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY)
5579 -+#define SQSH_EXTERN
5580 -+extern unsigned int squashfs_read_data(struct super_block *s, char *buffer,
5581 -+ long long index, unsigned int length,
5582 -+ long long *next_index, int srclength);
5583 -+extern int squashfs_get_cached_block(struct super_block *s, void *buffer,
5584 -+ long long block, unsigned int offset,
5585 -+ int length, long long *next_block,
5586 -+ unsigned int *next_offset);
5587 -+extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct
5588 -+ squashfs_fragment_cache *fragment);
5589 -+extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block
5590 -+ *s, long long start_block,
5591 -+ int length);
5592 -+extern struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number);
5593 -+extern const struct address_space_operations squashfs_symlink_aops;
5594 -+extern const struct address_space_operations squashfs_aops;
5595 -+extern struct inode_operations squashfs_dir_inode_ops;
5596 -+#else
5597 -+#define SQSH_EXTERN static
5598 -+#endif
5599 -+
5600 -+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
5601 -+extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk);
5602 -+#else
5603 -+static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk)
5604 -+{
5605 -+ return 0;
5606 -+}
5607 -+#endif
5608 -+
5609 -+#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
5610 -+extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk);
5611 -+#else
5612 -+static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
5613 -+{
5614 -+ return 0;
5615 -+}
5616 -+#endif
5617 -Index: linux-2.6.25-gentoo/include/linux/squashfs_fs.h
5618 -===================================================================
5619 ---- /dev/null
5620 -+++ linux-2.6.25-gentoo/include/linux/squashfs_fs.h
5621 -@@ -0,0 +1,935 @@
5622 -+#ifndef SQUASHFS_FS
5623 -+#define SQUASHFS_FS
5624 -+
5625 -+/*
5626 -+ * Squashfs
5627 -+ *
5628 -+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
5629 -+ * Phillip Lougher <phillip@××××××××××××××××.uk>
5630 -+ *
5631 -+ * This program is free software; you can redistribute it and/or
5632 -+ * modify it under the terms of the GNU General Public License
5633 -+ * as published by the Free Software Foundation; either version 2,
5634 -+ * or (at your option) any later version.
5635 -+ *
5636 -+ * This program is distributed in the hope that it will be useful,
5637 -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
5638 -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5639 -+ * GNU General Public License for more details.
5640 -+ *
5641 -+ * You should have received a copy of the GNU General Public License
5642 -+ * along with this program; if not, write to the Free Software
5643 -+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
5644 -+ *
5645 -+ * squashfs_fs.h
5646 -+ */
5647 -+
5648 -+#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY
5649 -+#define CONFIG_SQUASHFS_2_0_COMPATIBILITY
5650 -+#endif
5651 -+
5652 -+#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
5653 -+#define SQUASHFS_MAJOR 3
5654 -+#define SQUASHFS_MINOR 1
5655 -+#define SQUASHFS_MAGIC 0x73717368
5656 -+#define SQUASHFS_MAGIC_SWAP 0x68737173
5657 -+#define SQUASHFS_START 0
5658 -+
5659 -+/* size of metadata (inode and directory) blocks */
5660 -+#define SQUASHFS_METADATA_SIZE 8192
5661 -+#define SQUASHFS_METADATA_LOG 13
5662 -+
5663 -+/* default size of data blocks */
5664 -+#define SQUASHFS_FILE_SIZE 131072
5665 -+#define SQUASHFS_FILE_LOG 17
5666 -+
5667 -+#define SQUASHFS_FILE_MAX_SIZE 1048576
5668 -+
5669 -+/* Max number of uids and gids */
5670 -+#define SQUASHFS_UIDS 256
5671 -+#define SQUASHFS_GUIDS 255
5672 -+
5673 -+/* Max length of filename (not 255) */
5674 -+#define SQUASHFS_NAME_LEN 256
5675 -+
5676 -+#define SQUASHFS_INVALID ((long long) 0xffffffffffff)
5677 -+#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff)
5678 -+#define SQUASHFS_INVALID_BLK ((long long) -1)
5679 -+#define SQUASHFS_USED_BLK ((long long) -2)
5680 -+
5681 -+/* Filesystem flags */
5682 -+#define SQUASHFS_NOI 0
5683 -+#define SQUASHFS_NOD 1
5684 -+#define SQUASHFS_CHECK 2
5685 -+#define SQUASHFS_NOF 3
5686 -+#define SQUASHFS_NO_FRAG 4
5687 -+#define SQUASHFS_ALWAYS_FRAG 5
5688 -+#define SQUASHFS_DUPLICATE 6
5689 -+#define SQUASHFS_EXPORT 7
5690 -+
5691 -+#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1)
5692 -+
5693 -+#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \
5694 -+ SQUASHFS_NOI)
5695 -+
5696 -+#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \
5697 -+ SQUASHFS_NOD)
5698 -+
5699 -+#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
5700 -+ SQUASHFS_NOF)
5701 -+
5702 -+#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
5703 -+ SQUASHFS_NO_FRAG)
5704 -+
5705 -+#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
5706 -+ SQUASHFS_ALWAYS_FRAG)
5707 -+
5708 -+#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \
5709 -+ SQUASHFS_DUPLICATE)
5710 -+
5711 -+#define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \
5712 -+ SQUASHFS_EXPORT)
5713 -+
5714 -+#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \
5715 -+ SQUASHFS_CHECK)
5716 -+
5717 -+#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \
5718 -+ duplicate_checking, exortable) (noi | (nod << 1) | (check_data << 2) \
5719 -+ | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \
5720 -+ (duplicate_checking << 6) | (exportable << 7))
5721 -+
5722 -+/* Max number of types and file types */
5723 -+#define SQUASHFS_DIR_TYPE 1
5724 -+#define SQUASHFS_FILE_TYPE 2
5725 -+#define SQUASHFS_SYMLINK_TYPE 3
5726 -+#define SQUASHFS_BLKDEV_TYPE 4
5727 -+#define SQUASHFS_CHRDEV_TYPE 5
5728 -+#define SQUASHFS_FIFO_TYPE 6
5729 -+#define SQUASHFS_SOCKET_TYPE 7
5730 -+#define SQUASHFS_LDIR_TYPE 8
5731 -+#define SQUASHFS_LREG_TYPE 9
5732 -+
5733 -+/* 1.0 filesystem type definitions */
5734 -+#define SQUASHFS_TYPES 5
5735 -+#define SQUASHFS_IPC_TYPE 0
5736 -+
5737 -+/* Flag whether block is compressed or uncompressed, bit is set if block is
5738 -+ * uncompressed */
5739 -+#define SQUASHFS_COMPRESSED_BIT (1 << 15)
5740 -+
5741 -+#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
5742 -+ (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT)
5743 -+
5744 -+#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT))
5745 -+
5746 -+#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24)
5747 -+
5748 -+#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) ((B) & \
5749 -+ ~SQUASHFS_COMPRESSED_BIT_BLOCK)
5750 -+
5751 -+#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
5752 -+
5753 -+/*
5754 -+ * Inode number ops. Inodes consist of a compressed block number, and an
5755 -+ * uncompressed offset within that block
5756 -+ */
5757 -+#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16))
5758 -+
5759 -+#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff))
5760 -+
5761 -+#define SQUASHFS_MKINODE(A, B) ((squashfs_inode_t)(((squashfs_inode_t) (A)\
5762 -+ << 16) + (B)))
5763 -+
5764 -+/* Compute 32 bit VFS inode number from squashfs inode number */
5765 -+#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \
5766 -+ ((b) >> 2) + 1))
5767 -+/* XXX */
5768 -+
5769 -+/* Translate between VFS mode and squashfs mode */
5770 -+#define SQUASHFS_MODE(a) ((a) & 0xfff)
5771 -+
5772 -+/* fragment and fragment table defines */
5773 -+#define SQUASHFS_FRAGMENT_BYTES(A) ((A) * sizeof(struct squashfs_fragment_entry))
5774 -+
5775 -+#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \
5776 -+ SQUASHFS_METADATA_SIZE)
5777 -+
5778 -+#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \
5779 -+ SQUASHFS_METADATA_SIZE)
5780 -+
5781 -+#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \
5782 -+ SQUASHFS_METADATA_SIZE - 1) / \
5783 -+ SQUASHFS_METADATA_SIZE)
5784 -+
5785 -+#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\
5786 -+ sizeof(long long))
5787 -+
5788 -+/* inode lookup table defines */
5789 -+#define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(squashfs_inode_t))
5790 -+
5791 -+#define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \
5792 -+ SQUASHFS_METADATA_SIZE)
5793 -+
5794 -+#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \
5795 -+ SQUASHFS_METADATA_SIZE)
5796 -+
5797 -+#define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \
5798 -+ SQUASHFS_METADATA_SIZE - 1) / \
5799 -+ SQUASHFS_METADATA_SIZE)
5800 -+
5801 -+#define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\
5802 -+ sizeof(long long))
5803 -+
5804 -+/* cached data constants for filesystem */
5805 -+#define SQUASHFS_CACHED_BLKS 8
5806 -+
5807 -+#define SQUASHFS_MAX_FILE_SIZE_LOG 64
5808 -+
5809 -+#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \
5810 -+ (SQUASHFS_MAX_FILE_SIZE_LOG - 2))
5811 -+
5812 -+#define SQUASHFS_MARKER_BYTE 0xff
5813 -+
5814 -+/* meta index cache */
5815 -+#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
5816 -+#define SQUASHFS_META_ENTRIES 31
5817 -+#define SQUASHFS_META_NUMBER 8
5818 -+#define SQUASHFS_SLOTS 4
5819 -+
5820 -+struct meta_entry {
5821 -+ long long data_block;
5822 -+ unsigned int index_block;
5823 -+ unsigned short offset;
5824 -+ unsigned short pad;
5825 -+};
5826 -+
5827 -+struct meta_index {
5828 -+ unsigned int inode_number;
5829 -+ unsigned int offset;
5830 -+ unsigned short entries;
5831 -+ unsigned short skip;
5832 -+ unsigned short locked;
5833 -+ unsigned short pad;
5834 -+ struct meta_entry meta_entry[SQUASHFS_META_ENTRIES];
5835 -+};
5836 -+
5837 -+
5838 -+/*
5839 -+ * definitions for structures on disk
5840 -+ */
5841 -+
5842 -+typedef long long squashfs_block_t;
5843 -+typedef long long squashfs_inode_t;
5844 -+
5845 -+struct squashfs_super_block {
5846 -+ unsigned int s_magic;
5847 -+ unsigned int inodes;
5848 -+ unsigned int bytes_used_2;
5849 -+ unsigned int uid_start_2;
5850 -+ unsigned int guid_start_2;
5851 -+ unsigned int inode_table_start_2;
5852 -+ unsigned int directory_table_start_2;
5853 -+ unsigned int s_major:16;
5854 -+ unsigned int s_minor:16;
5855 -+ unsigned int block_size_1:16;
5856 -+ unsigned int block_log:16;
5857 -+ unsigned int flags:8;
5858 -+ unsigned int no_uids:8;
5859 -+ unsigned int no_guids:8;
5860 -+ unsigned int mkfs_time /* time of filesystem creation */;
5861 -+ squashfs_inode_t root_inode;
5862 -+ unsigned int block_size;
5863 -+ unsigned int fragments;
5864 -+ unsigned int fragment_table_start_2;
5865 -+ long long bytes_used;
5866 -+ long long uid_start;
5867 -+ long long guid_start;
5868 -+ long long inode_table_start;
5869 -+ long long directory_table_start;
5870 -+ long long fragment_table_start;
5871 -+ long long lookup_table_start;
5872 -+} __attribute__ ((packed));
5873 -+
5874 -+struct squashfs_dir_index {
5875 -+ unsigned int index;
5876 -+ unsigned int start_block;
5877 -+ unsigned char size;
5878 -+ unsigned char name[0];
5879 -+} __attribute__ ((packed));
5880 -+
5881 -+#define SQUASHFS_BASE_INODE_HEADER \
5882 -+ unsigned int inode_type:4; \
5883 -+ unsigned int mode:12; \
5884 -+ unsigned int uid:8; \
5885 -+ unsigned int guid:8; \
5886 -+ unsigned int mtime; \
5887 -+ unsigned int inode_number;
5888 -+
5889 -+struct squashfs_base_inode_header {
5890 -+ SQUASHFS_BASE_INODE_HEADER;
5891 -+} __attribute__ ((packed));
5892 -+
5893 -+struct squashfs_ipc_inode_header {
5894 -+ SQUASHFS_BASE_INODE_HEADER;
5895 -+ unsigned int nlink;
5896 -+} __attribute__ ((packed));
5897 -+
5898 -+struct squashfs_dev_inode_header {
5899 -+ SQUASHFS_BASE_INODE_HEADER;
5900 -+ unsigned int nlink;
5901 -+ unsigned short rdev;
5902 -+} __attribute__ ((packed));
5903 -+
5904 -+struct squashfs_symlink_inode_header {
5905 -+ SQUASHFS_BASE_INODE_HEADER;
5906 -+ unsigned int nlink;
5907 -+ unsigned short symlink_size;
5908 -+ char symlink[0];
5909 -+} __attribute__ ((packed));
5910 -+
5911 -+struct squashfs_reg_inode_header {
5912 -+ SQUASHFS_BASE_INODE_HEADER;
5913 -+ squashfs_block_t start_block;
5914 -+ unsigned int fragment;
5915 -+ unsigned int offset;
5916 -+ unsigned int file_size;
5917 -+ unsigned short block_list[0];
5918 -+} __attribute__ ((packed));
5919 -+
5920 -+struct squashfs_lreg_inode_header {
5921 -+ SQUASHFS_BASE_INODE_HEADER;
5922 -+ unsigned int nlink;
5923 -+ squashfs_block_t start_block;
5924 -+ unsigned int fragment;
5925 -+ unsigned int offset;
5926 -+ long long file_size;
5927 -+ unsigned short block_list[0];
5928 -+} __attribute__ ((packed));
5929 -+
5930 -+struct squashfs_dir_inode_header {
5931 -+ SQUASHFS_BASE_INODE_HEADER;
5932 -+ unsigned int nlink;
5933 -+ unsigned int file_size:19;
5934 -+ unsigned int offset:13;
5935 -+ unsigned int start_block;
5936 -+ unsigned int parent_inode;
5937 -+} __attribute__ ((packed));
5938 -+
5939 -+struct squashfs_ldir_inode_header {
5940 -+ SQUASHFS_BASE_INODE_HEADER;
5941 -+ unsigned int nlink;
5942 -+ unsigned int file_size:27;
5943 -+ unsigned int offset:13;
5944 -+ unsigned int start_block;
5945 -+ unsigned int i_count:16;
5946 -+ unsigned int parent_inode;
5947 -+ struct squashfs_dir_index index[0];
5948 -+} __attribute__ ((packed));
5949 -+
5950 -+union squashfs_inode_header {
5951 -+ struct squashfs_base_inode_header base;
5952 -+ struct squashfs_dev_inode_header dev;
5953 -+ struct squashfs_symlink_inode_header symlink;
5954 -+ struct squashfs_reg_inode_header reg;
5955 -+ struct squashfs_lreg_inode_header lreg;
5956 -+ struct squashfs_dir_inode_header dir;
5957 -+ struct squashfs_ldir_inode_header ldir;
5958 -+ struct squashfs_ipc_inode_header ipc;
5959 -+};
5960 -+
5961 -+struct squashfs_dir_entry {
5962 -+ unsigned int offset:13;
5963 -+ unsigned int type:3;
5964 -+ unsigned int size:8;
5965 -+ int inode_number:16;
5966 -+ char name[0];
5967 -+} __attribute__ ((packed));
5968 -+
5969 -+struct squashfs_dir_header {
5970 -+ unsigned int count:8;
5971 -+ unsigned int start_block;
5972 -+ unsigned int inode_number;
5973 -+} __attribute__ ((packed));
5974 -+
5975 -+struct squashfs_fragment_entry {
5976 -+ long long start_block;
5977 -+ unsigned int size;
5978 -+ unsigned int pending;
5979 -+} __attribute__ ((packed));
5980 -+
5981 -+extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
5982 -+extern int squashfs_uncompress_init(void);
5983 -+extern int squashfs_uncompress_exit(void);
5984 -+
5985 -+/*
5986 -+ * macros to convert each packed bitfield structure from little endian to big
5987 -+ * endian and vice versa. These are needed when creating or using a filesystem
5988 -+ * on a machine with different byte ordering to the target architecture.
5989 -+ *
5990 -+ */
5991 -+
5992 -+#define SQUASHFS_SWAP_START \
5993 -+ int bits;\
5994 -+ int b_pos;\
5995 -+ unsigned long long val;\
5996 -+ unsigned char *s;\
5997 -+ unsigned char *d;
5998 -+
5999 -+#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
6000 -+ SQUASHFS_SWAP_START\
6001 -+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\
6002 -+ SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
6003 -+ SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
6004 -+ SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
6005 -+ SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
6006 -+ SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
6007 -+ SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
6008 -+ SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
6009 -+ SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
6010 -+ SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
6011 -+ SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
6012 -+ SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
6013 -+ SQUASHFS_SWAP((s)->flags, d, 288, 8);\
6014 -+ SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
6015 -+ SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
6016 -+ SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
6017 -+ SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
6018 -+ SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
6019 -+ SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
6020 -+ SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
6021 -+ SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
6022 -+ SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
6023 -+ SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
6024 -+ SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
6025 -+ SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
6026 -+ SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
6027 -+ SQUASHFS_SWAP((s)->lookup_table_start, d, 888, 64);\
6028 -+}
6029 -+
6030 -+#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
6031 -+ SQUASHFS_MEMSET(s, d, n);\
6032 -+ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
6033 -+ SQUASHFS_SWAP((s)->mode, d, 4, 12);\
6034 -+ SQUASHFS_SWAP((s)->uid, d, 16, 8);\
6035 -+ SQUASHFS_SWAP((s)->guid, d, 24, 8);\
6036 -+ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
6037 -+ SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
6038 -+
6039 -+#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
6040 -+ SQUASHFS_SWAP_START\
6041 -+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
6042 -+}
6043 -+
6044 -+#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\
6045 -+ SQUASHFS_SWAP_START\
6046 -+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
6047 -+ sizeof(struct squashfs_ipc_inode_header))\
6048 -+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
6049 -+}
6050 -+
6051 -+#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
6052 -+ SQUASHFS_SWAP_START\
6053 -+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
6054 -+ sizeof(struct squashfs_dev_inode_header)); \
6055 -+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
6056 -+ SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
6057 -+}
6058 -+
6059 -+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
6060 -+ SQUASHFS_SWAP_START\
6061 -+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
6062 -+ sizeof(struct squashfs_symlink_inode_header));\
6063 -+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
6064 -+ SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
6065 -+}
6066 -+
6067 -+#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
6068 -+ SQUASHFS_SWAP_START\
6069 -+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
6070 -+ sizeof(struct squashfs_reg_inode_header));\
6071 -+ SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
6072 -+ SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
6073 -+ SQUASHFS_SWAP((s)->offset, d, 192, 32);\
6074 -+ SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
6075 -+}
6076 -+
6077 -+#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\
6078 -+ SQUASHFS_SWAP_START\
6079 -+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
6080 -+ sizeof(struct squashfs_lreg_inode_header));\
6081 -+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
6082 -+ SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
6083 -+ SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
6084 -+ SQUASHFS_SWAP((s)->offset, d, 224, 32);\
6085 -+ SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
6086 -+}
6087 -+
6088 -+#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
6089 -+ SQUASHFS_SWAP_START\
6090 -+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
6091 -+ sizeof(struct squashfs_dir_inode_header));\
6092 -+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
6093 -+ SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
6094 -+ SQUASHFS_SWAP((s)->offset, d, 147, 13);\
6095 -+ SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
6096 -+ SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
6097 -+}
6098 -+
6099 -+#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\
6100 -+ SQUASHFS_SWAP_START\
6101 -+ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
6102 -+ sizeof(struct squashfs_ldir_inode_header));\
6103 -+ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
6104 -+ SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
6105 -+ SQUASHFS_SWAP((s)->offset, d, 155, 13);\
6106 -+ SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
6107 -+ SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
6108 -+ SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
6109 -+}
6110 -+
6111 -+#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\
6112 -+ SQUASHFS_SWAP_START\
6113 -+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\
6114 -+ SQUASHFS_SWAP((s)->index, d, 0, 32);\
6115 -+ SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
6116 -+ SQUASHFS_SWAP((s)->size, d, 64, 8);\
6117 -+}
6118 -+
6119 -+#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
6120 -+ SQUASHFS_SWAP_START\
6121 -+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\
6122 -+ SQUASHFS_SWAP((s)->count, d, 0, 8);\
6123 -+ SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
6124 -+ SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
6125 -+}
6126 -+
6127 -+#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
6128 -+ SQUASHFS_SWAP_START\
6129 -+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\
6130 -+ SQUASHFS_SWAP((s)->offset, d, 0, 13);\
6131 -+ SQUASHFS_SWAP((s)->type, d, 13, 3);\
6132 -+ SQUASHFS_SWAP((s)->size, d, 16, 8);\
6133 -+ SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
6134 -+}
6135 -+
6136 -+#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\
6137 -+ SQUASHFS_SWAP_START\
6138 -+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\
6139 -+ SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
6140 -+ SQUASHFS_SWAP((s)->size, d, 64, 32);\
6141 -+}
6142 -+
6143 -+#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1)
6144 -+
6145 -+#define SQUASHFS_SWAP_SHORTS(s, d, n) {\
6146 -+ int entry;\
6147 -+ int bit_position;\
6148 -+ SQUASHFS_SWAP_START\
6149 -+ SQUASHFS_MEMSET(s, d, n * 2);\
6150 -+ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
6151 -+ 16)\
6152 -+ SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
6153 -+}
6154 -+
6155 -+#define SQUASHFS_SWAP_INTS(s, d, n) {\
6156 -+ int entry;\
6157 -+ int bit_position;\
6158 -+ SQUASHFS_SWAP_START\
6159 -+ SQUASHFS_MEMSET(s, d, n * 4);\
6160 -+ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
6161 -+ 32)\
6162 -+ SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
6163 -+}
6164 -+
6165 -+#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\
6166 -+ int entry;\
6167 -+ int bit_position;\
6168 -+ SQUASHFS_SWAP_START\
6169 -+ SQUASHFS_MEMSET(s, d, n * 8);\
6170 -+ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
6171 -+ 64)\
6172 -+ SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
6173 -+}
6174 -+
6175 -+#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
6176 -+ int entry;\
6177 -+ int bit_position;\
6178 -+ SQUASHFS_SWAP_START\
6179 -+ SQUASHFS_MEMSET(s, d, n * bits / 8);\
6180 -+ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
6181 -+ bits)\
6182 -+ SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
6183 -+}
6184 -+
6185 -+#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
6186 -+#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
6187 -+
6188 -+#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
6189 -+
6190 -+struct squashfs_base_inode_header_1 {
6191 -+ unsigned int inode_type:4;
6192 -+ unsigned int mode:12; /* protection */
6193 -+ unsigned int uid:4; /* index into uid table */
6194 -+ unsigned int guid:4; /* index into guid table */
6195 -+} __attribute__ ((packed));
6196 -+
6197 -+struct squashfs_ipc_inode_header_1 {
6198 -+ unsigned int inode_type:4;
6199 -+ unsigned int mode:12; /* protection */
6200 -+ unsigned int uid:4; /* index into uid table */
6201 -+ unsigned int guid:4; /* index into guid table */
6202 -+ unsigned int type:4;
6203 -+ unsigned int offset:4;
6204 -+} __attribute__ ((packed));
6205 -+
6206 -+struct squashfs_dev_inode_header_1 {
6207 -+ unsigned int inode_type:4;
6208 -+ unsigned int mode:12; /* protection */
6209 -+ unsigned int uid:4; /* index into uid table */
6210 -+ unsigned int guid:4; /* index into guid table */
6211 -+ unsigned short rdev;
6212 -+} __attribute__ ((packed));
6213 -+
6214 -+struct squashfs_symlink_inode_header_1 {
6215 -+ unsigned int inode_type:4;
6216 -+ unsigned int mode:12; /* protection */
6217 -+ unsigned int uid:4; /* index into uid table */
6218 -+ unsigned int guid:4; /* index into guid table */
6219 -+ unsigned short symlink_size;
6220 -+ char symlink[0];
6221 -+} __attribute__ ((packed));
6222 -+
6223 -+struct squashfs_reg_inode_header_1 {
6224 -+ unsigned int inode_type:4;
6225 -+ unsigned int mode:12; /* protection */
6226 -+ unsigned int uid:4; /* index into uid table */
6227 -+ unsigned int guid:4; /* index into guid table */
6228 -+ unsigned int mtime;
6229 -+ unsigned int start_block;
6230 -+ unsigned int file_size:32;
6231 -+ unsigned short block_list[0];
6232 -+} __attribute__ ((packed));
6233 -+
6234 -+struct squashfs_dir_inode_header_1 {
6235 -+ unsigned int inode_type:4;
6236 -+ unsigned int mode:12; /* protection */
6237 -+ unsigned int uid:4; /* index into uid table */
6238 -+ unsigned int guid:4; /* index into guid table */
6239 -+ unsigned int file_size:19;
6240 -+ unsigned int offset:13;
6241 -+ unsigned int mtime;
6242 -+ unsigned int start_block:24;
6243 -+} __attribute__ ((packed));
6244 -+
6245 -+union squashfs_inode_header_1 {
6246 -+ struct squashfs_base_inode_header_1 base;
6247 -+ struct squashfs_dev_inode_header_1 dev;
6248 -+ struct squashfs_symlink_inode_header_1 symlink;
6249 -+ struct squashfs_reg_inode_header_1 reg;
6250 -+ struct squashfs_dir_inode_header_1 dir;
6251 -+ struct squashfs_ipc_inode_header_1 ipc;
6252 -+};
6253 -+
6254 -+#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
6255 -+ SQUASHFS_MEMSET(s, d, n);\
6256 -+ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
6257 -+ SQUASHFS_SWAP((s)->mode, d, 4, 12);\
6258 -+ SQUASHFS_SWAP((s)->uid, d, 16, 4);\
6259 -+ SQUASHFS_SWAP((s)->guid, d, 20, 4);
6260 -+
6261 -+#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
6262 -+ SQUASHFS_SWAP_START\
6263 -+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
6264 -+}
6265 -+
6266 -+#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
6267 -+ SQUASHFS_SWAP_START\
6268 -+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
6269 -+ sizeof(struct squashfs_ipc_inode_header_1));\
6270 -+ SQUASHFS_SWAP((s)->type, d, 24, 4);\
6271 -+ SQUASHFS_SWAP((s)->offset, d, 28, 4);\
6272 -+}
6273 -+
6274 -+#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
6275 -+ SQUASHFS_SWAP_START\
6276 -+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
6277 -+ sizeof(struct squashfs_dev_inode_header_1));\
6278 -+ SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
6279 -+}
6280 -+
6281 -+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
6282 -+ SQUASHFS_SWAP_START\
6283 -+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
6284 -+ sizeof(struct squashfs_symlink_inode_header_1));\
6285 -+ SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
6286 -+}
6287 -+
6288 -+#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
6289 -+ SQUASHFS_SWAP_START\
6290 -+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
6291 -+ sizeof(struct squashfs_reg_inode_header_1));\
6292 -+ SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
6293 -+ SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
6294 -+ SQUASHFS_SWAP((s)->file_size, d, 88, 32);\
6295 -+}
6296 -+
6297 -+#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
6298 -+ SQUASHFS_SWAP_START\
6299 -+ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
6300 -+ sizeof(struct squashfs_dir_inode_header_1));\
6301 -+ SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
6302 -+ SQUASHFS_SWAP((s)->offset, d, 43, 13);\
6303 -+ SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
6304 -+ SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
6305 -+}
6306 -+
6307 -+#endif
6308 -+
6309 -+#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
6310 -+
6311 -+struct squashfs_dir_index_2 {
6312 -+ unsigned int index:27;
6313 -+ unsigned int start_block:29;
6314 -+ unsigned char size;
6315 -+ unsigned char name[0];
6316 -+} __attribute__ ((packed));
6317 -+
6318 -+struct squashfs_base_inode_header_2 {
6319 -+ unsigned int inode_type:4;
6320 -+ unsigned int mode:12; /* protection */
6321 -+ unsigned int uid:8; /* index into uid table */
6322 -+ unsigned int guid:8; /* index into guid table */
6323 -+} __attribute__ ((packed));
6324 -+
6325 -+struct squashfs_ipc_inode_header_2 {
6326 -+ unsigned int inode_type:4;
6327 -+ unsigned int mode:12; /* protection */
6328 -+ unsigned int uid:8; /* index into uid table */
6329 -+ unsigned int guid:8; /* index into guid table */
6330 -+} __attribute__ ((packed));
6331 -+
6332 -+struct squashfs_dev_inode_header_2 {
6333 -+ unsigned int inode_type:4;
6334 -+ unsigned int mode:12; /* protection */
6335 -+ unsigned int uid:8; /* index into uid table */
6336 -+ unsigned int guid:8; /* index into guid table */
6337 -+ unsigned short rdev;
6338 -+} __attribute__ ((packed));
6339 -+
6340 -+struct squashfs_symlink_inode_header_2 {
6341 -+ unsigned int inode_type:4;
6342 -+ unsigned int mode:12; /* protection */
6343 -+ unsigned int uid:8; /* index into uid table */
6344 -+ unsigned int guid:8; /* index into guid table */
6345 -+ unsigned short symlink_size;
6346 -+ char symlink[0];
6347 -+} __attribute__ ((packed));
6348 -+
6349 -+struct squashfs_reg_inode_header_2 {
6350 -+ unsigned int inode_type:4;
6351 -+ unsigned int mode:12; /* protection */
6352 -+ unsigned int uid:8; /* index into uid table */
6353 -+ unsigned int guid:8; /* index into guid table */
6354 -+ unsigned int mtime;
6355 -+ unsigned int start_block;
6356 -+ unsigned int fragment;
6357 -+ unsigned int offset;
6358 -+ unsigned int file_size:32;
6359 -+ unsigned short block_list[0];
6360 -+} __attribute__ ((packed));
6361 -+
6362 -+struct squashfs_dir_inode_header_2 {
6363 -+ unsigned int inode_type:4;
6364 -+ unsigned int mode:12; /* protection */
6365 -+ unsigned int uid:8; /* index into uid table */
6366 -+ unsigned int guid:8; /* index into guid table */
6367 -+ unsigned int file_size:19;
6368 -+ unsigned int offset:13;
6369 -+ unsigned int mtime;
6370 -+ unsigned int start_block:24;
6371 -+} __attribute__ ((packed));
6372 -+
6373 -+struct squashfs_ldir_inode_header_2 {
6374 -+ unsigned int inode_type:4;
6375 -+ unsigned int mode:12; /* protection */
6376 -+ unsigned int uid:8; /* index into uid table */
6377 -+ unsigned int guid:8; /* index into guid table */
6378 -+ unsigned int file_size:27;
6379 -+ unsigned int offset:13;
6380 -+ unsigned int mtime;
6381 -+ unsigned int start_block:24;
6382 -+ unsigned int i_count:16;
6383 -+ struct squashfs_dir_index_2 index[0];
6384 -+} __attribute__ ((packed));
6385 -+
6386 -+union squashfs_inode_header_2 {
6387 -+ struct squashfs_base_inode_header_2 base;
6388 -+ struct squashfs_dev_inode_header_2 dev;
6389 -+ struct squashfs_symlink_inode_header_2 symlink;
6390 -+ struct squashfs_reg_inode_header_2 reg;
6391 -+ struct squashfs_dir_inode_header_2 dir;
6392 -+ struct squashfs_ldir_inode_header_2 ldir;
6393 -+ struct squashfs_ipc_inode_header_2 ipc;
6394 -+};
6395 -+
6396 -+struct squashfs_dir_header_2 {
6397 -+ unsigned int count:8;
6398 -+ unsigned int start_block:24;
6399 -+} __attribute__ ((packed));
6400 -+
6401 -+struct squashfs_dir_entry_2 {
6402 -+ unsigned int offset:13;
6403 -+ unsigned int type:3;
6404 -+ unsigned int size:8;
6405 -+ char name[0];
6406 -+} __attribute__ ((packed));
6407 -+
6408 -+struct squashfs_fragment_entry_2 {
6409 -+ unsigned int start_block;
6410 -+ unsigned int size;
6411 -+} __attribute__ ((packed));
6412 -+
6413 -+#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
6414 -+ SQUASHFS_MEMSET(s, d, n);\
6415 -+ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
6416 -+ SQUASHFS_SWAP((s)->mode, d, 4, 12);\
6417 -+ SQUASHFS_SWAP((s)->uid, d, 16, 8);\
6418 -+ SQUASHFS_SWAP((s)->guid, d, 24, 8);\
6419 -+
6420 -+#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
6421 -+ SQUASHFS_SWAP_START\
6422 -+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
6423 -+}
6424 -+
6425 -+#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
6426 -+ SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
6427 -+
6428 -+#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
6429 -+ SQUASHFS_SWAP_START\
6430 -+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
6431 -+ sizeof(struct squashfs_dev_inode_header_2)); \
6432 -+ SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
6433 -+}
6434 -+
6435 -+#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
6436 -+ SQUASHFS_SWAP_START\
6437 -+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
6438 -+ sizeof(struct squashfs_symlink_inode_header_2));\
6439 -+ SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
6440 -+}
6441 -+
6442 -+#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
6443 -+ SQUASHFS_SWAP_START\
6444 -+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
6445 -+ sizeof(struct squashfs_reg_inode_header_2));\
6446 -+ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
6447 -+ SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
6448 -+ SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
6449 -+ SQUASHFS_SWAP((s)->offset, d, 128, 32);\
6450 -+ SQUASHFS_SWAP((s)->file_size, d, 160, 32);\
6451 -+}
6452 -+
6453 -+#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
6454 -+ SQUASHFS_SWAP_START\
6455 -+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
6456 -+ sizeof(struct squashfs_dir_inode_header_2));\
6457 -+ SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
6458 -+ SQUASHFS_SWAP((s)->offset, d, 51, 13);\
6459 -+ SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
6460 -+ SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
6461 -+}
6462 -+
6463 -+#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
6464 -+ SQUASHFS_SWAP_START\
6465 -+ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
6466 -+ sizeof(struct squashfs_ldir_inode_header_2));\
6467 -+ SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
6468 -+ SQUASHFS_SWAP((s)->offset, d, 59, 13);\
6469 -+ SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
6470 -+ SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
6471 -+ SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
6472 -+}
6473 -+
6474 -+#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
6475 -+ SQUASHFS_SWAP_START\
6476 -+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
6477 -+ SQUASHFS_SWAP((s)->index, d, 0, 27);\
6478 -+ SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
6479 -+ SQUASHFS_SWAP((s)->size, d, 56, 8);\
6480 -+}
6481 -+#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
6482 -+ SQUASHFS_SWAP_START\
6483 -+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
6484 -+ SQUASHFS_SWAP((s)->count, d, 0, 8);\
6485 -+ SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
6486 -+}
6487 -+
6488 -+#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
6489 -+ SQUASHFS_SWAP_START\
6490 -+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
6491 -+ SQUASHFS_SWAP((s)->offset, d, 0, 13);\
6492 -+ SQUASHFS_SWAP((s)->type, d, 13, 3);\
6493 -+ SQUASHFS_SWAP((s)->size, d, 16, 8);\
6494 -+}
6495 -+
6496 -+#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
6497 -+ SQUASHFS_SWAP_START\
6498 -+ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
6499 -+ SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
6500 -+ SQUASHFS_SWAP((s)->size, d, 32, 32);\
6501 -+}
6502 -+
6503 -+#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n)
6504 -+
6505 -+/* fragment and fragment table defines */
6506 -+#define SQUASHFS_FRAGMENT_BYTES_2(A) (A * sizeof(struct squashfs_fragment_entry_2))
6507 -+
6508 -+#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \
6509 -+ SQUASHFS_METADATA_SIZE)
6510 -+
6511 -+#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \
6512 -+ SQUASHFS_METADATA_SIZE)
6513 -+
6514 -+#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \
6515 -+ SQUASHFS_METADATA_SIZE - 1) / \
6516 -+ SQUASHFS_METADATA_SIZE)
6517 -+
6518 -+#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\
6519 -+ sizeof(int))
6520 -+
6521 -+#endif
6522 -+
6523 -+#ifdef __KERNEL__
6524 -+
6525 -+/*
6526 -+ * macros used to swap each structure entry, taking into account
6527 -+ * bitfields and different bitfield placing conventions on differing
6528 -+ * architectures
6529 -+ */
6530 -+
6531 -+#include <asm/byteorder.h>
6532 -+
6533 -+#ifdef __BIG_ENDIAN
6534 -+ /* convert from little endian to big endian */
6535 -+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
6536 -+ tbits, b_pos)
6537 -+#else
6538 -+ /* convert from big endian to little endian */
6539 -+#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
6540 -+ tbits, 64 - tbits - b_pos)
6541 -+#endif
6542 -+
6543 -+#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
6544 -+ b_pos = pos % 8;\
6545 -+ val = 0;\
6546 -+ s = (unsigned char *)p + (pos / 8);\
6547 -+ d = ((unsigned char *) &val) + 7;\
6548 -+ for(bits = 0; bits < (tbits + b_pos); bits += 8) \
6549 -+ *d-- = *s++;\
6550 -+ value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
6551 -+}
6552 -+
6553 -+#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n);
6554 -+
6555 -+#endif
6556 -+#endif
6557 -Index: linux-2.6.25-gentoo/include/linux/squashfs_fs_i.h
6558 -===================================================================
6559 ---- /dev/null
6560 -+++ linux-2.6.25-gentoo/include/linux/squashfs_fs_i.h
6561 -@@ -0,0 +1,45 @@
6562 -+#ifndef SQUASHFS_FS_I
6563 -+#define SQUASHFS_FS_I
6564 -+/*
6565 -+ * Squashfs
6566 -+ *
6567 -+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
6568 -+ * Phillip Lougher <phillip@××××××××××××××××.uk>
6569 -+ *
6570 -+ * This program is free software; you can redistribute it and/or
6571 -+ * modify it under the terms of the GNU General Public License
6572 -+ * as published by the Free Software Foundation; either version 2,
6573 -+ * or (at your option) any later version.
6574 -+ *
6575 -+ * This program is distributed in the hope that it will be useful,
6576 -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
6577 -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6578 -+ * GNU General Public License for more details.
6579 -+ *
6580 -+ * You should have received a copy of the GNU General Public License
6581 -+ * along with this program; if not, write to the Free Software
6582 -+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
6583 -+ *
6584 -+ * squashfs_fs_i.h
6585 -+ */
6586 -+
6587 -+struct squashfs_inode_info {
6588 -+ long long start_block;
6589 -+ unsigned int offset;
6590 -+ union {
6591 -+ struct {
6592 -+ long long fragment_start_block;
6593 -+ unsigned int fragment_size;
6594 -+ unsigned int fragment_offset;
6595 -+ long long block_list_start;
6596 -+ } s1;
6597 -+ struct {
6598 -+ long long directory_index_start;
6599 -+ unsigned int directory_index_offset;
6600 -+ unsigned int directory_index_count;
6601 -+ unsigned int parent_inode;
6602 -+ } s2;
6603 -+ } u;
6604 -+ struct inode vfs_inode;
6605 -+};
6606 -+#endif
6607 -Index: linux-2.6.25-gentoo/include/linux/squashfs_fs_sb.h
6608 -===================================================================
6609 ---- /dev/null
6610 -+++ linux-2.6.25-gentoo/include/linux/squashfs_fs_sb.h
6611 -@@ -0,0 +1,76 @@
6612 -+#ifndef SQUASHFS_FS_SB
6613 -+#define SQUASHFS_FS_SB
6614 -+/*
6615 -+ * Squashfs
6616 -+ *
6617 -+ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007
6618 -+ * Phillip Lougher <phillip@××××××××××××××××.uk>
6619 -+ *
6620 -+ * This program is free software; you can redistribute it and/or
6621 -+ * modify it under the terms of the GNU General Public License
6622 -+ * as published by the Free Software Foundation; either version 2,
6623 -+ * or (at your option) any later version.
6624 -+ *
6625 -+ * This program is distributed in the hope that it will be useful,
6626 -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
6627 -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6628 -+ * GNU General Public License for more details.
6629 -+ *
6630 -+ * You should have received a copy of the GNU General Public License
6631 -+ * along with this program; if not, write to the Free Software
6632 -+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
6633 -+ *
6634 -+ * squashfs_fs_sb.h
6635 -+ */
6636 -+
6637 -+#include <linux/squashfs_fs.h>
6638 -+
6639 -+struct squashfs_cache {
6640 -+ long long block;
6641 -+ int length;
6642 -+ long long next_index;
6643 -+ char *data;
6644 -+};
6645 -+
6646 -+struct squashfs_fragment_cache {
6647 -+ long long block;
6648 -+ int length;
6649 -+ unsigned int locked;
6650 -+ char *data;
6651 -+};
6652 -+
6653 -+struct squashfs_sb_info {
6654 -+ struct squashfs_super_block sblk;
6655 -+ int devblksize;
6656 -+ int devblksize_log2;
6657 -+ int swap;
6658 -+ struct squashfs_cache *block_cache;
6659 -+ struct squashfs_fragment_cache *fragment;
6660 -+ int next_cache;
6661 -+ int next_fragment;
6662 -+ int next_meta_index;
6663 -+ unsigned int *uid;
6664 -+ unsigned int *guid;
6665 -+ long long *fragment_index;
6666 -+ unsigned int *fragment_index_2;
6667 -+ char *read_page;
6668 -+ struct mutex read_data_mutex;
6669 -+ struct mutex read_page_mutex;
6670 -+ struct mutex block_cache_mutex;
6671 -+ struct mutex fragment_mutex;
6672 -+ struct mutex meta_index_mutex;
6673 -+ wait_queue_head_t waitq;
6674 -+ wait_queue_head_t fragment_wait_queue;
6675 -+ struct meta_index *meta_index;
6676 -+ z_stream stream;
6677 -+ long long *inode_lookup_table;
6678 -+ int unused_cache_blks;
6679 -+ int unused_frag_blks;
6680 -+ int (*read_inode)(struct inode *i, squashfs_inode_t \
6681 -+ inode);
6682 -+ long long (*read_blocklist)(struct inode *inode, int \
6683 -+ index, int readahead_blks, char *block_list, \
6684 -+ unsigned short **block_p, unsigned int *bsize);
6685 -+ int (*read_fragment_index_table)(struct super_block *s);
6686 -+};
6687 -+#endif
6688 -Index: linux-2.6.25-gentoo/init/do_mounts_rd.c
6689 -===================================================================
6690 ---- linux-2.6.25-gentoo.orig/init/do_mounts_rd.c
6691 -+++ linux-2.6.25-gentoo/init/do_mounts_rd.c
6692 -@@ -5,6 +5,7 @@
6693 - #include <linux/ext2_fs.h>
6694 - #include <linux/romfs_fs.h>
6695 - #include <linux/cramfs_fs.h>
6696 -+#include <linux/squashfs_fs.h>
6697 - #include <linux/initrd.h>
6698 - #include <linux/string.h>
6699 -
6700 -@@ -39,6 +40,7 @@ static int __init crd_load(int in_fd, in
6701 - * numbers could not be found.
6702 - *
6703 - * We currently check for the following magic numbers:
6704 -+ * squashfs
6705 - * minix
6706 - * ext2
6707 - * romfs
6708 -@@ -53,6 +55,7 @@ identify_ramdisk_image(int fd, int start
6709 - struct ext2_super_block *ext2sb;
6710 - struct romfs_super_block *romfsb;
6711 - struct cramfs_super *cramfsb;
6712 -+ struct squashfs_super_block *squashfsb;
6713 - int nblocks = -1;
6714 - unsigned char *buf;
6715 -
6716 -@@ -64,6 +67,7 @@ identify_ramdisk_image(int fd, int start
6717 - ext2sb = (struct ext2_super_block *) buf;
6718 - romfsb = (struct romfs_super_block *) buf;
6719 - cramfsb = (struct cramfs_super *) buf;
6720 -+ squashfsb = (struct squashfs_super_block *) buf;
6721 - memset(buf, 0xe5, size);
6722 -
6723 - /*
6724 -@@ -101,6 +105,18 @@ identify_ramdisk_image(int fd, int start
6725 - goto done;
6726 - }
6727 -
6728 -+ /* squashfs is at block zero too */
6729 -+ if (squashfsb->s_magic == SQUASHFS_MAGIC) {
6730 -+ printk(KERN_NOTICE
6731 -+ "RAMDISK: squashfs filesystem found at block %d\n",
6732 -+ start_block);
6733 -+ if (squashfsb->s_major < 3)
6734 -+ nblocks = (squashfsb->bytes_used_2+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
6735 -+ else
6736 -+ nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
6737 -+ goto done;
6738 -+ }
6739 -+
6740 - /*
6741 - * Read block 1 to test for minix and ext2 superblock
6742 - */
6743
6744 Added: genpatches-2.6/trunk/2.6.27/4300_squashfs-3.4.patch
6745 ===================================================================
6746 --- genpatches-2.6/trunk/2.6.27/4300_squashfs-3.4.patch (rev 0)
6747 +++ genpatches-2.6/trunk/2.6.27/4300_squashfs-3.4.patch 2008-10-12 18:19:38 UTC (rev 1354)
6748 @@ -0,0 +1,4218 @@
6749 +diff -x .gitignore -Nurp linux-2.6.27-rc4/fs/Kconfig linux-2.6.27-rc4-squashfs3.4/fs/Kconfig
6750 +--- linux-2.6.27-rc4/fs/Kconfig 2008-08-11 15:20:41.000000000 +0100
6751 ++++ linux-2.6.27-rc4-squashfs3.4/fs/Kconfig 2008-08-19 18:31:56.000000000 +0100
6752 +@@ -1348,6 +1348,56 @@ config CRAMFS
6753 +
6754 + If unsure, say N.
6755 +
6756 ++config SQUASHFS
6757 ++ tristate "SquashFS 3.4 - Squashed file system support"
6758 ++ select ZLIB_INFLATE
6759 ++ help
6760 ++ Saying Y here includes support for SquashFS 3.4 (a Compressed
6761 ++ Read-Only File System). Squashfs is a highly compressed read-only
6762 ++ filesystem for Linux. It uses zlib compression to compress both
6763 ++ files, inodes and directories. Inodes in the system are very small
6764 ++ and all blocks are packed to minimise data overhead. Block sizes
6765 ++ greater than 4K are supported up to a maximum of 1 Mbytes (default
6766 ++ block size 128K). SquashFS 3.3 supports 64 bit filesystems and files
6767 ++ (larger than 4GB), full uid/gid information, hard links and timestamps.
6768 ++
6769 ++ Squashfs is intended for general read-only filesystem use, for
6770 ++ archival use (i.e. in cases where a .tar.gz file may be used), and in
6771 ++ embedded systems where low overhead is needed. Further information
6772 ++ and filesystem tools are available from http://squashfs.sourceforge.net.
6773 ++
6774 ++ If you want to compile this as a module ( = code which can be
6775 ++ inserted in and removed from the running kernel whenever you want),
6776 ++ say M here and read <file:Documentation/modules.txt>. The module
6777 ++ will be called squashfs. Note that the root file system (the one
6778 ++ containing the directory /) cannot be compiled as a module.
6779 ++
6780 ++ If unsure, say N.
6781 ++
6782 ++config SQUASHFS_EMBEDDED
6783 ++
6784 ++ bool "Additional option for memory-constrained systems"
6785 ++ depends on SQUASHFS
6786 ++ default n
6787 ++ help
6788 ++ Saying Y here allows you to specify cache size.
6789 ++
6790 ++ If unsure, say N.
6791 ++
6792 ++config SQUASHFS_FRAGMENT_CACHE_SIZE
6793 ++ int "Number of fragments cached" if SQUASHFS_EMBEDDED
6794 ++ depends on SQUASHFS
6795 ++ default "3"
6796 ++ help
6797 ++ By default SquashFS caches the last 3 fragments read from
6798 ++ the filesystem. Increasing this amount may mean SquashFS
6799 ++ has to re-read fragments less often from disk, at the expense
6800 ++ of extra system memory. Decreasing this amount will mean
6801 ++ SquashFS uses less memory at the expense of extra reads from disk.
6802 ++
6803 ++ Note there must be at least one cached fragment. Anything
6804 ++ much more than three will probably not make much difference.
6805 ++
6806 + config VXFS_FS
6807 + tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"
6808 + depends on BLOCK
6809 +diff -x .gitignore -Nurp linux-2.6.27-rc4/fs/Makefile linux-2.6.27-rc4-squashfs3.4/fs/Makefile
6810 +--- linux-2.6.27-rc4/fs/Makefile 2008-08-11 15:20:41.000000000 +0100
6811 ++++ linux-2.6.27-rc4-squashfs3.4/fs/Makefile 2008-08-19 18:31:56.000000000 +0100
6812 +@@ -74,6 +74,7 @@ obj-$(CONFIG_JBD) += jbd/
6813 + obj-$(CONFIG_JBD2) += jbd2/
6814 + obj-$(CONFIG_EXT2_FS) += ext2/
6815 + obj-$(CONFIG_CRAMFS) += cramfs/
6816 ++obj-$(CONFIG_SQUASHFS) += squashfs/
6817 + obj-y += ramfs/
6818 + obj-$(CONFIG_HUGETLBFS) += hugetlbfs/
6819 + obj-$(CONFIG_CODA_FS) += coda/
6820 +diff -x .gitignore -Nurp linux-2.6.27-rc4/fs/squashfs/inode.c linux-2.6.27-rc4-squashfs3.4/fs/squashfs/inode.c
6821 +--- linux-2.6.27-rc4/fs/squashfs/inode.c 1970-01-01 01:00:00.000000000 +0100
6822 ++++ linux-2.6.27-rc4-squashfs3.4/fs/squashfs/inode.c 2008-08-26 08:25:23.000000000 +0100
6823 +@@ -0,0 +1,2173 @@
6824 ++/*
6825 ++ * Squashfs - a compressed read only filesystem for Linux
6826 ++ *
6827 ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
6828 ++ * Phillip Lougher <phillip@××××××××××××××××.uk>
6829 ++ *
6830 ++ * This program is free software; you can redistribute it and/or
6831 ++ * modify it under the terms of the GNU General Public License
6832 ++ * as published by the Free Software Foundation; either version 2,
6833 ++ * or (at your option) any later version.
6834 ++ *
6835 ++ * This program is distributed in the hope that it will be useful,
6836 ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
6837 ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6838 ++ * GNU General Public License for more details.
6839 ++ *
6840 ++ * You should have received a copy of the GNU General Public License
6841 ++ * along with this program; if not, write to the Free Software
6842 ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
6843 ++ *
6844 ++ * inode.c
6845 ++ */
6846 ++
6847 ++#include <linux/squashfs_fs.h>
6848 ++#include <linux/module.h>
6849 ++#include <linux/zlib.h>
6850 ++#include <linux/fs.h>
6851 ++#include <linux/squashfs_fs_sb.h>
6852 ++#include <linux/squashfs_fs_i.h>
6853 ++#include <linux/buffer_head.h>
6854 ++#include <linux/vfs.h>
6855 ++#include <linux/vmalloc.h>
6856 ++#include <linux/spinlock.h>
6857 ++#include <linux/smp_lock.h>
6858 ++#include <linux/exportfs.h>
6859 ++
6860 ++#include "squashfs.h"
6861 ++
6862 ++static struct dentry *squashfs_fh_to_dentry(struct super_block *s,
6863 ++ struct fid *fid, int fh_len, int fh_type);
6864 ++static struct dentry *squashfs_fh_to_parent(struct super_block *s,
6865 ++ struct fid *fid, int fh_len, int fh_type);
6866 ++static struct dentry *squashfs_get_parent(struct dentry *child);
6867 ++static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode);
6868 ++static int squashfs_statfs(struct dentry *, struct kstatfs *);
6869 ++static int squashfs_symlink_readpage(struct file *file, struct page *page);
6870 ++static long long read_blocklist(struct inode *inode, int index,
6871 ++ int readahead_blks, char *block_list,
6872 ++ unsigned short **block_p, unsigned int *bsize);
6873 ++static int squashfs_readpage(struct file *file, struct page *page);
6874 ++static int squashfs_readdir(struct file *, void *, filldir_t);
6875 ++static struct dentry *squashfs_lookup(struct inode *, struct dentry *,
6876 ++ struct nameidata *);
6877 ++static int squashfs_remount(struct super_block *s, int *flags, char *data);
6878 ++static void squashfs_put_super(struct super_block *);
6879 ++static int squashfs_get_sb(struct file_system_type *,int, const char *, void *,
6880 ++ struct vfsmount *);
6881 ++static struct inode *squashfs_alloc_inode(struct super_block *sb);
6882 ++static void squashfs_destroy_inode(struct inode *inode);
6883 ++static int init_inodecache(void);
6884 ++static void destroy_inodecache(void);
6885 ++
6886 ++static struct file_system_type squashfs_fs_type = {
6887 ++ .owner = THIS_MODULE,
6888 ++ .name = "squashfs",
6889 ++ .get_sb = squashfs_get_sb,
6890 ++ .kill_sb = kill_block_super,
6891 ++ .fs_flags = FS_REQUIRES_DEV
6892 ++};
6893 ++
6894 ++static const unsigned char squashfs_filetype_table[] = {
6895 ++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
6896 ++};
6897 ++
6898 ++static struct super_operations squashfs_super_ops = {
6899 ++ .alloc_inode = squashfs_alloc_inode,
6900 ++ .destroy_inode = squashfs_destroy_inode,
6901 ++ .statfs = squashfs_statfs,
6902 ++ .put_super = squashfs_put_super,
6903 ++ .remount_fs = squashfs_remount
6904 ++};
6905 ++
6906 ++static struct export_operations squashfs_export_ops = {
6907 ++ .fh_to_dentry = squashfs_fh_to_dentry,
6908 ++ .fh_to_parent = squashfs_fh_to_parent,
6909 ++ .get_parent = squashfs_get_parent
6910 ++};
6911 ++
6912 ++SQSH_EXTERN const struct address_space_operations squashfs_symlink_aops = {
6913 ++ .readpage = squashfs_symlink_readpage
6914 ++};
6915 ++
6916 ++SQSH_EXTERN const struct address_space_operations squashfs_aops = {
6917 ++ .readpage = squashfs_readpage
6918 ++};
6919 ++
6920 ++static const struct file_operations squashfs_dir_ops = {
6921 ++ .read = generic_read_dir,
6922 ++ .readdir = squashfs_readdir
6923 ++};
6924 ++
6925 ++SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = {
6926 ++ .lookup = squashfs_lookup
6927 ++};
6928 ++
6929 ++
6930 ++static struct buffer_head *get_block_length(struct super_block *s,
6931 ++ int *cur_index, int *offset, int *c_byte)
6932 ++{
6933 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
6934 ++ unsigned short temp;
6935 ++ struct buffer_head *bh;
6936 ++
6937 ++ if (!(bh = sb_bread(s, *cur_index)))
6938 ++ goto out;
6939 ++
6940 ++ if (msblk->devblksize - *offset == 1) {
6941 ++ if (msblk->swap)
6942 ++ ((unsigned char *) &temp)[1] = *((unsigned char *)
6943 ++ (bh->b_data + *offset));
6944 ++ else
6945 ++ ((unsigned char *) &temp)[0] = *((unsigned char *)
6946 ++ (bh->b_data + *offset));
6947 ++ brelse(bh);
6948 ++ if (!(bh = sb_bread(s, ++(*cur_index))))
6949 ++ goto out;
6950 ++ if (msblk->swap)
6951 ++ ((unsigned char *) &temp)[0] = *((unsigned char *)
6952 ++ bh->b_data);
6953 ++ else
6954 ++ ((unsigned char *) &temp)[1] = *((unsigned char *)
6955 ++ bh->b_data);
6956 ++ *c_byte = temp;
6957 ++ *offset = 1;
6958 ++ } else {
6959 ++ if (msblk->swap) {
6960 ++ ((unsigned char *) &temp)[1] = *((unsigned char *)
6961 ++ (bh->b_data + *offset));
6962 ++ ((unsigned char *) &temp)[0] = *((unsigned char *)
6963 ++ (bh->b_data + *offset + 1));
6964 ++ } else {
6965 ++ ((unsigned char *) &temp)[0] = *((unsigned char *)
6966 ++ (bh->b_data + *offset));
6967 ++ ((unsigned char *) &temp)[1] = *((unsigned char *)
6968 ++ (bh->b_data + *offset + 1));
6969 ++ }
6970 ++ *c_byte = temp;
6971 ++ *offset += 2;
6972 ++ }
6973 ++
6974 ++ if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) {
6975 ++ if (*offset == msblk->devblksize) {
6976 ++ brelse(bh);
6977 ++ if (!(bh = sb_bread(s, ++(*cur_index))))
6978 ++ goto out;
6979 ++ *offset = 0;
6980 ++ }
6981 ++ if (*((unsigned char *) (bh->b_data + *offset)) !=
6982 ++ SQUASHFS_MARKER_BYTE) {
6983 ++ ERROR("Metadata block marker corrupt @ %x\n",
6984 ++ *cur_index);
6985 ++ brelse(bh);
6986 ++ goto out;
6987 ++ }
6988 ++ (*offset)++;
6989 ++ }
6990 ++ return bh;
6991 ++
6992 ++out:
6993 ++ return NULL;
6994 ++}
6995 ++
6996 ++
6997 ++SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
6998 ++ long long index, unsigned int length,
6999 ++ long long *next_index, int srclength)
7000 ++{
7001 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
7002 ++ struct squashfs_super_block *sblk = &msblk->sblk;
7003 ++ struct buffer_head **bh;
7004 ++ unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
7005 ++ unsigned int cur_index = index >> msblk->devblksize_log2;
7006 ++ int bytes, avail_bytes, b = 0, k = 0;
7007 ++ unsigned int compressed;
7008 ++ unsigned int c_byte = length;
7009 ++
7010 ++ bh = kmalloc(((sblk->block_size >> msblk->devblksize_log2) + 1) *
7011 ++ sizeof(struct buffer_head *), GFP_KERNEL);
7012 ++ if (bh == NULL)
7013 ++ goto read_failure;
7014 ++
7015 ++ if (c_byte) {
7016 ++ bytes = -offset;
7017 ++ compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
7018 ++ c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
7019 ++
7020 ++ TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", index,
7021 ++ compressed ? "" : "un", (unsigned int) c_byte, srclength);
7022 ++
7023 ++ if (c_byte > srclength || index < 0 || (index + c_byte) > sblk->bytes_used)
7024 ++ goto read_failure;
7025 ++
7026 ++ for (b = 0; bytes < (int) c_byte; b++, cur_index++) {
7027 ++ bh[b] = sb_getblk(s, cur_index);
7028 ++ if (bh[b] == NULL)
7029 ++ goto block_release;
7030 ++ bytes += msblk->devblksize;
7031 ++ }
7032 ++ ll_rw_block(READ, b, bh);
7033 ++ } else {
7034 ++ if (index < 0 || (index + 2) > sblk->bytes_used)
7035 ++ goto read_failure;
7036 ++
7037 ++ bh[0] = get_block_length(s, &cur_index, &offset, &c_byte);
7038 ++ if (bh[0] == NULL)
7039 ++ goto read_failure;
7040 ++ b = 1;
7041 ++
7042 ++ bytes = msblk->devblksize - offset;
7043 ++ compressed = SQUASHFS_COMPRESSED(c_byte);
7044 ++ c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
7045 ++
7046 ++ TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
7047 ++ ? "" : "un", (unsigned int) c_byte);
7048 ++
7049 ++ if (c_byte > srclength || (index + c_byte) > sblk->bytes_used)
7050 ++ goto block_release;
7051 ++
7052 ++ for (; bytes < c_byte; b++) {
7053 ++ bh[b] = sb_getblk(s, ++cur_index);
7054 ++ if (bh[b] == NULL)
7055 ++ goto block_release;
7056 ++ bytes += msblk->devblksize;
7057 ++ }
7058 ++ ll_rw_block(READ, b - 1, bh + 1);
7059 ++ }
7060 ++
7061 ++ if (compressed) {
7062 ++ int zlib_err = 0;
7063 ++
7064 ++ /*
7065 ++ * uncompress block
7066 ++ */
7067 ++
7068 ++ mutex_lock(&msblk->read_data_mutex);
7069 ++
7070 ++ msblk->stream.next_out = buffer;
7071 ++ msblk->stream.avail_out = srclength;
7072 ++
7073 ++ for (bytes = 0; k < b; k++) {
7074 ++ avail_bytes = min(c_byte - bytes, msblk->devblksize - offset);
7075 ++
7076 ++ wait_on_buffer(bh[k]);
7077 ++ if (!buffer_uptodate(bh[k]))
7078 ++ goto release_mutex;
7079 ++
7080 ++ msblk->stream.next_in = bh[k]->b_data + offset;
7081 ++ msblk->stream.avail_in = avail_bytes;
7082 ++
7083 ++ if (k == 0) {
7084 ++ zlib_err = zlib_inflateInit(&msblk->stream);
7085 ++ if (zlib_err != Z_OK) {
7086 ++ ERROR("zlib_inflateInit returned unexpected result 0x%x,"
7087 ++ " srclength %d\n", zlib_err, srclength);
7088 ++ goto release_mutex;
7089 ++ }
7090 ++
7091 ++ if (avail_bytes == 0) {
7092 ++ offset = 0;
7093 ++ brelse(bh[k]);
7094 ++ continue;
7095 ++ }
7096 ++ }
7097 ++
7098 ++ zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH);
7099 ++ if (zlib_err != Z_OK && zlib_err != Z_STREAM_END) {
7100 ++ ERROR("zlib_inflate returned unexpected result 0x%x,"
7101 ++ " srclength %d, avail_in %d, avail_out %d\n", zlib_err,
7102 ++ srclength, msblk->stream.avail_in, msblk->stream.avail_out);
7103 ++ goto release_mutex;
7104 ++ }
7105 ++
7106 ++ bytes += avail_bytes;
7107 ++ offset = 0;
7108 ++ brelse(bh[k]);
7109 ++ }
7110 ++
7111 ++ if (zlib_err != Z_STREAM_END)
7112 ++ goto release_mutex;
7113 ++
7114 ++ zlib_err = zlib_inflateEnd(&msblk->stream);
7115 ++ if (zlib_err != Z_OK) {
7116 ++ ERROR("zlib_inflateEnd returned unexpected result 0x%x,"
7117 ++ " srclength %d\n", zlib_err, srclength);
7118 ++ goto release_mutex;
7119 ++ }
7120 ++ bytes = msblk->stream.total_out;
7121 ++ mutex_unlock(&msblk->read_data_mutex);
7122 ++ } else {
7123 ++ int i;
7124 ++
7125 ++ for(i = 0; i < b; i++) {
7126 ++ wait_on_buffer(bh[i]);
7127 ++ if (!buffer_uptodate(bh[i]))
7128 ++ goto block_release;
7129 ++ }
7130 ++
7131 ++ for (bytes = 0; k < b; k++) {
7132 ++ avail_bytes = min(c_byte - bytes, msblk->devblksize - offset);
7133 ++
7134 ++ memcpy(buffer + bytes, bh[k]->b_data + offset, avail_bytes);
7135 ++ bytes += avail_bytes;
7136 ++ offset = 0;
7137 ++ brelse(bh[k]);
7138 ++ }
7139 ++ }
7140 ++
7141 ++ if (next_index)
7142 ++ *next_index = index + c_byte + (length ? 0 :
7143 ++ (SQUASHFS_CHECK_DATA(msblk->sblk.flags) ? 3 : 2));
7144 ++
7145 ++ kfree(bh);
7146 ++ return bytes;
7147 ++
7148 ++release_mutex:
7149 ++ mutex_unlock(&msblk->read_data_mutex);
7150 ++
7151 ++block_release:
7152 ++ for (; k < b; k++)
7153 ++ brelse(bh[k]);
7154 ++
7155 ++read_failure:
7156 ++ ERROR("sb_bread failed reading block 0x%x\n", cur_index);
7157 ++ kfree(bh);
7158 ++ return 0;
7159 ++}
7160 ++
7161 ++
7162 ++static struct squashfs_cache_entry *squashfs_cache_get(struct super_block *s,
7163 ++ struct squashfs_cache *cache, long long block, int length)
7164 ++{
7165 ++ int i, n;
7166 ++ struct squashfs_cache_entry *entry;
7167 ++
7168 ++ spin_lock(&cache->lock);
7169 ++
7170 ++ while (1) {
7171 ++ for (i = 0; i < cache->entries && cache->entry[i].block != block; i++);
7172 ++
7173 ++ if (i == cache->entries) {
7174 ++ if (cache->unused_blks == 0) {
7175 ++ cache->waiting ++;
7176 ++ spin_unlock(&cache->lock);
7177 ++ wait_event(cache->wait_queue, cache->unused_blks);
7178 ++ spin_lock(&cache->lock);
7179 ++ cache->waiting --;
7180 ++ continue;
7181 ++ }
7182 ++
7183 ++ i = cache->next_blk;
7184 ++ for (n = 0; n < cache->entries; n++) {
7185 ++ if (cache->entry[i].locked == 0)
7186 ++ break;
7187 ++ i = (i + 1) % cache->entries;
7188 ++ }
7189 ++
7190 ++ cache->next_blk = (i + 1) % cache->entries;
7191 ++ entry = &cache->entry[i];
7192 ++
7193 ++ cache->unused_blks --;
7194 ++ entry->block = block;
7195 ++ entry->locked = 1;
7196 ++ entry->pending = 1;
7197 ++ entry->waiting = 0;
7198 ++ entry->error = 0;
7199 ++ spin_unlock(&cache->lock);
7200 ++
7201 ++ entry->length = squashfs_read_data(s, entry->data,
7202 ++ block, length, &entry->next_index, cache->block_size);
7203 ++
7204 ++ spin_lock(&cache->lock);
7205 ++
7206 ++ if (entry->length == 0)
7207 ++ entry->error = 1;
7208 ++
7209 ++ entry->pending = 0;
7210 ++ spin_unlock(&cache->lock);
7211 ++ if (entry->waiting)
7212 ++ wake_up_all(&entry->wait_queue);
7213 ++ goto out;
7214 ++ }
7215 ++
7216 ++ entry = &cache->entry[i];
7217 ++ if (entry->locked == 0)
7218 ++ cache->unused_blks --;
7219 ++ entry->locked++;
7220 ++
7221 ++ if (entry->pending) {
7222 ++ entry->waiting ++;
7223 ++ spin_unlock(&cache->lock);
7224 ++ wait_event(entry->wait_queue, !entry->pending);
7225 ++ goto out;
7226 ++ }
7227 ++
7228 ++ spin_unlock(&cache->lock);
7229 ++ goto out;
7230 ++ }
7231 ++
7232 ++out:
7233 ++ TRACE("Got %s %d, start block %lld, locked %d, error %d\n", i,
7234 ++ cache->name, entry->block, entry->locked, entry->error);
7235 ++ if (entry->error)
7236 ++ ERROR("Unable to read %s cache entry [%llx]\n", cache->name, block);
7237 ++ return entry;
7238 ++}
7239 ++
7240 ++
7241 ++static void squashfs_cache_put(struct squashfs_cache *cache,
7242 ++ struct squashfs_cache_entry *entry)
7243 ++{
7244 ++ spin_lock(&cache->lock);
7245 ++ entry->locked --;
7246 ++ if (entry->locked == 0) {
7247 ++ cache->unused_blks ++;
7248 ++ spin_unlock(&cache->lock);
7249 ++ if (cache->waiting)
7250 ++ wake_up(&cache->wait_queue);
7251 ++ } else
7252 ++ spin_unlock(&cache->lock);
7253 ++}
7254 ++
7255 ++
7256 ++static void squashfs_cache_delete(struct squashfs_cache *cache)
7257 ++{
7258 ++ int i;
7259 ++
7260 ++ if (cache == NULL)
7261 ++ return;
7262 ++
7263 ++ for (i = 0; i < cache->entries; i++)
7264 ++ if (cache->entry[i].data) {
7265 ++ if (cache->use_vmalloc)
7266 ++ vfree(cache->entry[i].data);
7267 ++ else
7268 ++ kfree(cache->entry[i].data);
7269 ++ }
7270 ++
7271 ++ kfree(cache);
7272 ++}
7273 ++
7274 ++
7275 ++static struct squashfs_cache *squashfs_cache_init(char *name, int entries,
7276 ++ int block_size, int use_vmalloc)
7277 ++{
7278 ++ int i;
7279 ++ struct squashfs_cache *cache = kzalloc(sizeof(struct squashfs_cache) +
7280 ++ entries * sizeof(struct squashfs_cache_entry), GFP_KERNEL);
7281 ++ if (cache == NULL) {
7282 ++ ERROR("Failed to allocate %s cache\n", name);
7283 ++ goto failed;
7284 ++ }
7285 ++
7286 ++ cache->next_blk = 0;
7287 ++ cache->unused_blks = entries;
7288 ++ cache->entries = entries;
7289 ++ cache->block_size = block_size;
7290 ++ cache->use_vmalloc = use_vmalloc;
7291 ++ cache->name = name;
7292 ++ cache->waiting = 0;
7293 ++ spin_lock_init(&cache->lock);
7294 ++ init_waitqueue_head(&cache->wait_queue);
7295 ++
7296 ++ for (i = 0; i < entries; i++) {
7297 ++ init_waitqueue_head(&cache->entry[i].wait_queue);
7298 ++ cache->entry[i].block = SQUASHFS_INVALID_BLK;
7299 ++ cache->entry[i].data = use_vmalloc ? vmalloc(block_size) :
7300 ++ kmalloc(block_size, GFP_KERNEL);
7301 ++ if (cache->entry[i].data == NULL) {
7302 ++ ERROR("Failed to allocate %s cache entry\n", name);
7303 ++ goto cleanup;
7304 ++ }
7305 ++ }
7306 ++
7307 ++ return cache;
7308 ++
7309 ++cleanup:
7310 ++ squashfs_cache_delete(cache);
7311 ++failed:
7312 ++ return NULL;
7313 ++}
7314 ++
7315 ++
7316 ++SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, void *buffer,
7317 ++ long long block, unsigned int offset,
7318 ++ int length, long long *next_block,
7319 ++ unsigned int *next_offset)
7320 ++{
7321 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
7322 ++ int bytes, return_length = length;
7323 ++ struct squashfs_cache_entry *entry;
7324 ++
7325 ++ TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
7326 ++
7327 ++ while (1) {
7328 ++ entry = squashfs_cache_get(s, msblk->block_cache, block, 0);
7329 ++ bytes = entry->length - offset;
7330 ++
7331 ++ if (entry->error || bytes < 1) {
7332 ++ return_length = 0;
7333 ++ goto finish;
7334 ++ } else if (bytes >= length) {
7335 ++ if (buffer)
7336 ++ memcpy(buffer, entry->data + offset, length);
7337 ++ if (entry->length - offset == length) {
7338 ++ *next_block = entry->next_index;
7339 ++ *next_offset = 0;
7340 ++ } else {
7341 ++ *next_block = block;
7342 ++ *next_offset = offset + length;
7343 ++ }
7344 ++ goto finish;
7345 ++ } else {
7346 ++ if (buffer) {
7347 ++ memcpy(buffer, entry->data + offset, bytes);
7348 ++ buffer = (char *) buffer + bytes;
7349 ++ }
7350 ++ block = entry->next_index;
7351 ++ squashfs_cache_put(msblk->block_cache, entry);
7352 ++ length -= bytes;
7353 ++ offset = 0;
7354 ++ }
7355 ++ }
7356 ++
7357 ++finish:
7358 ++ squashfs_cache_put(msblk->block_cache, entry);
7359 ++ return return_length;
7360 ++}
7361 ++
7362 ++
7363 ++static int get_fragment_location(struct super_block *s, unsigned int fragment,
7364 ++ long long *fragment_start_block,
7365 ++ unsigned int *fragment_size)
7366 ++{
7367 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
7368 ++ long long start_block =
7369 ++ msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];
7370 ++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
7371 ++ struct squashfs_fragment_entry fragment_entry;
7372 ++
7373 ++ if (msblk->swap) {
7374 ++ struct squashfs_fragment_entry sfragment_entry;
7375 ++
7376 ++ if (!squashfs_get_cached_block(s, &sfragment_entry, start_block, offset,
7377 ++ sizeof(sfragment_entry), &start_block, &offset))
7378 ++ goto out;
7379 ++ SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);
7380 ++ } else
7381 ++ if (!squashfs_get_cached_block(s, &fragment_entry, start_block, offset,
7382 ++ sizeof(fragment_entry), &start_block, &offset))
7383 ++ goto out;
7384 ++
7385 ++ *fragment_start_block = fragment_entry.start_block;
7386 ++ *fragment_size = fragment_entry.size;
7387 ++
7388 ++ return 1;
7389 ++
7390 ++out:
7391 ++ return 0;
7392 ++}
7393 ++
7394 ++
7395 ++SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk,
7396 ++ struct squashfs_cache_entry *fragment)
7397 ++{
7398 ++ squashfs_cache_put(msblk->fragment_cache, fragment);
7399 ++}
7400 ++
7401 ++
7402 ++SQSH_EXTERN
7403 ++struct squashfs_cache_entry *get_cached_fragment(struct super_block *s,
7404 ++ long long start_block, int length)
7405 ++{
7406 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
7407 ++
7408 ++ return squashfs_cache_get(s, msblk->fragment_cache, start_block, length);
7409 ++}
7410 ++
7411 ++
7412 ++static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i,
7413 ++ struct squashfs_base_inode_header *inodeb)
7414 ++{
7415 ++ i->i_ino = inodeb->inode_number;
7416 ++ i->i_mtime.tv_sec = inodeb->mtime;
7417 ++ i->i_atime.tv_sec = inodeb->mtime;
7418 ++ i->i_ctime.tv_sec = inodeb->mtime;
7419 ++ i->i_uid = msblk->uid[inodeb->uid];
7420 ++ i->i_mode = inodeb->mode;
7421 ++ i->i_size = 0;
7422 ++
7423 ++ if (inodeb->guid == SQUASHFS_GUIDS)
7424 ++ i->i_gid = i->i_uid;
7425 ++ else
7426 ++ i->i_gid = msblk->guid[inodeb->guid];
7427 ++}
7428 ++
7429 ++
7430 ++static squashfs_inode_t squashfs_inode_lookup(struct super_block *s, int ino)
7431 ++{
7432 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
7433 ++ long long start = msblk->inode_lookup_table[SQUASHFS_LOOKUP_BLOCK(ino - 1)];
7434 ++ int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino - 1);
7435 ++ squashfs_inode_t inode;
7436 ++
7437 ++ TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino);
7438 ++
7439 ++ if (msblk->swap) {
7440 ++ squashfs_inode_t sinode;
7441 ++
7442 ++ if (!squashfs_get_cached_block(s, &sinode, start, offset,
7443 ++ sizeof(sinode), &start, &offset))
7444 ++ goto out;
7445 ++ SQUASHFS_SWAP_INODE_T((&inode), &sinode);
7446 ++ } else if (!squashfs_get_cached_block(s, &inode, start, offset,
7447 ++ sizeof(inode), &start, &offset))
7448 ++ goto out;
7449 ++
7450 ++ TRACE("squashfs_inode_lookup, inode = 0x%llx\n", inode);
7451 ++
7452 ++ return inode;
7453 ++
7454 ++out:
7455 ++ return SQUASHFS_INVALID_BLK;
7456 ++}
7457 ++
7458 ++
7459 ++
7460 ++static struct dentry *squashfs_export_iget(struct super_block *s,
7461 ++ unsigned int inode_number)
7462 ++{
7463 ++ squashfs_inode_t inode;
7464 ++ struct inode *i;
7465 ++ struct dentry *dentry;
7466 ++
7467 ++ TRACE("Entered squashfs_export_iget\n");
7468 ++
7469 ++ inode = squashfs_inode_lookup(s, inode_number);
7470 ++ if(inode == SQUASHFS_INVALID_BLK) {
7471 ++ dentry = ERR_PTR(-ENOENT);
7472 ++ goto failure;
7473 ++ }
7474 ++
7475 ++ i = squashfs_iget(s, inode, inode_number);
7476 ++ if(i == NULL) {
7477 ++ dentry = ERR_PTR(-EACCES);
7478 ++ goto failure;
7479 ++ }
7480 ++
7481 ++ dentry = d_alloc_anon(i);
7482 ++ if (dentry == NULL) {
7483 ++ iput(i);
7484 ++ dentry = ERR_PTR(-ENOMEM);
7485 ++ }
7486 ++
7487 ++failure:
7488 ++ return dentry;
7489 ++}
7490 ++
7491 ++
7492 ++static struct dentry *squashfs_fh_to_dentry(struct super_block *s,
7493 ++ struct fid *fid, int fh_len, int fh_type)
7494 ++{
7495 ++ if((fh_type != FILEID_INO32_GEN && fh_type != FILEID_INO32_GEN_PARENT) ||
7496 ++ fh_len < 2)
7497 ++ return NULL;
7498 ++
7499 ++ return squashfs_export_iget(s, fid->i32.ino);
7500 ++}
7501 ++
7502 ++
7503 ++static struct dentry *squashfs_fh_to_parent(struct super_block *s,
7504 ++ struct fid *fid, int fh_len, int fh_type)
7505 ++{
7506 ++ if(fh_type != FILEID_INO32_GEN_PARENT || fh_len < 4)
7507 ++ return NULL;
7508 ++
7509 ++ return squashfs_export_iget(s, fid->i32.parent_ino);
7510 ++}
7511 ++
7512 ++
7513 ++static struct dentry *squashfs_get_parent(struct dentry *child)
7514 ++{
7515 ++ struct inode *i = child->d_inode;
7516 ++
7517 ++ TRACE("Entered squashfs_get_parent\n");
7518 ++
7519 ++ return squashfs_export_iget(i->i_sb, SQUASHFS_I(i)->u.s2.parent_inode);
7520 ++}
7521 ++
7522 ++
7523 ++SQSH_EXTERN struct inode *squashfs_iget(struct super_block *s,
7524 ++ squashfs_inode_t inode, unsigned int inode_number)
7525 ++{
7526 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
7527 ++ struct inode *i = iget_locked(s, inode_number);
7528 ++
7529 ++ TRACE("Entered squashfs_iget\n");
7530 ++
7531 ++ if(i && (i->i_state & I_NEW)) {
7532 ++ (msblk->read_inode)(i, inode);
7533 ++ unlock_new_inode(i);
7534 ++ }
7535 ++
7536 ++ return i;
7537 ++}
7538 ++
7539 ++
7540 ++static int squashfs_read_inode(struct inode *i, squashfs_inode_t inode)
7541 ++{
7542 ++ struct super_block *s = i->i_sb;
7543 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
7544 ++ struct squashfs_super_block *sblk = &msblk->sblk;
7545 ++ long long block = SQUASHFS_INODE_BLK(inode) + sblk->inode_table_start;
7546 ++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
7547 ++ long long next_block;
7548 ++ unsigned int next_offset;
7549 ++ union squashfs_inode_header id, sid;
7550 ++ struct squashfs_base_inode_header *inodeb = &id.base, *sinodeb = &sid.base;
7551 ++
7552 ++ TRACE("Entered squashfs_read_inode\n");
7553 ++
7554 ++ if (msblk->swap) {
7555 ++ if (!squashfs_get_cached_block(s, sinodeb, block, offset,
7556 ++ sizeof(*sinodeb), &next_block, &next_offset))
7557 ++ goto failed_read;
7558 ++ SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb, sizeof(*sinodeb));
7559 ++ } else
7560 ++ if (!squashfs_get_cached_block(s, inodeb, block, offset,
7561 ++ sizeof(*inodeb), &next_block, &next_offset))
7562 ++ goto failed_read;
7563 ++
7564 ++ squashfs_new_inode(msblk, i, inodeb);
7565 ++
7566 ++ switch(inodeb->inode_type) {
7567 ++ case SQUASHFS_FILE_TYPE: {
7568 ++ unsigned int frag_size;
7569 ++ long long frag_blk;
7570 ++ struct squashfs_reg_inode_header *inodep = &id.reg;
7571 ++ struct squashfs_reg_inode_header *sinodep = &sid.reg;
7572 ++
7573 ++ if (msblk->swap) {
7574 ++ if (!squashfs_get_cached_block(s, sinodep, block, offset,
7575 ++ sizeof(*sinodep), &next_block, &next_offset))
7576 ++ goto failed_read;
7577 ++ SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);
7578 ++ } else
7579 ++ if (!squashfs_get_cached_block(s, inodep, block, offset,
7580 ++ sizeof(*inodep), &next_block, &next_offset))
7581 ++ goto failed_read;
7582 ++
7583 ++ frag_blk = SQUASHFS_INVALID_BLK;
7584 ++
7585 ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG)
7586 ++ if(!get_fragment_location(s, inodep->fragment, &frag_blk,
7587 ++ &frag_size))
7588 ++ goto failed_read;
7589 ++
7590 ++ i->i_nlink = 1;
7591 ++ i->i_size = inodep->file_size;
7592 ++ i->i_fop = &generic_ro_fops;
7593 ++ i->i_mode |= S_IFREG;
7594 ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
7595 ++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
7596 ++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
7597 ++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
7598 ++ SQUASHFS_I(i)->start_block = inodep->start_block;
7599 ++ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
7600 ++ SQUASHFS_I(i)->offset = next_offset;
7601 ++ i->i_data.a_ops = &squashfs_aops;
7602 ++
7603 ++ TRACE("File inode %x:%x, start_block %llx, "
7604 ++ "block_list_start %llx, offset %x\n",
7605 ++ SQUASHFS_INODE_BLK(inode), offset,
7606 ++ inodep->start_block, next_block,
7607 ++ next_offset);
7608 ++ break;
7609 ++ }
7610 ++ case SQUASHFS_LREG_TYPE: {
7611 ++ unsigned int frag_size;
7612 ++ long long frag_blk;
7613 ++ struct squashfs_lreg_inode_header *inodep = &id.lreg;
7614 ++ struct squashfs_lreg_inode_header *sinodep = &sid.lreg;
7615 ++
7616 ++ if (msblk->swap) {
7617 ++ if (!squashfs_get_cached_block(s, sinodep, block, offset,
7618 ++ sizeof(*sinodep), &next_block, &next_offset))
7619 ++ goto failed_read;
7620 ++ SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);
7621 ++ } else
7622 ++ if (!squashfs_get_cached_block(s, inodep, block, offset,
7623 ++ sizeof(*inodep), &next_block, &next_offset))
7624 ++ goto failed_read;
7625 ++
7626 ++ frag_blk = SQUASHFS_INVALID_BLK;
7627 ++
7628 ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG)
7629 ++ if (!get_fragment_location(s, inodep->fragment, &frag_blk,
7630 ++ &frag_size))
7631 ++ goto failed_read;
7632 ++
7633 ++ i->i_nlink = inodep->nlink;
7634 ++ i->i_size = inodep->file_size;
7635 ++ i->i_fop = &generic_ro_fops;
7636 ++ i->i_mode |= S_IFREG;
7637 ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
7638 ++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
7639 ++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
7640 ++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
7641 ++ SQUASHFS_I(i)->start_block = inodep->start_block;
7642 ++ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
7643 ++ SQUASHFS_I(i)->offset = next_offset;
7644 ++ i->i_data.a_ops = &squashfs_aops;
7645 ++
7646 ++ TRACE("File inode %x:%x, start_block %llx, "
7647 ++ "block_list_start %llx, offset %x\n",
7648 ++ SQUASHFS_INODE_BLK(inode), offset,
7649 ++ inodep->start_block, next_block,
7650 ++ next_offset);
7651 ++ break;
7652 ++ }
7653 ++ case SQUASHFS_DIR_TYPE: {
7654 ++ struct squashfs_dir_inode_header *inodep = &id.dir;
7655 ++ struct squashfs_dir_inode_header *sinodep = &sid.dir;
7656 ++
7657 ++ if (msblk->swap) {
7658 ++ if (!squashfs_get_cached_block(s, sinodep, block, offset,
7659 ++ sizeof(*sinodep), &next_block, &next_offset))
7660 ++ goto failed_read;
7661 ++ SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);
7662 ++ } else
7663 ++ if (!squashfs_get_cached_block(s, inodep, block, offset,
7664 ++ sizeof(*inodep), &next_block, &next_offset))
7665 ++ goto failed_read;
7666 ++
7667 ++ i->i_nlink = inodep->nlink;
7668 ++ i->i_size = inodep->file_size;
7669 ++ i->i_op = &squashfs_dir_inode_ops;
7670 ++ i->i_fop = &squashfs_dir_ops;
7671 ++ i->i_mode |= S_IFDIR;
7672 ++ SQUASHFS_I(i)->start_block = inodep->start_block;
7673 ++ SQUASHFS_I(i)->offset = inodep->offset;
7674 ++ SQUASHFS_I(i)->u.s2.directory_index_count = 0;
7675 ++ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
7676 ++
7677 ++ TRACE("Directory inode %x:%x, start_block %x, offset "
7678 ++ "%x\n", SQUASHFS_INODE_BLK(inode),
7679 ++ offset, inodep->start_block,
7680 ++ inodep->offset);
7681 ++ break;
7682 ++ }
7683 ++ case SQUASHFS_LDIR_TYPE: {
7684 ++ struct squashfs_ldir_inode_header *inodep = &id.ldir;
7685 ++ struct squashfs_ldir_inode_header *sinodep = &sid.ldir;
7686 ++
7687 ++ if (msblk->swap) {
7688 ++ if (!squashfs_get_cached_block(s, sinodep, block, offset,
7689 ++ sizeof(*sinodep), &next_block, &next_offset))
7690 ++ goto failed_read;
7691 ++ SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep, sinodep);
7692 ++ } else
7693 ++ if (!squashfs_get_cached_block(s, inodep, block, offset,
7694 ++ sizeof(*inodep), &next_block, &next_offset))
7695 ++ goto failed_read;
7696 ++
7697 ++ i->i_nlink = inodep->nlink;
7698 ++ i->i_size = inodep->file_size;
7699 ++ i->i_op = &squashfs_dir_inode_ops;
7700 ++ i->i_fop = &squashfs_dir_ops;
7701 ++ i->i_mode |= S_IFDIR;
7702 ++ SQUASHFS_I(i)->start_block = inodep->start_block;
7703 ++ SQUASHFS_I(i)->offset = inodep->offset;
7704 ++ SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
7705 ++ SQUASHFS_I(i)->u.s2.directory_index_offset = next_offset;
7706 ++ SQUASHFS_I(i)->u.s2.directory_index_count = inodep->i_count;
7707 ++ SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
7708 ++
7709 ++ TRACE("Long directory inode %x:%x, start_block %x, offset %x\n",
7710 ++ SQUASHFS_INODE_BLK(inode), offset,
7711 ++ inodep->start_block, inodep->offset);
7712 ++ break;
7713 ++ }
7714 ++ case SQUASHFS_SYMLINK_TYPE: {
7715 ++ struct squashfs_symlink_inode_header *inodep = &id.symlink;
7716 ++ struct squashfs_symlink_inode_header *sinodep = &sid.symlink;
7717 ++
7718 ++ if (msblk->swap) {
7719 ++ if (!squashfs_get_cached_block(s, sinodep, block, offset,
7720 ++ sizeof(*sinodep), &next_block, &next_offset))
7721 ++ goto failed_read;
7722 ++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep, sinodep);
7723 ++ } else
7724 ++ if (!squashfs_get_cached_block(s, inodep, block, offset,
7725 ++ sizeof(*inodep), &next_block, &next_offset))
7726 ++ goto failed_read;
7727 ++
7728 ++ i->i_nlink = inodep->nlink;
7729 ++ i->i_size = inodep->symlink_size;
7730 ++ i->i_op = &page_symlink_inode_operations;
7731 ++ i->i_data.a_ops = &squashfs_symlink_aops;
7732 ++ i->i_mode |= S_IFLNK;
7733 ++ SQUASHFS_I(i)->start_block = next_block;
7734 ++ SQUASHFS_I(i)->offset = next_offset;
7735 ++
7736 ++ TRACE("Symbolic link inode %x:%x, start_block %llx, offset %x\n",
7737 ++ SQUASHFS_INODE_BLK(inode), offset,
7738 ++ next_block, next_offset);
7739 ++ break;
7740 ++ }
7741 ++ case SQUASHFS_BLKDEV_TYPE:
7742 ++ case SQUASHFS_CHRDEV_TYPE: {
7743 ++ struct squashfs_dev_inode_header *inodep = &id.dev;
7744 ++ struct squashfs_dev_inode_header *sinodep = &sid.dev;
7745 ++
7746 ++ if (msblk->swap) {
7747 ++ if (!squashfs_get_cached_block(s, sinodep, block, offset,
7748 ++ sizeof(*sinodep), &next_block, &next_offset))
7749 ++ goto failed_read;
7750 ++ SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);
7751 ++ } else
7752 ++ if (!squashfs_get_cached_block(s, inodep, block, offset,
7753 ++ sizeof(*inodep), &next_block, &next_offset))
7754 ++ goto failed_read;
7755 ++
7756 ++ i->i_nlink = inodep->nlink;
7757 ++ i->i_mode |= (inodeb->inode_type == SQUASHFS_CHRDEV_TYPE) ?
7758 ++ S_IFCHR : S_IFBLK;
7759 ++ init_special_inode(i, i->i_mode, old_decode_dev(inodep->rdev));
7760 ++
7761 ++ TRACE("Device inode %x:%x, rdev %x\n",
7762 ++ SQUASHFS_INODE_BLK(inode), offset, inodep->rdev);
7763 ++ break;
7764 ++ }
7765 ++ case SQUASHFS_FIFO_TYPE:
7766 ++ case SQUASHFS_SOCKET_TYPE: {
7767 ++ struct squashfs_ipc_inode_header *inodep = &id.ipc;
7768 ++ struct squashfs_ipc_inode_header *sinodep = &sid.ipc;
7769 ++
7770 ++ if (msblk->swap) {
7771 ++ if (!squashfs_get_cached_block(s, sinodep, block, offset,
7772 ++ sizeof(*sinodep), &next_block, &next_offset))
7773 ++ goto failed_read;
7774 ++ SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);
7775 ++ } else
7776 ++ if (!squashfs_get_cached_block(s, inodep, block, offset,
7777 ++ sizeof(*inodep), &next_block, &next_offset))
7778 ++ goto failed_read;
7779 ++
7780 ++ i->i_nlink = inodep->nlink;
7781 ++ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
7782 ++ ? S_IFIFO : S_IFSOCK;
7783 ++ init_special_inode(i, i->i_mode, 0);
7784 ++ break;
7785 ++ }
7786 ++ default:
7787 ++ ERROR("Unknown inode type %d in squashfs_iget!\n",
7788 ++ inodeb->inode_type);
7789 ++ goto failed_read1;
7790 ++ }
7791 ++
7792 ++ return 1;
7793 ++
7794 ++failed_read:
7795 ++ ERROR("Unable to read inode [%llx:%x]\n", block, offset);
7796 ++
7797 ++failed_read1:
7798 ++ make_bad_inode(i);
7799 ++ return 0;
7800 ++}
7801 ++
7802 ++
7803 ++static int read_inode_lookup_table(struct super_block *s)
7804 ++{
7805 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
7806 ++ struct squashfs_super_block *sblk = &msblk->sblk;
7807 ++ unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(sblk->inodes);
7808 ++
7809 ++ TRACE("In read_inode_lookup_table, length %d\n", length);
7810 ++
7811 ++ /* Allocate inode lookup table */
7812 ++ msblk->inode_lookup_table = kmalloc(length, GFP_KERNEL);
7813 ++ if (msblk->inode_lookup_table == NULL) {
7814 ++ ERROR("Failed to allocate inode lookup table\n");
7815 ++ return 0;
7816 ++ }
7817 ++
7818 ++ if (!squashfs_read_data(s, (char *) msblk->inode_lookup_table,
7819 ++ sblk->lookup_table_start, length |
7820 ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) {
7821 ++ ERROR("unable to read inode lookup table\n");
7822 ++ return 0;
7823 ++ }
7824 ++
7825 ++ if (msblk->swap) {
7826 ++ int i;
7827 ++ long long block;
7828 ++
7829 ++ for (i = 0; i < SQUASHFS_LOOKUP_BLOCKS(sblk->inodes); i++) {
7830 ++ /* XXX */
7831 ++ SQUASHFS_SWAP_LOOKUP_BLOCKS((&block),
7832 ++ &msblk->inode_lookup_table[i], 1);
7833 ++ msblk->inode_lookup_table[i] = block;
7834 ++ }
7835 ++ }
7836 ++
7837 ++ return 1;
7838 ++}
7839 ++
7840 ++
7841 ++static int read_fragment_index_table(struct super_block *s)
7842 ++{
7843 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
7844 ++ struct squashfs_super_block *sblk = &msblk->sblk;
7845 ++ unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments);
7846 ++
7847 ++ if(length == 0)
7848 ++ return 1;
7849 ++
7850 ++ /* Allocate fragment index table */
7851 ++ msblk->fragment_index = kmalloc(length, GFP_KERNEL);
7852 ++ if (msblk->fragment_index == NULL) {
7853 ++ ERROR("Failed to allocate fragment index table\n");
7854 ++ return 0;
7855 ++ }
7856 ++
7857 ++ if (!squashfs_read_data(s, (char *) msblk->fragment_index,
7858 ++ sblk->fragment_table_start, length |
7859 ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length)) {
7860 ++ ERROR("unable to read fragment index table\n");
7861 ++ return 0;
7862 ++ }
7863 ++
7864 ++ if (msblk->swap) {
7865 ++ int i;
7866 ++ long long fragment;
7867 ++
7868 ++ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments); i++) {
7869 ++ /* XXX */
7870 ++ SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
7871 ++ &msblk->fragment_index[i], 1);
7872 ++ msblk->fragment_index[i] = fragment;
7873 ++ }
7874 ++ }
7875 ++
7876 ++ return 1;
7877 ++}
7878 ++
7879 ++
7880 ++static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
7881 ++{
7882 ++ struct squashfs_super_block *sblk = &msblk->sblk;
7883 ++
7884 ++ msblk->read_inode = squashfs_read_inode;
7885 ++ msblk->read_blocklist = read_blocklist;
7886 ++ msblk->read_fragment_index_table = read_fragment_index_table;
7887 ++
7888 ++ if (sblk->s_major == 1) {
7889 ++ if (!squashfs_1_0_supported(msblk)) {
7890 ++ SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "
7891 ++ "are unsupported\n");
7892 ++ SERROR("Please recompile with Squashfs 1.0 support enabled\n");
7893 ++ return 0;
7894 ++ }
7895 ++ } else if (sblk->s_major == 2) {
7896 ++ if (!squashfs_2_0_supported(msblk)) {
7897 ++ SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "
7898 ++ "are unsupported\n");
7899 ++ SERROR("Please recompile with Squashfs 2.0 support enabled\n");
7900 ++ return 0;
7901 ++ }
7902 ++ } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
7903 ++ SQUASHFS_MINOR) {
7904 ++ SERROR("Major/Minor mismatch, trying to mount newer %d.%d "
7905 ++ "filesystem\n", sblk->s_major, sblk->s_minor);
7906 ++ SERROR("Please update your kernel\n");
7907 ++ return 0;
7908 ++ }
7909 ++
7910 ++ return 1;
7911 ++}
7912 ++
7913 ++
7914 ++static int squashfs_fill_super(struct super_block *s, void *data, int silent)
7915 ++{
7916 ++ struct squashfs_sb_info *msblk;
7917 ++ struct squashfs_super_block *sblk;
7918 ++ char b[BDEVNAME_SIZE];
7919 ++ struct inode *root;
7920 ++
7921 ++ TRACE("Entered squashfs_fill_superblock\n");
7922 ++
7923 ++ s->s_fs_info = kzalloc(sizeof(struct squashfs_sb_info), GFP_KERNEL);
7924 ++ if (s->s_fs_info == NULL) {
7925 ++ ERROR("Failed to allocate superblock\n");
7926 ++ goto failure;
7927 ++ }
7928 ++ msblk = s->s_fs_info;
7929 ++
7930 ++ msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize());
7931 ++ if (msblk->stream.workspace == NULL) {
7932 ++ ERROR("Failed to allocate zlib workspace\n");
7933 ++ goto failure;
7934 ++ }
7935 ++ sblk = &msblk->sblk;
7936 ++
7937 ++ msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE);
7938 ++ msblk->devblksize_log2 = ffz(~msblk->devblksize);
7939 ++
7940 ++ mutex_init(&msblk->read_data_mutex);
7941 ++ mutex_init(&msblk->read_page_mutex);
7942 ++ mutex_init(&msblk->meta_index_mutex);
7943 ++
7944 ++ /* sblk->bytes_used is checked in squashfs_read_data to ensure reads are not
7945 ++ * beyond filesystem end. As we're using squashfs_read_data to read sblk here,
7946 ++ * first set sblk->bytes_used to a useful value */
7947 ++ sblk->bytes_used = sizeof(struct squashfs_super_block);
7948 ++ if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
7949 ++ sizeof(struct squashfs_super_block) |
7950 ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, sizeof(struct squashfs_super_block))) {
7951 ++ SERROR("unable to read superblock\n");
7952 ++ goto failed_mount;
7953 ++ }
7954 ++
7955 ++ /* Check it is a SQUASHFS superblock */
7956 ++ if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) {
7957 ++ if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) {
7958 ++ struct squashfs_super_block ssblk;
7959 ++
7960 ++ WARNING("Mounting a different endian SQUASHFS filesystem on %s\n",
7961 ++ bdevname(s->s_bdev, b));
7962 ++
7963 ++ SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);
7964 ++ memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));
7965 ++ msblk->swap = 1;
7966 ++ } else {
7967 ++ SERROR("Can't find a SQUASHFS superblock on %s\n",
7968 ++ bdevname(s->s_bdev, b));
7969 ++ goto failed_mount;
7970 ++ }
7971 ++ }
7972 ++
7973 ++ /* Check the MAJOR & MINOR versions */
7974 ++ if(!supported_squashfs_filesystem(msblk, silent))
7975 ++ goto failed_mount;
7976 ++
7977 ++ /* Check the filesystem does not extend beyond the end of the
7978 ++ block device */
7979 ++ if(sblk->bytes_used < 0 || sblk->bytes_used > i_size_read(s->s_bdev->bd_inode))
7980 ++ goto failed_mount;
7981 ++
7982 ++ /* Check the root inode for sanity */
7983 ++ if (SQUASHFS_INODE_OFFSET(sblk->root_inode) > SQUASHFS_METADATA_SIZE)
7984 ++ goto failed_mount;
7985 ++
7986 ++ TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b));
7987 ++ TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sblk->flags)
7988 ++ ? "un" : "");
7989 ++ TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
7990 ++ ? "un" : "");
7991 ++ TRACE("Check data is %spresent in the filesystem\n",
7992 ++ SQUASHFS_CHECK_DATA(sblk->flags) ? "" : "not ");
7993 ++ TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);
7994 ++ TRACE("Block size %d\n", sblk->block_size);
7995 ++ TRACE("Number of inodes %d\n", sblk->inodes);
7996 ++ if (sblk->s_major > 1)
7997 ++ TRACE("Number of fragments %d\n", sblk->fragments);
7998 ++ TRACE("Number of uids %d\n", sblk->no_uids);
7999 ++ TRACE("Number of gids %d\n", sblk->no_guids);
8000 ++ TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);
8001 ++ TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);
8002 ++ if (sblk->s_major > 1)
8003 ++ TRACE("sblk->fragment_table_start %llx\n", sblk->fragment_table_start);
8004 ++ TRACE("sblk->uid_start %llx\n", sblk->uid_start);
8005 ++
8006 ++ s->s_maxbytes = MAX_LFS_FILESIZE;
8007 ++ s->s_flags |= MS_RDONLY;
8008 ++ s->s_op = &squashfs_super_ops;
8009 ++
8010 ++ msblk->block_cache = squashfs_cache_init("metadata", SQUASHFS_CACHED_BLKS,
8011 ++ SQUASHFS_METADATA_SIZE, 0);
8012 ++ if (msblk->block_cache == NULL)
8013 ++ goto failed_mount;
8014 ++
8015 ++ /* Allocate read_page block */
8016 ++ msblk->read_page = vmalloc(sblk->block_size);
8017 ++ if (msblk->read_page == NULL) {
8018 ++ ERROR("Failed to allocate read_page block\n");
8019 ++ goto failed_mount;
8020 ++ }
8021 ++
8022 ++ /* Allocate uid and gid tables */
8023 ++ msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
8024 ++ sizeof(unsigned int), GFP_KERNEL);
8025 ++ if (msblk->uid == NULL) {
8026 ++ ERROR("Failed to allocate uid/gid table\n");
8027 ++ goto failed_mount;
8028 ++ }
8029 ++ msblk->guid = msblk->uid + sblk->no_uids;
8030 ++
8031 ++ if (msblk->swap) {
8032 ++ unsigned int suid[sblk->no_uids + sblk->no_guids];
8033 ++
8034 ++ if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,
8035 ++ ((sblk->no_uids + sblk->no_guids) *
8036 ++ sizeof(unsigned int)) |
8037 ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) {
8038 ++ ERROR("unable to read uid/gid table\n");
8039 ++ goto failed_mount;
8040 ++ }
8041 ++
8042 ++ SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids +
8043 ++ sblk->no_guids), (sizeof(unsigned int) * 8));
8044 ++ } else
8045 ++ if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,
8046 ++ ((sblk->no_uids + sblk->no_guids) *
8047 ++ sizeof(unsigned int)) |
8048 ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, (sblk->no_uids + sblk->no_guids) * sizeof(unsigned int))) {
8049 ++ ERROR("unable to read uid/gid table\n");
8050 ++ goto failed_mount;
8051 ++ }
8052 ++
8053 ++
8054 ++ if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))
8055 ++ goto allocate_root;
8056 ++
8057 ++ msblk->fragment_cache = squashfs_cache_init("fragment",
8058 ++ SQUASHFS_CACHED_FRAGMENTS, sblk->block_size, 1);
8059 ++ if (msblk->fragment_cache == NULL)
8060 ++ goto failed_mount;
8061 ++
8062 ++ /* Allocate and read fragment index table */
8063 ++ if (msblk->read_fragment_index_table(s) == 0)
8064 ++ goto failed_mount;
8065 ++
8066 ++ if(sblk->s_major < 3 || sblk->lookup_table_start == SQUASHFS_INVALID_BLK)
8067 ++ goto allocate_root;
8068 ++
8069 ++ /* Allocate and read inode lookup table */
8070 ++ if (read_inode_lookup_table(s) == 0)
8071 ++ goto failed_mount;
8072 ++
8073 ++ s->s_export_op = &squashfs_export_ops;
8074 ++
8075 ++allocate_root:
8076 ++ root = new_inode(s);
8077 ++ if ((msblk->read_inode)(root, sblk->root_inode) == 0)
8078 ++ goto failed_mount;
8079 ++ insert_inode_hash(root);
8080 ++
8081 ++ s->s_root = d_alloc_root(root);
8082 ++ if (s->s_root == NULL) {
8083 ++ ERROR("Root inode create failed\n");
8084 ++ iput(root);
8085 ++ goto failed_mount;
8086 ++ }
8087 ++
8088 ++ TRACE("Leaving squashfs_fill_super\n");
8089 ++ return 0;
8090 ++
8091 ++failed_mount:
8092 ++ kfree(msblk->inode_lookup_table);
8093 ++ kfree(msblk->fragment_index);
8094 ++ squashfs_cache_delete(msblk->fragment_cache);
8095 ++ kfree(msblk->uid);
8096 ++ vfree(msblk->read_page);
8097 ++ squashfs_cache_delete(msblk->block_cache);
8098 ++ kfree(msblk->fragment_index_2);
8099 ++ vfree(msblk->stream.workspace);
8100 ++ kfree(s->s_fs_info);
8101 ++ s->s_fs_info = NULL;
8102 ++ return -EINVAL;
8103 ++
8104 ++failure:
8105 ++ return -ENOMEM;
8106 ++}
8107 ++
8108 ++
8109 ++static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
8110 ++{
8111 ++ struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info;
8112 ++ struct squashfs_super_block *sblk = &msblk->sblk;
8113 ++
8114 ++ TRACE("Entered squashfs_statfs\n");
8115 ++
8116 ++ buf->f_type = SQUASHFS_MAGIC;
8117 ++ buf->f_bsize = sblk->block_size;
8118 ++ buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1;
8119 ++ buf->f_bfree = buf->f_bavail = 0;
8120 ++ buf->f_files = sblk->inodes;
8121 ++ buf->f_ffree = 0;
8122 ++ buf->f_namelen = SQUASHFS_NAME_LEN;
8123 ++
8124 ++ return 0;
8125 ++}
8126 ++
8127 ++
8128 ++static int squashfs_symlink_readpage(struct file *file, struct page *page)
8129 ++{
8130 ++ struct inode *inode = page->mapping->host;
8131 ++ int index = page->index << PAGE_CACHE_SHIFT, length, bytes, avail_bytes;
8132 ++ long long block = SQUASHFS_I(inode)->start_block;
8133 ++ int offset = SQUASHFS_I(inode)->offset;
8134 ++ void *pageaddr = kmap(page);
8135 ++
8136 ++ TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
8137 ++ "%llx, offset %x\n", page->index,
8138 ++ SQUASHFS_I(inode)->start_block,
8139 ++ SQUASHFS_I(inode)->offset);
8140 ++
8141 ++ for (length = 0; length < index; length += bytes) {
8142 ++ bytes = squashfs_get_cached_block(inode->i_sb, NULL, block,
8143 ++ offset, PAGE_CACHE_SIZE, &block, &offset);
8144 ++ if (bytes == 0) {
8145 ++ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
8146 ++ goto skip_read;
8147 ++ }
8148 ++ }
8149 ++
8150 ++ if (length != index) {
8151 ++ ERROR("(squashfs_symlink_readpage) length != index\n");
8152 ++ bytes = 0;
8153 ++ goto skip_read;
8154 ++ }
8155 ++
8156 ++ avail_bytes = min_t(int, i_size_read(inode) - length, PAGE_CACHE_SIZE);
8157 ++
8158 ++ bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block, offset,
8159 ++ avail_bytes, &block, &offset);
8160 ++ if (bytes == 0)
8161 ++ ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
8162 ++
8163 ++skip_read:
8164 ++ memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
8165 ++ kunmap(page);
8166 ++ flush_dcache_page(page);
8167 ++ SetPageUptodate(page);
8168 ++ unlock_page(page);
8169 ++
8170 ++ return 0;
8171 ++}
8172 ++
8173 ++
8174 ++static struct meta_index *locate_meta_index(struct inode *inode, int index, int offset)
8175 ++{
8176 ++ struct meta_index *meta = NULL;
8177 ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
8178 ++ int i;
8179 ++
8180 ++ mutex_lock(&msblk->meta_index_mutex);
8181 ++
8182 ++ TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
8183 ++
8184 ++ if (msblk->meta_index == NULL)
8185 ++ goto not_allocated;
8186 ++
8187 ++ for (i = 0; i < SQUASHFS_META_NUMBER; i ++) {
8188 ++ if (msblk->meta_index[i].inode_number == inode->i_ino &&
8189 ++ msblk->meta_index[i].offset >= offset &&
8190 ++ msblk->meta_index[i].offset <= index &&
8191 ++ msblk->meta_index[i].locked == 0) {
8192 ++ TRACE("locate_meta_index: entry %d, offset %d\n", i,
8193 ++ msblk->meta_index[i].offset);
8194 ++ meta = &msblk->meta_index[i];
8195 ++ offset = meta->offset;
8196 ++ }
8197 ++ }
8198 ++
8199 ++ if (meta)
8200 ++ meta->locked = 1;
8201 ++
8202 ++not_allocated:
8203 ++ mutex_unlock(&msblk->meta_index_mutex);
8204 ++
8205 ++ return meta;
8206 ++}
8207 ++
8208 ++
8209 ++static struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip)
8210 ++{
8211 ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
8212 ++ struct meta_index *meta = NULL;
8213 ++ int i;
8214 ++
8215 ++ mutex_lock(&msblk->meta_index_mutex);
8216 ++
8217 ++ TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
8218 ++
8219 ++ if (msblk->meta_index == NULL) {
8220 ++ msblk->meta_index = kmalloc(sizeof(struct meta_index) *
8221 ++ SQUASHFS_META_NUMBER, GFP_KERNEL);
8222 ++ if (msblk->meta_index == NULL) {
8223 ++ ERROR("Failed to allocate meta_index\n");
8224 ++ goto failed;
8225 ++ }
8226 ++ for (i = 0; i < SQUASHFS_META_NUMBER; i++) {
8227 ++ msblk->meta_index[i].inode_number = 0;
8228 ++ msblk->meta_index[i].locked = 0;
8229 ++ }
8230 ++ msblk->next_meta_index = 0;
8231 ++ }
8232 ++
8233 ++ for (i = SQUASHFS_META_NUMBER; i &&
8234 ++ msblk->meta_index[msblk->next_meta_index].locked; i --)
8235 ++ msblk->next_meta_index = (msblk->next_meta_index + 1) %
8236 ++ SQUASHFS_META_NUMBER;
8237 ++
8238 ++ if (i == 0) {
8239 ++ TRACE("empty_meta_index: failed!\n");
8240 ++ goto failed;
8241 ++ }
8242 ++
8243 ++ TRACE("empty_meta_index: returned meta entry %d, %p\n",
8244 ++ msblk->next_meta_index,
8245 ++ &msblk->meta_index[msblk->next_meta_index]);
8246 ++
8247 ++ meta = &msblk->meta_index[msblk->next_meta_index];
8248 ++ msblk->next_meta_index = (msblk->next_meta_index + 1) %
8249 ++ SQUASHFS_META_NUMBER;
8250 ++
8251 ++ meta->inode_number = inode->i_ino;
8252 ++ meta->offset = offset;
8253 ++ meta->skip = skip;
8254 ++ meta->entries = 0;
8255 ++ meta->locked = 1;
8256 ++
8257 ++failed:
8258 ++ mutex_unlock(&msblk->meta_index_mutex);
8259 ++ return meta;
8260 ++}
8261 ++
8262 ++
8263 ++static void release_meta_index(struct inode *inode, struct meta_index *meta)
8264 ++{
8265 ++ meta->locked = 0;
8266 ++ smp_mb();
8267 ++}
8268 ++
8269 ++
8270 ++static int read_block_index(struct super_block *s, int blocks, char *block_list,
8271 ++ long long *start_block, int *offset)
8272 ++{
8273 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
8274 ++ unsigned int *block_listp;
8275 ++ int block = 0;
8276 ++
8277 ++ if (msblk->swap) {
8278 ++ char sblock_list[blocks << 2];
8279 ++
8280 ++ if (!squashfs_get_cached_block(s, sblock_list, *start_block,
8281 ++ *offset, blocks << 2, start_block, offset)) {
8282 ++ ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset);
8283 ++ goto failure;
8284 ++ }
8285 ++ SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
8286 ++ ((unsigned int *)sblock_list), blocks);
8287 ++ } else {
8288 ++ if (!squashfs_get_cached_block(s, block_list, *start_block,
8289 ++ *offset, blocks << 2, start_block, offset)) {
8290 ++ ERROR("Fail reading block list [%llx:%x]\n", *start_block, *offset);
8291 ++ goto failure;
8292 ++ }
8293 ++ }
8294 ++
8295 ++ for (block_listp = (unsigned int *) block_list; blocks;
8296 ++ block_listp++, blocks --)
8297 ++ block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);
8298 ++
8299 ++ return block;
8300 ++
8301 ++failure:
8302 ++ return -1;
8303 ++}
8304 ++
8305 ++
8306 ++#define SIZE 256
8307 ++
8308 ++static inline int calculate_skip(int blocks) {
8309 ++ int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES);
8310 ++ return skip >= 7 ? 7 : skip + 1;
8311 ++}
8312 ++
8313 ++
8314 ++static int get_meta_index(struct inode *inode, int index,
8315 ++ long long *index_block, int *index_offset,
8316 ++ long long *data_block, char *block_list)
8317 ++{
8318 ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
8319 ++ struct squashfs_super_block *sblk = &msblk->sblk;
8320 ++ int skip = calculate_skip(i_size_read(inode) >> sblk->block_log);
8321 ++ int offset = 0;
8322 ++ struct meta_index *meta;
8323 ++ struct meta_entry *meta_entry;
8324 ++ long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start;
8325 ++ int cur_offset = SQUASHFS_I(inode)->offset;
8326 ++ long long cur_data_block = SQUASHFS_I(inode)->start_block;
8327 ++ int i;
8328 ++
8329 ++ index /= SQUASHFS_META_INDEXES * skip;
8330 ++
8331 ++ while (offset < index) {
8332 ++ meta = locate_meta_index(inode, index, offset + 1);
8333 ++
8334 ++ if (meta == NULL) {
8335 ++ meta = empty_meta_index(inode, offset + 1, skip);
8336 ++ if (meta == NULL)
8337 ++ goto all_done;
8338 ++ } else {
8339 ++ if(meta->entries == 0)
8340 ++ goto failed;
8341 ++ /* XXX */
8342 ++ offset = index < meta->offset + meta->entries ? index :
8343 ++ meta->offset + meta->entries - 1;
8344 ++ /* XXX */
8345 ++ meta_entry = &meta->meta_entry[offset - meta->offset];
8346 ++ cur_index_block = meta_entry->index_block + sblk->inode_table_start;
8347 ++ cur_offset = meta_entry->offset;
8348 ++ cur_data_block = meta_entry->data_block;
8349 ++ TRACE("get_meta_index: offset %d, meta->offset %d, "
8350 ++ "meta->entries %d\n", offset, meta->offset, meta->entries);
8351 ++ TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
8352 ++ " data_block 0x%llx\n", cur_index_block,
8353 ++ cur_offset, cur_data_block);
8354 ++ }
8355 ++
8356 ++ for (i = meta->offset + meta->entries; i <= index &&
8357 ++ i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
8358 ++ int blocks = skip * SQUASHFS_META_INDEXES;
8359 ++
8360 ++ while (blocks) {
8361 ++ int block = blocks > (SIZE >> 2) ? (SIZE >> 2) : blocks;
8362 ++ int res = read_block_index(inode->i_sb, block, block_list,
8363 ++ &cur_index_block, &cur_offset);
8364 ++
8365 ++ if (res == -1)
8366 ++ goto failed;
8367 ++
8368 ++ cur_data_block += res;
8369 ++ blocks -= block;
8370 ++ }
8371 ++
8372 ++ meta_entry = &meta->meta_entry[i - meta->offset];
8373 ++ meta_entry->index_block = cur_index_block - sblk->inode_table_start;
8374 ++ meta_entry->offset = cur_offset;
8375 ++ meta_entry->data_block = cur_data_block;
8376 ++ meta->entries ++;
8377 ++ offset ++;
8378 ++ }
8379 ++
8380 ++ TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
8381 ++ meta->offset, meta->entries);
8382 ++
8383 ++ release_meta_index(inode, meta);
8384 ++ }
8385 ++
8386 ++all_done:
8387 ++ *index_block = cur_index_block;
8388 ++ *index_offset = cur_offset;
8389 ++ *data_block = cur_data_block;
8390 ++
8391 ++ return offset * SQUASHFS_META_INDEXES * skip;
8392 ++
8393 ++failed:
8394 ++ release_meta_index(inode, meta);
8395 ++ return -1;
8396 ++}
8397 ++
8398 ++
8399 ++static long long read_blocklist(struct inode *inode, int index,
8400 ++ int readahead_blks, char *block_list,
8401 ++ unsigned short **block_p, unsigned int *bsize)
8402 ++{
8403 ++ long long block_ptr;
8404 ++ int offset;
8405 ++ long long block;
8406 ++ int res = get_meta_index(inode, index, &block_ptr, &offset, &block,
8407 ++ block_list);
8408 ++
8409 ++ TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"
8410 ++ " 0x%x, block 0x%llx\n", res, index, block_ptr, offset, block);
8411 ++
8412 ++ if(res == -1)
8413 ++ goto failure;
8414 ++
8415 ++ index -= res;
8416 ++
8417 ++ while (index) {
8418 ++ int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
8419 ++ int res = read_block_index(inode->i_sb, blocks, block_list,
8420 ++ &block_ptr, &offset);
8421 ++ if (res == -1)
8422 ++ goto failure;
8423 ++ block += res;
8424 ++ index -= blocks;
8425 ++ }
8426 ++
8427 ++ if (read_block_index(inode->i_sb, 1, block_list, &block_ptr, &offset) == -1)
8428 ++ goto failure;
8429 ++ *bsize = *((unsigned int *) block_list);
8430 ++
8431 ++ return block;
8432 ++
8433 ++failure:
8434 ++ return 0;
8435 ++}
8436 ++
8437 ++
8438 ++static int squashfs_readpage(struct file *file, struct page *page)
8439 ++{
8440 ++ struct inode *inode = page->mapping->host;
8441 ++ struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
8442 ++ struct squashfs_super_block *sblk = &msblk->sblk;
8443 ++ unsigned char *block_list = NULL;
8444 ++ long long block;
8445 ++ unsigned int bsize, i;
8446 ++ int bytes;
8447 ++ int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
8448 ++ void *pageaddr;
8449 ++ struct squashfs_cache_entry *fragment = NULL;
8450 ++ char *data_ptr = msblk->read_page;
8451 ++
8452 ++ int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
8453 ++ int start_index = page->index & ~mask;
8454 ++ int end_index = start_index | mask;
8455 ++ int file_end = i_size_read(inode) >> sblk->block_log;
8456 ++ int sparse = 0;
8457 ++
8458 ++ TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
8459 ++ page->index, SQUASHFS_I(inode)->start_block);
8460 ++
8461 ++ if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
8462 ++ PAGE_CACHE_SHIFT))
8463 ++ goto out;
8464 ++
8465 ++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
8466 ++ || index < file_end) {
8467 ++ block_list = kmalloc(SIZE, GFP_KERNEL);
8468 ++ if (block_list == NULL) {
8469 ++ ERROR("Failed to allocate block_list\n");
8470 ++ goto error_out;
8471 ++ }
8472 ++
8473 ++ block = (msblk->read_blocklist)(inode, index, 1, block_list, NULL, &bsize);
8474 ++ if (block == 0)
8475 ++ goto error_out;
8476 ++
8477 ++ if (bsize == 0) { /* hole */
8478 ++ bytes = index == file_end ?
8479 ++ (i_size_read(inode) & (sblk->block_size - 1)) : sblk->block_size;
8480 ++ sparse = 1;
8481 ++ } else {
8482 ++ mutex_lock(&msblk->read_page_mutex);
8483 ++
8484 ++ bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
8485 ++ bsize, NULL, sblk->block_size);
8486 ++
8487 ++ if (bytes == 0) {
8488 ++ ERROR("Unable to read page, block %llx, size %x\n", block, bsize);
8489 ++ mutex_unlock(&msblk->read_page_mutex);
8490 ++ goto error_out;
8491 ++ }
8492 ++ }
8493 ++ } else {
8494 ++ fragment = get_cached_fragment(inode->i_sb,
8495 ++ SQUASHFS_I(inode)-> u.s1.fragment_start_block,
8496 ++ SQUASHFS_I(inode)->u.s1.fragment_size);
8497 ++
8498 ++ if (fragment->error) {
8499 ++ ERROR("Unable to read page, block %llx, size %x\n",
8500 ++ SQUASHFS_I(inode)->u.s1.fragment_start_block,
8501 ++ (int) SQUASHFS_I(inode)->u.s1.fragment_size);
8502 ++ release_cached_fragment(msblk, fragment);
8503 ++ goto error_out;
8504 ++ }
8505 ++ bytes = i_size_read(inode) & (sblk->block_size - 1);
8506 ++ data_ptr = fragment->data + SQUASHFS_I(inode)->u.s1.fragment_offset;
8507 ++ }
8508 ++
8509 ++ for (i = start_index; i <= end_index && bytes > 0; i++,
8510 ++ bytes -= PAGE_CACHE_SIZE, data_ptr += PAGE_CACHE_SIZE) {
8511 ++ struct page *push_page;
8512 ++ int avail = sparse ? 0 : min_t(unsigned int, bytes, PAGE_CACHE_SIZE);
8513 ++
8514 ++ TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail);
8515 ++
8516 ++ push_page = (i == page->index) ? page :
8517 ++ grab_cache_page_nowait(page->mapping, i);
8518 ++
8519 ++ if (!push_page)
8520 ++ continue;
8521 ++
8522 ++ if (PageUptodate(push_page))
8523 ++ goto skip_page;
8524 ++
8525 ++ pageaddr = kmap_atomic(push_page, KM_USER0);
8526 ++ memcpy(pageaddr, data_ptr, avail);
8527 ++ memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail);
8528 ++ kunmap_atomic(pageaddr, KM_USER0);
8529 ++ flush_dcache_page(push_page);
8530 ++ SetPageUptodate(push_page);
8531 ++skip_page:
8532 ++ unlock_page(push_page);
8533 ++ if(i != page->index)
8534 ++ page_cache_release(push_page);
8535 ++ }
8536 ++
8537 ++ if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
8538 ++ || index < file_end) {
8539 ++ if (!sparse)
8540 ++ mutex_unlock(&msblk->read_page_mutex);
8541 ++ kfree(block_list);
8542 ++ } else
8543 ++ release_cached_fragment(msblk, fragment);
8544 ++
8545 ++ return 0;
8546 ++
8547 ++error_out:
8548 ++ SetPageError(page);
8549 ++out:
8550 ++ pageaddr = kmap_atomic(page, KM_USER0);
8551 ++ memset(pageaddr, 0, PAGE_CACHE_SIZE);
8552 ++ kunmap_atomic(pageaddr, KM_USER0);
8553 ++ flush_dcache_page(page);
8554 ++ if (!PageError(page))
8555 ++ SetPageUptodate(page);
8556 ++ unlock_page(page);
8557 ++
8558 ++ kfree(block_list);
8559 ++ return 0;
8560 ++}
8561 ++
8562 ++
8563 ++static int get_dir_index_using_offset(struct super_block *s,
8564 ++ long long *next_block, unsigned int *next_offset,
8565 ++ long long index_start, unsigned int index_offset, int i_count,
8566 ++ long long f_pos)
8567 ++{
8568 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
8569 ++ struct squashfs_super_block *sblk = &msblk->sblk;
8570 ++ int i, length = 0;
8571 ++ struct squashfs_dir_index index;
8572 ++
8573 ++ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
8574 ++ i_count, (unsigned int) f_pos);
8575 ++
8576 ++ f_pos -= 3;
8577 ++ if (f_pos == 0)
8578 ++ goto finish;
8579 ++
8580 ++ for (i = 0; i < i_count; i++) {
8581 ++ if (msblk->swap) {
8582 ++ struct squashfs_dir_index sindex;
8583 ++ squashfs_get_cached_block(s, &sindex, index_start, index_offset,
8584 ++ sizeof(sindex), &index_start, &index_offset);
8585 ++ SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
8586 ++ } else
8587 ++ squashfs_get_cached_block(s, &index, index_start, index_offset,
8588 ++ sizeof(index), &index_start, &index_offset);
8589 ++
8590 ++ if (index.index > f_pos)
8591 ++ break;
8592 ++
8593 ++ squashfs_get_cached_block(s, NULL, index_start, index_offset,
8594 ++ index.size + 1, &index_start, &index_offset);
8595 ++
8596 ++ length = index.index;
8597 ++ *next_block = index.start_block + sblk->directory_table_start;
8598 ++ }
8599 ++
8600 ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
8601 ++
8602 ++finish:
8603 ++ return length + 3;
8604 ++}
8605 ++
8606 ++
8607 ++static int get_dir_index_using_name(struct super_block *s,
8608 ++ long long *next_block, unsigned int *next_offset,
8609 ++ long long index_start, unsigned int index_offset, int i_count,
8610 ++ const char *name, int size)
8611 ++{
8612 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
8613 ++ struct squashfs_super_block *sblk = &msblk->sblk;
8614 ++ int i, length = 0;
8615 ++ struct squashfs_dir_index *index;
8616 ++ char *str;
8617 ++
8618 ++ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
8619 ++
8620 ++ str = kmalloc(sizeof(struct squashfs_dir_index) +
8621 ++ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL);
8622 ++ if (str == NULL) {
8623 ++ ERROR("Failed to allocate squashfs_dir_index\n");
8624 ++ goto failure;
8625 ++ }
8626 ++
8627 ++ index = (struct squashfs_dir_index *) (str + SQUASHFS_NAME_LEN + 1);
8628 ++ strncpy(str, name, size);
8629 ++ str[size] = '\0';
8630 ++
8631 ++ for (i = 0; i < i_count; i++) {
8632 ++ if (msblk->swap) {
8633 ++ struct squashfs_dir_index sindex;
8634 ++ squashfs_get_cached_block(s, &sindex, index_start, index_offset,
8635 ++ sizeof(sindex), &index_start, &index_offset);
8636 ++ SQUASHFS_SWAP_DIR_INDEX(index, &sindex);
8637 ++ } else
8638 ++ squashfs_get_cached_block(s, index, index_start, index_offset,
8639 ++ sizeof(struct squashfs_dir_index), &index_start, &index_offset);
8640 ++
8641 ++ squashfs_get_cached_block(s, index->name, index_start, index_offset,
8642 ++ index->size + 1, &index_start, &index_offset);
8643 ++
8644 ++ index->name[index->size + 1] = '\0';
8645 ++
8646 ++ if (strcmp(index->name, str) > 0)
8647 ++ break;
8648 ++
8649 ++ length = index->index;
8650 ++ *next_block = index->start_block + sblk->directory_table_start;
8651 ++ }
8652 ++
8653 ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
8654 ++ kfree(str);
8655 ++
8656 ++failure:
8657 ++ return length + 3;
8658 ++}
8659 ++
8660 ++
8661 ++static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
8662 ++{
8663 ++ struct inode *i = file->f_dentry->d_inode;
8664 ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
8665 ++ struct squashfs_super_block *sblk = &msblk->sblk;
8666 ++ long long next_block = SQUASHFS_I(i)->start_block +
8667 ++ sblk->directory_table_start;
8668 ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count;
8669 ++ struct squashfs_dir_header dirh;
8670 ++ struct squashfs_dir_entry *dire;
8671 ++
8672 ++ TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
8673 ++
8674 ++ dire = kmalloc(sizeof(struct squashfs_dir_entry) +
8675 ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
8676 ++ if (dire == NULL) {
8677 ++ ERROR("Failed to allocate squashfs_dir_entry\n");
8678 ++ goto finish;
8679 ++ }
8680 ++
8681 ++ while(file->f_pos < 3) {
8682 ++ char *name;
8683 ++ int size, i_ino;
8684 ++
8685 ++ if(file->f_pos == 0) {
8686 ++ name = ".";
8687 ++ size = 1;
8688 ++ i_ino = i->i_ino;
8689 ++ } else {
8690 ++ name = "..";
8691 ++ size = 2;
8692 ++ i_ino = SQUASHFS_I(i)->u.s2.parent_inode;
8693 ++ }
8694 ++ TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n",
8695 ++ (unsigned int) dirent, name, size, (int)
8696 ++ file->f_pos, i_ino, squashfs_filetype_table[1]);
8697 ++
8698 ++ if (filldir(dirent, name, size, file->f_pos, i_ino,
8699 ++ squashfs_filetype_table[1]) < 0) {
8700 ++ TRACE("Filldir returned less than 0\n");
8701 ++ goto finish;
8702 ++ }
8703 ++ file->f_pos += size;
8704 ++ }
8705 ++
8706 ++ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
8707 ++ SQUASHFS_I(i)->u.s2.directory_index_start,
8708 ++ SQUASHFS_I(i)->u.s2.directory_index_offset,
8709 ++ SQUASHFS_I(i)->u.s2.directory_index_count, file->f_pos);
8710 ++
8711 ++ while (length < i_size_read(i)) {
8712 ++ /* read directory header */
8713 ++ if (msblk->swap) {
8714 ++ struct squashfs_dir_header sdirh;
8715 ++
8716 ++ if (!squashfs_get_cached_block(i->i_sb, &sdirh, next_block,
8717 ++ next_offset, sizeof(sdirh), &next_block, &next_offset))
8718 ++ goto failed_read;
8719 ++
8720 ++ length += sizeof(sdirh);
8721 ++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
8722 ++ } else {
8723 ++ if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block,
8724 ++ next_offset, sizeof(dirh), &next_block, &next_offset))
8725 ++ goto failed_read;
8726 ++
8727 ++ length += sizeof(dirh);
8728 ++ }
8729 ++
8730 ++ dir_count = dirh.count + 1;
8731 ++ while (dir_count--) {
8732 ++ if (msblk->swap) {
8733 ++ struct squashfs_dir_entry sdire;
8734 ++ if (!squashfs_get_cached_block(i->i_sb, &sdire, next_block,
8735 ++ next_offset, sizeof(sdire), &next_block, &next_offset))
8736 ++ goto failed_read;
8737 ++
8738 ++ length += sizeof(sdire);
8739 ++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
8740 ++ } else {
8741 ++ if (!squashfs_get_cached_block(i->i_sb, dire, next_block,
8742 ++ next_offset, sizeof(*dire), &next_block, &next_offset))
8743 ++ goto failed_read;
8744 ++
8745 ++ length += sizeof(*dire);
8746 ++ }
8747 ++
8748 ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block,
8749 ++ next_offset, dire->size + 1, &next_block, &next_offset))
8750 ++ goto failed_read;
8751 ++
8752 ++ length += dire->size + 1;
8753 ++
8754 ++ if (file->f_pos >= length)
8755 ++ continue;
8756 ++
8757 ++ dire->name[dire->size + 1] = '\0';
8758 ++
8759 ++ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n",
8760 ++ (unsigned int) dirent, dire->name, dire->size + 1,
8761 ++ (int) file->f_pos, dirh.start_block, dire->offset,
8762 ++ dirh.inode_number + dire->inode_number,
8763 ++ squashfs_filetype_table[dire->type]);
8764 ++
8765 ++ if (filldir(dirent, dire->name, dire->size + 1, file->f_pos,
8766 ++ dirh.inode_number + dire->inode_number,
8767 ++ squashfs_filetype_table[dire->type]) < 0) {
8768 ++ TRACE("Filldir returned less than 0\n");
8769 ++ goto finish;
8770 ++ }
8771 ++ file->f_pos = length;
8772 ++ }
8773 ++ }
8774 ++
8775 ++finish:
8776 ++ kfree(dire);
8777 ++ return 0;
8778 ++
8779 ++failed_read:
8780 ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
8781 ++ next_offset);
8782 ++ kfree(dire);
8783 ++ return 0;
8784 ++}
8785 ++
8786 ++
8787 ++static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry,
8788 ++ struct nameidata *nd)
8789 ++{
8790 ++ const unsigned char *name = dentry->d_name.name;
8791 ++ int len = dentry->d_name.len;
8792 ++ struct inode *inode = NULL;
8793 ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
8794 ++ struct squashfs_super_block *sblk = &msblk->sblk;
8795 ++ long long next_block = SQUASHFS_I(i)->start_block +
8796 ++ sblk->directory_table_start;
8797 ++ int next_offset = SQUASHFS_I(i)->offset, length = 0, dir_count;
8798 ++ struct squashfs_dir_header dirh;
8799 ++ struct squashfs_dir_entry *dire;
8800 ++
8801 ++ TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
8802 ++
8803 ++ dire = kmalloc(sizeof(struct squashfs_dir_entry) +
8804 ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
8805 ++ if (dire == NULL) {
8806 ++ ERROR("Failed to allocate squashfs_dir_entry\n");
8807 ++ goto exit_lookup;
8808 ++ }
8809 ++
8810 ++ if (len > SQUASHFS_NAME_LEN)
8811 ++ goto exit_lookup;
8812 ++
8813 ++ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
8814 ++ SQUASHFS_I(i)->u.s2.directory_index_start,
8815 ++ SQUASHFS_I(i)->u.s2.directory_index_offset,
8816 ++ SQUASHFS_I(i)->u.s2.directory_index_count, name, len);
8817 ++
8818 ++ while (length < i_size_read(i)) {
8819 ++ /* read directory header */
8820 ++ if (msblk->swap) {
8821 ++ struct squashfs_dir_header sdirh;
8822 ++ if (!squashfs_get_cached_block(i->i_sb, &sdirh, next_block,
8823 ++ next_offset, sizeof(sdirh), &next_block, &next_offset))
8824 ++ goto failed_read;
8825 ++
8826 ++ length += sizeof(sdirh);
8827 ++ SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
8828 ++ } else {
8829 ++ if (!squashfs_get_cached_block(i->i_sb, &dirh, next_block,
8830 ++ next_offset, sizeof(dirh), &next_block, &next_offset))
8831 ++ goto failed_read;
8832 ++
8833 ++ length += sizeof(dirh);
8834 ++ }
8835 ++
8836 ++ dir_count = dirh.count + 1;
8837 ++ while (dir_count--) {
8838 ++ if (msblk->swap) {
8839 ++ struct squashfs_dir_entry sdire;
8840 ++ if (!squashfs_get_cached_block(i->i_sb, &sdire, next_block,
8841 ++ next_offset, sizeof(sdire), &next_block, &next_offset))
8842 ++ goto failed_read;
8843 ++
8844 ++ length += sizeof(sdire);
8845 ++ SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
8846 ++ } else {
8847 ++ if (!squashfs_get_cached_block(i->i_sb, dire, next_block,
8848 ++ next_offset, sizeof(*dire), &next_block, &next_offset))
8849 ++ goto failed_read;
8850 ++
8851 ++ length += sizeof(*dire);
8852 ++ }
8853 ++
8854 ++ if (!squashfs_get_cached_block(i->i_sb, dire->name, next_block,
8855 ++ next_offset, dire->size + 1, &next_block, &next_offset))
8856 ++ goto failed_read;
8857 ++
8858 ++ length += dire->size + 1;
8859 ++
8860 ++ if (name[0] < dire->name[0])
8861 ++ goto exit_lookup;
8862 ++
8863 ++ if ((len == dire->size + 1) && !strncmp(name, dire->name, len)) {
8864 ++ squashfs_inode_t ino = SQUASHFS_MKINODE(dirh.start_block,
8865 ++ dire->offset);
8866 ++
8867 ++ TRACE("calling squashfs_iget for directory entry %s, inode"
8868 ++ " %x:%x, %d\n", name, dirh.start_block, dire->offset,
8869 ++ dirh.inode_number + dire->inode_number);
8870 ++
8871 ++ inode = squashfs_iget(i->i_sb, ino, dirh.inode_number + dire->inode_number);
8872 ++
8873 ++ goto exit_lookup;
8874 ++ }
8875 ++ }
8876 ++ }
8877 ++
8878 ++exit_lookup:
8879 ++ kfree(dire);
8880 ++ if (inode)
8881 ++ return d_splice_alias(inode, dentry);
8882 ++ d_add(dentry, inode);
8883 ++ return ERR_PTR(0);
8884 ++
8885 ++failed_read:
8886 ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
8887 ++ next_offset);
8888 ++ goto exit_lookup;
8889 ++}
8890 ++
8891 ++
8892 ++static int squashfs_remount(struct super_block *s, int *flags, char *data)
8893 ++{
8894 ++ *flags |= MS_RDONLY;
8895 ++ return 0;
8896 ++}
8897 ++
8898 ++
8899 ++static void squashfs_put_super(struct super_block *s)
8900 ++{
8901 ++ if (s->s_fs_info) {
8902 ++ struct squashfs_sb_info *sbi = s->s_fs_info;
8903 ++ squashfs_cache_delete(sbi->block_cache);
8904 ++ squashfs_cache_delete(sbi->fragment_cache);
8905 ++ vfree(sbi->read_page);
8906 ++ kfree(sbi->uid);
8907 ++ kfree(sbi->fragment_index);
8908 ++ kfree(sbi->fragment_index_2);
8909 ++ kfree(sbi->meta_index);
8910 ++ vfree(sbi->stream.workspace);
8911 ++ kfree(s->s_fs_info);
8912 ++ s->s_fs_info = NULL;
8913 ++ }
8914 ++}
8915 ++
8916 ++
8917 ++static int squashfs_get_sb(struct file_system_type *fs_type, int flags,
8918 ++ const char *dev_name, void *data, struct vfsmount *mnt)
8919 ++{
8920 ++ return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super,
8921 ++ mnt);
8922 ++}
8923 ++
8924 ++
8925 ++static int __init init_squashfs_fs(void)
8926 ++{
8927 ++ int err = init_inodecache();
8928 ++ if (err)
8929 ++ goto out;
8930 ++
8931 ++ printk(KERN_INFO "squashfs: version 3.4 (2008/08/26) "
8932 ++ "Phillip Lougher\n");
8933 ++
8934 ++ err = register_filesystem(&squashfs_fs_type);
8935 ++ if (err)
8936 ++ destroy_inodecache();
8937 ++
8938 ++out:
8939 ++ return err;
8940 ++}
8941 ++
8942 ++
8943 ++static void __exit exit_squashfs_fs(void)
8944 ++{
8945 ++ unregister_filesystem(&squashfs_fs_type);
8946 ++ destroy_inodecache();
8947 ++}
8948 ++
8949 ++
8950 ++static struct kmem_cache * squashfs_inode_cachep;
8951 ++
8952 ++
8953 ++static struct inode *squashfs_alloc_inode(struct super_block *sb)
8954 ++{
8955 ++ struct squashfs_inode_info *ei;
8956 ++ ei = kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL);
8957 ++ return ei ? &ei->vfs_inode : NULL;
8958 ++}
8959 ++
8960 ++
8961 ++static void squashfs_destroy_inode(struct inode *inode)
8962 ++{
8963 ++ kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode));
8964 ++}
8965 ++
8966 ++
8967 ++static void init_once(void *foo)
8968 ++{
8969 ++ struct squashfs_inode_info *ei = foo;
8970 ++
8971 ++ inode_init_once(&ei->vfs_inode);
8972 ++}
8973 ++
8974 ++
8975 ++static int __init init_inodecache(void)
8976 ++{
8977 ++ squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache",
8978 ++ sizeof(struct squashfs_inode_info), 0,
8979 ++ SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, init_once);
8980 ++ if (squashfs_inode_cachep == NULL)
8981 ++ return -ENOMEM;
8982 ++ return 0;
8983 ++}
8984 ++
8985 ++
8986 ++static void destroy_inodecache(void)
8987 ++{
8988 ++ kmem_cache_destroy(squashfs_inode_cachep);
8989 ++}
8990 ++
8991 ++
8992 ++module_init(init_squashfs_fs);
8993 ++module_exit(exit_squashfs_fs);
8994 ++MODULE_DESCRIPTION("squashfs 3.4, a compressed read-only filesystem");
8995 ++MODULE_AUTHOR("Phillip Lougher <phillip@××××××××××××××××.uk>");
8996 ++MODULE_LICENSE("GPL");
8997 +diff -x .gitignore -Nurp linux-2.6.27-rc4/fs/squashfs/Makefile linux-2.6.27-rc4-squashfs3.4/fs/squashfs/Makefile
8998 +--- linux-2.6.27-rc4/fs/squashfs/Makefile 1970-01-01 01:00:00.000000000 +0100
8999 ++++ linux-2.6.27-rc4-squashfs3.4/fs/squashfs/Makefile 2008-08-19 18:31:56.000000000 +0100
9000 +@@ -0,0 +1,7 @@
9001 ++#
9002 ++# Makefile for the linux squashfs routines.
9003 ++#
9004 ++
9005 ++obj-$(CONFIG_SQUASHFS) += squashfs.o
9006 ++squashfs-y += inode.o
9007 ++squashfs-y += squashfs2_0.o
9008 +diff -x .gitignore -Nurp linux-2.6.27-rc4/fs/squashfs/squashfs2_0.c linux-2.6.27-rc4-squashfs3.4/fs/squashfs/squashfs2_0.c
9009 +--- linux-2.6.27-rc4/fs/squashfs/squashfs2_0.c 1970-01-01 01:00:00.000000000 +0100
9010 ++++ linux-2.6.27-rc4-squashfs3.4/fs/squashfs/squashfs2_0.c 2008-08-19 18:31:56.000000000 +0100
9011 +@@ -0,0 +1,740 @@
9012 ++/*
9013 ++ * Squashfs - a compressed read only filesystem for Linux
9014 ++ *
9015 ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
9016 ++ * Phillip Lougher <phillip@××××××××××××××××.uk>
9017 ++ *
9018 ++ * This program is free software; you can redistribute it and/or
9019 ++ * modify it under the terms of the GNU General Public License
9020 ++ * as published by the Free Software Foundation; either version 2,
9021 ++ * or (at your option) any later version.
9022 ++ *
9023 ++ * This program is distributed in the hope that it will be useful,
9024 ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
9025 ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9026 ++ * GNU General Public License for more details.
9027 ++ *
9028 ++ * You should have received a copy of the GNU General Public License
9029 ++ * along with this program; if not, write to the Free Software
9030 ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
9031 ++ *
9032 ++ * squashfs2_0.c
9033 ++ */
9034 ++
9035 ++#include <linux/squashfs_fs.h>
9036 ++#include <linux/module.h>
9037 ++#include <linux/zlib.h>
9038 ++#include <linux/fs.h>
9039 ++#include <linux/squashfs_fs_sb.h>
9040 ++#include <linux/squashfs_fs_i.h>
9041 ++
9042 ++#include "squashfs.h"
9043 ++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir);
9044 ++static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *,
9045 ++ struct nameidata *);
9046 ++
9047 ++static struct file_operations squashfs_dir_ops_2 = {
9048 ++ .read = generic_read_dir,
9049 ++ .readdir = squashfs_readdir_2
9050 ++};
9051 ++
9052 ++static struct inode_operations squashfs_dir_inode_ops_2 = {
9053 ++ .lookup = squashfs_lookup_2
9054 ++};
9055 ++
9056 ++static unsigned char squashfs_filetype_table[] = {
9057 ++ DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
9058 ++};
9059 ++
9060 ++static int read_fragment_index_table_2(struct super_block *s)
9061 ++{
9062 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
9063 ++ struct squashfs_super_block *sblk = &msblk->sblk;
9064 ++
9065 ++ if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2
9066 ++ (sblk->fragments), GFP_KERNEL))) {
9067 ++ ERROR("Failed to allocate uid/gid table\n");
9068 ++ return 0;
9069 ++ }
9070 ++
9071 ++ if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) &&
9072 ++ !squashfs_read_data(s, (char *)
9073 ++ msblk->fragment_index_2,
9074 ++ sblk->fragment_table_start,
9075 ++ SQUASHFS_FRAGMENT_INDEX_BYTES_2
9076 ++ (sblk->fragments) |
9077 ++ SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) {
9078 ++ ERROR("unable to read fragment index table\n");
9079 ++ return 0;
9080 ++ }
9081 ++
9082 ++ if (msblk->swap) {
9083 ++ int i;
9084 ++ unsigned int fragment;
9085 ++
9086 ++ for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments);
9087 ++ i++) {
9088 ++ SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment),
9089 ++ &msblk->fragment_index_2[i], 1);
9090 ++ msblk->fragment_index_2[i] = fragment;
9091 ++ }
9092 ++ }
9093 ++
9094 ++ return 1;
9095 ++}
9096 ++
9097 ++
9098 ++static int get_fragment_location_2(struct super_block *s, unsigned int fragment,
9099 ++ long long *fragment_start_block,
9100 ++ unsigned int *fragment_size)
9101 ++{
9102 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
9103 ++ long long start_block =
9104 ++ msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)];
9105 ++ int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment);
9106 ++ struct squashfs_fragment_entry_2 fragment_entry;
9107 ++
9108 ++ if (msblk->swap) {
9109 ++ struct squashfs_fragment_entry_2 sfragment_entry;
9110 ++
9111 ++ if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
9112 ++ start_block, offset,
9113 ++ sizeof(sfragment_entry), &start_block,
9114 ++ &offset))
9115 ++ goto out;
9116 ++ SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry);
9117 ++ } else
9118 ++ if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
9119 ++ start_block, offset,
9120 ++ sizeof(fragment_entry), &start_block,
9121 ++ &offset))
9122 ++ goto out;
9123 ++
9124 ++ *fragment_start_block = fragment_entry.start_block;
9125 ++ *fragment_size = fragment_entry.size;
9126 ++
9127 ++ return 1;
9128 ++
9129 ++out:
9130 ++ return 0;
9131 ++}
9132 ++
9133 ++
9134 ++static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i,
9135 ++ struct squashfs_base_inode_header_2 *inodeb, unsigned int ino)
9136 ++{
9137 ++ struct squashfs_super_block *sblk = &msblk->sblk;
9138 ++
9139 ++ i->i_ino = ino;
9140 ++ i->i_mtime.tv_sec = sblk->mkfs_time;
9141 ++ i->i_atime.tv_sec = sblk->mkfs_time;
9142 ++ i->i_ctime.tv_sec = sblk->mkfs_time;
9143 ++ i->i_uid = msblk->uid[inodeb->uid];
9144 ++ i->i_mode = inodeb->mode;
9145 ++ i->i_nlink = 1;
9146 ++ i->i_size = 0;
9147 ++ if (inodeb->guid == SQUASHFS_GUIDS)
9148 ++ i->i_gid = i->i_uid;
9149 ++ else
9150 ++ i->i_gid = msblk->guid[inodeb->guid];
9151 ++}
9152 ++
9153 ++
9154 ++static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode)
9155 ++{
9156 ++ struct super_block *s = i->i_sb;
9157 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
9158 ++ struct squashfs_super_block *sblk = &msblk->sblk;
9159 ++ unsigned int block = SQUASHFS_INODE_BLK(inode) +
9160 ++ sblk->inode_table_start;
9161 ++ unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
9162 ++ unsigned int ino = SQUASHFS_MK_VFS_INODE(block -
9163 ++ sblk->inode_table_start, offset);
9164 ++ long long next_block;
9165 ++ unsigned int next_offset;
9166 ++ union squashfs_inode_header_2 id, sid;
9167 ++ struct squashfs_base_inode_header_2 *inodeb = &id.base,
9168 ++ *sinodeb = &sid.base;
9169 ++
9170 ++ TRACE("Entered squashfs_read_inode_2\n");
9171 ++
9172 ++ if (msblk->swap) {
9173 ++ if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
9174 ++ offset, sizeof(*sinodeb), &next_block,
9175 ++ &next_offset))
9176 ++ goto failed_read;
9177 ++ SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb,
9178 ++ sizeof(*sinodeb));
9179 ++ } else
9180 ++ if (!squashfs_get_cached_block(s, (char *) inodeb, block,
9181 ++ offset, sizeof(*inodeb), &next_block,
9182 ++ &next_offset))
9183 ++ goto failed_read;
9184 ++
9185 ++ squashfs_new_inode(msblk, i, inodeb, ino);
9186 ++
9187 ++ switch(inodeb->inode_type) {
9188 ++ case SQUASHFS_FILE_TYPE: {
9189 ++ struct squashfs_reg_inode_header_2 *inodep = &id.reg;
9190 ++ struct squashfs_reg_inode_header_2 *sinodep = &sid.reg;
9191 ++ long long frag_blk;
9192 ++ unsigned int frag_size = 0;
9193 ++
9194 ++ if (msblk->swap) {
9195 ++ if (!squashfs_get_cached_block(s, (char *)
9196 ++ sinodep, block, offset,
9197 ++ sizeof(*sinodep), &next_block,
9198 ++ &next_offset))
9199 ++ goto failed_read;
9200 ++ SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep);
9201 ++ } else
9202 ++ if (!squashfs_get_cached_block(s, (char *)
9203 ++ inodep, block, offset,
9204 ++ sizeof(*inodep), &next_block,
9205 ++ &next_offset))
9206 ++ goto failed_read;
9207 ++
9208 ++ frag_blk = SQUASHFS_INVALID_BLK;
9209 ++ if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
9210 ++ !get_fragment_location_2(s,
9211 ++ inodep->fragment, &frag_blk, &frag_size))
9212 ++ goto failed_read;
9213 ++
9214 ++ i->i_size = inodep->file_size;
9215 ++ i->i_fop = &generic_ro_fops;
9216 ++ i->i_mode |= S_IFREG;
9217 ++ i->i_mtime.tv_sec = inodep->mtime;
9218 ++ i->i_atime.tv_sec = inodep->mtime;
9219 ++ i->i_ctime.tv_sec = inodep->mtime;
9220 ++ i->i_blocks = ((i->i_size - 1) >> 9) + 1;
9221 ++ SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
9222 ++ SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
9223 ++ SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
9224 ++ SQUASHFS_I(i)->start_block = inodep->start_block;
9225 ++ SQUASHFS_I(i)->u.s1.block_list_start = next_block;
9226 ++ SQUASHFS_I(i)->offset = next_offset;
9227 ++ i->i_data.a_ops = &squashfs_aops;
9228 ++
9229 ++ TRACE("File inode %x:%x, start_block %x, "
9230 ++ "block_list_start %llx, offset %x\n",
9231 ++ SQUASHFS_INODE_BLK(inode), offset,
9232 ++ inodep->start_block, next_block,
9233 ++ next_offset);
9234 ++ break;
9235 ++ }
9236 ++ case SQUASHFS_DIR_TYPE: {
9237 ++ struct squashfs_dir_inode_header_2 *inodep = &id.dir;
9238 ++ struct squashfs_dir_inode_header_2 *sinodep = &sid.dir;
9239 ++
9240 ++ if (msblk->swap) {
9241 ++ if (!squashfs_get_cached_block(s, (char *)
9242 ++ sinodep, block, offset,
9243 ++ sizeof(*sinodep), &next_block,
9244 ++ &next_offset))
9245 ++ goto failed_read;
9246 ++ SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep);
9247 ++ } else
9248 ++ if (!squashfs_get_cached_block(s, (char *)
9249 ++ inodep, block, offset,
9250 ++ sizeof(*inodep), &next_block,
9251 ++ &next_offset))
9252 ++ goto failed_read;
9253 ++
9254 ++ i->i_size = inodep->file_size;
9255 ++ i->i_op = &squashfs_dir_inode_ops_2;
9256 ++ i->i_fop = &squashfs_dir_ops_2;
9257 ++ i->i_mode |= S_IFDIR;
9258 ++ i->i_mtime.tv_sec = inodep->mtime;
9259 ++ i->i_atime.tv_sec = inodep->mtime;
9260 ++ i->i_ctime.tv_sec = inodep->mtime;
9261 ++ SQUASHFS_I(i)->start_block = inodep->start_block;
9262 ++ SQUASHFS_I(i)->offset = inodep->offset;
9263 ++ SQUASHFS_I(i)->u.s2.directory_index_count = 0;
9264 ++ SQUASHFS_I(i)->u.s2.parent_inode = 0;
9265 ++
9266 ++ TRACE("Directory inode %x:%x, start_block %x, offset "
9267 ++ "%x\n", SQUASHFS_INODE_BLK(inode),
9268 ++ offset, inodep->start_block,
9269 ++ inodep->offset);
9270 ++ break;
9271 ++ }
9272 ++ case SQUASHFS_LDIR_TYPE: {
9273 ++ struct squashfs_ldir_inode_header_2 *inodep = &id.ldir;
9274 ++ struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir;
9275 ++
9276 ++ if (msblk->swap) {
9277 ++ if (!squashfs_get_cached_block(s, (char *)
9278 ++ sinodep, block, offset,
9279 ++ sizeof(*sinodep), &next_block,
9280 ++ &next_offset))
9281 ++ goto failed_read;
9282 ++ SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep,
9283 ++ sinodep);
9284 ++ } else
9285 ++ if (!squashfs_get_cached_block(s, (char *)
9286 ++ inodep, block, offset,
9287 ++ sizeof(*inodep), &next_block,
9288 ++ &next_offset))
9289 ++ goto failed_read;
9290 ++
9291 ++ i->i_size = inodep->file_size;
9292 ++ i->i_op = &squashfs_dir_inode_ops_2;
9293 ++ i->i_fop = &squashfs_dir_ops_2;
9294 ++ i->i_mode |= S_IFDIR;
9295 ++ i->i_mtime.tv_sec = inodep->mtime;
9296 ++ i->i_atime.tv_sec = inodep->mtime;
9297 ++ i->i_ctime.tv_sec = inodep->mtime;
9298 ++ SQUASHFS_I(i)->start_block = inodep->start_block;
9299 ++ SQUASHFS_I(i)->offset = inodep->offset;
9300 ++ SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
9301 ++ SQUASHFS_I(i)->u.s2.directory_index_offset =
9302 ++ next_offset;
9303 ++ SQUASHFS_I(i)->u.s2.directory_index_count =
9304 ++ inodep->i_count;
9305 ++ SQUASHFS_I(i)->u.s2.parent_inode = 0;
9306 ++
9307 ++ TRACE("Long directory inode %x:%x, start_block %x, "
9308 ++ "offset %x\n",
9309 ++ SQUASHFS_INODE_BLK(inode), offset,
9310 ++ inodep->start_block, inodep->offset);
9311 ++ break;
9312 ++ }
9313 ++ case SQUASHFS_SYMLINK_TYPE: {
9314 ++ struct squashfs_symlink_inode_header_2 *inodep =
9315 ++ &id.symlink;
9316 ++ struct squashfs_symlink_inode_header_2 *sinodep =
9317 ++ &sid.symlink;
9318 ++
9319 ++ if (msblk->swap) {
9320 ++ if (!squashfs_get_cached_block(s, (char *)
9321 ++ sinodep, block, offset,
9322 ++ sizeof(*sinodep), &next_block,
9323 ++ &next_offset))
9324 ++ goto failed_read;
9325 ++ SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
9326 ++ sinodep);
9327 ++ } else
9328 ++ if (!squashfs_get_cached_block(s, (char *)
9329 ++ inodep, block, offset,
9330 ++ sizeof(*inodep), &next_block,
9331 ++ &next_offset))
9332 ++ goto failed_read;
9333 ++
9334 ++ i->i_size = inodep->symlink_size;
9335 ++ i->i_op = &page_symlink_inode_operations;
9336 ++ i->i_data.a_ops = &squashfs_symlink_aops;
9337 ++ i->i_mode |= S_IFLNK;
9338 ++ SQUASHFS_I(i)->start_block = next_block;
9339 ++ SQUASHFS_I(i)->offset = next_offset;
9340 ++
9341 ++ TRACE("Symbolic link inode %x:%x, start_block %llx, "
9342 ++ "offset %x\n",
9343 ++ SQUASHFS_INODE_BLK(inode), offset,
9344 ++ next_block, next_offset);
9345 ++ break;
9346 ++ }
9347 ++ case SQUASHFS_BLKDEV_TYPE:
9348 ++ case SQUASHFS_CHRDEV_TYPE: {
9349 ++ struct squashfs_dev_inode_header_2 *inodep = &id.dev;
9350 ++ struct squashfs_dev_inode_header_2 *sinodep = &sid.dev;
9351 ++
9352 ++ if (msblk->swap) {
9353 ++ if (!squashfs_get_cached_block(s, (char *)
9354 ++ sinodep, block, offset,
9355 ++ sizeof(*sinodep), &next_block,
9356 ++ &next_offset))
9357 ++ goto failed_read;
9358 ++ SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep);
9359 ++ } else
9360 ++ if (!squashfs_get_cached_block(s, (char *)
9361 ++ inodep, block, offset,
9362 ++ sizeof(*inodep), &next_block,
9363 ++ &next_offset))
9364 ++ goto failed_read;
9365 ++
9366 ++ i->i_mode |= (inodeb->inode_type ==
9367 ++ SQUASHFS_CHRDEV_TYPE) ? S_IFCHR :
9368 ++ S_IFBLK;
9369 ++ init_special_inode(i, i->i_mode,
9370 ++ old_decode_dev(inodep->rdev));
9371 ++
9372 ++ TRACE("Device inode %x:%x, rdev %x\n",
9373 ++ SQUASHFS_INODE_BLK(inode), offset,
9374 ++ inodep->rdev);
9375 ++ break;
9376 ++ }
9377 ++ case SQUASHFS_FIFO_TYPE:
9378 ++ case SQUASHFS_SOCKET_TYPE: {
9379 ++
9380 ++ i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
9381 ++ ? S_IFIFO : S_IFSOCK;
9382 ++ init_special_inode(i, i->i_mode, 0);
9383 ++ break;
9384 ++ }
9385 ++ default:
9386 ++ ERROR("Unknown inode type %d in squashfs_iget!\n",
9387 ++ inodeb->inode_type);
9388 ++ goto failed_read1;
9389 ++ }
9390 ++
9391 ++ return 1;
9392 ++
9393 ++failed_read:
9394 ++ ERROR("Unable to read inode [%x:%x]\n", block, offset);
9395 ++
9396 ++failed_read1:
9397 ++ return 0;
9398 ++}
9399 ++
9400 ++
9401 ++static int get_dir_index_using_offset(struct super_block *s, long long
9402 ++ *next_block, unsigned int *next_offset,
9403 ++ long long index_start,
9404 ++ unsigned int index_offset, int i_count,
9405 ++ long long f_pos)
9406 ++{
9407 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
9408 ++ struct squashfs_super_block *sblk = &msblk->sblk;
9409 ++ int i, length = 0;
9410 ++ struct squashfs_dir_index_2 index;
9411 ++
9412 ++ TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
9413 ++ i_count, (unsigned int) f_pos);
9414 ++
9415 ++ if (f_pos == 0)
9416 ++ goto finish;
9417 ++
9418 ++ for (i = 0; i < i_count; i++) {
9419 ++ if (msblk->swap) {
9420 ++ struct squashfs_dir_index_2 sindex;
9421 ++ squashfs_get_cached_block(s, (char *) &sindex,
9422 ++ index_start, index_offset,
9423 ++ sizeof(sindex), &index_start,
9424 ++ &index_offset);
9425 ++ SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex);
9426 ++ } else
9427 ++ squashfs_get_cached_block(s, (char *) &index,
9428 ++ index_start, index_offset,
9429 ++ sizeof(index), &index_start,
9430 ++ &index_offset);
9431 ++
9432 ++ if (index.index > f_pos)
9433 ++ break;
9434 ++
9435 ++ squashfs_get_cached_block(s, NULL, index_start, index_offset,
9436 ++ index.size + 1, &index_start,
9437 ++ &index_offset);
9438 ++
9439 ++ length = index.index;
9440 ++ *next_block = index.start_block + sblk->directory_table_start;
9441 ++ }
9442 ++
9443 ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
9444 ++
9445 ++finish:
9446 ++ return length;
9447 ++}
9448 ++
9449 ++
9450 ++static int get_dir_index_using_name(struct super_block *s, long long
9451 ++ *next_block, unsigned int *next_offset,
9452 ++ long long index_start,
9453 ++ unsigned int index_offset, int i_count,
9454 ++ const char *name, int size)
9455 ++{
9456 ++ struct squashfs_sb_info *msblk = s->s_fs_info;
9457 ++ struct squashfs_super_block *sblk = &msblk->sblk;
9458 ++ int i, length = 0;
9459 ++ struct squashfs_dir_index_2 *index;
9460 ++ char *str;
9461 ++
9462 ++ TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
9463 ++
9464 ++ if (!(str = kmalloc(sizeof(struct squashfs_dir_index) +
9465 ++ (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) {
9466 ++ ERROR("Failed to allocate squashfs_dir_index\n");
9467 ++ goto failure;
9468 ++ }
9469 ++
9470 ++ index = (struct squashfs_dir_index_2 *) (str + SQUASHFS_NAME_LEN + 1);
9471 ++ strncpy(str, name, size);
9472 ++ str[size] = '\0';
9473 ++
9474 ++ for (i = 0; i < i_count; i++) {
9475 ++ if (msblk->swap) {
9476 ++ struct squashfs_dir_index_2 sindex;
9477 ++ squashfs_get_cached_block(s, (char *) &sindex,
9478 ++ index_start, index_offset,
9479 ++ sizeof(sindex), &index_start,
9480 ++ &index_offset);
9481 ++ SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex);
9482 ++ } else
9483 ++ squashfs_get_cached_block(s, (char *) index,
9484 ++ index_start, index_offset,
9485 ++ sizeof(struct squashfs_dir_index_2),
9486 ++ &index_start, &index_offset);
9487 ++
9488 ++ squashfs_get_cached_block(s, index->name, index_start,
9489 ++ index_offset, index->size + 1,
9490 ++ &index_start, &index_offset);
9491 ++
9492 ++ index->name[index->size + 1] = '\0';
9493 ++
9494 ++ if (strcmp(index->name, str) > 0)
9495 ++ break;
9496 ++
9497 ++ length = index->index;
9498 ++ *next_block = index->start_block + sblk->directory_table_start;
9499 ++ }
9500 ++
9501 ++ *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
9502 ++ kfree(str);
9503 ++failure:
9504 ++ return length;
9505 ++}
9506 ++
9507 ++
9508 ++static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir)
9509 ++{
9510 ++ struct inode *i = file->f_dentry->d_inode;
9511 ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
9512 ++ struct squashfs_super_block *sblk = &msblk->sblk;
9513 ++ long long next_block = SQUASHFS_I(i)->start_block +
9514 ++ sblk->directory_table_start;
9515 ++ int next_offset = SQUASHFS_I(i)->offset, length = 0,
9516 ++ dir_count;
9517 ++ struct squashfs_dir_header_2 dirh;
9518 ++ struct squashfs_dir_entry_2 *dire;
9519 ++
9520 ++ TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset);
9521 ++
9522 ++ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
9523 ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
9524 ++ ERROR("Failed to allocate squashfs_dir_entry\n");
9525 ++ goto finish;
9526 ++ }
9527 ++
9528 ++ length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
9529 ++ SQUASHFS_I(i)->u.s2.directory_index_start,
9530 ++ SQUASHFS_I(i)->u.s2.directory_index_offset,
9531 ++ SQUASHFS_I(i)->u.s2.directory_index_count,
9532 ++ file->f_pos);
9533 ++
9534 ++ while (length < i_size_read(i)) {
9535 ++ /* read directory header */
9536 ++ if (msblk->swap) {
9537 ++ struct squashfs_dir_header_2 sdirh;
9538 ++
9539 ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
9540 ++ next_block, next_offset, sizeof(sdirh),
9541 ++ &next_block, &next_offset))
9542 ++ goto failed_read;
9543 ++
9544 ++ length += sizeof(sdirh);
9545 ++ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
9546 ++ } else {
9547 ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
9548 ++ next_block, next_offset, sizeof(dirh),
9549 ++ &next_block, &next_offset))
9550 ++ goto failed_read;
9551 ++
9552 ++ length += sizeof(dirh);
9553 ++ }
9554 ++
9555 ++ dir_count = dirh.count + 1;
9556 ++ while (dir_count--) {
9557 ++ if (msblk->swap) {
9558 ++ struct squashfs_dir_entry_2 sdire;
9559 ++ if (!squashfs_get_cached_block(i->i_sb, (char *)
9560 ++ &sdire, next_block, next_offset,
9561 ++ sizeof(sdire), &next_block,
9562 ++ &next_offset))
9563 ++ goto failed_read;
9564 ++
9565 ++ length += sizeof(sdire);
9566 ++ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
9567 ++ } else {
9568 ++ if (!squashfs_get_cached_block(i->i_sb, (char *)
9569 ++ dire, next_block, next_offset,
9570 ++ sizeof(*dire), &next_block,
9571 ++ &next_offset))
9572 ++ goto failed_read;
9573 ++
9574 ++ length += sizeof(*dire);
9575 ++ }
9576 ++
9577 ++ if (!squashfs_get_cached_block(i->i_sb, dire->name,
9578 ++ next_block, next_offset,
9579 ++ dire->size + 1, &next_block,
9580 ++ &next_offset))
9581 ++ goto failed_read;
9582 ++
9583 ++ length += dire->size + 1;
9584 ++
9585 ++ if (file->f_pos >= length)
9586 ++ continue;
9587 ++
9588 ++ dire->name[dire->size + 1] = '\0';
9589 ++
9590 ++ TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n",
9591 ++ (unsigned int) dirent, dire->name,
9592 ++ dire->size + 1, (int) file->f_pos,
9593 ++ dirh.start_block, dire->offset,
9594 ++ squashfs_filetype_table[dire->type]);
9595 ++
9596 ++ if (filldir(dirent, dire->name, dire->size + 1,
9597 ++ file->f_pos, SQUASHFS_MK_VFS_INODE(
9598 ++ dirh.start_block, dire->offset),
9599 ++ squashfs_filetype_table[dire->type])
9600 ++ < 0) {
9601 ++ TRACE("Filldir returned less than 0\n");
9602 ++ goto finish;
9603 ++ }
9604 ++ file->f_pos = length;
9605 ++ }
9606 ++ }
9607 ++
9608 ++finish:
9609 ++ kfree(dire);
9610 ++ return 0;
9611 ++
9612 ++failed_read:
9613 ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
9614 ++ next_offset);
9615 ++ kfree(dire);
9616 ++ return 0;
9617 ++}
9618 ++
9619 ++
9620 ++static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry,
9621 ++ struct nameidata *nd)
9622 ++{
9623 ++ const unsigned char *name = dentry->d_name.name;
9624 ++ int len = dentry->d_name.len;
9625 ++ struct inode *inode = NULL;
9626 ++ struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
9627 ++ struct squashfs_super_block *sblk = &msblk->sblk;
9628 ++ long long next_block = SQUASHFS_I(i)->start_block +
9629 ++ sblk->directory_table_start;
9630 ++ int next_offset = SQUASHFS_I(i)->offset, length = 0,
9631 ++ dir_count;
9632 ++ struct squashfs_dir_header_2 dirh;
9633 ++ struct squashfs_dir_entry_2 *dire;
9634 ++ int sorted = sblk->s_major == 2 && sblk->s_minor >= 1;
9635 ++
9636 ++ TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset);
9637 ++
9638 ++ if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
9639 ++ SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
9640 ++ ERROR("Failed to allocate squashfs_dir_entry\n");
9641 ++ goto exit_loop;
9642 ++ }
9643 ++
9644 ++ if (len > SQUASHFS_NAME_LEN)
9645 ++ goto exit_loop;
9646 ++
9647 ++ length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
9648 ++ SQUASHFS_I(i)->u.s2.directory_index_start,
9649 ++ SQUASHFS_I(i)->u.s2.directory_index_offset,
9650 ++ SQUASHFS_I(i)->u.s2.directory_index_count, name,
9651 ++ len);
9652 ++
9653 ++ while (length < i_size_read(i)) {
9654 ++ /* read directory header */
9655 ++ if (msblk->swap) {
9656 ++ struct squashfs_dir_header_2 sdirh;
9657 ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
9658 ++ next_block, next_offset, sizeof(sdirh),
9659 ++ &next_block, &next_offset))
9660 ++ goto failed_read;
9661 ++
9662 ++ length += sizeof(sdirh);
9663 ++ SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
9664 ++ } else {
9665 ++ if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
9666 ++ next_block, next_offset, sizeof(dirh),
9667 ++ &next_block, &next_offset))
9668 ++ goto failed_read;
9669 ++
9670 ++ length += sizeof(dirh);
9671 ++ }
9672 ++
9673 ++ dir_count = dirh.count + 1;
9674 ++ while (dir_count--) {
9675 ++ if (msblk->swap) {
9676 ++ struct squashfs_dir_entry_2 sdire;
9677 ++ if (!squashfs_get_cached_block(i->i_sb, (char *)
9678 ++ &sdire, next_block,next_offset,
9679 ++ sizeof(sdire), &next_block,
9680 ++ &next_offset))
9681 ++ goto failed_read;
9682 ++
9683 ++ length += sizeof(sdire);
9684 ++ SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
9685 ++ } else {
9686 ++ if (!squashfs_get_cached_block(i->i_sb, (char *)
9687 ++ dire, next_block,next_offset,
9688 ++ sizeof(*dire), &next_block,
9689 ++ &next_offset))
9690 ++ goto failed_read;
9691 ++
9692 ++ length += sizeof(*dire);
9693 ++ }
9694 ++
9695 ++ if (!squashfs_get_cached_block(i->i_sb, dire->name,
9696 ++ next_block, next_offset, dire->size + 1,
9697 ++ &next_block, &next_offset))
9698 ++ goto failed_read;
9699 ++
9700 ++ length += dire->size + 1;
9701 ++
9702 ++ if (sorted && name[0] < dire->name[0])
9703 ++ goto exit_loop;
9704 ++
9705 ++ if ((len == dire->size + 1) && !strncmp(name,
9706 ++ dire->name, len)) {
9707 ++ squashfs_inode_t ino =
9708 ++ SQUASHFS_MKINODE(dirh.start_block,
9709 ++ dire->offset);
9710 ++ unsigned int inode_number = SQUASHFS_MK_VFS_INODE(dirh.start_block,
9711 ++ dire->offset);
9712 ++
9713 ++ TRACE("calling squashfs_iget for directory "
9714 ++ "entry %s, inode %x:%x, %lld\n", name,
9715 ++ dirh.start_block, dire->offset, ino);
9716 ++
9717 ++ inode = squashfs_iget(i->i_sb, ino, inode_number);
9718 ++
9719 ++ goto exit_loop;
9720 ++ }
9721 ++ }
9722 ++ }
9723 ++
9724 ++exit_loop:
9725 ++ kfree(dire);
9726 ++ d_add(dentry, inode);
9727 ++ return ERR_PTR(0);
9728 ++
9729 ++failed_read:
9730 ++ ERROR("Unable to read directory block [%llx:%x]\n", next_block,
9731 ++ next_offset);
9732 ++ goto exit_loop;
9733 ++}
9734 ++
9735 ++
9736 ++int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
9737 ++{
9738 ++ struct squashfs_super_block *sblk = &msblk->sblk;
9739 ++
9740 ++ msblk->read_inode = squashfs_read_inode_2;
9741 ++ msblk->read_fragment_index_table = read_fragment_index_table_2;
9742 ++
9743 ++ sblk->bytes_used = sblk->bytes_used_2;
9744 ++ sblk->uid_start = sblk->uid_start_2;
9745 ++ sblk->guid_start = sblk->guid_start_2;
9746 ++ sblk->inode_table_start = sblk->inode_table_start_2;
9747 ++ sblk->directory_table_start = sblk->directory_table_start_2;
9748 ++ sblk->fragment_table_start = sblk->fragment_table_start_2;
9749 ++
9750 ++ return 1;
9751 ++}
9752 +diff -x .gitignore -Nurp linux-2.6.27-rc4/fs/squashfs/squashfs.h linux-2.6.27-rc4-squashfs3.4/fs/squashfs/squashfs.h
9753 +--- linux-2.6.27-rc4/fs/squashfs/squashfs.h 1970-01-01 01:00:00.000000000 +0100
9754 ++++ linux-2.6.27-rc4-squashfs3.4/fs/squashfs/squashfs.h 2008-08-19 18:31:56.000000000 +0100
9755 +@@ -0,0 +1,86 @@
9756 ++/*
9757 ++ * Squashfs - a compressed read only filesystem for Linux
9758 ++ *
9759 ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
9760 ++ * Phillip Lougher <phillip@××××××××××××××××.uk>
9761 ++ *
9762 ++ * This program is free software; you can redistribute it and/or
9763 ++ * modify it under the terms of the GNU General Public License
9764 ++ * as published by the Free Software Foundation; either version 2,
9765 ++ * or (at your option) any later version.
9766 ++ *
9767 ++ * This program is distributed in the hope that it will be useful,
9768 ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
9769 ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9770 ++ * GNU General Public License for more details.
9771 ++ *
9772 ++ * You should have received a copy of the GNU General Public License
9773 ++ * along with this program; if not, write to the Free Software
9774 ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
9775 ++ *
9776 ++ * squashfs.h
9777 ++ */
9778 ++
9779 ++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
9780 ++#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
9781 ++#endif
9782 ++
9783 ++#ifdef SQUASHFS_TRACE
9784 ++#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args)
9785 ++#else
9786 ++#define TRACE(s, args...) {}
9787 ++#endif
9788 ++
9789 ++#define ERROR(s, args...) printk(KERN_ERR "SQUASHFS error: "s, ## args)
9790 ++
9791 ++#define SERROR(s, args...) do { \
9792 ++ if (!silent) \
9793 ++ printk(KERN_ERR "SQUASHFS error: "s, ## args);\
9794 ++ } while(0)
9795 ++
9796 ++#define WARNING(s, args...) printk(KERN_WARNING "SQUASHFS: "s, ## args)
9797 ++
9798 ++static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode)
9799 ++{
9800 ++ return list_entry(inode, struct squashfs_inode_info, vfs_inode);
9801 ++}
9802 ++
9803 ++#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY)
9804 ++#define SQSH_EXTERN
9805 ++extern unsigned int squashfs_read_data(struct super_block *s, char *buffer,
9806 ++ long long index, unsigned int length,
9807 ++ long long *next_index, int srclength);
9808 ++extern int squashfs_get_cached_block(struct super_block *s, void *buffer,
9809 ++ long long block, unsigned int offset,
9810 ++ int length, long long *next_block,
9811 ++ unsigned int *next_offset);
9812 ++extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct
9813 ++ squashfs_cache_entry *fragment);
9814 ++extern struct squashfs_cache_entry *get_cached_fragment(struct super_block
9815 ++ *s, long long start_block,
9816 ++ int length);
9817 ++extern struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode, unsigned int inode_number);
9818 ++extern const struct address_space_operations squashfs_symlink_aops;
9819 ++extern const struct address_space_operations squashfs_aops;
9820 ++extern struct inode_operations squashfs_dir_inode_ops;
9821 ++#else
9822 ++#define SQSH_EXTERN static
9823 ++#endif
9824 ++
9825 ++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
9826 ++extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk);
9827 ++#else
9828 ++static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk)
9829 ++{
9830 ++ return 0;
9831 ++}
9832 ++#endif
9833 ++
9834 ++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
9835 ++extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk);
9836 ++#else
9837 ++static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
9838 ++{
9839 ++ return 0;
9840 ++}
9841 ++#endif
9842 +diff -x .gitignore -Nurp linux-2.6.27-rc4/include/linux/squashfs_fs.h linux-2.6.27-rc4-squashfs3.4/include/linux/squashfs_fs.h
9843 +--- linux-2.6.27-rc4/include/linux/squashfs_fs.h 1970-01-01 01:00:00.000000000 +0100
9844 ++++ linux-2.6.27-rc4-squashfs3.4/include/linux/squashfs_fs.h 2008-08-19 18:31:56.000000000 +0100
9845 +@@ -0,0 +1,935 @@
9846 ++#ifndef SQUASHFS_FS
9847 ++#define SQUASHFS_FS
9848 ++
9849 ++/*
9850 ++ * Squashfs
9851 ++ *
9852 ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
9853 ++ * Phillip Lougher <phillip@××××××××××××××××.uk>
9854 ++ *
9855 ++ * This program is free software; you can redistribute it and/or
9856 ++ * modify it under the terms of the GNU General Public License
9857 ++ * as published by the Free Software Foundation; either version 2,
9858 ++ * or (at your option) any later version.
9859 ++ *
9860 ++ * This program is distributed in the hope that it will be useful,
9861 ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
9862 ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9863 ++ * GNU General Public License for more details.
9864 ++ *
9865 ++ * You should have received a copy of the GNU General Public License
9866 ++ * along with this program; if not, write to the Free Software
9867 ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
9868 ++ *
9869 ++ * squashfs_fs.h
9870 ++ */
9871 ++
9872 ++#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY
9873 ++#define CONFIG_SQUASHFS_2_0_COMPATIBILITY
9874 ++#endif
9875 ++
9876 ++#define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE
9877 ++#define SQUASHFS_MAJOR 3
9878 ++#define SQUASHFS_MINOR 1
9879 ++#define SQUASHFS_MAGIC 0x73717368
9880 ++#define SQUASHFS_MAGIC_SWAP 0x68737173
9881 ++#define SQUASHFS_START 0
9882 ++
9883 ++/* size of metadata (inode and directory) blocks */
9884 ++#define SQUASHFS_METADATA_SIZE 8192
9885 ++#define SQUASHFS_METADATA_LOG 13
9886 ++
9887 ++/* default size of data blocks */
9888 ++#define SQUASHFS_FILE_SIZE 131072
9889 ++#define SQUASHFS_FILE_LOG 17
9890 ++
9891 ++#define SQUASHFS_FILE_MAX_SIZE 1048576
9892 ++
9893 ++/* Max number of uids and gids */
9894 ++#define SQUASHFS_UIDS 256
9895 ++#define SQUASHFS_GUIDS 255
9896 ++
9897 ++/* Max length of filename (not 255) */
9898 ++#define SQUASHFS_NAME_LEN 256
9899 ++
9900 ++#define SQUASHFS_INVALID ((long long) 0xffffffffffff)
9901 ++#define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff)
9902 ++#define SQUASHFS_INVALID_BLK ((long long) -1)
9903 ++#define SQUASHFS_USED_BLK ((long long) -2)
9904 ++
9905 ++/* Filesystem flags */
9906 ++#define SQUASHFS_NOI 0
9907 ++#define SQUASHFS_NOD 1
9908 ++#define SQUASHFS_CHECK 2
9909 ++#define SQUASHFS_NOF 3
9910 ++#define SQUASHFS_NO_FRAG 4
9911 ++#define SQUASHFS_ALWAYS_FRAG 5
9912 ++#define SQUASHFS_DUPLICATE 6
9913 ++#define SQUASHFS_EXPORT 7
9914 ++
9915 ++#define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1)
9916 ++
9917 ++#define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \
9918 ++ SQUASHFS_NOI)
9919 ++
9920 ++#define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \
9921 ++ SQUASHFS_NOD)
9922 ++
9923 ++#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
9924 ++ SQUASHFS_NOF)
9925 ++
9926 ++#define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
9927 ++ SQUASHFS_NO_FRAG)
9928 ++
9929 ++#define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \
9930 ++ SQUASHFS_ALWAYS_FRAG)
9931 ++
9932 ++#define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \
9933 ++ SQUASHFS_DUPLICATE)
9934 ++
9935 ++#define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \
9936 ++ SQUASHFS_EXPORT)
9937 ++
9938 ++#define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \
9939 ++ SQUASHFS_CHECK)
9940 ++
9941 ++#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \
9942 ++ duplicate_checking, exportable) (noi | (nod << 1) | (check_data << 2) \
9943 ++ | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \
9944 ++ (duplicate_checking << 6) | (exportable << 7))
9945 ++
9946 ++/* Max number of types and file types */
9947 ++#define SQUASHFS_DIR_TYPE 1
9948 ++#define SQUASHFS_FILE_TYPE 2
9949 ++#define SQUASHFS_SYMLINK_TYPE 3
9950 ++#define SQUASHFS_BLKDEV_TYPE 4
9951 ++#define SQUASHFS_CHRDEV_TYPE 5
9952 ++#define SQUASHFS_FIFO_TYPE 6
9953 ++#define SQUASHFS_SOCKET_TYPE 7
9954 ++#define SQUASHFS_LDIR_TYPE 8
9955 ++#define SQUASHFS_LREG_TYPE 9
9956 ++
9957 ++/* 1.0 filesystem type definitions */
9958 ++#define SQUASHFS_TYPES 5
9959 ++#define SQUASHFS_IPC_TYPE 0
9960 ++
9961 ++/* Flag whether block is compressed or uncompressed, bit is set if block is
9962 ++ * uncompressed */
9963 ++#define SQUASHFS_COMPRESSED_BIT (1 << 15)
9964 ++
9965 ++#define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
9966 ++ (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT)
9967 ++
9968 ++#define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT))
9969 ++
9970 ++#define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24)
9971 ++
9972 ++#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) ((B) & \
9973 ++ ~SQUASHFS_COMPRESSED_BIT_BLOCK)
9974 ++
9975 ++#define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
9976 ++
9977 ++/*
9978 ++ * Inode number ops. Inodes consist of a compressed block number, and an
9979 ++ * uncompressed offset within that block
9980 ++ */
9981 ++#define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16))
9982 ++
9983 ++#define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff))
9984 ++
9985 ++#define SQUASHFS_MKINODE(A, B) ((squashfs_inode_t)(((squashfs_inode_t) (A)\
9986 ++ << 16) + (B)))
9987 ++
9988 ++/* Compute 32 bit VFS inode number from squashfs inode number */
9989 ++#define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \
9990 ++ ((b) >> 2) + 1))
9991 ++/* XXX */
9992 ++
9993 ++/* Translate between VFS mode and squashfs mode */
9994 ++#define SQUASHFS_MODE(a) ((a) & 0xfff)
9995 ++
9996 ++/* fragment and fragment table defines */
9997 ++#define SQUASHFS_FRAGMENT_BYTES(A) ((A) * sizeof(struct squashfs_fragment_entry))
9998 ++
9999 ++#define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \
10000 ++ SQUASHFS_METADATA_SIZE)
10001 ++
10002 ++#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \
10003 ++ SQUASHFS_METADATA_SIZE)
10004 ++
10005 ++#define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \
10006 ++ SQUASHFS_METADATA_SIZE - 1) / \
10007 ++ SQUASHFS_METADATA_SIZE)
10008 ++
10009 ++#define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\
10010 ++ sizeof(long long))
10011 ++
10012 ++/* inode lookup table defines */
10013 ++#define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(squashfs_inode_t))
10014 ++
10015 ++#define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \
10016 ++ SQUASHFS_METADATA_SIZE)
10017 ++
10018 ++#define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \
10019 ++ SQUASHFS_METADATA_SIZE)
10020 ++
10021 ++#define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \
10022 ++ SQUASHFS_METADATA_SIZE - 1) / \
10023 ++ SQUASHFS_METADATA_SIZE)
10024 ++
10025 ++#define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\
10026 ++ sizeof(long long))
10027 ++
10028 ++/* cached data constants for filesystem */
10029 ++#define SQUASHFS_CACHED_BLKS 8
10030 ++
10031 ++#define SQUASHFS_MAX_FILE_SIZE_LOG 64
10032 ++
10033 ++#define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \
10034 ++ (SQUASHFS_MAX_FILE_SIZE_LOG - 2))
10035 ++
10036 ++#define SQUASHFS_MARKER_BYTE 0xff
10037 ++
10038 ++/* meta index cache */
10039 ++#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
10040 ++#define SQUASHFS_META_ENTRIES 31
10041 ++#define SQUASHFS_META_NUMBER 8
10042 ++#define SQUASHFS_SLOTS 4
10043 ++
10044 ++struct meta_entry {
10045 ++ long long data_block;
10046 ++ unsigned int index_block;
10047 ++ unsigned short offset;
10048 ++ unsigned short pad;
10049 ++};
10050 ++
10051 ++struct meta_index {
10052 ++ unsigned int inode_number;
10053 ++ unsigned int offset;
10054 ++ unsigned short entries;
10055 ++ unsigned short skip;
10056 ++ unsigned short locked;
10057 ++ unsigned short pad;
10058 ++ struct meta_entry meta_entry[SQUASHFS_META_ENTRIES];
10059 ++};
10060 ++
10061 ++
10062 ++/*
10063 ++ * definitions for structures on disk
10064 ++ */
10065 ++
10066 ++typedef long long squashfs_block_t;
10067 ++typedef long long squashfs_inode_t;
10068 ++
10069 ++struct squashfs_super_block {
10070 ++ unsigned int s_magic;
10071 ++ unsigned int inodes;
10072 ++ unsigned int bytes_used_2;
10073 ++ unsigned int uid_start_2;
10074 ++ unsigned int guid_start_2;
10075 ++ unsigned int inode_table_start_2;
10076 ++ unsigned int directory_table_start_2;
10077 ++ unsigned int s_major:16;
10078 ++ unsigned int s_minor:16;
10079 ++ unsigned int block_size_1:16;
10080 ++ unsigned int block_log:16;
10081 ++ unsigned int flags:8;
10082 ++ unsigned int no_uids:8;
10083 ++ unsigned int no_guids:8;
10084 ++ unsigned int mkfs_time /* time of filesystem creation */;
10085 ++ squashfs_inode_t root_inode;
10086 ++ unsigned int block_size;
10087 ++ unsigned int fragments;
10088 ++ unsigned int fragment_table_start_2;
10089 ++ long long bytes_used;
10090 ++ long long uid_start;
10091 ++ long long guid_start;
10092 ++ long long inode_table_start;
10093 ++ long long directory_table_start;
10094 ++ long long fragment_table_start;
10095 ++ long long lookup_table_start;
10096 ++} __attribute__ ((packed));
10097 ++
10098 ++struct squashfs_dir_index {
10099 ++ unsigned int index;
10100 ++ unsigned int start_block;
10101 ++ unsigned char size;
10102 ++ unsigned char name[0];
10103 ++} __attribute__ ((packed));
10104 ++
10105 ++#define SQUASHFS_BASE_INODE_HEADER \
10106 ++ unsigned int inode_type:4; \
10107 ++ unsigned int mode:12; \
10108 ++ unsigned int uid:8; \
10109 ++ unsigned int guid:8; \
10110 ++ unsigned int mtime; \
10111 ++ unsigned int inode_number;
10112 ++
10113 ++struct squashfs_base_inode_header {
10114 ++ SQUASHFS_BASE_INODE_HEADER;
10115 ++} __attribute__ ((packed));
10116 ++
10117 ++struct squashfs_ipc_inode_header {
10118 ++ SQUASHFS_BASE_INODE_HEADER;
10119 ++ unsigned int nlink;
10120 ++} __attribute__ ((packed));
10121 ++
10122 ++struct squashfs_dev_inode_header {
10123 ++ SQUASHFS_BASE_INODE_HEADER;
10124 ++ unsigned int nlink;
10125 ++ unsigned short rdev;
10126 ++} __attribute__ ((packed));
10127 ++
10128 ++struct squashfs_symlink_inode_header {
10129 ++ SQUASHFS_BASE_INODE_HEADER;
10130 ++ unsigned int nlink;
10131 ++ unsigned short symlink_size;
10132 ++ char symlink[0];
10133 ++} __attribute__ ((packed));
10134 ++
10135 ++struct squashfs_reg_inode_header {
10136 ++ SQUASHFS_BASE_INODE_HEADER;
10137 ++ squashfs_block_t start_block;
10138 ++ unsigned int fragment;
10139 ++ unsigned int offset;
10140 ++ unsigned int file_size;
10141 ++ unsigned short block_list[0];
10142 ++} __attribute__ ((packed));
10143 ++
10144 ++struct squashfs_lreg_inode_header {
10145 ++ SQUASHFS_BASE_INODE_HEADER;
10146 ++ unsigned int nlink;
10147 ++ squashfs_block_t start_block;
10148 ++ unsigned int fragment;
10149 ++ unsigned int offset;
10150 ++ long long file_size;
10151 ++ unsigned short block_list[0];
10152 ++} __attribute__ ((packed));
10153 ++
10154 ++struct squashfs_dir_inode_header {
10155 ++ SQUASHFS_BASE_INODE_HEADER;
10156 ++ unsigned int nlink;
10157 ++ unsigned int file_size:19;
10158 ++ unsigned int offset:13;
10159 ++ unsigned int start_block;
10160 ++ unsigned int parent_inode;
10161 ++} __attribute__ ((packed));
10162 ++
10163 ++struct squashfs_ldir_inode_header {
10164 ++ SQUASHFS_BASE_INODE_HEADER;
10165 ++ unsigned int nlink;
10166 ++ unsigned int file_size:27;
10167 ++ unsigned int offset:13;
10168 ++ unsigned int start_block;
10169 ++ unsigned int i_count:16;
10170 ++ unsigned int parent_inode;
10171 ++ struct squashfs_dir_index index[0];
10172 ++} __attribute__ ((packed));
10173 ++
10174 ++union squashfs_inode_header {
10175 ++ struct squashfs_base_inode_header base;
10176 ++ struct squashfs_dev_inode_header dev;
10177 ++ struct squashfs_symlink_inode_header symlink;
10178 ++ struct squashfs_reg_inode_header reg;
10179 ++ struct squashfs_lreg_inode_header lreg;
10180 ++ struct squashfs_dir_inode_header dir;
10181 ++ struct squashfs_ldir_inode_header ldir;
10182 ++ struct squashfs_ipc_inode_header ipc;
10183 ++};
10184 ++
10185 ++struct squashfs_dir_entry {
10186 ++ unsigned int offset:13;
10187 ++ unsigned int type:3;
10188 ++ unsigned int size:8;
10189 ++ int inode_number:16;
10190 ++ char name[0];
10191 ++} __attribute__ ((packed));
10192 ++
10193 ++struct squashfs_dir_header {
10194 ++ unsigned int count:8;
10195 ++ unsigned int start_block;
10196 ++ unsigned int inode_number;
10197 ++} __attribute__ ((packed));
10198 ++
10199 ++struct squashfs_fragment_entry {
10200 ++ long long start_block;
10201 ++ unsigned int size;
10202 ++ unsigned int unused;
10203 ++} __attribute__ ((packed));
10204 ++
10205 ++extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
10206 ++extern int squashfs_uncompress_init(void);
10207 ++extern int squashfs_uncompress_exit(void);
10208 ++
10209 ++/*
10210 ++ * macros to convert each packed bitfield structure from little endian to big
10211 ++ * endian and vice versa. These are needed when creating or using a filesystem
10212 ++ * on a machine with different byte ordering to the target architecture.
10213 ++ *
10214 ++ */
10215 ++
10216 ++#define SQUASHFS_SWAP_START \
10217 ++ int bits;\
10218 ++ int b_pos;\
10219 ++ unsigned long long val;\
10220 ++ unsigned char *s;\
10221 ++ unsigned char *d;
10222 ++
10223 ++#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
10224 ++ SQUASHFS_SWAP_START\
10225 ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\
10226 ++ SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
10227 ++ SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
10228 ++ SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
10229 ++ SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
10230 ++ SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
10231 ++ SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
10232 ++ SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
10233 ++ SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
10234 ++ SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
10235 ++ SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
10236 ++ SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
10237 ++ SQUASHFS_SWAP((s)->flags, d, 288, 8);\
10238 ++ SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
10239 ++ SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
10240 ++ SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
10241 ++ SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
10242 ++ SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
10243 ++ SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
10244 ++ SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
10245 ++ SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
10246 ++ SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
10247 ++ SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
10248 ++ SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
10249 ++ SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
10250 ++ SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
10251 ++ SQUASHFS_SWAP((s)->lookup_table_start, d, 888, 64);\
10252 ++}
10253 ++
10254 ++#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
10255 ++ SQUASHFS_MEMSET(s, d, n);\
10256 ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
10257 ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\
10258 ++ SQUASHFS_SWAP((s)->uid, d, 16, 8);\
10259 ++ SQUASHFS_SWAP((s)->guid, d, 24, 8);\
10260 ++ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
10261 ++ SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
10262 ++
10263 ++#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
10264 ++ SQUASHFS_SWAP_START\
10265 ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
10266 ++}
10267 ++
10268 ++#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\
10269 ++ SQUASHFS_SWAP_START\
10270 ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
10271 ++ sizeof(struct squashfs_ipc_inode_header))\
10272 ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
10273 ++}
10274 ++
10275 ++#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
10276 ++ SQUASHFS_SWAP_START\
10277 ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
10278 ++ sizeof(struct squashfs_dev_inode_header)); \
10279 ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
10280 ++ SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
10281 ++}
10282 ++
10283 ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
10284 ++ SQUASHFS_SWAP_START\
10285 ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
10286 ++ sizeof(struct squashfs_symlink_inode_header));\
10287 ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
10288 ++ SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
10289 ++}
10290 ++
10291 ++#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
10292 ++ SQUASHFS_SWAP_START\
10293 ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
10294 ++ sizeof(struct squashfs_reg_inode_header));\
10295 ++ SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
10296 ++ SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
10297 ++ SQUASHFS_SWAP((s)->offset, d, 192, 32);\
10298 ++ SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
10299 ++}
10300 ++
10301 ++#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\
10302 ++ SQUASHFS_SWAP_START\
10303 ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
10304 ++ sizeof(struct squashfs_lreg_inode_header));\
10305 ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
10306 ++ SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
10307 ++ SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
10308 ++ SQUASHFS_SWAP((s)->offset, d, 224, 32);\
10309 ++ SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
10310 ++}
10311 ++
10312 ++#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
10313 ++ SQUASHFS_SWAP_START\
10314 ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
10315 ++ sizeof(struct squashfs_dir_inode_header));\
10316 ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
10317 ++ SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
10318 ++ SQUASHFS_SWAP((s)->offset, d, 147, 13);\
10319 ++ SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
10320 ++ SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
10321 ++}
10322 ++
10323 ++#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\
10324 ++ SQUASHFS_SWAP_START\
10325 ++ SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
10326 ++ sizeof(struct squashfs_ldir_inode_header));\
10327 ++ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
10328 ++ SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
10329 ++ SQUASHFS_SWAP((s)->offset, d, 155, 13);\
10330 ++ SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
10331 ++ SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
10332 ++ SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
10333 ++}
10334 ++
10335 ++#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\
10336 ++ SQUASHFS_SWAP_START\
10337 ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\
10338 ++ SQUASHFS_SWAP((s)->index, d, 0, 32);\
10339 ++ SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
10340 ++ SQUASHFS_SWAP((s)->size, d, 64, 8);\
10341 ++}
10342 ++
10343 ++#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
10344 ++ SQUASHFS_SWAP_START\
10345 ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\
10346 ++ SQUASHFS_SWAP((s)->count, d, 0, 8);\
10347 ++ SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
10348 ++ SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
10349 ++}
10350 ++
10351 ++#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
10352 ++ SQUASHFS_SWAP_START\
10353 ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\
10354 ++ SQUASHFS_SWAP((s)->offset, d, 0, 13);\
10355 ++ SQUASHFS_SWAP((s)->type, d, 13, 3);\
10356 ++ SQUASHFS_SWAP((s)->size, d, 16, 8);\
10357 ++ SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
10358 ++}
10359 ++
10360 ++#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\
10361 ++ SQUASHFS_SWAP_START\
10362 ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\
10363 ++ SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
10364 ++ SQUASHFS_SWAP((s)->size, d, 64, 32);\
10365 ++}
10366 ++
10367 ++#define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1)
10368 ++
10369 ++#define SQUASHFS_SWAP_SHORTS(s, d, n) {\
10370 ++ int entry;\
10371 ++ int bit_position;\
10372 ++ SQUASHFS_SWAP_START\
10373 ++ SQUASHFS_MEMSET(s, d, n * 2);\
10374 ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
10375 ++ 16)\
10376 ++ SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
10377 ++}
10378 ++
10379 ++#define SQUASHFS_SWAP_INTS(s, d, n) {\
10380 ++ int entry;\
10381 ++ int bit_position;\
10382 ++ SQUASHFS_SWAP_START\
10383 ++ SQUASHFS_MEMSET(s, d, n * 4);\
10384 ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
10385 ++ 32)\
10386 ++ SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
10387 ++}
10388 ++
10389 ++#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\
10390 ++ int entry;\
10391 ++ int bit_position;\
10392 ++ SQUASHFS_SWAP_START\
10393 ++ SQUASHFS_MEMSET(s, d, n * 8);\
10394 ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
10395 ++ 64)\
10396 ++ SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
10397 ++}
10398 ++
10399 ++#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
10400 ++ int entry;\
10401 ++ int bit_position;\
10402 ++ SQUASHFS_SWAP_START\
10403 ++ SQUASHFS_MEMSET(s, d, n * bits / 8);\
10404 ++ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
10405 ++ bits)\
10406 ++ SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
10407 ++}
10408 ++
10409 ++#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
10410 ++#define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
10411 ++
10412 ++#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
10413 ++
10414 ++struct squashfs_base_inode_header_1 {
10415 ++ unsigned int inode_type:4;
10416 ++ unsigned int mode:12; /* protection */
10417 ++ unsigned int uid:4; /* index into uid table */
10418 ++ unsigned int guid:4; /* index into guid table */
10419 ++} __attribute__ ((packed));
10420 ++
10421 ++struct squashfs_ipc_inode_header_1 {
10422 ++ unsigned int inode_type:4;
10423 ++ unsigned int mode:12; /* protection */
10424 ++ unsigned int uid:4; /* index into uid table */
10425 ++ unsigned int guid:4; /* index into guid table */
10426 ++ unsigned int type:4;
10427 ++ unsigned int offset:4;
10428 ++} __attribute__ ((packed));
10429 ++
10430 ++struct squashfs_dev_inode_header_1 {
10431 ++ unsigned int inode_type:4;
10432 ++ unsigned int mode:12; /* protection */
10433 ++ unsigned int uid:4; /* index into uid table */
10434 ++ unsigned int guid:4; /* index into guid table */
10435 ++ unsigned short rdev;
10436 ++} __attribute__ ((packed));
10437 ++
10438 ++struct squashfs_symlink_inode_header_1 {
10439 ++ unsigned int inode_type:4;
10440 ++ unsigned int mode:12; /* protection */
10441 ++ unsigned int uid:4; /* index into uid table */
10442 ++ unsigned int guid:4; /* index into guid table */
10443 ++ unsigned short symlink_size;
10444 ++ char symlink[0];
10445 ++} __attribute__ ((packed));
10446 ++
10447 ++struct squashfs_reg_inode_header_1 {
10448 ++ unsigned int inode_type:4;
10449 ++ unsigned int mode:12; /* protection */
10450 ++ unsigned int uid:4; /* index into uid table */
10451 ++ unsigned int guid:4; /* index into guid table */
10452 ++ unsigned int mtime;
10453 ++ unsigned int start_block;
10454 ++ unsigned int file_size:32;
10455 ++ unsigned short block_list[0];
10456 ++} __attribute__ ((packed));
10457 ++
10458 ++struct squashfs_dir_inode_header_1 {
10459 ++ unsigned int inode_type:4;
10460 ++ unsigned int mode:12; /* protection */
10461 ++ unsigned int uid:4; /* index into uid table */
10462 ++ unsigned int guid:4; /* index into guid table */
10463 ++ unsigned int file_size:19;
10464 ++ unsigned int offset:13;
10465 ++ unsigned int mtime;
10466 ++ unsigned int start_block:24;
10467 ++} __attribute__ ((packed));
10468 ++
10469 ++union squashfs_inode_header_1 {
10470 ++ struct squashfs_base_inode_header_1 base;
10471 ++ struct squashfs_dev_inode_header_1 dev;
10472 ++ struct squashfs_symlink_inode_header_1 symlink;
10473 ++ struct squashfs_reg_inode_header_1 reg;
10474 ++ struct squashfs_dir_inode_header_1 dir;
10475 ++ struct squashfs_ipc_inode_header_1 ipc;
10476 ++};
10477 ++
10478 ++#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
10479 ++ SQUASHFS_MEMSET(s, d, n);\
10480 ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
10481 ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\
10482 ++ SQUASHFS_SWAP((s)->uid, d, 16, 4);\
10483 ++ SQUASHFS_SWAP((s)->guid, d, 20, 4);
10484 ++
10485 ++#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
10486 ++ SQUASHFS_SWAP_START\
10487 ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
10488 ++}
10489 ++
10490 ++#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
10491 ++ SQUASHFS_SWAP_START\
10492 ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
10493 ++ sizeof(struct squashfs_ipc_inode_header_1));\
10494 ++ SQUASHFS_SWAP((s)->type, d, 24, 4);\
10495 ++ SQUASHFS_SWAP((s)->offset, d, 28, 4);\
10496 ++}
10497 ++
10498 ++#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
10499 ++ SQUASHFS_SWAP_START\
10500 ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
10501 ++ sizeof(struct squashfs_dev_inode_header_1));\
10502 ++ SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
10503 ++}
10504 ++
10505 ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
10506 ++ SQUASHFS_SWAP_START\
10507 ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
10508 ++ sizeof(struct squashfs_symlink_inode_header_1));\
10509 ++ SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
10510 ++}
10511 ++
10512 ++#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
10513 ++ SQUASHFS_SWAP_START\
10514 ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
10515 ++ sizeof(struct squashfs_reg_inode_header_1));\
10516 ++ SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
10517 ++ SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
10518 ++ SQUASHFS_SWAP((s)->file_size, d, 88, 32);\
10519 ++}
10520 ++
10521 ++#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
10522 ++ SQUASHFS_SWAP_START\
10523 ++ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
10524 ++ sizeof(struct squashfs_dir_inode_header_1));\
10525 ++ SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
10526 ++ SQUASHFS_SWAP((s)->offset, d, 43, 13);\
10527 ++ SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
10528 ++ SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
10529 ++}
10530 ++
10531 ++#endif
10532 ++
10533 ++#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
10534 ++
10535 ++struct squashfs_dir_index_2 {
10536 ++ unsigned int index:27;
10537 ++ unsigned int start_block:29;
10538 ++ unsigned char size;
10539 ++ unsigned char name[0];
10540 ++} __attribute__ ((packed));
10541 ++
10542 ++struct squashfs_base_inode_header_2 {
10543 ++ unsigned int inode_type:4;
10544 ++ unsigned int mode:12; /* protection */
10545 ++ unsigned int uid:8; /* index into uid table */
10546 ++ unsigned int guid:8; /* index into guid table */
10547 ++} __attribute__ ((packed));
10548 ++
10549 ++struct squashfs_ipc_inode_header_2 {
10550 ++ unsigned int inode_type:4;
10551 ++ unsigned int mode:12; /* protection */
10552 ++ unsigned int uid:8; /* index into uid table */
10553 ++ unsigned int guid:8; /* index into guid table */
10554 ++} __attribute__ ((packed));
10555 ++
10556 ++struct squashfs_dev_inode_header_2 {
10557 ++ unsigned int inode_type:4;
10558 ++ unsigned int mode:12; /* protection */
10559 ++ unsigned int uid:8; /* index into uid table */
10560 ++ unsigned int guid:8; /* index into guid table */
10561 ++ unsigned short rdev;
10562 ++} __attribute__ ((packed));
10563 ++
10564 ++struct squashfs_symlink_inode_header_2 {
10565 ++ unsigned int inode_type:4;
10566 ++ unsigned int mode:12; /* protection */
10567 ++ unsigned int uid:8; /* index into uid table */
10568 ++ unsigned int guid:8; /* index into guid table */
10569 ++ unsigned short symlink_size;
10570 ++ char symlink[0];
10571 ++} __attribute__ ((packed));
10572 ++
10573 ++struct squashfs_reg_inode_header_2 {
10574 ++ unsigned int inode_type:4;
10575 ++ unsigned int mode:12; /* protection */
10576 ++ unsigned int uid:8; /* index into uid table */
10577 ++ unsigned int guid:8; /* index into guid table */
10578 ++ unsigned int mtime;
10579 ++ unsigned int start_block;
10580 ++ unsigned int fragment;
10581 ++ unsigned int offset;
10582 ++ unsigned int file_size:32;
10583 ++ unsigned short block_list[0];
10584 ++} __attribute__ ((packed));
10585 ++
10586 ++struct squashfs_dir_inode_header_2 {
10587 ++ unsigned int inode_type:4;
10588 ++ unsigned int mode:12; /* protection */
10589 ++ unsigned int uid:8; /* index into uid table */
10590 ++ unsigned int guid:8; /* index into guid table */
10591 ++ unsigned int file_size:19;
10592 ++ unsigned int offset:13;
10593 ++ unsigned int mtime;
10594 ++ unsigned int start_block:24;
10595 ++} __attribute__ ((packed));
10596 ++
10597 ++struct squashfs_ldir_inode_header_2 {
10598 ++ unsigned int inode_type:4;
10599 ++ unsigned int mode:12; /* protection */
10600 ++ unsigned int uid:8; /* index into uid table */
10601 ++ unsigned int guid:8; /* index into guid table */
10602 ++ unsigned int file_size:27;
10603 ++ unsigned int offset:13;
10604 ++ unsigned int mtime;
10605 ++ unsigned int start_block:24;
10606 ++ unsigned int i_count:16;
10607 ++ struct squashfs_dir_index_2 index[0];
10608 ++} __attribute__ ((packed));
10609 ++
10610 ++union squashfs_inode_header_2 {
10611 ++ struct squashfs_base_inode_header_2 base;
10612 ++ struct squashfs_dev_inode_header_2 dev;
10613 ++ struct squashfs_symlink_inode_header_2 symlink;
10614 ++ struct squashfs_reg_inode_header_2 reg;
10615 ++ struct squashfs_dir_inode_header_2 dir;
10616 ++ struct squashfs_ldir_inode_header_2 ldir;
10617 ++ struct squashfs_ipc_inode_header_2 ipc;
10618 ++};
10619 ++
10620 ++struct squashfs_dir_header_2 {
10621 ++ unsigned int count:8;
10622 ++ unsigned int start_block:24;
10623 ++} __attribute__ ((packed));
10624 ++
10625 ++struct squashfs_dir_entry_2 {
10626 ++ unsigned int offset:13;
10627 ++ unsigned int type:3;
10628 ++ unsigned int size:8;
10629 ++ char name[0];
10630 ++} __attribute__ ((packed));
10631 ++
10632 ++struct squashfs_fragment_entry_2 {
10633 ++ unsigned int start_block;
10634 ++ unsigned int size;
10635 ++} __attribute__ ((packed));
10636 ++
10637 ++#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
10638 ++ SQUASHFS_MEMSET(s, d, n);\
10639 ++ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
10640 ++ SQUASHFS_SWAP((s)->mode, d, 4, 12);\
10641 ++ SQUASHFS_SWAP((s)->uid, d, 16, 8);\
10642 ++ SQUASHFS_SWAP((s)->guid, d, 24, 8);\
10643 ++
10644 ++#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
10645 ++ SQUASHFS_SWAP_START\
10646 ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
10647 ++}
10648 ++
10649 ++#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
10650 ++ SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
10651 ++
10652 ++#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
10653 ++ SQUASHFS_SWAP_START\
10654 ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
10655 ++ sizeof(struct squashfs_dev_inode_header_2)); \
10656 ++ SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
10657 ++}
10658 ++
10659 ++#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
10660 ++ SQUASHFS_SWAP_START\
10661 ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
10662 ++ sizeof(struct squashfs_symlink_inode_header_2));\
10663 ++ SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
10664 ++}
10665 ++
10666 ++#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
10667 ++ SQUASHFS_SWAP_START\
10668 ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
10669 ++ sizeof(struct squashfs_reg_inode_header_2));\
10670 ++ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
10671 ++ SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
10672 ++ SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
10673 ++ SQUASHFS_SWAP((s)->offset, d, 128, 32);\
10674 ++ SQUASHFS_SWAP((s)->file_size, d, 160, 32);\
10675 ++}
10676 ++
10677 ++#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
10678 ++ SQUASHFS_SWAP_START\
10679 ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
10680 ++ sizeof(struct squashfs_dir_inode_header_2));\
10681 ++ SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
10682 ++ SQUASHFS_SWAP((s)->offset, d, 51, 13);\
10683 ++ SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
10684 ++ SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
10685 ++}
10686 ++
10687 ++#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
10688 ++ SQUASHFS_SWAP_START\
10689 ++ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
10690 ++ sizeof(struct squashfs_ldir_inode_header_2));\
10691 ++ SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
10692 ++ SQUASHFS_SWAP((s)->offset, d, 59, 13);\
10693 ++ SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
10694 ++ SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
10695 ++ SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
10696 ++}
10697 ++
10698 ++#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
10699 ++ SQUASHFS_SWAP_START\
10700 ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
10701 ++ SQUASHFS_SWAP((s)->index, d, 0, 27);\
10702 ++ SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
10703 ++ SQUASHFS_SWAP((s)->size, d, 56, 8);\
10704 ++}
10705 ++#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
10706 ++ SQUASHFS_SWAP_START\
10707 ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
10708 ++ SQUASHFS_SWAP((s)->count, d, 0, 8);\
10709 ++ SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
10710 ++}
10711 ++
10712 ++#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
10713 ++ SQUASHFS_SWAP_START\
10714 ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
10715 ++ SQUASHFS_SWAP((s)->offset, d, 0, 13);\
10716 ++ SQUASHFS_SWAP((s)->type, d, 13, 3);\
10717 ++ SQUASHFS_SWAP((s)->size, d, 16, 8);\
10718 ++}
10719 ++
10720 ++#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
10721 ++ SQUASHFS_SWAP_START\
10722 ++ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
10723 ++ SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
10724 ++ SQUASHFS_SWAP((s)->size, d, 32, 32);\
10725 ++}
10726 ++
10727 ++#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n)
10728 ++
10729 ++/* fragment and fragment table defines */
10730 ++#define SQUASHFS_FRAGMENT_BYTES_2(A) (A * sizeof(struct squashfs_fragment_entry_2))
10731 ++
10732 ++#define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \
10733 ++ SQUASHFS_METADATA_SIZE)
10734 ++
10735 ++#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \
10736 ++ SQUASHFS_METADATA_SIZE)
10737 ++
10738 ++#define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \
10739 ++ SQUASHFS_METADATA_SIZE - 1) / \
10740 ++ SQUASHFS_METADATA_SIZE)
10741 ++
10742 ++#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\
10743 ++ sizeof(int))
10744 ++
10745 ++#endif
10746 ++
10747 ++#ifdef __KERNEL__
10748 ++
10749 ++/*
10750 ++ * macros used to swap each structure entry, taking into account
10751 ++ * bitfields and different bitfield placing conventions on differing
10752 ++ * architectures
10753 ++ */
10754 ++
10755 ++#include <asm/byteorder.h>
10756 ++
10757 ++#ifdef __BIG_ENDIAN
10758 ++ /* convert from little endian to big endian */
10759 ++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
10760 ++ tbits, b_pos)
10761 ++#else
10762 ++ /* convert from big endian to little endian */
10763 ++#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
10764 ++ tbits, 64 - tbits - b_pos)
10765 ++#endif
10766 ++
10767 ++#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
10768 ++ b_pos = pos % 8;\
10769 ++ val = 0;\
10770 ++ s = (unsigned char *)p + (pos / 8);\
10771 ++ d = ((unsigned char *) &val) + 7;\
10772 ++ for(bits = 0; bits < (tbits + b_pos); bits += 8) \
10773 ++ *d-- = *s++;\
10774 ++ value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
10775 ++}
10776 ++
10777 ++#define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n);
10778 ++
10779 ++#endif
10780 ++#endif
10781 +diff -x .gitignore -Nurp linux-2.6.27-rc4/include/linux/squashfs_fs_i.h linux-2.6.27-rc4-squashfs3.4/include/linux/squashfs_fs_i.h
10782 +--- linux-2.6.27-rc4/include/linux/squashfs_fs_i.h 1970-01-01 01:00:00.000000000 +0100
10783 ++++ linux-2.6.27-rc4-squashfs3.4/include/linux/squashfs_fs_i.h 2008-08-19 18:31:56.000000000 +0100
10784 +@@ -0,0 +1,45 @@
10785 ++#ifndef SQUASHFS_FS_I
10786 ++#define SQUASHFS_FS_I
10787 ++/*
10788 ++ * Squashfs
10789 ++ *
10790 ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
10791 ++ * Phillip Lougher <phillip@××××××××××××××××.uk>
10792 ++ *
10793 ++ * This program is free software; you can redistribute it and/or
10794 ++ * modify it under the terms of the GNU General Public License
10795 ++ * as published by the Free Software Foundation; either version 2,
10796 ++ * or (at your option) any later version.
10797 ++ *
10798 ++ * This program is distributed in the hope that it will be useful,
10799 ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10800 ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10801 ++ * GNU General Public License for more details.
10802 ++ *
10803 ++ * You should have received a copy of the GNU General Public License
10804 ++ * along with this program; if not, write to the Free Software
10805 ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
10806 ++ *
10807 ++ * squashfs_fs_i.h
10808 ++ */
10809 ++
10810 ++struct squashfs_inode_info {
10811 ++ long long start_block;
10812 ++ unsigned int offset;
10813 ++ union {
10814 ++ struct {
10815 ++ long long fragment_start_block;
10816 ++ unsigned int fragment_size;
10817 ++ unsigned int fragment_offset;
10818 ++ long long block_list_start;
10819 ++ } s1;
10820 ++ struct {
10821 ++ long long directory_index_start;
10822 ++ unsigned int directory_index_offset;
10823 ++ unsigned int directory_index_count;
10824 ++ unsigned int parent_inode;
10825 ++ } s2;
10826 ++ } u;
10827 ++ struct inode vfs_inode;
10828 ++};
10829 ++#endif
10830 +diff -x .gitignore -Nurp linux-2.6.27-rc4/include/linux/squashfs_fs_sb.h linux-2.6.27-rc4-squashfs3.4/include/linux/squashfs_fs_sb.h
10831 +--- linux-2.6.27-rc4/include/linux/squashfs_fs_sb.h 1970-01-01 01:00:00.000000000 +0100
10832 ++++ linux-2.6.27-rc4-squashfs3.4/include/linux/squashfs_fs_sb.h 2008-08-19 18:31:56.000000000 +0100
10833 +@@ -0,0 +1,79 @@
10834 ++#ifndef SQUASHFS_FS_SB
10835 ++#define SQUASHFS_FS_SB
10836 ++/*
10837 ++ * Squashfs
10838 ++ *
10839 ++ * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
10840 ++ * Phillip Lougher <phillip@××××××××××××××××.uk>
10841 ++ *
10842 ++ * This program is free software; you can redistribute it and/or
10843 ++ * modify it under the terms of the GNU General Public License
10844 ++ * as published by the Free Software Foundation; either version 2,
10845 ++ * or (at your option) any later version.
10846 ++ *
10847 ++ * This program is distributed in the hope that it will be useful,
10848 ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10849 ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10850 ++ * GNU General Public License for more details.
10851 ++ *
10852 ++ * You should have received a copy of the GNU General Public License
10853 ++ * along with this program; if not, write to the Free Software
10854 ++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
10855 ++ *
10856 ++ * squashfs_fs_sb.h
10857 ++ */
10858 ++
10859 ++#include <linux/squashfs_fs.h>
10860 ++
10861 ++struct squashfs_cache_entry {
10862 ++ long long block;
10863 ++ int length;
10864 ++ int locked;
10865 ++ long long next_index;
10866 ++ char pending;
10867 ++ char error;
10868 ++ int waiting;
10869 ++ wait_queue_head_t wait_queue;
10870 ++ char *data;
10871 ++};
10872 ++
10873 ++struct squashfs_cache {
10874 ++ char *name;
10875 ++ int entries;
10876 ++ int block_size;
10877 ++ int next_blk;
10878 ++ int waiting;
10879 ++ int unused_blks;
10880 ++ int use_vmalloc;
10881 ++ spinlock_t lock;
10882 ++ wait_queue_head_t wait_queue;
10883 ++ struct squashfs_cache_entry entry[0];
10884 ++};
10885 ++
10886 ++struct squashfs_sb_info {
10887 ++ struct squashfs_super_block sblk;
10888 ++ int devblksize;
10889 ++ int devblksize_log2;
10890 ++ int swap;
10891 ++ struct squashfs_cache *block_cache;
10892 ++ struct squashfs_cache *fragment_cache;
10893 ++ int next_meta_index;
10894 ++ unsigned int *uid;
10895 ++ unsigned int *guid;
10896 ++ long long *fragment_index;
10897 ++ unsigned int *fragment_index_2;
10898 ++ char *read_page;
10899 ++ struct mutex read_data_mutex;
10900 ++ struct mutex read_page_mutex;
10901 ++ struct mutex meta_index_mutex;
10902 ++ struct meta_index *meta_index;
10903 ++ z_stream stream;
10904 ++ long long *inode_lookup_table;
10905 ++ int (*read_inode)(struct inode *i, squashfs_inode_t \
10906 ++ inode);
10907 ++ long long (*read_blocklist)(struct inode *inode, int \
10908 ++ index, int readahead_blks, char *block_list, \
10909 ++ unsigned short **block_p, unsigned int *bsize);
10910 ++ int (*read_fragment_index_table)(struct super_block *s);
10911 ++};
10912 ++#endif
10913 +diff -x .gitignore -Nurp linux-2.6.27-rc4/init/do_mounts_rd.c linux-2.6.27-rc4-squashfs3.4/init/do_mounts_rd.c
10914 +--- linux-2.6.27-rc4/init/do_mounts_rd.c 2008-08-11 15:20:55.000000000 +0100
10915 ++++ linux-2.6.27-rc4-squashfs3.4/init/do_mounts_rd.c 2008-08-19 18:31:56.000000000 +0100
10916 +@@ -5,6 +5,7 @@
10917 + #include <linux/ext2_fs.h>
10918 + #include <linux/romfs_fs.h>
10919 + #include <linux/cramfs_fs.h>
10920 ++#include <linux/squashfs_fs.h>
10921 + #include <linux/initrd.h>
10922 + #include <linux/string.h>
10923 +
10924 +@@ -37,6 +38,7 @@ static int __init crd_load(int in_fd, in
10925 + * numbers could not be found.
10926 + *
10927 + * We currently check for the following magic numbers:
10928 ++ * squashfs
10929 + * minix
10930 + * ext2
10931 + * romfs
10932 +@@ -51,6 +53,7 @@ identify_ramdisk_image(int fd, int start
10933 + struct ext2_super_block *ext2sb;
10934 + struct romfs_super_block *romfsb;
10935 + struct cramfs_super *cramfsb;
10936 ++ struct squashfs_super_block *squashfsb;
10937 + int nblocks = -1;
10938 + unsigned char *buf;
10939 +
10940 +@@ -62,6 +65,7 @@ identify_ramdisk_image(int fd, int start
10941 + ext2sb = (struct ext2_super_block *) buf;
10942 + romfsb = (struct romfs_super_block *) buf;
10943 + cramfsb = (struct cramfs_super *) buf;
10944 ++ squashfsb = (struct squashfs_super_block *) buf;
10945 + memset(buf, 0xe5, size);
10946 +
10947 + /*
10948 +@@ -99,6 +103,18 @@ identify_ramdisk_image(int fd, int start
10949 + goto done;
10950 + }
10951 +
10952 ++ /* squashfs is at block zero too */
10953 ++ if (squashfsb->s_magic == SQUASHFS_MAGIC) {
10954 ++ printk(KERN_NOTICE
10955 ++ "RAMDISK: squashfs filesystem found at block %d\n",
10956 ++ start_block);
10957 ++ if (squashfsb->s_major < 3)
10958 ++ nblocks = (squashfsb->bytes_used_2+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
10959 ++ else
10960 ++ nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
10961 ++ goto done;
10962 ++ }
10963 ++
10964 + /*
10965 + * Read block 1 to test for minix and ext2 superblock
10966 + */
10967
10968 Added: genpatches-2.6/trunk/2.6.27/4400_alpha-sysctl-uac.patch
10969 ===================================================================
10970 --- genpatches-2.6/trunk/2.6.27/4400_alpha-sysctl-uac.patch (rev 0)
10971 +++ genpatches-2.6/trunk/2.6.27/4400_alpha-sysctl-uac.patch 2008-10-12 18:19:38 UTC (rev 1354)
10972 @@ -0,0 +1,162 @@
10973 +Index: linux-2.6.26-gentoo/arch/alpha/Kconfig
10974 +===================================================================
10975 +--- linux-2.6.26-gentoo.orig/arch/alpha/Kconfig
10976 ++++ linux-2.6.26-gentoo/arch/alpha/Kconfig
10977 +@@ -624,6 +624,32 @@ config HZ
10978 + default 1200 if ALPHA_RAWHIDE
10979 + default 1024
10980 +
10981 ++config ALPHA_UAC_SYSCTL
10982 ++ bool "Configure UAC policy via sysctl"
10983 ++ depends on SYSCTL
10984 ++ default y
10985 ++ ---help---
10986 ++ Configuring the UAC (unaligned access control) policy on a Linux
10987 ++ system usually involves setting a compile time define. If you say
10988 ++ Y here, you will be able to modify the UAC policy at runtime using
10989 ++ the /proc interface.
10990 ++
10991 ++ The UAC policy defines the action Linux should take when an
10992 ++ unaligned memory access occurs. The action can include printing a
10993 ++ warning message (NOPRINT), sending a signal to the offending
10994 ++ program to help developers debug their applications (SIGBUS), or
10995 ++ disabling the transparent fixing (NOFIX).
10996 ++
10997 ++ The sysctls will be initialized to the compile-time defined UAC
10998 ++ policy. You can change these manually, or with the sysctl(8)
10999 ++ userspace utility.
11000 ++
11001 ++ To disable the warning messages at runtime, you would use
11002 ++
11003 ++ echo 1 > /proc/sys/kernel/uac/noprint
11004 ++
11005 ++ This is pretty harmless. Say Y if you're not sure.
11006 ++
11007 + source "drivers/pci/Kconfig"
11008 + source "drivers/eisa/Kconfig"
11009 +
11010 +Index: linux-2.6.26-gentoo/arch/alpha/kernel/traps.c
11011 +===================================================================
11012 +--- linux-2.6.26-gentoo.orig/arch/alpha/kernel/traps.c
11013 ++++ linux-2.6.26-gentoo/arch/alpha/kernel/traps.c
11014 +@@ -103,6 +103,52 @@ static char * ireg_name[] = {"v0", "t0",
11015 + "t10", "t11", "ra", "pv", "at", "gp", "sp", "zero"};
11016 + #endif
11017 +
11018 ++#ifdef CONFIG_ALPHA_UAC_SYSCTL
11019 ++
11020 ++#include <linux/sysctl.h>
11021 ++
11022 ++static int enabled_noprint = 0;
11023 ++static int enabled_sigbus = 0;
11024 ++static int enabled_nofix = 0;
11025 ++
11026 ++ctl_table uac_table[] = {
11027 ++ {
11028 ++ .ctl_name = CTL_UNNUMBERED,
11029 ++ .procname = "noprint",
11030 ++ .data = &enabled_noprint,
11031 ++ .maxlen = sizeof (int),
11032 ++ .mode = 0644,
11033 ++ .proc_handler = &proc_dointvec,
11034 ++ },
11035 ++ {
11036 ++ .ctl_name = CTL_UNNUMBERED,
11037 ++ .procname = "sigbus",
11038 ++ .data = &enabled_sigbus,
11039 ++ .maxlen = sizeof (int),
11040 ++ .mode = 0644,
11041 ++ .proc_handler = &proc_dointvec,
11042 ++ },
11043 ++ {
11044 ++ .ctl_name = CTL_UNNUMBERED,
11045 ++ .procname = "nofix",
11046 ++ .data = &enabled_nofix,
11047 ++ .maxlen = sizeof (int),
11048 ++ .mode = 0644,
11049 ++ .proc_handler = &proc_dointvec,
11050 ++ },
11051 ++ { .ctl_name = 0 }
11052 ++};
11053 ++
11054 ++static int __init init_uac_sysctl(void)
11055 ++{
11056 ++ /* Initialize sysctls with the #defined UAC policy */
11057 ++ enabled_noprint = (test_thread_flag (TIF_UAC_NOPRINT)) ? 1 : 0;
11058 ++ enabled_sigbus = (test_thread_flag (TIF_UAC_SIGBUS)) ? 1 : 0;
11059 ++ enabled_nofix = (test_thread_flag (TIF_UAC_NOFIX)) ? 1 : 0;
11060 ++ return 0;
11061 ++}
11062 ++#endif
11063 ++
11064 + static void
11065 + dik_show_code(unsigned int *pc)
11066 + {
11067 +@@ -782,7 +828,11 @@ do_entUnaUser(void __user * va, unsigned
11068 + /* Check the UAC bits to decide what the user wants us to do
11069 + with the unaliged access. */
11070 +
11071 ++#ifndef CONFIG_ALPHA_UAC_SYSCTL
11072 + if (!test_thread_flag (TIF_UAC_NOPRINT)) {
11073 ++#else /* CONFIG_ALPHA_UAC_SYSCTL */
11074 ++ if (!(enabled_noprint)) {
11075 ++#endif /* CONFIG_ALPHA_UAC_SYSCTL */
11076 + if (cnt >= 5 && time_after(jiffies, last_time + 5 * HZ)) {
11077 + cnt = 0;
11078 + }
11079 +@@ -793,10 +843,18 @@ do_entUnaUser(void __user * va, unsigned
11080 + }
11081 + last_time = jiffies;
11082 + }
11083 ++#ifndef CONFIG_ALPHA_UAC_SYSCTL
11084 + if (test_thread_flag (TIF_UAC_SIGBUS))
11085 ++#else /* CONFIG_ALPHA_UAC_SYSCTL */
11086 ++ if (enabled_sigbus)
11087 ++#endif /* CONFIG_ALPHA_UAC_SYSCTL */
11088 + goto give_sigbus;
11089 + /* Not sure why you'd want to use this, but... */
11090 ++#ifndef CONFIG_ALPHA_UAC_SYSCTL
11091 + if (test_thread_flag (TIF_UAC_NOFIX))
11092 ++#else /* CONFIG_ALPHA_UAC_SYSCTL */
11093 ++ if (enabled_nofix)
11094 ++#endif /* CONFIG_ALPHA_UAC_SYSCTL */
11095 + return;
11096 +
11097 + /* Don't bother reading ds in the access check since we already
11098 +@@ -1091,3 +1149,7 @@ trap_init(void)
11099 + wrent(entSys, 5);
11100 + wrent(entDbg, 6);
11101 + }
11102 ++
11103 ++#ifdef CONFIG_ALPHA_UAC_SYSCTL
11104 ++ __initcall(init_uac_sysctl);
11105 ++#endif
11106 +Index: linux-2.6.26-gentoo/kernel/sysctl.c
11107 +===================================================================
11108 +--- linux-2.6.26-gentoo.orig/kernel/sysctl.c
11109 ++++ linux-2.6.26-gentoo/kernel/sysctl.c
11110 +@@ -177,6 +177,9 @@ extern struct ctl_table random_table[];
11111 + #ifdef CONFIG_INOTIFY_USER
11112 + extern struct ctl_table inotify_table[];
11113 + #endif
11114 ++#ifdef CONFIG_ALPHA_UAC_SYSCTL
11115 ++extern struct ctl_table uac_table[];
11116 ++#endif
11117 +
11118 + #ifdef HAVE_ARCH_PICK_MMAP_LAYOUT
11119 + int sysctl_legacy_va_layout;
11120 +@@ -832,6 +835,14 @@ static struct ctl_table kern_table[] = {
11121 + * NOTE: do not add new entries to this table unless you have read
11122 + * Documentation/sysctl/ctl_unnumbered.txt
11123 + */
11124 ++#ifdef CONFIG_ALPHA_UAC_SYSCTL
11125 ++ {
11126 ++ .ctl_name = CTL_UNNUMBERED,
11127 ++ .procname = "uac",
11128 ++ .mode = 0555,
11129 ++ .child = uac_table,
11130 ++ },
11131 ++#endif /* CONFIG_ALPHA_UAC_SYSCTL */
11132 + { .ctl_name = 0 }
11133 + };
11134 +
11135
11136 Deleted: genpatches-2.6/trunk/2.6.27/4405_alpha-sysctl-uac.patch
11137 ===================================================================
11138 --- genpatches-2.6/trunk/2.6.27/4405_alpha-sysctl-uac.patch 2008-10-11 01:09:49 UTC (rev 1353)
11139 +++ genpatches-2.6/trunk/2.6.27/4405_alpha-sysctl-uac.patch 2008-10-12 18:19:38 UTC (rev 1354)
11140 @@ -1,162 +0,0 @@
11141 -Index: linux-2.6.26-gentoo/arch/alpha/Kconfig
11142 -===================================================================
11143 ---- linux-2.6.26-gentoo.orig/arch/alpha/Kconfig
11144 -+++ linux-2.6.26-gentoo/arch/alpha/Kconfig
11145 -@@ -624,6 +624,32 @@ config HZ
11146 - default 1200 if ALPHA_RAWHIDE
11147 - default 1024
11148 -
11149 -+config ALPHA_UAC_SYSCTL
11150 -+ bool "Configure UAC policy via sysctl"
11151 -+ depends on SYSCTL
11152 -+ default y
11153 -+ ---help---
11154 -+ Configuring the UAC (unaligned access control) policy on a Linux
11155 -+ system usually involves setting a compile time define. If you say
11156 -+ Y here, you will be able to modify the UAC policy at runtime using
11157 -+ the /proc interface.
11158 -+
11159 -+ The UAC policy defines the action Linux should take when an
11160 -+ unaligned memory access occurs. The action can include printing a
11161 -+ warning message (NOPRINT), sending a signal to the offending
11162 -+ program to help developers debug their applications (SIGBUS), or
11163 -+ disabling the transparent fixing (NOFIX).
11164 -+
11165 -+ The sysctls will be initialized to the compile-time defined UAC
11166 -+ policy. You can change these manually, or with the sysctl(8)
11167 -+ userspace utility.
11168 -+
11169 -+ To disable the warning messages at runtime, you would use
11170 -+
11171 -+ echo 1 > /proc/sys/kernel/uac/noprint
11172 -+
11173 -+ This is pretty harmless. Say Y if you're not sure.
11174 -+
11175 - source "drivers/pci/Kconfig"
11176 - source "drivers/eisa/Kconfig"
11177 -
11178 -Index: linux-2.6.26-gentoo/arch/alpha/kernel/traps.c
11179 -===================================================================
11180 ---- linux-2.6.26-gentoo.orig/arch/alpha/kernel/traps.c
11181 -+++ linux-2.6.26-gentoo/arch/alpha/kernel/traps.c
11182 -@@ -103,6 +103,52 @@ static char * ireg_name[] = {"v0", "t0",
11183 - "t10", "t11", "ra", "pv", "at", "gp", "sp", "zero"};
11184 - #endif
11185 -
11186 -+#ifdef CONFIG_ALPHA_UAC_SYSCTL
11187 -+
11188 -+#include <linux/sysctl.h>
11189 -+
11190 -+static int enabled_noprint = 0;
11191 -+static int enabled_sigbus = 0;
11192 -+static int enabled_nofix = 0;
11193 -+
11194 -+ctl_table uac_table[] = {
11195 -+ {
11196 -+ .ctl_name = CTL_UNNUMBERED,
11197 -+ .procname = "noprint",
11198 -+ .data = &enabled_noprint,
11199 -+ .maxlen = sizeof (int),
11200 -+ .mode = 0644,
11201 -+ .proc_handler = &proc_dointvec,
11202 -+ },
11203 -+ {
11204 -+ .ctl_name = CTL_UNNUMBERED,
11205 -+ .procname = "sigbus",
11206 -+ .data = &enabled_sigbus,
11207 -+ .maxlen = sizeof (int),
11208 -+ .mode = 0644,
11209 -+ .proc_handler = &proc_dointvec,
11210 -+ },
11211 -+ {
11212 -+ .ctl_name = CTL_UNNUMBERED,
11213 -+ .procname = "nofix",
11214 -+ .data = &enabled_nofix,
11215 -+ .maxlen = sizeof (int),
11216 -+ .mode = 0644,
11217 -+ .proc_handler = &proc_dointvec,
11218 -+ },
11219 -+ { .ctl_name = 0 }
11220 -+};
11221 -+
11222 -+static int __init init_uac_sysctl(void)
11223 -+{
11224 -+ /* Initialize sysctls with the #defined UAC policy */
11225 -+ enabled_noprint = (test_thread_flag (TIF_UAC_NOPRINT)) ? 1 : 0;
11226 -+ enabled_sigbus = (test_thread_flag (TIF_UAC_SIGBUS)) ? 1 : 0;
11227 -+ enabled_nofix = (test_thread_flag (TIF_UAC_NOFIX)) ? 1 : 0;
11228 -+ return 0;
11229 -+}
11230 -+#endif
11231 -+
11232 - static void
11233 - dik_show_code(unsigned int *pc)
11234 - {
11235 -@@ -782,7 +828,11 @@ do_entUnaUser(void __user * va, unsigned
11236 - /* Check the UAC bits to decide what the user wants us to do
11237 - with the unaliged access. */
11238 -
11239 -+#ifndef CONFIG_ALPHA_UAC_SYSCTL
11240 - if (!test_thread_flag (TIF_UAC_NOPRINT)) {
11241 -+#else /* CONFIG_ALPHA_UAC_SYSCTL */
11242 -+ if (!(enabled_noprint)) {
11243 -+#endif /* CONFIG_ALPHA_UAC_SYSCTL */
11244 - if (cnt >= 5 && time_after(jiffies, last_time + 5 * HZ)) {
11245 - cnt = 0;
11246 - }
11247 -@@ -793,10 +843,18 @@ do_entUnaUser(void __user * va, unsigned
11248 - }
11249 - last_time = jiffies;
11250 - }
11251 -+#ifndef CONFIG_ALPHA_UAC_SYSCTL
11252 - if (test_thread_flag (TIF_UAC_SIGBUS))
11253 -+#else /* CONFIG_ALPHA_UAC_SYSCTL */
11254 -+ if (enabled_sigbus)
11255 -+#endif /* CONFIG_ALPHA_UAC_SYSCTL */
11256 - goto give_sigbus;
11257 - /* Not sure why you'd want to use this, but... */
11258 -+#ifndef CONFIG_ALPHA_UAC_SYSCTL
11259 - if (test_thread_flag (TIF_UAC_NOFIX))
11260 -+#else /* CONFIG_ALPHA_UAC_SYSCTL */
11261 -+ if (enabled_nofix)
11262 -+#endif /* CONFIG_ALPHA_UAC_SYSCTL */
11263 - return;
11264 -
11265 - /* Don't bother reading ds in the access check since we already
11266 -@@ -1091,3 +1149,7 @@ trap_init(void)
11267 - wrent(entSys, 5);
11268 - wrent(entDbg, 6);
11269 - }
11270 -+
11271 -+#ifdef CONFIG_ALPHA_UAC_SYSCTL
11272 -+ __initcall(init_uac_sysctl);
11273 -+#endif
11274 -Index: linux-2.6.26-gentoo/kernel/sysctl.c
11275 -===================================================================
11276 ---- linux-2.6.26-gentoo.orig/kernel/sysctl.c
11277 -+++ linux-2.6.26-gentoo/kernel/sysctl.c
11278 -@@ -177,6 +177,9 @@ extern struct ctl_table random_table[];
11279 - #ifdef CONFIG_INOTIFY_USER
11280 - extern struct ctl_table inotify_table[];
11281 - #endif
11282 -+#ifdef CONFIG_ALPHA_UAC_SYSCTL
11283 -+extern struct ctl_table uac_table[];
11284 -+#endif
11285 -
11286 - #ifdef HAVE_ARCH_PICK_MMAP_LAYOUT
11287 - int sysctl_legacy_va_layout;
11288 -@@ -832,6 +835,14 @@ static struct ctl_table kern_table[] = {
11289 - * NOTE: do not add new entries to this table unless you have read
11290 - * Documentation/sysctl/ctl_unnumbered.txt
11291 - */
11292 -+#ifdef CONFIG_ALPHA_UAC_SYSCTL
11293 -+ {
11294 -+ .ctl_name = CTL_UNNUMBERED,
11295 -+ .procname = "uac",
11296 -+ .mode = 0555,
11297 -+ .child = uac_table,
11298 -+ },
11299 -+#endif /* CONFIG_ALPHA_UAC_SYSCTL */
11300 - { .ctl_name = 0 }
11301 - };
11302 -