diff options
Diffstat (limited to 'fs/squashfs')
-rw-r--r-- | fs/squashfs/Makefile | 8 | ||||
-rw-r--r-- | fs/squashfs/block.c | 274 | ||||
-rw-r--r-- | fs/squashfs/cache.c | 412 | ||||
-rw-r--r-- | fs/squashfs/dir.c | 235 | ||||
-rw-r--r-- | fs/squashfs/export.c | 155 | ||||
-rw-r--r-- | fs/squashfs/file.c | 502 | ||||
-rw-r--r-- | fs/squashfs/fragment.c | 98 | ||||
-rw-r--r-- | fs/squashfs/id.c | 94 | ||||
-rw-r--r-- | fs/squashfs/inode.c | 346 | ||||
-rw-r--r-- | fs/squashfs/namei.c | 242 | ||||
-rw-r--r-- | fs/squashfs/squashfs.h | 90 | ||||
-rw-r--r-- | fs/squashfs/squashfs_fs.h | 381 | ||||
-rw-r--r-- | fs/squashfs/squashfs_fs_i.h | 45 | ||||
-rw-r--r-- | fs/squashfs/squashfs_fs_sb.h | 76 | ||||
-rw-r--r-- | fs/squashfs/super.c | 440 | ||||
-rw-r--r-- | fs/squashfs/symlink.c | 118 |
16 files changed, 3516 insertions, 0 deletions
diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile new file mode 100644 index 000000000000..8258cf9a0317 --- /dev/null +++ b/fs/squashfs/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for the linux squashfs routines. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_SQUASHFS) += squashfs.o | ||
6 | squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o | ||
7 | squashfs-y += namei.o super.o symlink.o | ||
8 | #squashfs-y += squashfs2_0.o | ||
diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c new file mode 100644 index 000000000000..c837dfc2b3c6 --- /dev/null +++ b/fs/squashfs/block.c | |||
@@ -0,0 +1,274 @@ | |||
1 | /* | ||
2 | * Squashfs - a compressed read only filesystem for Linux | ||
3 | * | ||
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | ||
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2, | ||
10 | * or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | * | ||
21 | * block.c | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * This file implements the low-level routines to read and decompress | ||
26 | * datablocks and metadata blocks. | ||
27 | */ | ||
28 | |||
29 | #include <linux/fs.h> | ||
30 | #include <linux/vfs.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/mutex.h> | ||
33 | #include <linux/string.h> | ||
34 | #include <linux/buffer_head.h> | ||
35 | #include <linux/zlib.h> | ||
36 | |||
37 | #include "squashfs_fs.h" | ||
38 | #include "squashfs_fs_sb.h" | ||
39 | #include "squashfs_fs_i.h" | ||
40 | #include "squashfs.h" | ||
41 | |||
42 | /* | ||
43 | * Read the metadata block length, this is stored in the first two | ||
44 | * bytes of the metadata block. | ||
45 | */ | ||
46 | static struct buffer_head *get_block_length(struct super_block *sb, | ||
47 | u64 *cur_index, int *offset, int *length) | ||
48 | { | ||
49 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
50 | struct buffer_head *bh; | ||
51 | |||
52 | bh = sb_bread(sb, *cur_index); | ||
53 | if (bh == NULL) | ||
54 | return NULL; | ||
55 | |||
56 | if (msblk->devblksize - *offset == 1) { | ||
57 | *length = (unsigned char) bh->b_data[*offset]; | ||
58 | put_bh(bh); | ||
59 | bh = sb_bread(sb, ++(*cur_index)); | ||
60 | if (bh == NULL) | ||
61 | return NULL; | ||
62 | *length |= (unsigned char) bh->b_data[0] << 8; | ||
63 | *offset = 1; | ||
64 | } else { | ||
65 | *length = (unsigned char) bh->b_data[*offset] | | ||
66 | (unsigned char) bh->b_data[*offset + 1] << 8; | ||
67 | *offset += 2; | ||
68 | } | ||
69 | |||
70 | return bh; | ||
71 | } | ||
72 | |||
73 | |||
74 | /* | ||
75 | * Read and decompress a metadata block or datablock. Length is non-zero | ||
76 | * if a datablock is being read (the size is stored elsewhere in the | ||
77 | * filesystem), otherwise the length is obtained from the first two bytes of | ||
78 | * the metadata block. A bit in the length field indicates if the block | ||
79 | * is stored uncompressed in the filesystem (usually because compression | ||
80 | * generated a larger block - this does occasionally happen with zlib). | ||
81 | */ | ||
82 | int squashfs_read_data(struct super_block *sb, void **buffer, u64 index, | ||
83 | int length, u64 *next_index, int srclength) | ||
84 | { | ||
85 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
86 | struct buffer_head **bh; | ||
87 | int offset = index & ((1 << msblk->devblksize_log2) - 1); | ||
88 | u64 cur_index = index >> msblk->devblksize_log2; | ||
89 | int bytes, compressed, b = 0, k = 0, page = 0, avail; | ||
90 | |||
91 | |||
92 | bh = kcalloc((msblk->block_size >> msblk->devblksize_log2) + 1, | ||
93 | sizeof(*bh), GFP_KERNEL); | ||
94 | if (bh == NULL) | ||
95 | return -ENOMEM; | ||
96 | |||
97 | if (length) { | ||
98 | /* | ||
99 | * Datablock. | ||
100 | */ | ||
101 | bytes = -offset; | ||
102 | compressed = SQUASHFS_COMPRESSED_BLOCK(length); | ||
103 | length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length); | ||
104 | if (next_index) | ||
105 | *next_index = index + length; | ||
106 | |||
107 | TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n", | ||
108 | index, compressed ? "" : "un", length, srclength); | ||
109 | |||
110 | if (length < 0 || length > srclength || | ||
111 | (index + length) > msblk->bytes_used) | ||
112 | goto read_failure; | ||
113 | |||
114 | for (b = 0; bytes < length; b++, cur_index++) { | ||
115 | bh[b] = sb_getblk(sb, cur_index); | ||
116 | if (bh[b] == NULL) | ||
117 | goto block_release; | ||
118 | bytes += msblk->devblksize; | ||
119 | } | ||
120 | ll_rw_block(READ, b, bh); | ||
121 | } else { | ||
122 | /* | ||
123 | * Metadata block. | ||
124 | */ | ||
125 | if ((index + 2) > msblk->bytes_used) | ||
126 | goto read_failure; | ||
127 | |||
128 | bh[0] = get_block_length(sb, &cur_index, &offset, &length); | ||
129 | if (bh[0] == NULL) | ||
130 | goto read_failure; | ||
131 | b = 1; | ||
132 | |||
133 | bytes = msblk->devblksize - offset; | ||
134 | compressed = SQUASHFS_COMPRESSED(length); | ||
135 | length = SQUASHFS_COMPRESSED_SIZE(length); | ||
136 | if (next_index) | ||
137 | *next_index = index + length + 2; | ||
138 | |||
139 | TRACE("Block @ 0x%llx, %scompressed size %d\n", index, | ||
140 | compressed ? "" : "un", length); | ||
141 | |||
142 | if (length < 0 || length > srclength || | ||
143 | (index + length) > msblk->bytes_used) | ||
144 | goto block_release; | ||
145 | |||
146 | for (; bytes < length; b++) { | ||
147 | bh[b] = sb_getblk(sb, ++cur_index); | ||
148 | if (bh[b] == NULL) | ||
149 | goto block_release; | ||
150 | bytes += msblk->devblksize; | ||
151 | } | ||
152 | ll_rw_block(READ, b - 1, bh + 1); | ||
153 | } | ||
154 | |||
155 | if (compressed) { | ||
156 | int zlib_err = 0, zlib_init = 0; | ||
157 | |||
158 | /* | ||
159 | * Uncompress block. | ||
160 | */ | ||
161 | |||
162 | mutex_lock(&msblk->read_data_mutex); | ||
163 | |||
164 | msblk->stream.avail_out = 0; | ||
165 | msblk->stream.avail_in = 0; | ||
166 | |||
167 | bytes = length; | ||
168 | do { | ||
169 | if (msblk->stream.avail_in == 0 && k < b) { | ||
170 | avail = min(bytes, msblk->devblksize - offset); | ||
171 | bytes -= avail; | ||
172 | wait_on_buffer(bh[k]); | ||
173 | if (!buffer_uptodate(bh[k])) | ||
174 | goto release_mutex; | ||
175 | |||
176 | if (avail == 0) { | ||
177 | offset = 0; | ||
178 | put_bh(bh[k++]); | ||
179 | continue; | ||
180 | } | ||
181 | |||
182 | msblk->stream.next_in = bh[k]->b_data + offset; | ||
183 | msblk->stream.avail_in = avail; | ||
184 | offset = 0; | ||
185 | } | ||
186 | |||
187 | if (msblk->stream.avail_out == 0) { | ||
188 | msblk->stream.next_out = buffer[page++]; | ||
189 | msblk->stream.avail_out = PAGE_CACHE_SIZE; | ||
190 | } | ||
191 | |||
192 | if (!zlib_init) { | ||
193 | zlib_err = zlib_inflateInit(&msblk->stream); | ||
194 | if (zlib_err != Z_OK) { | ||
195 | ERROR("zlib_inflateInit returned" | ||
196 | " unexpected result 0x%x," | ||
197 | " srclength %d\n", zlib_err, | ||
198 | srclength); | ||
199 | goto release_mutex; | ||
200 | } | ||
201 | zlib_init = 1; | ||
202 | } | ||
203 | |||
204 | zlib_err = zlib_inflate(&msblk->stream, Z_NO_FLUSH); | ||
205 | |||
206 | if (msblk->stream.avail_in == 0 && k < b) | ||
207 | put_bh(bh[k++]); | ||
208 | } while (zlib_err == Z_OK); | ||
209 | |||
210 | if (zlib_err != Z_STREAM_END) { | ||
211 | ERROR("zlib_inflate returned unexpected result" | ||
212 | " 0x%x, srclength %d, avail_in %d," | ||
213 | " avail_out %d\n", zlib_err, srclength, | ||
214 | msblk->stream.avail_in, | ||
215 | msblk->stream.avail_out); | ||
216 | goto release_mutex; | ||
217 | } | ||
218 | |||
219 | zlib_err = zlib_inflateEnd(&msblk->stream); | ||
220 | if (zlib_err != Z_OK) { | ||
221 | ERROR("zlib_inflateEnd returned unexpected result 0x%x," | ||
222 | " srclength %d\n", zlib_err, srclength); | ||
223 | goto release_mutex; | ||
224 | } | ||
225 | length = msblk->stream.total_out; | ||
226 | mutex_unlock(&msblk->read_data_mutex); | ||
227 | } else { | ||
228 | /* | ||
229 | * Block is uncompressed. | ||
230 | */ | ||
231 | int i, in, pg_offset = 0; | ||
232 | |||
233 | for (i = 0; i < b; i++) { | ||
234 | wait_on_buffer(bh[i]); | ||
235 | if (!buffer_uptodate(bh[i])) | ||
236 | goto block_release; | ||
237 | } | ||
238 | |||
239 | for (bytes = length; k < b; k++) { | ||
240 | in = min(bytes, msblk->devblksize - offset); | ||
241 | bytes -= in; | ||
242 | while (in) { | ||
243 | if (pg_offset == PAGE_CACHE_SIZE) { | ||
244 | page++; | ||
245 | pg_offset = 0; | ||
246 | } | ||
247 | avail = min_t(int, in, PAGE_CACHE_SIZE - | ||
248 | pg_offset); | ||
249 | memcpy(buffer[page] + pg_offset, | ||
250 | bh[k]->b_data + offset, avail); | ||
251 | in -= avail; | ||
252 | pg_offset += avail; | ||
253 | offset += avail; | ||
254 | } | ||
255 | offset = 0; | ||
256 | put_bh(bh[k]); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | kfree(bh); | ||
261 | return length; | ||
262 | |||
263 | release_mutex: | ||
264 | mutex_unlock(&msblk->read_data_mutex); | ||
265 | |||
266 | block_release: | ||
267 | for (; k < b; k++) | ||
268 | put_bh(bh[k]); | ||
269 | |||
270 | read_failure: | ||
271 | ERROR("sb_bread failed reading block 0x%llx\n", cur_index); | ||
272 | kfree(bh); | ||
273 | return -EIO; | ||
274 | } | ||
diff --git a/fs/squashfs/cache.c b/fs/squashfs/cache.c new file mode 100644 index 000000000000..f29eda16d25e --- /dev/null +++ b/fs/squashfs/cache.c | |||
@@ -0,0 +1,412 @@ | |||
1 | /* | ||
2 | * Squashfs - a compressed read only filesystem for Linux | ||
3 | * | ||
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | ||
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2, | ||
10 | * or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | * | ||
21 | * cache.c | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * Blocks in Squashfs are compressed. To avoid repeatedly decompressing | ||
26 | * recently accessed data Squashfs uses two small metadata and fragment caches. | ||
27 | * | ||
28 | * This file implements a generic cache implementation used for both caches, | ||
29 | * plus functions layered ontop of the generic cache implementation to | ||
30 | * access the metadata and fragment caches. | ||
31 | * | ||
32 | * To avoid out of memory and fragmentation isssues with vmalloc the cache | ||
33 | * uses sequences of kmalloced PAGE_CACHE_SIZE buffers. | ||
34 | * | ||
35 | * It should be noted that the cache is not used for file datablocks, these | ||
36 | * are decompressed and cached in the page-cache in the normal way. The | ||
37 | * cache is only used to temporarily cache fragment and metadata blocks | ||
38 | * which have been read as as a result of a metadata (i.e. inode or | ||
39 | * directory) or fragment access. Because metadata and fragments are packed | ||
40 | * together into blocks (to gain greater compression) the read of a particular | ||
41 | * piece of metadata or fragment will retrieve other metadata/fragments which | ||
42 | * have been packed with it, these because of locality-of-reference may be read | ||
43 | * in the near future. Temporarily caching them ensures they are available for | ||
44 | * near future access without requiring an additional read and decompress. | ||
45 | */ | ||
46 | |||
47 | #include <linux/fs.h> | ||
48 | #include <linux/vfs.h> | ||
49 | #include <linux/slab.h> | ||
50 | #include <linux/vmalloc.h> | ||
51 | #include <linux/sched.h> | ||
52 | #include <linux/spinlock.h> | ||
53 | #include <linux/wait.h> | ||
54 | #include <linux/zlib.h> | ||
55 | #include <linux/pagemap.h> | ||
56 | |||
57 | #include "squashfs_fs.h" | ||
58 | #include "squashfs_fs_sb.h" | ||
59 | #include "squashfs_fs_i.h" | ||
60 | #include "squashfs.h" | ||
61 | |||
62 | /* | ||
63 | * Look-up block in cache, and increment usage count. If not in cache, read | ||
64 | * and decompress it from disk. | ||
65 | */ | ||
66 | struct squashfs_cache_entry *squashfs_cache_get(struct super_block *sb, | ||
67 | struct squashfs_cache *cache, u64 block, int length) | ||
68 | { | ||
69 | int i, n; | ||
70 | struct squashfs_cache_entry *entry; | ||
71 | |||
72 | spin_lock(&cache->lock); | ||
73 | |||
74 | while (1) { | ||
75 | for (i = 0; i < cache->entries; i++) | ||
76 | if (cache->entry[i].block == block) | ||
77 | break; | ||
78 | |||
79 | if (i == cache->entries) { | ||
80 | /* | ||
81 | * Block not in cache, if all cache entries are used | ||
82 | * go to sleep waiting for one to become available. | ||
83 | */ | ||
84 | if (cache->unused == 0) { | ||
85 | cache->num_waiters++; | ||
86 | spin_unlock(&cache->lock); | ||
87 | wait_event(cache->wait_queue, cache->unused); | ||
88 | spin_lock(&cache->lock); | ||
89 | cache->num_waiters--; | ||
90 | continue; | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * At least one unused cache entry. A simple | ||
95 | * round-robin strategy is used to choose the entry to | ||
96 | * be evicted from the cache. | ||
97 | */ | ||
98 | i = cache->next_blk; | ||
99 | for (n = 0; n < cache->entries; n++) { | ||
100 | if (cache->entry[i].refcount == 0) | ||
101 | break; | ||
102 | i = (i + 1) % cache->entries; | ||
103 | } | ||
104 | |||
105 | cache->next_blk = (i + 1) % cache->entries; | ||
106 | entry = &cache->entry[i]; | ||
107 | |||
108 | /* | ||
109 | * Initialise choosen cache entry, and fill it in from | ||
110 | * disk. | ||
111 | */ | ||
112 | cache->unused--; | ||
113 | entry->block = block; | ||
114 | entry->refcount = 1; | ||
115 | entry->pending = 1; | ||
116 | entry->num_waiters = 0; | ||
117 | entry->error = 0; | ||
118 | spin_unlock(&cache->lock); | ||
119 | |||
120 | entry->length = squashfs_read_data(sb, entry->data, | ||
121 | block, length, &entry->next_index, | ||
122 | cache->block_size); | ||
123 | |||
124 | spin_lock(&cache->lock); | ||
125 | |||
126 | if (entry->length < 0) | ||
127 | entry->error = entry->length; | ||
128 | |||
129 | entry->pending = 0; | ||
130 | |||
131 | /* | ||
132 | * While filling this entry one or more other processes | ||
133 | * have looked it up in the cache, and have slept | ||
134 | * waiting for it to become available. | ||
135 | */ | ||
136 | if (entry->num_waiters) { | ||
137 | spin_unlock(&cache->lock); | ||
138 | wake_up_all(&entry->wait_queue); | ||
139 | } else | ||
140 | spin_unlock(&cache->lock); | ||
141 | |||
142 | goto out; | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * Block already in cache. Increment refcount so it doesn't | ||
147 | * get reused until we're finished with it, if it was | ||
148 | * previously unused there's one less cache entry available | ||
149 | * for reuse. | ||
150 | */ | ||
151 | entry = &cache->entry[i]; | ||
152 | if (entry->refcount == 0) | ||
153 | cache->unused--; | ||
154 | entry->refcount++; | ||
155 | |||
156 | /* | ||
157 | * If the entry is currently being filled in by another process | ||
158 | * go to sleep waiting for it to become available. | ||
159 | */ | ||
160 | if (entry->pending) { | ||
161 | entry->num_waiters++; | ||
162 | spin_unlock(&cache->lock); | ||
163 | wait_event(entry->wait_queue, !entry->pending); | ||
164 | } else | ||
165 | spin_unlock(&cache->lock); | ||
166 | |||
167 | goto out; | ||
168 | } | ||
169 | |||
170 | out: | ||
171 | TRACE("Got %s %d, start block %lld, refcount %d, error %d\n", | ||
172 | cache->name, i, entry->block, entry->refcount, entry->error); | ||
173 | |||
174 | if (entry->error) | ||
175 | ERROR("Unable to read %s cache entry [%llx]\n", cache->name, | ||
176 | block); | ||
177 | return entry; | ||
178 | } | ||
179 | |||
180 | |||
181 | /* | ||
182 | * Release cache entry, once usage count is zero it can be reused. | ||
183 | */ | ||
184 | void squashfs_cache_put(struct squashfs_cache_entry *entry) | ||
185 | { | ||
186 | struct squashfs_cache *cache = entry->cache; | ||
187 | |||
188 | spin_lock(&cache->lock); | ||
189 | entry->refcount--; | ||
190 | if (entry->refcount == 0) { | ||
191 | cache->unused++; | ||
192 | /* | ||
193 | * If there's any processes waiting for a block to become | ||
194 | * available, wake one up. | ||
195 | */ | ||
196 | if (cache->num_waiters) { | ||
197 | spin_unlock(&cache->lock); | ||
198 | wake_up(&cache->wait_queue); | ||
199 | return; | ||
200 | } | ||
201 | } | ||
202 | spin_unlock(&cache->lock); | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * Delete cache reclaiming all kmalloced buffers. | ||
207 | */ | ||
208 | void squashfs_cache_delete(struct squashfs_cache *cache) | ||
209 | { | ||
210 | int i, j; | ||
211 | |||
212 | if (cache == NULL) | ||
213 | return; | ||
214 | |||
215 | for (i = 0; i < cache->entries; i++) { | ||
216 | if (cache->entry[i].data) { | ||
217 | for (j = 0; j < cache->pages; j++) | ||
218 | kfree(cache->entry[i].data[j]); | ||
219 | kfree(cache->entry[i].data); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | kfree(cache->entry); | ||
224 | kfree(cache); | ||
225 | } | ||
226 | |||
227 | |||
228 | /* | ||
229 | * Initialise cache allocating the specified number of entries, each of | ||
230 | * size block_size. To avoid vmalloc fragmentation issues each entry | ||
231 | * is allocated as a sequence of kmalloced PAGE_CACHE_SIZE buffers. | ||
232 | */ | ||
233 | struct squashfs_cache *squashfs_cache_init(char *name, int entries, | ||
234 | int block_size) | ||
235 | { | ||
236 | int i, j; | ||
237 | struct squashfs_cache *cache = kzalloc(sizeof(*cache), GFP_KERNEL); | ||
238 | |||
239 | if (cache == NULL) { | ||
240 | ERROR("Failed to allocate %s cache\n", name); | ||
241 | return NULL; | ||
242 | } | ||
243 | |||
244 | cache->entry = kcalloc(entries, sizeof(*(cache->entry)), GFP_KERNEL); | ||
245 | if (cache->entry == NULL) { | ||
246 | ERROR("Failed to allocate %s cache\n", name); | ||
247 | goto cleanup; | ||
248 | } | ||
249 | |||
250 | cache->next_blk = 0; | ||
251 | cache->unused = entries; | ||
252 | cache->entries = entries; | ||
253 | cache->block_size = block_size; | ||
254 | cache->pages = block_size >> PAGE_CACHE_SHIFT; | ||
255 | cache->name = name; | ||
256 | cache->num_waiters = 0; | ||
257 | spin_lock_init(&cache->lock); | ||
258 | init_waitqueue_head(&cache->wait_queue); | ||
259 | |||
260 | for (i = 0; i < entries; i++) { | ||
261 | struct squashfs_cache_entry *entry = &cache->entry[i]; | ||
262 | |||
263 | init_waitqueue_head(&cache->entry[i].wait_queue); | ||
264 | entry->cache = cache; | ||
265 | entry->block = SQUASHFS_INVALID_BLK; | ||
266 | entry->data = kcalloc(cache->pages, sizeof(void *), GFP_KERNEL); | ||
267 | if (entry->data == NULL) { | ||
268 | ERROR("Failed to allocate %s cache entry\n", name); | ||
269 | goto cleanup; | ||
270 | } | ||
271 | |||
272 | for (j = 0; j < cache->pages; j++) { | ||
273 | entry->data[j] = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); | ||
274 | if (entry->data[j] == NULL) { | ||
275 | ERROR("Failed to allocate %s buffer\n", name); | ||
276 | goto cleanup; | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | |||
281 | return cache; | ||
282 | |||
283 | cleanup: | ||
284 | squashfs_cache_delete(cache); | ||
285 | return NULL; | ||
286 | } | ||
287 | |||
288 | |||
289 | /* | ||
290 | * Copy upto length bytes from cache entry to buffer starting at offset bytes | ||
291 | * into the cache entry. If there's not length bytes then copy the number of | ||
292 | * bytes available. In all cases return the number of bytes copied. | ||
293 | */ | ||
294 | int squashfs_copy_data(void *buffer, struct squashfs_cache_entry *entry, | ||
295 | int offset, int length) | ||
296 | { | ||
297 | int remaining = length; | ||
298 | |||
299 | if (length == 0) | ||
300 | return 0; | ||
301 | else if (buffer == NULL) | ||
302 | return min(length, entry->length - offset); | ||
303 | |||
304 | while (offset < entry->length) { | ||
305 | void *buff = entry->data[offset / PAGE_CACHE_SIZE] | ||
306 | + (offset % PAGE_CACHE_SIZE); | ||
307 | int bytes = min_t(int, entry->length - offset, | ||
308 | PAGE_CACHE_SIZE - (offset % PAGE_CACHE_SIZE)); | ||
309 | |||
310 | if (bytes >= remaining) { | ||
311 | memcpy(buffer, buff, remaining); | ||
312 | remaining = 0; | ||
313 | break; | ||
314 | } | ||
315 | |||
316 | memcpy(buffer, buff, bytes); | ||
317 | buffer += bytes; | ||
318 | remaining -= bytes; | ||
319 | offset += bytes; | ||
320 | } | ||
321 | |||
322 | return length - remaining; | ||
323 | } | ||
324 | |||
325 | |||
326 | /* | ||
327 | * Read length bytes from metadata position <block, offset> (block is the | ||
328 | * start of the compressed block on disk, and offset is the offset into | ||
329 | * the block once decompressed). Data is packed into consecutive blocks, | ||
330 | * and length bytes may require reading more than one block. | ||
331 | */ | ||
332 | int squashfs_read_metadata(struct super_block *sb, void *buffer, | ||
333 | u64 *block, int *offset, int length) | ||
334 | { | ||
335 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
336 | int bytes, copied = length; | ||
337 | struct squashfs_cache_entry *entry; | ||
338 | |||
339 | TRACE("Entered squashfs_read_metadata [%llx:%x]\n", *block, *offset); | ||
340 | |||
341 | while (length) { | ||
342 | entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0); | ||
343 | if (entry->error) | ||
344 | return entry->error; | ||
345 | else if (*offset >= entry->length) | ||
346 | return -EIO; | ||
347 | |||
348 | bytes = squashfs_copy_data(buffer, entry, *offset, length); | ||
349 | if (buffer) | ||
350 | buffer += bytes; | ||
351 | length -= bytes; | ||
352 | *offset += bytes; | ||
353 | |||
354 | if (*offset == entry->length) { | ||
355 | *block = entry->next_index; | ||
356 | *offset = 0; | ||
357 | } | ||
358 | |||
359 | squashfs_cache_put(entry); | ||
360 | } | ||
361 | |||
362 | return copied; | ||
363 | } | ||
364 | |||
365 | |||
366 | /* | ||
367 | * Look-up in the fragmment cache the fragment located at <start_block> in the | ||
368 | * filesystem. If necessary read and decompress it from disk. | ||
369 | */ | ||
370 | struct squashfs_cache_entry *squashfs_get_fragment(struct super_block *sb, | ||
371 | u64 start_block, int length) | ||
372 | { | ||
373 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
374 | |||
375 | return squashfs_cache_get(sb, msblk->fragment_cache, start_block, | ||
376 | length); | ||
377 | } | ||
378 | |||
379 | |||
380 | /* | ||
381 | * Read and decompress the datablock located at <start_block> in the | ||
382 | * filesystem. The cache is used here to avoid duplicating locking and | ||
383 | * read/decompress code. | ||
384 | */ | ||
385 | struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *sb, | ||
386 | u64 start_block, int length) | ||
387 | { | ||
388 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
389 | |||
390 | return squashfs_cache_get(sb, msblk->read_page, start_block, length); | ||
391 | } | ||
392 | |||
393 | |||
394 | /* | ||
395 | * Read a filesystem table (uncompressed sequence of bytes) from disk | ||
396 | */ | ||
397 | int squashfs_read_table(struct super_block *sb, void *buffer, u64 block, | ||
398 | int length) | ||
399 | { | ||
400 | int pages = (length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
401 | int i, res; | ||
402 | void **data = kcalloc(pages, sizeof(void *), GFP_KERNEL); | ||
403 | if (data == NULL) | ||
404 | return -ENOMEM; | ||
405 | |||
406 | for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE) | ||
407 | data[i] = buffer; | ||
408 | res = squashfs_read_data(sb, data, block, length | | ||
409 | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length); | ||
410 | kfree(data); | ||
411 | return res; | ||
412 | } | ||
diff --git a/fs/squashfs/dir.c b/fs/squashfs/dir.c new file mode 100644 index 000000000000..566b0eaed868 --- /dev/null +++ b/fs/squashfs/dir.c | |||
@@ -0,0 +1,235 @@ | |||
1 | /* | ||
2 | * Squashfs - a compressed read only filesystem for Linux | ||
3 | * | ||
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | ||
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2, | ||
10 | * or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | * | ||
21 | * dir.c | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * This file implements code to read directories from disk. | ||
26 | * | ||
27 | * See namei.c for a description of directory organisation on disk. | ||
28 | */ | ||
29 | |||
30 | #include <linux/fs.h> | ||
31 | #include <linux/vfs.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/zlib.h> | ||
34 | |||
35 | #include "squashfs_fs.h" | ||
36 | #include "squashfs_fs_sb.h" | ||
37 | #include "squashfs_fs_i.h" | ||
38 | #include "squashfs.h" | ||
39 | |||
40 | static const unsigned char squashfs_filetype_table[] = { | ||
41 | DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK | ||
42 | }; | ||
43 | |||
44 | /* | ||
45 | * Lookup offset (f_pos) in the directory index, returning the | ||
46 | * metadata block containing it. | ||
47 | * | ||
48 | * If we get an error reading the index then return the part of the index | ||
49 | * (if any) we have managed to read - the index isn't essential, just | ||
50 | * quicker. | ||
51 | */ | ||
52 | static int get_dir_index_using_offset(struct super_block *sb, | ||
53 | u64 *next_block, int *next_offset, u64 index_start, int index_offset, | ||
54 | int i_count, u64 f_pos) | ||
55 | { | ||
56 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
57 | int err, i, index, length = 0; | ||
58 | struct squashfs_dir_index dir_index; | ||
59 | |||
60 | TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %lld\n", | ||
61 | i_count, f_pos); | ||
62 | |||
63 | /* | ||
64 | * Translate from external f_pos to the internal f_pos. This | ||
65 | * is offset by 3 because we invent "." and ".." entries which are | ||
66 | * not actually stored in the directory. | ||
67 | */ | ||
68 | if (f_pos < 3) | ||
69 | return f_pos; | ||
70 | f_pos -= 3; | ||
71 | |||
72 | for (i = 0; i < i_count; i++) { | ||
73 | err = squashfs_read_metadata(sb, &dir_index, &index_start, | ||
74 | &index_offset, sizeof(dir_index)); | ||
75 | if (err < 0) | ||
76 | break; | ||
77 | |||
78 | index = le32_to_cpu(dir_index.index); | ||
79 | if (index > f_pos) | ||
80 | /* | ||
81 | * Found the index we're looking for. | ||
82 | */ | ||
83 | break; | ||
84 | |||
85 | err = squashfs_read_metadata(sb, NULL, &index_start, | ||
86 | &index_offset, le32_to_cpu(dir_index.size) + 1); | ||
87 | if (err < 0) | ||
88 | break; | ||
89 | |||
90 | length = index; | ||
91 | *next_block = le32_to_cpu(dir_index.start_block) + | ||
92 | msblk->directory_table; | ||
93 | } | ||
94 | |||
95 | *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; | ||
96 | |||
97 | /* | ||
98 | * Translate back from internal f_pos to external f_pos. | ||
99 | */ | ||
100 | return length + 3; | ||
101 | } | ||
102 | |||
103 | |||
104 | static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir) | ||
105 | { | ||
106 | struct inode *inode = file->f_dentry->d_inode; | ||
107 | struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; | ||
108 | u64 block = squashfs_i(inode)->start + msblk->directory_table; | ||
109 | int offset = squashfs_i(inode)->offset, length = 0, dir_count, size, | ||
110 | type, err; | ||
111 | unsigned int inode_number; | ||
112 | struct squashfs_dir_header dirh; | ||
113 | struct squashfs_dir_entry *dire; | ||
114 | |||
115 | TRACE("Entered squashfs_readdir [%llx:%x]\n", block, offset); | ||
116 | |||
117 | dire = kmalloc(sizeof(*dire) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL); | ||
118 | if (dire == NULL) { | ||
119 | ERROR("Failed to allocate squashfs_dir_entry\n"); | ||
120 | goto finish; | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * Return "." and ".." entries as the first two filenames in the | ||
125 | * directory. To maximise compression these two entries are not | ||
126 | * stored in the directory, and so we invent them here. | ||
127 | * | ||
128 | * It also means that the external f_pos is offset by 3 from the | ||
129 | * on-disk directory f_pos. | ||
130 | */ | ||
131 | while (file->f_pos < 3) { | ||
132 | char *name; | ||
133 | int i_ino; | ||
134 | |||
135 | if (file->f_pos == 0) { | ||
136 | name = "."; | ||
137 | size = 1; | ||
138 | i_ino = inode->i_ino; | ||
139 | } else { | ||
140 | name = ".."; | ||
141 | size = 2; | ||
142 | i_ino = squashfs_i(inode)->parent; | ||
143 | } | ||
144 | |||
145 | TRACE("Calling filldir(%p, %s, %d, %lld, %d, %d)\n", | ||
146 | dirent, name, size, file->f_pos, i_ino, | ||
147 | squashfs_filetype_table[1]); | ||
148 | |||
149 | if (filldir(dirent, name, size, file->f_pos, i_ino, | ||
150 | squashfs_filetype_table[1]) < 0) { | ||
151 | TRACE("Filldir returned less than 0\n"); | ||
152 | goto finish; | ||
153 | } | ||
154 | |||
155 | file->f_pos += size; | ||
156 | } | ||
157 | |||
158 | length = get_dir_index_using_offset(inode->i_sb, &block, &offset, | ||
159 | squashfs_i(inode)->dir_idx_start, | ||
160 | squashfs_i(inode)->dir_idx_offset, | ||
161 | squashfs_i(inode)->dir_idx_cnt, | ||
162 | file->f_pos); | ||
163 | |||
164 | while (length < i_size_read(inode)) { | ||
165 | /* | ||
166 | * Read directory header | ||
167 | */ | ||
168 | err = squashfs_read_metadata(inode->i_sb, &dirh, &block, | ||
169 | &offset, sizeof(dirh)); | ||
170 | if (err < 0) | ||
171 | goto failed_read; | ||
172 | |||
173 | length += sizeof(dirh); | ||
174 | |||
175 | dir_count = le32_to_cpu(dirh.count) + 1; | ||
176 | while (dir_count--) { | ||
177 | /* | ||
178 | * Read directory entry. | ||
179 | */ | ||
180 | err = squashfs_read_metadata(inode->i_sb, dire, &block, | ||
181 | &offset, sizeof(*dire)); | ||
182 | if (err < 0) | ||
183 | goto failed_read; | ||
184 | |||
185 | size = le16_to_cpu(dire->size) + 1; | ||
186 | |||
187 | err = squashfs_read_metadata(inode->i_sb, dire->name, | ||
188 | &block, &offset, size); | ||
189 | if (err < 0) | ||
190 | goto failed_read; | ||
191 | |||
192 | length += sizeof(*dire) + size; | ||
193 | |||
194 | if (file->f_pos >= length) | ||
195 | continue; | ||
196 | |||
197 | dire->name[size] = '\0'; | ||
198 | inode_number = le32_to_cpu(dirh.inode_number) + | ||
199 | ((short) le16_to_cpu(dire->inode_number)); | ||
200 | type = le16_to_cpu(dire->type); | ||
201 | |||
202 | TRACE("Calling filldir(%p, %s, %d, %lld, %x:%x, %d, %d)" | ||
203 | "\n", dirent, dire->name, size, | ||
204 | file->f_pos, | ||
205 | le32_to_cpu(dirh.start_block), | ||
206 | le16_to_cpu(dire->offset), | ||
207 | inode_number, | ||
208 | squashfs_filetype_table[type]); | ||
209 | |||
210 | if (filldir(dirent, dire->name, size, file->f_pos, | ||
211 | inode_number, | ||
212 | squashfs_filetype_table[type]) < 0) { | ||
213 | TRACE("Filldir returned less than 0\n"); | ||
214 | goto finish; | ||
215 | } | ||
216 | |||
217 | file->f_pos = length; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | finish: | ||
222 | kfree(dire); | ||
223 | return 0; | ||
224 | |||
225 | failed_read: | ||
226 | ERROR("Unable to read directory block [%llx:%x]\n", block, offset); | ||
227 | kfree(dire); | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | |||
232 | const struct file_operations squashfs_dir_ops = { | ||
233 | .read = generic_read_dir, | ||
234 | .readdir = squashfs_readdir | ||
235 | }; | ||
diff --git a/fs/squashfs/export.c b/fs/squashfs/export.c new file mode 100644 index 000000000000..69e971d5ddc1 --- /dev/null +++ b/fs/squashfs/export.c | |||
@@ -0,0 +1,155 @@ | |||
1 | /* | ||
2 | * Squashfs - a compressed read only filesystem for Linux | ||
3 | * | ||
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | ||
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2, | ||
10 | * or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | * | ||
21 | * export.c | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * This file implements code to make Squashfs filesystems exportable (NFS etc.) | ||
26 | * | ||
27 | * The export code uses an inode lookup table to map inode numbers passed in | ||
28 | * filehandles to an inode location on disk. This table is stored compressed | ||
29 | * into metadata blocks. A second index table is used to locate these. This | ||
30 | * second index table for speed of access (and because it is small) is read at | ||
31 | * mount time and cached in memory. | ||
32 | * | ||
33 | * The inode lookup table is used only by the export code, inode disk | ||
34 | * locations are directly encoded in directories, enabling direct access | ||
35 | * without an intermediate lookup for all operations except the export ops. | ||
36 | */ | ||
37 | |||
38 | #include <linux/fs.h> | ||
39 | #include <linux/vfs.h> | ||
40 | #include <linux/dcache.h> | ||
41 | #include <linux/exportfs.h> | ||
42 | #include <linux/zlib.h> | ||
43 | |||
44 | #include "squashfs_fs.h" | ||
45 | #include "squashfs_fs_sb.h" | ||
46 | #include "squashfs_fs_i.h" | ||
47 | #include "squashfs.h" | ||
48 | |||
49 | /* | ||
50 | * Look-up inode number (ino) in table, returning the inode location. | ||
51 | */ | ||
52 | static long long squashfs_inode_lookup(struct super_block *sb, int ino_num) | ||
53 | { | ||
54 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
55 | int blk = SQUASHFS_LOOKUP_BLOCK(ino_num - 1); | ||
56 | int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino_num - 1); | ||
57 | u64 start = le64_to_cpu(msblk->inode_lookup_table[blk]); | ||
58 | __le64 ino; | ||
59 | int err; | ||
60 | |||
61 | TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino_num); | ||
62 | |||
63 | err = squashfs_read_metadata(sb, &ino, &start, &offset, sizeof(ino)); | ||
64 | if (err < 0) | ||
65 | return err; | ||
66 | |||
67 | TRACE("squashfs_inode_lookup, inode = 0x%llx\n", | ||
68 | (u64) le64_to_cpu(ino)); | ||
69 | |||
70 | return le64_to_cpu(ino); | ||
71 | } | ||
72 | |||
73 | |||
74 | static struct dentry *squashfs_export_iget(struct super_block *sb, | ||
75 | unsigned int ino_num) | ||
76 | { | ||
77 | long long ino; | ||
78 | struct dentry *dentry = ERR_PTR(-ENOENT); | ||
79 | |||
80 | TRACE("Entered squashfs_export_iget\n"); | ||
81 | |||
82 | ino = squashfs_inode_lookup(sb, ino_num); | ||
83 | if (ino >= 0) | ||
84 | dentry = d_obtain_alias(squashfs_iget(sb, ino, ino_num)); | ||
85 | |||
86 | return dentry; | ||
87 | } | ||
88 | |||
89 | |||
90 | static struct dentry *squashfs_fh_to_dentry(struct super_block *sb, | ||
91 | struct fid *fid, int fh_len, int fh_type) | ||
92 | { | ||
93 | if ((fh_type != FILEID_INO32_GEN && fh_type != FILEID_INO32_GEN_PARENT) | ||
94 | || fh_len < 2) | ||
95 | return NULL; | ||
96 | |||
97 | return squashfs_export_iget(sb, fid->i32.ino); | ||
98 | } | ||
99 | |||
100 | |||
101 | static struct dentry *squashfs_fh_to_parent(struct super_block *sb, | ||
102 | struct fid *fid, int fh_len, int fh_type) | ||
103 | { | ||
104 | if (fh_type != FILEID_INO32_GEN_PARENT || fh_len < 4) | ||
105 | return NULL; | ||
106 | |||
107 | return squashfs_export_iget(sb, fid->i32.parent_ino); | ||
108 | } | ||
109 | |||
110 | |||
111 | static struct dentry *squashfs_get_parent(struct dentry *child) | ||
112 | { | ||
113 | struct inode *inode = child->d_inode; | ||
114 | unsigned int parent_ino = squashfs_i(inode)->parent; | ||
115 | |||
116 | return squashfs_export_iget(inode->i_sb, parent_ino); | ||
117 | } | ||
118 | |||
119 | |||
120 | /* | ||
121 | * Read uncompressed inode lookup table indexes off disk into memory | ||
122 | */ | ||
123 | __le64 *squashfs_read_inode_lookup_table(struct super_block *sb, | ||
124 | u64 lookup_table_start, unsigned int inodes) | ||
125 | { | ||
126 | unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(inodes); | ||
127 | __le64 *inode_lookup_table; | ||
128 | int err; | ||
129 | |||
130 | TRACE("In read_inode_lookup_table, length %d\n", length); | ||
131 | |||
132 | /* Allocate inode lookup table indexes */ | ||
133 | inode_lookup_table = kmalloc(length, GFP_KERNEL); | ||
134 | if (inode_lookup_table == NULL) { | ||
135 | ERROR("Failed to allocate inode lookup table\n"); | ||
136 | return ERR_PTR(-ENOMEM); | ||
137 | } | ||
138 | |||
139 | err = squashfs_read_table(sb, inode_lookup_table, lookup_table_start, | ||
140 | length); | ||
141 | if (err < 0) { | ||
142 | ERROR("unable to read inode lookup table\n"); | ||
143 | kfree(inode_lookup_table); | ||
144 | return ERR_PTR(err); | ||
145 | } | ||
146 | |||
147 | return inode_lookup_table; | ||
148 | } | ||
149 | |||
150 | |||
151 | const struct export_operations squashfs_export_ops = { | ||
152 | .fh_to_dentry = squashfs_fh_to_dentry, | ||
153 | .fh_to_parent = squashfs_fh_to_parent, | ||
154 | .get_parent = squashfs_get_parent | ||
155 | }; | ||
diff --git a/fs/squashfs/file.c b/fs/squashfs/file.c new file mode 100644 index 000000000000..717767d831df --- /dev/null +++ b/fs/squashfs/file.c | |||
@@ -0,0 +1,502 @@ | |||
1 | /* | ||
2 | * Squashfs - a compressed read only filesystem for Linux | ||
3 | * | ||
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | ||
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2, | ||
10 | * or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | * | ||
21 | * file.c | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * This file contains code for handling regular files. A regular file | ||
26 | * consists of a sequence of contiguous compressed blocks, and/or a | ||
27 | * compressed fragment block (tail-end packed block). The compressed size | ||
28 | * of each datablock is stored in a block list contained within the | ||
29 | * file inode (itself stored in one or more compressed metadata blocks). | ||
30 | * | ||
31 | * To speed up access to datablocks when reading 'large' files (256 Mbytes or | ||
32 | * larger), the code implements an index cache that caches the mapping from | ||
33 | * block index to datablock location on disk. | ||
34 | * | ||
35 | * The index cache allows Squashfs to handle large files (up to 1.75 TiB) while | ||
36 | * retaining a simple and space-efficient block list on disk. The cache | ||
37 | * is split into slots, caching up to eight 224 GiB files (128 KiB blocks). | ||
38 | * Larger files use multiple slots, with 1.75 TiB files using all 8 slots. | ||
39 | * The index cache is designed to be memory efficient, and by default uses | ||
40 | * 16 KiB. | ||
41 | */ | ||
42 | |||
43 | #include <linux/fs.h> | ||
44 | #include <linux/vfs.h> | ||
45 | #include <linux/kernel.h> | ||
46 | #include <linux/slab.h> | ||
47 | #include <linux/string.h> | ||
48 | #include <linux/pagemap.h> | ||
49 | #include <linux/mutex.h> | ||
50 | #include <linux/zlib.h> | ||
51 | |||
52 | #include "squashfs_fs.h" | ||
53 | #include "squashfs_fs_sb.h" | ||
54 | #include "squashfs_fs_i.h" | ||
55 | #include "squashfs.h" | ||
56 | |||
57 | /* | ||
58 | * Locate cache slot in range [offset, index] for specified inode. If | ||
59 | * there's more than one return the slot closest to index. | ||
60 | */ | ||
61 | static struct meta_index *locate_meta_index(struct inode *inode, int offset, | ||
62 | int index) | ||
63 | { | ||
64 | struct meta_index *meta = NULL; | ||
65 | struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; | ||
66 | int i; | ||
67 | |||
68 | mutex_lock(&msblk->meta_index_mutex); | ||
69 | |||
70 | TRACE("locate_meta_index: index %d, offset %d\n", index, offset); | ||
71 | |||
72 | if (msblk->meta_index == NULL) | ||
73 | goto not_allocated; | ||
74 | |||
75 | for (i = 0; i < SQUASHFS_META_SLOTS; i++) { | ||
76 | if (msblk->meta_index[i].inode_number == inode->i_ino && | ||
77 | msblk->meta_index[i].offset >= offset && | ||
78 | msblk->meta_index[i].offset <= index && | ||
79 | msblk->meta_index[i].locked == 0) { | ||
80 | TRACE("locate_meta_index: entry %d, offset %d\n", i, | ||
81 | msblk->meta_index[i].offset); | ||
82 | meta = &msblk->meta_index[i]; | ||
83 | offset = meta->offset; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | if (meta) | ||
88 | meta->locked = 1; | ||
89 | |||
90 | not_allocated: | ||
91 | mutex_unlock(&msblk->meta_index_mutex); | ||
92 | |||
93 | return meta; | ||
94 | } | ||
95 | |||
96 | |||
97 | /* | ||
98 | * Find and initialise an empty cache slot for index offset. | ||
99 | */ | ||
100 | static struct meta_index *empty_meta_index(struct inode *inode, int offset, | ||
101 | int skip) | ||
102 | { | ||
103 | struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; | ||
104 | struct meta_index *meta = NULL; | ||
105 | int i; | ||
106 | |||
107 | mutex_lock(&msblk->meta_index_mutex); | ||
108 | |||
109 | TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip); | ||
110 | |||
111 | if (msblk->meta_index == NULL) { | ||
112 | /* | ||
113 | * First time cache index has been used, allocate and | ||
114 | * initialise. The cache index could be allocated at | ||
115 | * mount time but doing it here means it is allocated only | ||
116 | * if a 'large' file is read. | ||
117 | */ | ||
118 | msblk->meta_index = kcalloc(SQUASHFS_META_SLOTS, | ||
119 | sizeof(*(msblk->meta_index)), GFP_KERNEL); | ||
120 | if (msblk->meta_index == NULL) { | ||
121 | ERROR("Failed to allocate meta_index\n"); | ||
122 | goto failed; | ||
123 | } | ||
124 | for (i = 0; i < SQUASHFS_META_SLOTS; i++) { | ||
125 | msblk->meta_index[i].inode_number = 0; | ||
126 | msblk->meta_index[i].locked = 0; | ||
127 | } | ||
128 | msblk->next_meta_index = 0; | ||
129 | } | ||
130 | |||
131 | for (i = SQUASHFS_META_SLOTS; i && | ||
132 | msblk->meta_index[msblk->next_meta_index].locked; i--) | ||
133 | msblk->next_meta_index = (msblk->next_meta_index + 1) % | ||
134 | SQUASHFS_META_SLOTS; | ||
135 | |||
136 | if (i == 0) { | ||
137 | TRACE("empty_meta_index: failed!\n"); | ||
138 | goto failed; | ||
139 | } | ||
140 | |||
141 | TRACE("empty_meta_index: returned meta entry %d, %p\n", | ||
142 | msblk->next_meta_index, | ||
143 | &msblk->meta_index[msblk->next_meta_index]); | ||
144 | |||
145 | meta = &msblk->meta_index[msblk->next_meta_index]; | ||
146 | msblk->next_meta_index = (msblk->next_meta_index + 1) % | ||
147 | SQUASHFS_META_SLOTS; | ||
148 | |||
149 | meta->inode_number = inode->i_ino; | ||
150 | meta->offset = offset; | ||
151 | meta->skip = skip; | ||
152 | meta->entries = 0; | ||
153 | meta->locked = 1; | ||
154 | |||
155 | failed: | ||
156 | mutex_unlock(&msblk->meta_index_mutex); | ||
157 | return meta; | ||
158 | } | ||
159 | |||
160 | |||
161 | static void release_meta_index(struct inode *inode, struct meta_index *meta) | ||
162 | { | ||
163 | struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; | ||
164 | mutex_lock(&msblk->meta_index_mutex); | ||
165 | meta->locked = 0; | ||
166 | mutex_unlock(&msblk->meta_index_mutex); | ||
167 | } | ||
168 | |||
169 | |||
170 | /* | ||
171 | * Read the next n blocks from the block list, starting from | ||
172 | * metadata block <start_block, offset>. | ||
173 | */ | ||
174 | static long long read_indexes(struct super_block *sb, int n, | ||
175 | u64 *start_block, int *offset) | ||
176 | { | ||
177 | int err, i; | ||
178 | long long block = 0; | ||
179 | __le32 *blist = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); | ||
180 | |||
181 | if (blist == NULL) { | ||
182 | ERROR("read_indexes: Failed to allocate block_list\n"); | ||
183 | return -ENOMEM; | ||
184 | } | ||
185 | |||
186 | while (n) { | ||
187 | int blocks = min_t(int, n, PAGE_CACHE_SIZE >> 2); | ||
188 | |||
189 | err = squashfs_read_metadata(sb, blist, start_block, | ||
190 | offset, blocks << 2); | ||
191 | if (err < 0) { | ||
192 | ERROR("read_indexes: reading block [%llx:%x]\n", | ||
193 | *start_block, *offset); | ||
194 | goto failure; | ||
195 | } | ||
196 | |||
197 | for (i = 0; i < blocks; i++) { | ||
198 | int size = le32_to_cpu(blist[i]); | ||
199 | block += SQUASHFS_COMPRESSED_SIZE_BLOCK(size); | ||
200 | } | ||
201 | n -= blocks; | ||
202 | } | ||
203 | |||
204 | kfree(blist); | ||
205 | return block; | ||
206 | |||
207 | failure: | ||
208 | kfree(blist); | ||
209 | return err; | ||
210 | } | ||
211 | |||
212 | |||
213 | /* | ||
214 | * Each cache index slot has SQUASHFS_META_ENTRIES, each of which | ||
215 | * can cache one index -> datablock/blocklist-block mapping. We wish | ||
216 | * to distribute these over the length of the file, entry[0] maps index x, | ||
217 | * entry[1] maps index x + skip, entry[2] maps index x + 2 * skip, and so on. | ||
218 | * The larger the file, the greater the skip factor. The skip factor is | ||
219 | * limited to the size of the metadata cache (SQUASHFS_CACHED_BLKS) to ensure | ||
220 | * the number of metadata blocks that need to be read fits into the cache. | ||
221 | * If the skip factor is limited in this way then the file will use multiple | ||
222 | * slots. | ||
223 | */ | ||
224 | static inline int calculate_skip(int blocks) | ||
225 | { | ||
226 | int skip = blocks / ((SQUASHFS_META_ENTRIES + 1) | ||
227 | * SQUASHFS_META_INDEXES); | ||
228 | return min(SQUASHFS_CACHED_BLKS - 1, skip + 1); | ||
229 | } | ||
230 | |||
231 | |||
232 | /* | ||
233 | * Search and grow the index cache for the specified inode, returning the | ||
234 | * on-disk locations of the datablock and block list metadata block | ||
235 | * <index_block, index_offset> for index (scaled to nearest cache index). | ||
236 | */ | ||
237 | static int fill_meta_index(struct inode *inode, int index, | ||
238 | u64 *index_block, int *index_offset, u64 *data_block) | ||
239 | { | ||
240 | struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; | ||
241 | int skip = calculate_skip(i_size_read(inode) >> msblk->block_log); | ||
242 | int offset = 0; | ||
243 | struct meta_index *meta; | ||
244 | struct meta_entry *meta_entry; | ||
245 | u64 cur_index_block = squashfs_i(inode)->block_list_start; | ||
246 | int cur_offset = squashfs_i(inode)->offset; | ||
247 | u64 cur_data_block = squashfs_i(inode)->start; | ||
248 | int err, i; | ||
249 | |||
250 | /* | ||
251 | * Scale index to cache index (cache slot entry) | ||
252 | */ | ||
253 | index /= SQUASHFS_META_INDEXES * skip; | ||
254 | |||
255 | while (offset < index) { | ||
256 | meta = locate_meta_index(inode, offset + 1, index); | ||
257 | |||
258 | if (meta == NULL) { | ||
259 | meta = empty_meta_index(inode, offset + 1, skip); | ||
260 | if (meta == NULL) | ||
261 | goto all_done; | ||
262 | } else { | ||
263 | offset = index < meta->offset + meta->entries ? index : | ||
264 | meta->offset + meta->entries - 1; | ||
265 | meta_entry = &meta->meta_entry[offset - meta->offset]; | ||
266 | cur_index_block = meta_entry->index_block + | ||
267 | msblk->inode_table; | ||
268 | cur_offset = meta_entry->offset; | ||
269 | cur_data_block = meta_entry->data_block; | ||
270 | TRACE("get_meta_index: offset %d, meta->offset %d, " | ||
271 | "meta->entries %d\n", offset, meta->offset, | ||
272 | meta->entries); | ||
273 | TRACE("get_meta_index: index_block 0x%llx, offset 0x%x" | ||
274 | " data_block 0x%llx\n", cur_index_block, | ||
275 | cur_offset, cur_data_block); | ||
276 | } | ||
277 | |||
278 | /* | ||
279 | * If necessary grow cache slot by reading block list. Cache | ||
280 | * slot is extended up to index or to the end of the slot, in | ||
281 | * which case further slots will be used. | ||
282 | */ | ||
283 | for (i = meta->offset + meta->entries; i <= index && | ||
284 | i < meta->offset + SQUASHFS_META_ENTRIES; i++) { | ||
285 | int blocks = skip * SQUASHFS_META_INDEXES; | ||
286 | long long res = read_indexes(inode->i_sb, blocks, | ||
287 | &cur_index_block, &cur_offset); | ||
288 | |||
289 | if (res < 0) { | ||
290 | if (meta->entries == 0) | ||
291 | /* | ||
292 | * Don't leave an empty slot on read | ||
293 | * error allocated to this inode... | ||
294 | */ | ||
295 | meta->inode_number = 0; | ||
296 | err = res; | ||
297 | goto failed; | ||
298 | } | ||
299 | |||
300 | cur_data_block += res; | ||
301 | meta_entry = &meta->meta_entry[i - meta->offset]; | ||
302 | meta_entry->index_block = cur_index_block - | ||
303 | msblk->inode_table; | ||
304 | meta_entry->offset = cur_offset; | ||
305 | meta_entry->data_block = cur_data_block; | ||
306 | meta->entries++; | ||
307 | offset++; | ||
308 | } | ||
309 | |||
310 | TRACE("get_meta_index: meta->offset %d, meta->entries %d\n", | ||
311 | meta->offset, meta->entries); | ||
312 | |||
313 | release_meta_index(inode, meta); | ||
314 | } | ||
315 | |||
316 | all_done: | ||
317 | *index_block = cur_index_block; | ||
318 | *index_offset = cur_offset; | ||
319 | *data_block = cur_data_block; | ||
320 | |||
321 | /* | ||
322 | * Scale cache index (cache slot entry) to index | ||
323 | */ | ||
324 | return offset * SQUASHFS_META_INDEXES * skip; | ||
325 | |||
326 | failed: | ||
327 | release_meta_index(inode, meta); | ||
328 | return err; | ||
329 | } | ||
330 | |||
331 | |||
332 | /* | ||
333 | * Get the on-disk location and compressed size of the datablock | ||
334 | * specified by index. Fill_meta_index() does most of the work. | ||
335 | */ | ||
336 | static int read_blocklist(struct inode *inode, int index, u64 *block) | ||
337 | { | ||
338 | u64 start; | ||
339 | long long blks; | ||
340 | int offset; | ||
341 | __le32 size; | ||
342 | int res = fill_meta_index(inode, index, &start, &offset, block); | ||
343 | |||
344 | TRACE("read_blocklist: res %d, index %d, start 0x%llx, offset" | ||
345 | " 0x%x, block 0x%llx\n", res, index, start, offset, | ||
346 | *block); | ||
347 | |||
348 | if (res < 0) | ||
349 | return res; | ||
350 | |||
351 | /* | ||
352 | * res contains the index of the mapping returned by fill_meta_index(), | ||
353 | * this will likely be less than the desired index (because the | ||
354 | * meta_index cache works at a higher granularity). Read any | ||
355 | * extra block indexes needed. | ||
356 | */ | ||
357 | if (res < index) { | ||
358 | blks = read_indexes(inode->i_sb, index - res, &start, &offset); | ||
359 | if (blks < 0) | ||
360 | return (int) blks; | ||
361 | *block += blks; | ||
362 | } | ||
363 | |||
364 | /* | ||
365 | * Read length of block specified by index. | ||
366 | */ | ||
367 | res = squashfs_read_metadata(inode->i_sb, &size, &start, &offset, | ||
368 | sizeof(size)); | ||
369 | if (res < 0) | ||
370 | return res; | ||
371 | return le32_to_cpu(size); | ||
372 | } | ||
373 | |||
374 | |||
375 | static int squashfs_readpage(struct file *file, struct page *page) | ||
376 | { | ||
377 | struct inode *inode = page->mapping->host; | ||
378 | struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; | ||
379 | int bytes, i, offset = 0, sparse = 0; | ||
380 | struct squashfs_cache_entry *buffer = NULL; | ||
381 | void *pageaddr; | ||
382 | |||
383 | int mask = (1 << (msblk->block_log - PAGE_CACHE_SHIFT)) - 1; | ||
384 | int index = page->index >> (msblk->block_log - PAGE_CACHE_SHIFT); | ||
385 | int start_index = page->index & ~mask; | ||
386 | int end_index = start_index | mask; | ||
387 | int file_end = i_size_read(inode) >> msblk->block_log; | ||
388 | |||
389 | TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n", | ||
390 | page->index, squashfs_i(inode)->start); | ||
391 | |||
392 | if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> | ||
393 | PAGE_CACHE_SHIFT)) | ||
394 | goto out; | ||
395 | |||
396 | if (index < file_end || squashfs_i(inode)->fragment_block == | ||
397 | SQUASHFS_INVALID_BLK) { | ||
398 | /* | ||
399 | * Reading a datablock from disk. Need to read block list | ||
400 | * to get location and block size. | ||
401 | */ | ||
402 | u64 block = 0; | ||
403 | int bsize = read_blocklist(inode, index, &block); | ||
404 | if (bsize < 0) | ||
405 | goto error_out; | ||
406 | |||
407 | if (bsize == 0) { /* hole */ | ||
408 | bytes = index == file_end ? | ||
409 | (i_size_read(inode) & (msblk->block_size - 1)) : | ||
410 | msblk->block_size; | ||
411 | sparse = 1; | ||
412 | } else { | ||
413 | /* | ||
414 | * Read and decompress datablock. | ||
415 | */ | ||
416 | buffer = squashfs_get_datablock(inode->i_sb, | ||
417 | block, bsize); | ||
418 | if (buffer->error) { | ||
419 | ERROR("Unable to read page, block %llx, size %x" | ||
420 | "\n", block, bsize); | ||
421 | squashfs_cache_put(buffer); | ||
422 | goto error_out; | ||
423 | } | ||
424 | bytes = buffer->length; | ||
425 | } | ||
426 | } else { | ||
427 | /* | ||
428 | * Datablock is stored inside a fragment (tail-end packed | ||
429 | * block). | ||
430 | */ | ||
431 | buffer = squashfs_get_fragment(inode->i_sb, | ||
432 | squashfs_i(inode)->fragment_block, | ||
433 | squashfs_i(inode)->fragment_size); | ||
434 | |||
435 | if (buffer->error) { | ||
436 | ERROR("Unable to read page, block %llx, size %x\n", | ||
437 | squashfs_i(inode)->fragment_block, | ||
438 | squashfs_i(inode)->fragment_size); | ||
439 | squashfs_cache_put(buffer); | ||
440 | goto error_out; | ||
441 | } | ||
442 | bytes = i_size_read(inode) & (msblk->block_size - 1); | ||
443 | offset = squashfs_i(inode)->fragment_offset; | ||
444 | } | ||
445 | |||
446 | /* | ||
447 | * Loop copying datablock into pages. As the datablock likely covers | ||
448 | * many PAGE_CACHE_SIZE pages (default block size is 128 KiB) explicitly | ||
449 | * grab the pages from the page cache, except for the page that we've | ||
450 | * been called to fill. | ||
451 | */ | ||
452 | for (i = start_index; i <= end_index && bytes > 0; i++, | ||
453 | bytes -= PAGE_CACHE_SIZE, offset += PAGE_CACHE_SIZE) { | ||
454 | struct page *push_page; | ||
455 | int avail = sparse ? 0 : min_t(int, bytes, PAGE_CACHE_SIZE); | ||
456 | |||
457 | TRACE("bytes %d, i %d, available_bytes %d\n", bytes, i, avail); | ||
458 | |||
459 | push_page = (i == page->index) ? page : | ||
460 | grab_cache_page_nowait(page->mapping, i); | ||
461 | |||
462 | if (!push_page) | ||
463 | continue; | ||
464 | |||
465 | if (PageUptodate(push_page)) | ||
466 | goto skip_page; | ||
467 | |||
468 | pageaddr = kmap_atomic(push_page, KM_USER0); | ||
469 | squashfs_copy_data(pageaddr, buffer, offset, avail); | ||
470 | memset(pageaddr + avail, 0, PAGE_CACHE_SIZE - avail); | ||
471 | kunmap_atomic(pageaddr, KM_USER0); | ||
472 | flush_dcache_page(push_page); | ||
473 | SetPageUptodate(push_page); | ||
474 | skip_page: | ||
475 | unlock_page(push_page); | ||
476 | if (i != page->index) | ||
477 | page_cache_release(push_page); | ||
478 | } | ||
479 | |||
480 | if (!sparse) | ||
481 | squashfs_cache_put(buffer); | ||
482 | |||
483 | return 0; | ||
484 | |||
485 | error_out: | ||
486 | SetPageError(page); | ||
487 | out: | ||
488 | pageaddr = kmap_atomic(page, KM_USER0); | ||
489 | memset(pageaddr, 0, PAGE_CACHE_SIZE); | ||
490 | kunmap_atomic(pageaddr, KM_USER0); | ||
491 | flush_dcache_page(page); | ||
492 | if (!PageError(page)) | ||
493 | SetPageUptodate(page); | ||
494 | unlock_page(page); | ||
495 | |||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | |||
500 | const struct address_space_operations squashfs_aops = { | ||
501 | .readpage = squashfs_readpage | ||
502 | }; | ||
diff --git a/fs/squashfs/fragment.c b/fs/squashfs/fragment.c new file mode 100644 index 000000000000..b5a2c15bbbc7 --- /dev/null +++ b/fs/squashfs/fragment.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * Squashfs - a compressed read only filesystem for Linux | ||
3 | * | ||
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | ||
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2, | ||
10 | * or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | * | ||
21 | * fragment.c | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * This file implements code to handle compressed fragments (tail-end packed | ||
26 | * datablocks). | ||
27 | * | ||
28 | * Regular files contain a fragment index which is mapped to a fragment | ||
29 | * location on disk and compressed size using a fragment lookup table. | ||
30 | * Like everything in Squashfs this fragment lookup table is itself stored | ||
31 | * compressed into metadata blocks. A second index table is used to locate | ||
32 | * these. This second index table for speed of access (and because it | ||
33 | * is small) is read at mount time and cached in memory. | ||
34 | */ | ||
35 | |||
36 | #include <linux/fs.h> | ||
37 | #include <linux/vfs.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include <linux/zlib.h> | ||
40 | |||
41 | #include "squashfs_fs.h" | ||
42 | #include "squashfs_fs_sb.h" | ||
43 | #include "squashfs_fs_i.h" | ||
44 | #include "squashfs.h" | ||
45 | |||
46 | /* | ||
47 | * Look-up fragment using the fragment index table. Return the on disk | ||
48 | * location of the fragment and its compressed size | ||
49 | */ | ||
50 | int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment, | ||
51 | u64 *fragment_block) | ||
52 | { | ||
53 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
54 | int block = SQUASHFS_FRAGMENT_INDEX(fragment); | ||
55 | int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); | ||
56 | u64 start_block = le64_to_cpu(msblk->fragment_index[block]); | ||
57 | struct squashfs_fragment_entry fragment_entry; | ||
58 | int size; | ||
59 | |||
60 | size = squashfs_read_metadata(sb, &fragment_entry, &start_block, | ||
61 | &offset, sizeof(fragment_entry)); | ||
62 | if (size < 0) | ||
63 | return size; | ||
64 | |||
65 | *fragment_block = le64_to_cpu(fragment_entry.start_block); | ||
66 | size = le32_to_cpu(fragment_entry.size); | ||
67 | |||
68 | return size; | ||
69 | } | ||
70 | |||
71 | |||
72 | /* | ||
73 | * Read the uncompressed fragment lookup table indexes off disk into memory | ||
74 | */ | ||
75 | __le64 *squashfs_read_fragment_index_table(struct super_block *sb, | ||
76 | u64 fragment_table_start, unsigned int fragments) | ||
77 | { | ||
78 | unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(fragments); | ||
79 | __le64 *fragment_index; | ||
80 | int err; | ||
81 | |||
82 | /* Allocate fragment lookup table indexes */ | ||
83 | fragment_index = kmalloc(length, GFP_KERNEL); | ||
84 | if (fragment_index == NULL) { | ||
85 | ERROR("Failed to allocate fragment index table\n"); | ||
86 | return ERR_PTR(-ENOMEM); | ||
87 | } | ||
88 | |||
89 | err = squashfs_read_table(sb, fragment_index, fragment_table_start, | ||
90 | length); | ||
91 | if (err < 0) { | ||
92 | ERROR("unable to read fragment index table\n"); | ||
93 | kfree(fragment_index); | ||
94 | return ERR_PTR(err); | ||
95 | } | ||
96 | |||
97 | return fragment_index; | ||
98 | } | ||
diff --git a/fs/squashfs/id.c b/fs/squashfs/id.c new file mode 100644 index 000000000000..3795b837ba28 --- /dev/null +++ b/fs/squashfs/id.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | * Squashfs - a compressed read only filesystem for Linux | ||
3 | * | ||
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | ||
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2, | ||
10 | * or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | * | ||
21 | * id.c | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * This file implements code to handle uids and gids. | ||
26 | * | ||
27 | * For space efficiency regular files store uid and gid indexes, which are | ||
28 | * converted to 32-bit uids/gids using an id look up table. This table is | ||
29 | * stored compressed into metadata blocks. A second index table is used to | ||
30 | * locate these. This second index table for speed of access (and because it | ||
31 | * is small) is read at mount time and cached in memory. | ||
32 | */ | ||
33 | |||
34 | #include <linux/fs.h> | ||
35 | #include <linux/vfs.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/zlib.h> | ||
38 | |||
39 | #include "squashfs_fs.h" | ||
40 | #include "squashfs_fs_sb.h" | ||
41 | #include "squashfs_fs_i.h" | ||
42 | #include "squashfs.h" | ||
43 | |||
44 | /* | ||
45 | * Map uid/gid index into real 32-bit uid/gid using the id look up table | ||
46 | */ | ||
47 | int squashfs_get_id(struct super_block *sb, unsigned int index, | ||
48 | unsigned int *id) | ||
49 | { | ||
50 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
51 | int block = SQUASHFS_ID_BLOCK(index); | ||
52 | int offset = SQUASHFS_ID_BLOCK_OFFSET(index); | ||
53 | u64 start_block = le64_to_cpu(msblk->id_table[block]); | ||
54 | __le32 disk_id; | ||
55 | int err; | ||
56 | |||
57 | err = squashfs_read_metadata(sb, &disk_id, &start_block, &offset, | ||
58 | sizeof(disk_id)); | ||
59 | if (err < 0) | ||
60 | return err; | ||
61 | |||
62 | *id = le32_to_cpu(disk_id); | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | |||
67 | /* | ||
68 | * Read uncompressed id lookup table indexes from disk into memory | ||
69 | */ | ||
70 | __le64 *squashfs_read_id_index_table(struct super_block *sb, | ||
71 | u64 id_table_start, unsigned short no_ids) | ||
72 | { | ||
73 | unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids); | ||
74 | __le64 *id_table; | ||
75 | int err; | ||
76 | |||
77 | TRACE("In read_id_index_table, length %d\n", length); | ||
78 | |||
79 | /* Allocate id lookup table indexes */ | ||
80 | id_table = kmalloc(length, GFP_KERNEL); | ||
81 | if (id_table == NULL) { | ||
82 | ERROR("Failed to allocate id index table\n"); | ||
83 | return ERR_PTR(-ENOMEM); | ||
84 | } | ||
85 | |||
86 | err = squashfs_read_table(sb, id_table, id_table_start, length); | ||
87 | if (err < 0) { | ||
88 | ERROR("unable to read id index table\n"); | ||
89 | kfree(id_table); | ||
90 | return ERR_PTR(err); | ||
91 | } | ||
92 | |||
93 | return id_table; | ||
94 | } | ||
diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c new file mode 100644 index 000000000000..7a63398bb855 --- /dev/null +++ b/fs/squashfs/inode.c | |||
@@ -0,0 +1,346 @@ | |||
1 | /* | ||
2 | * Squashfs - a compressed read only filesystem for Linux | ||
3 | * | ||
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | ||
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2, | ||
10 | * or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | * | ||
21 | * inode.c | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * This file implements code to create and read inodes from disk. | ||
26 | * | ||
27 | * Inodes in Squashfs are identified by a 48-bit inode which encodes the | ||
28 | * location of the compressed metadata block containing the inode, and the byte | ||
29 | * offset into that block where the inode is placed (<block, offset>). | ||
30 | * | ||
31 | * To maximise compression there are different inodes for each file type | ||
32 | * (regular file, directory, device, etc.), the inode contents and length | ||
33 | * varying with the type. | ||
34 | * | ||
35 | * To further maximise compression, two types of regular file inode and | ||
36 | * directory inode are defined: inodes optimised for frequently occurring | ||
37 | * regular files and directories, and extended types where extra | ||
38 | * information has to be stored. | ||
39 | */ | ||
40 | |||
41 | #include <linux/fs.h> | ||
42 | #include <linux/vfs.h> | ||
43 | #include <linux/zlib.h> | ||
44 | |||
45 | #include "squashfs_fs.h" | ||
46 | #include "squashfs_fs_sb.h" | ||
47 | #include "squashfs_fs_i.h" | ||
48 | #include "squashfs.h" | ||
49 | |||
50 | /* | ||
51 | * Initialise VFS inode with the base inode information common to all | ||
52 | * Squashfs inode types. Sqsh_ino contains the unswapped base inode | ||
53 | * off disk. | ||
54 | */ | ||
55 | static int squashfs_new_inode(struct super_block *sb, struct inode *inode, | ||
56 | struct squashfs_base_inode *sqsh_ino) | ||
57 | { | ||
58 | int err; | ||
59 | |||
60 | err = squashfs_get_id(sb, le16_to_cpu(sqsh_ino->uid), &inode->i_uid); | ||
61 | if (err) | ||
62 | return err; | ||
63 | |||
64 | err = squashfs_get_id(sb, le16_to_cpu(sqsh_ino->guid), &inode->i_gid); | ||
65 | if (err) | ||
66 | return err; | ||
67 | |||
68 | inode->i_ino = le32_to_cpu(sqsh_ino->inode_number); | ||
69 | inode->i_mtime.tv_sec = le32_to_cpu(sqsh_ino->mtime); | ||
70 | inode->i_atime.tv_sec = inode->i_mtime.tv_sec; | ||
71 | inode->i_ctime.tv_sec = inode->i_mtime.tv_sec; | ||
72 | inode->i_mode = le16_to_cpu(sqsh_ino->mode); | ||
73 | inode->i_size = 0; | ||
74 | |||
75 | return err; | ||
76 | } | ||
77 | |||
78 | |||
79 | struct inode *squashfs_iget(struct super_block *sb, long long ino, | ||
80 | unsigned int ino_number) | ||
81 | { | ||
82 | struct inode *inode = iget_locked(sb, ino_number); | ||
83 | int err; | ||
84 | |||
85 | TRACE("Entered squashfs_iget\n"); | ||
86 | |||
87 | if (!inode) | ||
88 | return ERR_PTR(-ENOMEM); | ||
89 | if (!(inode->i_state & I_NEW)) | ||
90 | return inode; | ||
91 | |||
92 | err = squashfs_read_inode(inode, ino); | ||
93 | if (err) { | ||
94 | iget_failed(inode); | ||
95 | return ERR_PTR(err); | ||
96 | } | ||
97 | |||
98 | unlock_new_inode(inode); | ||
99 | return inode; | ||
100 | } | ||
101 | |||
102 | |||
103 | /* | ||
104 | * Initialise VFS inode by reading inode from inode table (compressed | ||
105 | * metadata). The format and amount of data read depends on type. | ||
106 | */ | ||
107 | int squashfs_read_inode(struct inode *inode, long long ino) | ||
108 | { | ||
109 | struct super_block *sb = inode->i_sb; | ||
110 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
111 | u64 block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table; | ||
112 | int err, type, offset = SQUASHFS_INODE_OFFSET(ino); | ||
113 | union squashfs_inode squashfs_ino; | ||
114 | struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base; | ||
115 | |||
116 | TRACE("Entered squashfs_read_inode\n"); | ||
117 | |||
118 | /* | ||
119 | * Read inode base common to all inode types. | ||
120 | */ | ||
121 | err = squashfs_read_metadata(sb, sqshb_ino, &block, | ||
122 | &offset, sizeof(*sqshb_ino)); | ||
123 | if (err < 0) | ||
124 | goto failed_read; | ||
125 | |||
126 | err = squashfs_new_inode(sb, inode, sqshb_ino); | ||
127 | if (err) | ||
128 | goto failed_read; | ||
129 | |||
130 | block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table; | ||
131 | offset = SQUASHFS_INODE_OFFSET(ino); | ||
132 | |||
133 | type = le16_to_cpu(sqshb_ino->inode_type); | ||
134 | switch (type) { | ||
135 | case SQUASHFS_REG_TYPE: { | ||
136 | unsigned int frag_offset, frag_size, frag; | ||
137 | u64 frag_blk; | ||
138 | struct squashfs_reg_inode *sqsh_ino = &squashfs_ino.reg; | ||
139 | |||
140 | err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, | ||
141 | sizeof(*sqsh_ino)); | ||
142 | if (err < 0) | ||
143 | goto failed_read; | ||
144 | |||
145 | frag = le32_to_cpu(sqsh_ino->fragment); | ||
146 | if (frag != SQUASHFS_INVALID_FRAG) { | ||
147 | frag_offset = le32_to_cpu(sqsh_ino->offset); | ||
148 | frag_size = squashfs_frag_lookup(sb, frag, &frag_blk); | ||
149 | if (frag_size < 0) { | ||
150 | err = frag_size; | ||
151 | goto failed_read; | ||
152 | } | ||
153 | } else { | ||
154 | frag_blk = SQUASHFS_INVALID_BLK; | ||
155 | frag_size = 0; | ||
156 | frag_offset = 0; | ||
157 | } | ||
158 | |||
159 | inode->i_nlink = 1; | ||
160 | inode->i_size = le32_to_cpu(sqsh_ino->file_size); | ||
161 | inode->i_fop = &generic_ro_fops; | ||
162 | inode->i_mode |= S_IFREG; | ||
163 | inode->i_blocks = ((inode->i_size - 1) >> 9) + 1; | ||
164 | squashfs_i(inode)->fragment_block = frag_blk; | ||
165 | squashfs_i(inode)->fragment_size = frag_size; | ||
166 | squashfs_i(inode)->fragment_offset = frag_offset; | ||
167 | squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block); | ||
168 | squashfs_i(inode)->block_list_start = block; | ||
169 | squashfs_i(inode)->offset = offset; | ||
170 | inode->i_data.a_ops = &squashfs_aops; | ||
171 | |||
172 | TRACE("File inode %x:%x, start_block %llx, block_list_start " | ||
173 | "%llx, offset %x\n", SQUASHFS_INODE_BLK(ino), | ||
174 | offset, squashfs_i(inode)->start, block, offset); | ||
175 | break; | ||
176 | } | ||
177 | case SQUASHFS_LREG_TYPE: { | ||
178 | unsigned int frag_offset, frag_size, frag; | ||
179 | u64 frag_blk; | ||
180 | struct squashfs_lreg_inode *sqsh_ino = &squashfs_ino.lreg; | ||
181 | |||
182 | err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, | ||
183 | sizeof(*sqsh_ino)); | ||
184 | if (err < 0) | ||
185 | goto failed_read; | ||
186 | |||
187 | frag = le32_to_cpu(sqsh_ino->fragment); | ||
188 | if (frag != SQUASHFS_INVALID_FRAG) { | ||
189 | frag_offset = le32_to_cpu(sqsh_ino->offset); | ||
190 | frag_size = squashfs_frag_lookup(sb, frag, &frag_blk); | ||
191 | if (frag_size < 0) { | ||
192 | err = frag_size; | ||
193 | goto failed_read; | ||
194 | } | ||
195 | } else { | ||
196 | frag_blk = SQUASHFS_INVALID_BLK; | ||
197 | frag_size = 0; | ||
198 | frag_offset = 0; | ||
199 | } | ||
200 | |||
201 | inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); | ||
202 | inode->i_size = le64_to_cpu(sqsh_ino->file_size); | ||
203 | inode->i_fop = &generic_ro_fops; | ||
204 | inode->i_mode |= S_IFREG; | ||
205 | inode->i_blocks = ((inode->i_size - | ||
206 | le64_to_cpu(sqsh_ino->sparse) - 1) >> 9) + 1; | ||
207 | |||
208 | squashfs_i(inode)->fragment_block = frag_blk; | ||
209 | squashfs_i(inode)->fragment_size = frag_size; | ||
210 | squashfs_i(inode)->fragment_offset = frag_offset; | ||
211 | squashfs_i(inode)->start = le64_to_cpu(sqsh_ino->start_block); | ||
212 | squashfs_i(inode)->block_list_start = block; | ||
213 | squashfs_i(inode)->offset = offset; | ||
214 | inode->i_data.a_ops = &squashfs_aops; | ||
215 | |||
216 | TRACE("File inode %x:%x, start_block %llx, block_list_start " | ||
217 | "%llx, offset %x\n", SQUASHFS_INODE_BLK(ino), | ||
218 | offset, squashfs_i(inode)->start, block, offset); | ||
219 | break; | ||
220 | } | ||
221 | case SQUASHFS_DIR_TYPE: { | ||
222 | struct squashfs_dir_inode *sqsh_ino = &squashfs_ino.dir; | ||
223 | |||
224 | err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, | ||
225 | sizeof(*sqsh_ino)); | ||
226 | if (err < 0) | ||
227 | goto failed_read; | ||
228 | |||
229 | inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); | ||
230 | inode->i_size = le16_to_cpu(sqsh_ino->file_size); | ||
231 | inode->i_op = &squashfs_dir_inode_ops; | ||
232 | inode->i_fop = &squashfs_dir_ops; | ||
233 | inode->i_mode |= S_IFDIR; | ||
234 | squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block); | ||
235 | squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset); | ||
236 | squashfs_i(inode)->dir_idx_cnt = 0; | ||
237 | squashfs_i(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode); | ||
238 | |||
239 | TRACE("Directory inode %x:%x, start_block %llx, offset %x\n", | ||
240 | SQUASHFS_INODE_BLK(ino), offset, | ||
241 | squashfs_i(inode)->start, | ||
242 | le16_to_cpu(sqsh_ino->offset)); | ||
243 | break; | ||
244 | } | ||
245 | case SQUASHFS_LDIR_TYPE: { | ||
246 | struct squashfs_ldir_inode *sqsh_ino = &squashfs_ino.ldir; | ||
247 | |||
248 | err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, | ||
249 | sizeof(*sqsh_ino)); | ||
250 | if (err < 0) | ||
251 | goto failed_read; | ||
252 | |||
253 | inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); | ||
254 | inode->i_size = le32_to_cpu(sqsh_ino->file_size); | ||
255 | inode->i_op = &squashfs_dir_inode_ops; | ||
256 | inode->i_fop = &squashfs_dir_ops; | ||
257 | inode->i_mode |= S_IFDIR; | ||
258 | squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block); | ||
259 | squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset); | ||
260 | squashfs_i(inode)->dir_idx_start = block; | ||
261 | squashfs_i(inode)->dir_idx_offset = offset; | ||
262 | squashfs_i(inode)->dir_idx_cnt = le16_to_cpu(sqsh_ino->i_count); | ||
263 | squashfs_i(inode)->parent = le32_to_cpu(sqsh_ino->parent_inode); | ||
264 | |||
265 | TRACE("Long directory inode %x:%x, start_block %llx, offset " | ||
266 | "%x\n", SQUASHFS_INODE_BLK(ino), offset, | ||
267 | squashfs_i(inode)->start, | ||
268 | le16_to_cpu(sqsh_ino->offset)); | ||
269 | break; | ||
270 | } | ||
271 | case SQUASHFS_SYMLINK_TYPE: | ||
272 | case SQUASHFS_LSYMLINK_TYPE: { | ||
273 | struct squashfs_symlink_inode *sqsh_ino = &squashfs_ino.symlink; | ||
274 | |||
275 | err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, | ||
276 | sizeof(*sqsh_ino)); | ||
277 | if (err < 0) | ||
278 | goto failed_read; | ||
279 | |||
280 | inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); | ||
281 | inode->i_size = le32_to_cpu(sqsh_ino->symlink_size); | ||
282 | inode->i_op = &page_symlink_inode_operations; | ||
283 | inode->i_data.a_ops = &squashfs_symlink_aops; | ||
284 | inode->i_mode |= S_IFLNK; | ||
285 | squashfs_i(inode)->start = block; | ||
286 | squashfs_i(inode)->offset = offset; | ||
287 | |||
288 | TRACE("Symbolic link inode %x:%x, start_block %llx, offset " | ||
289 | "%x\n", SQUASHFS_INODE_BLK(ino), offset, | ||
290 | block, offset); | ||
291 | break; | ||
292 | } | ||
293 | case SQUASHFS_BLKDEV_TYPE: | ||
294 | case SQUASHFS_CHRDEV_TYPE: | ||
295 | case SQUASHFS_LBLKDEV_TYPE: | ||
296 | case SQUASHFS_LCHRDEV_TYPE: { | ||
297 | struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev; | ||
298 | unsigned int rdev; | ||
299 | |||
300 | err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, | ||
301 | sizeof(*sqsh_ino)); | ||
302 | if (err < 0) | ||
303 | goto failed_read; | ||
304 | |||
305 | if (type == SQUASHFS_CHRDEV_TYPE) | ||
306 | inode->i_mode |= S_IFCHR; | ||
307 | else | ||
308 | inode->i_mode |= S_IFBLK; | ||
309 | inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); | ||
310 | rdev = le32_to_cpu(sqsh_ino->rdev); | ||
311 | init_special_inode(inode, inode->i_mode, new_decode_dev(rdev)); | ||
312 | |||
313 | TRACE("Device inode %x:%x, rdev %x\n", | ||
314 | SQUASHFS_INODE_BLK(ino), offset, rdev); | ||
315 | break; | ||
316 | } | ||
317 | case SQUASHFS_FIFO_TYPE: | ||
318 | case SQUASHFS_SOCKET_TYPE: | ||
319 | case SQUASHFS_LFIFO_TYPE: | ||
320 | case SQUASHFS_LSOCKET_TYPE: { | ||
321 | struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc; | ||
322 | |||
323 | err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, | ||
324 | sizeof(*sqsh_ino)); | ||
325 | if (err < 0) | ||
326 | goto failed_read; | ||
327 | |||
328 | if (type == SQUASHFS_FIFO_TYPE) | ||
329 | inode->i_mode |= S_IFIFO; | ||
330 | else | ||
331 | inode->i_mode |= S_IFSOCK; | ||
332 | inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); | ||
333 | init_special_inode(inode, inode->i_mode, 0); | ||
334 | break; | ||
335 | } | ||
336 | default: | ||
337 | ERROR("Unknown inode type %d in squashfs_iget!\n", type); | ||
338 | return -EINVAL; | ||
339 | } | ||
340 | |||
341 | return 0; | ||
342 | |||
343 | failed_read: | ||
344 | ERROR("Unable to read inode 0x%llx\n", ino); | ||
345 | return err; | ||
346 | } | ||
diff --git a/fs/squashfs/namei.c b/fs/squashfs/namei.c new file mode 100644 index 000000000000..9e398653b22b --- /dev/null +++ b/fs/squashfs/namei.c | |||
@@ -0,0 +1,242 @@ | |||
1 | /* | ||
2 | * Squashfs - a compressed read only filesystem for Linux | ||
3 | * | ||
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | ||
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2, | ||
10 | * or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | * | ||
21 | * namei.c | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * This file implements code to do filename lookup in directories. | ||
26 | * | ||
27 | * Like inodes, directories are packed into compressed metadata blocks, stored | ||
28 | * in a directory table. Directories are accessed using the start address of | ||
29 | * the metablock containing the directory and the offset into the | ||
30 | * decompressed block (<block, offset>). | ||
31 | * | ||
32 | * Directories are organised in a slightly complex way, and are not simply | ||
33 | * a list of file names. The organisation takes advantage of the | ||
34 | * fact that (in most cases) the inodes of the files will be in the same | ||
35 | * compressed metadata block, and therefore, can share the start block. | ||
36 | * Directories are therefore organised in a two level list, a directory | ||
37 | * header containing the shared start block value, and a sequence of directory | ||
38 | * entries, each of which share the shared start block. A new directory header | ||
39 | * is written once/if the inode start block changes. The directory | ||
40 | * header/directory entry list is repeated as many times as necessary. | ||
41 | * | ||
42 | * Directories are sorted, and can contain a directory index to speed up | ||
43 | * file lookup. Directory indexes store one entry per metablock, each entry | ||
44 | * storing the index/filename mapping to the first directory header | ||
45 | * in each metadata block. Directories are sorted in alphabetical order, | ||
46 | * and at lookup the index is scanned linearly looking for the first filename | ||
47 | * alphabetically larger than the filename being looked up. At this point the | ||
48 | * location of the metadata block the filename is in has been found. | ||
49 | * The general idea of the index is ensure only one metadata block needs to be | ||
50 | * decompressed to do a lookup irrespective of the length of the directory. | ||
51 | * This scheme has the advantage that it doesn't require extra memory overhead | ||
52 | * and doesn't require much extra storage on disk. | ||
53 | */ | ||
54 | |||
55 | #include <linux/fs.h> | ||
56 | #include <linux/vfs.h> | ||
57 | #include <linux/slab.h> | ||
58 | #include <linux/string.h> | ||
59 | #include <linux/dcache.h> | ||
60 | #include <linux/zlib.h> | ||
61 | |||
62 | #include "squashfs_fs.h" | ||
63 | #include "squashfs_fs_sb.h" | ||
64 | #include "squashfs_fs_i.h" | ||
65 | #include "squashfs.h" | ||
66 | |||
67 | /* | ||
68 | * Lookup name in the directory index, returning the location of the metadata | ||
69 | * block containing it, and the directory index this represents. | ||
70 | * | ||
71 | * If we get an error reading the index then return the part of the index | ||
72 | * (if any) we have managed to read - the index isn't essential, just | ||
73 | * quicker. | ||
74 | */ | ||
75 | static int get_dir_index_using_name(struct super_block *sb, | ||
76 | u64 *next_block, int *next_offset, u64 index_start, | ||
77 | int index_offset, int i_count, const char *name, | ||
78 | int len) | ||
79 | { | ||
80 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
81 | int i, size, length = 0, err; | ||
82 | struct squashfs_dir_index *index; | ||
83 | char *str; | ||
84 | |||
85 | TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); | ||
86 | |||
87 | index = kmalloc(sizeof(*index) + SQUASHFS_NAME_LEN * 2 + 2, GFP_KERNEL); | ||
88 | if (index == NULL) { | ||
89 | ERROR("Failed to allocate squashfs_dir_index\n"); | ||
90 | goto out; | ||
91 | } | ||
92 | |||
93 | str = &index->name[SQUASHFS_NAME_LEN + 1]; | ||
94 | strncpy(str, name, len); | ||
95 | str[len] = '\0'; | ||
96 | |||
97 | for (i = 0; i < i_count; i++) { | ||
98 | err = squashfs_read_metadata(sb, index, &index_start, | ||
99 | &index_offset, sizeof(*index)); | ||
100 | if (err < 0) | ||
101 | break; | ||
102 | |||
103 | |||
104 | size = le32_to_cpu(index->size) + 1; | ||
105 | |||
106 | err = squashfs_read_metadata(sb, index->name, &index_start, | ||
107 | &index_offset, size); | ||
108 | if (err < 0) | ||
109 | break; | ||
110 | |||
111 | index->name[size] = '\0'; | ||
112 | |||
113 | if (strcmp(index->name, str) > 0) | ||
114 | break; | ||
115 | |||
116 | length = le32_to_cpu(index->index); | ||
117 | *next_block = le32_to_cpu(index->start_block) + | ||
118 | msblk->directory_table; | ||
119 | } | ||
120 | |||
121 | *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; | ||
122 | kfree(index); | ||
123 | |||
124 | out: | ||
125 | /* | ||
126 | * Return index (f_pos) of the looked up metadata block. Translate | ||
127 | * from internal f_pos to external f_pos which is offset by 3 because | ||
128 | * we invent "." and ".." entries which are not actually stored in the | ||
129 | * directory. | ||
130 | */ | ||
131 | return length + 3; | ||
132 | } | ||
133 | |||
134 | |||
135 | static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry, | ||
136 | struct nameidata *nd) | ||
137 | { | ||
138 | const unsigned char *name = dentry->d_name.name; | ||
139 | int len = dentry->d_name.len; | ||
140 | struct inode *inode = NULL; | ||
141 | struct squashfs_sb_info *msblk = dir->i_sb->s_fs_info; | ||
142 | struct squashfs_dir_header dirh; | ||
143 | struct squashfs_dir_entry *dire; | ||
144 | u64 block = squashfs_i(dir)->start + msblk->directory_table; | ||
145 | int offset = squashfs_i(dir)->offset; | ||
146 | int err, length = 0, dir_count, size; | ||
147 | |||
148 | TRACE("Entered squashfs_lookup [%llx:%x]\n", block, offset); | ||
149 | |||
150 | dire = kmalloc(sizeof(*dire) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL); | ||
151 | if (dire == NULL) { | ||
152 | ERROR("Failed to allocate squashfs_dir_entry\n"); | ||
153 | return ERR_PTR(-ENOMEM); | ||
154 | } | ||
155 | |||
156 | if (len > SQUASHFS_NAME_LEN) { | ||
157 | err = -ENAMETOOLONG; | ||
158 | goto failed; | ||
159 | } | ||
160 | |||
161 | length = get_dir_index_using_name(dir->i_sb, &block, &offset, | ||
162 | squashfs_i(dir)->dir_idx_start, | ||
163 | squashfs_i(dir)->dir_idx_offset, | ||
164 | squashfs_i(dir)->dir_idx_cnt, name, len); | ||
165 | |||
166 | while (length < i_size_read(dir)) { | ||
167 | /* | ||
168 | * Read directory header. | ||
169 | */ | ||
170 | err = squashfs_read_metadata(dir->i_sb, &dirh, &block, | ||
171 | &offset, sizeof(dirh)); | ||
172 | if (err < 0) | ||
173 | goto read_failure; | ||
174 | |||
175 | length += sizeof(dirh); | ||
176 | |||
177 | dir_count = le32_to_cpu(dirh.count) + 1; | ||
178 | while (dir_count--) { | ||
179 | /* | ||
180 | * Read directory entry. | ||
181 | */ | ||
182 | err = squashfs_read_metadata(dir->i_sb, dire, &block, | ||
183 | &offset, sizeof(*dire)); | ||
184 | if (err < 0) | ||
185 | goto read_failure; | ||
186 | |||
187 | size = le16_to_cpu(dire->size) + 1; | ||
188 | |||
189 | err = squashfs_read_metadata(dir->i_sb, dire->name, | ||
190 | &block, &offset, size); | ||
191 | if (err < 0) | ||
192 | goto read_failure; | ||
193 | |||
194 | length += sizeof(*dire) + size; | ||
195 | |||
196 | if (name[0] < dire->name[0]) | ||
197 | goto exit_lookup; | ||
198 | |||
199 | if (len == size && !strncmp(name, dire->name, len)) { | ||
200 | unsigned int blk, off, ino_num; | ||
201 | long long ino; | ||
202 | blk = le32_to_cpu(dirh.start_block); | ||
203 | off = le16_to_cpu(dire->offset); | ||
204 | ino_num = le32_to_cpu(dirh.inode_number) + | ||
205 | (short) le16_to_cpu(dire->inode_number); | ||
206 | ino = SQUASHFS_MKINODE(blk, off); | ||
207 | |||
208 | TRACE("calling squashfs_iget for directory " | ||
209 | "entry %s, inode %x:%x, %d\n", name, | ||
210 | blk, off, ino_num); | ||
211 | |||
212 | inode = squashfs_iget(dir->i_sb, ino, ino_num); | ||
213 | if (IS_ERR(inode)) { | ||
214 | err = PTR_ERR(inode); | ||
215 | goto failed; | ||
216 | } | ||
217 | |||
218 | goto exit_lookup; | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | |||
223 | exit_lookup: | ||
224 | kfree(dire); | ||
225 | if (inode) | ||
226 | return d_splice_alias(inode, dentry); | ||
227 | d_add(dentry, inode); | ||
228 | return ERR_PTR(0); | ||
229 | |||
230 | read_failure: | ||
231 | ERROR("Unable to read directory block [%llx:%x]\n", | ||
232 | squashfs_i(dir)->start + msblk->directory_table, | ||
233 | squashfs_i(dir)->offset); | ||
234 | failed: | ||
235 | kfree(dire); | ||
236 | return ERR_PTR(err); | ||
237 | } | ||
238 | |||
239 | |||
240 | const struct inode_operations squashfs_dir_inode_ops = { | ||
241 | .lookup = squashfs_lookup | ||
242 | }; | ||
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h new file mode 100644 index 000000000000..6b2515d027d5 --- /dev/null +++ b/fs/squashfs/squashfs.h | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * Squashfs - a compressed read only filesystem for Linux | ||
3 | * | ||
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | ||
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2, | ||
10 | * or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | * | ||
21 | * squashfs.h | ||
22 | */ | ||
23 | |||
24 | #define TRACE(s, args...) pr_debug("SQUASHFS: "s, ## args) | ||
25 | |||
26 | #define ERROR(s, args...) pr_err("SQUASHFS error: "s, ## args) | ||
27 | |||
28 | #define WARNING(s, args...) pr_warning("SQUASHFS: "s, ## args) | ||
29 | |||
30 | static inline struct squashfs_inode_info *squashfs_i(struct inode *inode) | ||
31 | { | ||
32 | return list_entry(inode, struct squashfs_inode_info, vfs_inode); | ||
33 | } | ||
34 | |||
35 | /* block.c */ | ||
36 | extern int squashfs_read_data(struct super_block *, void **, u64, int, u64 *, | ||
37 | int); | ||
38 | |||
39 | /* cache.c */ | ||
40 | extern struct squashfs_cache *squashfs_cache_init(char *, int, int); | ||
41 | extern void squashfs_cache_delete(struct squashfs_cache *); | ||
42 | extern struct squashfs_cache_entry *squashfs_cache_get(struct super_block *, | ||
43 | struct squashfs_cache *, u64, int); | ||
44 | extern void squashfs_cache_put(struct squashfs_cache_entry *); | ||
45 | extern int squashfs_copy_data(void *, struct squashfs_cache_entry *, int, int); | ||
46 | extern int squashfs_read_metadata(struct super_block *, void *, u64 *, | ||
47 | int *, int); | ||
48 | extern struct squashfs_cache_entry *squashfs_get_fragment(struct super_block *, | ||
49 | u64, int); | ||
50 | extern struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *, | ||
51 | u64, int); | ||
52 | extern int squashfs_read_table(struct super_block *, void *, u64, int); | ||
53 | |||
54 | /* export.c */ | ||
55 | extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, | ||
56 | unsigned int); | ||
57 | |||
58 | /* fragment.c */ | ||
59 | extern int squashfs_frag_lookup(struct super_block *, unsigned int, u64 *); | ||
60 | extern __le64 *squashfs_read_fragment_index_table(struct super_block *, | ||
61 | u64, unsigned int); | ||
62 | |||
63 | /* id.c */ | ||
64 | extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); | ||
65 | extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, | ||
66 | unsigned short); | ||
67 | |||
68 | /* inode.c */ | ||
69 | extern struct inode *squashfs_iget(struct super_block *, long long, | ||
70 | unsigned int); | ||
71 | extern int squashfs_read_inode(struct inode *, long long); | ||
72 | |||
73 | /* | ||
74 | * Inodes and files operations | ||
75 | */ | ||
76 | |||
77 | /* dir.c */ | ||
78 | extern const struct file_operations squashfs_dir_ops; | ||
79 | |||
80 | /* export.c */ | ||
81 | extern const struct export_operations squashfs_export_ops; | ||
82 | |||
83 | /* file.c */ | ||
84 | extern const struct address_space_operations squashfs_aops; | ||
85 | |||
86 | /* namei.c */ | ||
87 | extern const struct inode_operations squashfs_dir_inode_ops; | ||
88 | |||
89 | /* symlink.c */ | ||
90 | extern const struct address_space_operations squashfs_symlink_aops; | ||
diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h new file mode 100644 index 000000000000..6840da1bf21e --- /dev/null +++ b/fs/squashfs/squashfs_fs.h | |||
@@ -0,0 +1,381 @@ | |||
1 | #ifndef SQUASHFS_FS | ||
2 | #define SQUASHFS_FS | ||
3 | /* | ||
4 | * Squashfs | ||
5 | * | ||
6 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | ||
7 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version 2, | ||
12 | * or (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
22 | * | ||
23 | * squashfs_fs.h | ||
24 | */ | ||
25 | |||
26 | #define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE | ||
27 | #define SQUASHFS_MAJOR 4 | ||
28 | #define SQUASHFS_MINOR 0 | ||
29 | #define SQUASHFS_MAGIC 0x73717368 | ||
30 | #define SQUASHFS_START 0 | ||
31 | |||
32 | /* size of metadata (inode and directory) blocks */ | ||
33 | #define SQUASHFS_METADATA_SIZE 8192 | ||
34 | #define SQUASHFS_METADATA_LOG 13 | ||
35 | |||
36 | /* default size of data blocks */ | ||
37 | #define SQUASHFS_FILE_SIZE 131072 | ||
38 | #define SQUASHFS_FILE_LOG 17 | ||
39 | |||
40 | #define SQUASHFS_FILE_MAX_SIZE 1048576 | ||
41 | #define SQUASHFS_FILE_MAX_LOG 20 | ||
42 | |||
43 | /* Max number of uids and gids */ | ||
44 | #define SQUASHFS_IDS 65536 | ||
45 | |||
46 | /* Max length of filename (not 255) */ | ||
47 | #define SQUASHFS_NAME_LEN 256 | ||
48 | |||
49 | #define SQUASHFS_INVALID_FRAG (0xffffffffU) | ||
50 | #define SQUASHFS_INVALID_BLK (-1LL) | ||
51 | |||
52 | /* Filesystem flags */ | ||
53 | #define SQUASHFS_NOI 0 | ||
54 | #define SQUASHFS_NOD 1 | ||
55 | #define SQUASHFS_NOF 3 | ||
56 | #define SQUASHFS_NO_FRAG 4 | ||
57 | #define SQUASHFS_ALWAYS_FRAG 5 | ||
58 | #define SQUASHFS_DUPLICATE 6 | ||
59 | #define SQUASHFS_EXPORT 7 | ||
60 | |||
61 | #define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) | ||
62 | |||
63 | #define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \ | ||
64 | SQUASHFS_NOI) | ||
65 | |||
66 | #define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \ | ||
67 | SQUASHFS_NOD) | ||
68 | |||
69 | #define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ | ||
70 | SQUASHFS_NOF) | ||
71 | |||
72 | #define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ | ||
73 | SQUASHFS_NO_FRAG) | ||
74 | |||
75 | #define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ | ||
76 | SQUASHFS_ALWAYS_FRAG) | ||
77 | |||
78 | #define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \ | ||
79 | SQUASHFS_DUPLICATE) | ||
80 | |||
81 | #define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \ | ||
82 | SQUASHFS_EXPORT) | ||
83 | |||
84 | /* Max number of types and file types */ | ||
85 | #define SQUASHFS_DIR_TYPE 1 | ||
86 | #define SQUASHFS_REG_TYPE 2 | ||
87 | #define SQUASHFS_SYMLINK_TYPE 3 | ||
88 | #define SQUASHFS_BLKDEV_TYPE 4 | ||
89 | #define SQUASHFS_CHRDEV_TYPE 5 | ||
90 | #define SQUASHFS_FIFO_TYPE 6 | ||
91 | #define SQUASHFS_SOCKET_TYPE 7 | ||
92 | #define SQUASHFS_LDIR_TYPE 8 | ||
93 | #define SQUASHFS_LREG_TYPE 9 | ||
94 | #define SQUASHFS_LSYMLINK_TYPE 10 | ||
95 | #define SQUASHFS_LBLKDEV_TYPE 11 | ||
96 | #define SQUASHFS_LCHRDEV_TYPE 12 | ||
97 | #define SQUASHFS_LFIFO_TYPE 13 | ||
98 | #define SQUASHFS_LSOCKET_TYPE 14 | ||
99 | |||
100 | /* Flag whether block is compressed or uncompressed, bit is set if block is | ||
101 | * uncompressed */ | ||
102 | #define SQUASHFS_COMPRESSED_BIT (1 << 15) | ||
103 | |||
104 | #define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \ | ||
105 | (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT) | ||
106 | |||
107 | #define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT)) | ||
108 | |||
109 | #define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24) | ||
110 | |||
111 | #define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) ((B) & \ | ||
112 | ~SQUASHFS_COMPRESSED_BIT_BLOCK) | ||
113 | |||
114 | #define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) | ||
115 | |||
116 | /* | ||
117 | * Inode number ops. Inodes consist of a compressed block number, and an | ||
118 | * uncompressed offset within that block | ||
119 | */ | ||
120 | #define SQUASHFS_INODE_BLK(A) ((unsigned int) ((A) >> 16)) | ||
121 | |||
122 | #define SQUASHFS_INODE_OFFSET(A) ((unsigned int) ((A) & 0xffff)) | ||
123 | |||
124 | #define SQUASHFS_MKINODE(A, B) ((long long)(((long long) (A)\ | ||
125 | << 16) + (B))) | ||
126 | |||
127 | /* Translate between VFS mode and squashfs mode */ | ||
128 | #define SQUASHFS_MODE(A) ((A) & 0xfff) | ||
129 | |||
130 | /* fragment and fragment table defines */ | ||
131 | #define SQUASHFS_FRAGMENT_BYTES(A) \ | ||
132 | ((A) * sizeof(struct squashfs_fragment_entry)) | ||
133 | |||
134 | #define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \ | ||
135 | SQUASHFS_METADATA_SIZE) | ||
136 | |||
137 | #define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \ | ||
138 | SQUASHFS_METADATA_SIZE) | ||
139 | |||
140 | #define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \ | ||
141 | SQUASHFS_METADATA_SIZE - 1) / \ | ||
142 | SQUASHFS_METADATA_SIZE) | ||
143 | |||
144 | #define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\ | ||
145 | sizeof(u64)) | ||
146 | |||
147 | /* inode lookup table defines */ | ||
148 | #define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(u64)) | ||
149 | |||
150 | #define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \ | ||
151 | SQUASHFS_METADATA_SIZE) | ||
152 | |||
153 | #define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \ | ||
154 | SQUASHFS_METADATA_SIZE) | ||
155 | |||
156 | #define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \ | ||
157 | SQUASHFS_METADATA_SIZE - 1) / \ | ||
158 | SQUASHFS_METADATA_SIZE) | ||
159 | |||
160 | #define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\ | ||
161 | sizeof(u64)) | ||
162 | |||
163 | /* uid/gid lookup table defines */ | ||
164 | #define SQUASHFS_ID_BYTES(A) ((A) * sizeof(unsigned int)) | ||
165 | |||
166 | #define SQUASHFS_ID_BLOCK(A) (SQUASHFS_ID_BYTES(A) / \ | ||
167 | SQUASHFS_METADATA_SIZE) | ||
168 | |||
169 | #define SQUASHFS_ID_BLOCK_OFFSET(A) (SQUASHFS_ID_BYTES(A) % \ | ||
170 | SQUASHFS_METADATA_SIZE) | ||
171 | |||
172 | #define SQUASHFS_ID_BLOCKS(A) ((SQUASHFS_ID_BYTES(A) + \ | ||
173 | SQUASHFS_METADATA_SIZE - 1) / \ | ||
174 | SQUASHFS_METADATA_SIZE) | ||
175 | |||
176 | #define SQUASHFS_ID_BLOCK_BYTES(A) (SQUASHFS_ID_BLOCKS(A) *\ | ||
177 | sizeof(u64)) | ||
178 | |||
179 | /* cached data constants for filesystem */ | ||
180 | #define SQUASHFS_CACHED_BLKS 8 | ||
181 | |||
182 | #define SQUASHFS_MAX_FILE_SIZE_LOG 64 | ||
183 | |||
184 | #define SQUASHFS_MAX_FILE_SIZE (1LL << \ | ||
185 | (SQUASHFS_MAX_FILE_SIZE_LOG - 2)) | ||
186 | |||
187 | #define SQUASHFS_MARKER_BYTE 0xff | ||
188 | |||
189 | /* meta index cache */ | ||
190 | #define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int)) | ||
191 | #define SQUASHFS_META_ENTRIES 127 | ||
192 | #define SQUASHFS_META_SLOTS 8 | ||
193 | |||
194 | struct meta_entry { | ||
195 | u64 data_block; | ||
196 | unsigned int index_block; | ||
197 | unsigned short offset; | ||
198 | unsigned short pad; | ||
199 | }; | ||
200 | |||
201 | struct meta_index { | ||
202 | unsigned int inode_number; | ||
203 | unsigned int offset; | ||
204 | unsigned short entries; | ||
205 | unsigned short skip; | ||
206 | unsigned short locked; | ||
207 | unsigned short pad; | ||
208 | struct meta_entry meta_entry[SQUASHFS_META_ENTRIES]; | ||
209 | }; | ||
210 | |||
211 | |||
212 | /* | ||
213 | * definitions for structures on disk | ||
214 | */ | ||
215 | #define ZLIB_COMPRESSION 1 | ||
216 | |||
217 | struct squashfs_super_block { | ||
218 | __le32 s_magic; | ||
219 | __le32 inodes; | ||
220 | __le32 mkfs_time; | ||
221 | __le32 block_size; | ||
222 | __le32 fragments; | ||
223 | __le16 compression; | ||
224 | __le16 block_log; | ||
225 | __le16 flags; | ||
226 | __le16 no_ids; | ||
227 | __le16 s_major; | ||
228 | __le16 s_minor; | ||
229 | __le64 root_inode; | ||
230 | __le64 bytes_used; | ||
231 | __le64 id_table_start; | ||
232 | __le64 xattr_table_start; | ||
233 | __le64 inode_table_start; | ||
234 | __le64 directory_table_start; | ||
235 | __le64 fragment_table_start; | ||
236 | __le64 lookup_table_start; | ||
237 | }; | ||
238 | |||
239 | struct squashfs_dir_index { | ||
240 | __le32 index; | ||
241 | __le32 start_block; | ||
242 | __le32 size; | ||
243 | unsigned char name[0]; | ||
244 | }; | ||
245 | |||
246 | struct squashfs_base_inode { | ||
247 | __le16 inode_type; | ||
248 | __le16 mode; | ||
249 | __le16 uid; | ||
250 | __le16 guid; | ||
251 | __le32 mtime; | ||
252 | __le32 inode_number; | ||
253 | }; | ||
254 | |||
255 | struct squashfs_ipc_inode { | ||
256 | __le16 inode_type; | ||
257 | __le16 mode; | ||
258 | __le16 uid; | ||
259 | __le16 guid; | ||
260 | __le32 mtime; | ||
261 | __le32 inode_number; | ||
262 | __le32 nlink; | ||
263 | }; | ||
264 | |||
265 | struct squashfs_dev_inode { | ||
266 | __le16 inode_type; | ||
267 | __le16 mode; | ||
268 | __le16 uid; | ||
269 | __le16 guid; | ||
270 | __le32 mtime; | ||
271 | __le32 inode_number; | ||
272 | __le32 nlink; | ||
273 | __le32 rdev; | ||
274 | }; | ||
275 | |||
276 | struct squashfs_symlink_inode { | ||
277 | __le16 inode_type; | ||
278 | __le16 mode; | ||
279 | __le16 uid; | ||
280 | __le16 guid; | ||
281 | __le32 mtime; | ||
282 | __le32 inode_number; | ||
283 | __le32 nlink; | ||
284 | __le32 symlink_size; | ||
285 | char symlink[0]; | ||
286 | }; | ||
287 | |||
288 | struct squashfs_reg_inode { | ||
289 | __le16 inode_type; | ||
290 | __le16 mode; | ||
291 | __le16 uid; | ||
292 | __le16 guid; | ||
293 | __le32 mtime; | ||
294 | __le32 inode_number; | ||
295 | __le32 start_block; | ||
296 | __le32 fragment; | ||
297 | __le32 offset; | ||
298 | __le32 file_size; | ||
299 | __le16 block_list[0]; | ||
300 | }; | ||
301 | |||
302 | struct squashfs_lreg_inode { | ||
303 | __le16 inode_type; | ||
304 | __le16 mode; | ||
305 | __le16 uid; | ||
306 | __le16 guid; | ||
307 | __le32 mtime; | ||
308 | __le32 inode_number; | ||
309 | __le64 start_block; | ||
310 | __le64 file_size; | ||
311 | __le64 sparse; | ||
312 | __le32 nlink; | ||
313 | __le32 fragment; | ||
314 | __le32 offset; | ||
315 | __le32 xattr; | ||
316 | __le16 block_list[0]; | ||
317 | }; | ||
318 | |||
319 | struct squashfs_dir_inode { | ||
320 | __le16 inode_type; | ||
321 | __le16 mode; | ||
322 | __le16 uid; | ||
323 | __le16 guid; | ||
324 | __le32 mtime; | ||
325 | __le32 inode_number; | ||
326 | __le32 start_block; | ||
327 | __le32 nlink; | ||
328 | __le16 file_size; | ||
329 | __le16 offset; | ||
330 | __le32 parent_inode; | ||
331 | }; | ||
332 | |||
333 | struct squashfs_ldir_inode { | ||
334 | __le16 inode_type; | ||
335 | __le16 mode; | ||
336 | __le16 uid; | ||
337 | __le16 guid; | ||
338 | __le32 mtime; | ||
339 | __le32 inode_number; | ||
340 | __le32 nlink; | ||
341 | __le32 file_size; | ||
342 | __le32 start_block; | ||
343 | __le32 parent_inode; | ||
344 | __le16 i_count; | ||
345 | __le16 offset; | ||
346 | __le32 xattr; | ||
347 | struct squashfs_dir_index index[0]; | ||
348 | }; | ||
349 | |||
350 | union squashfs_inode { | ||
351 | struct squashfs_base_inode base; | ||
352 | struct squashfs_dev_inode dev; | ||
353 | struct squashfs_symlink_inode symlink; | ||
354 | struct squashfs_reg_inode reg; | ||
355 | struct squashfs_lreg_inode lreg; | ||
356 | struct squashfs_dir_inode dir; | ||
357 | struct squashfs_ldir_inode ldir; | ||
358 | struct squashfs_ipc_inode ipc; | ||
359 | }; | ||
360 | |||
361 | struct squashfs_dir_entry { | ||
362 | __le16 offset; | ||
363 | __le16 inode_number; | ||
364 | __le16 type; | ||
365 | __le16 size; | ||
366 | char name[0]; | ||
367 | }; | ||
368 | |||
369 | struct squashfs_dir_header { | ||
370 | __le32 count; | ||
371 | __le32 start_block; | ||
372 | __le32 inode_number; | ||
373 | }; | ||
374 | |||
375 | struct squashfs_fragment_entry { | ||
376 | __le64 start_block; | ||
377 | __le32 size; | ||
378 | unsigned int unused; | ||
379 | }; | ||
380 | |||
381 | #endif | ||
diff --git a/fs/squashfs/squashfs_fs_i.h b/fs/squashfs/squashfs_fs_i.h new file mode 100644 index 000000000000..fbfca30c0c68 --- /dev/null +++ b/fs/squashfs/squashfs_fs_i.h | |||
@@ -0,0 +1,45 @@ | |||
1 | #ifndef SQUASHFS_FS_I | ||
2 | #define SQUASHFS_FS_I | ||
3 | /* | ||
4 | * Squashfs | ||
5 | * | ||
6 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | ||
7 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version 2, | ||
12 | * or (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
22 | * | ||
23 | * squashfs_fs_i.h | ||
24 | */ | ||
25 | |||
26 | struct squashfs_inode_info { | ||
27 | u64 start; | ||
28 | int offset; | ||
29 | union { | ||
30 | struct { | ||
31 | u64 fragment_block; | ||
32 | int fragment_size; | ||
33 | int fragment_offset; | ||
34 | u64 block_list_start; | ||
35 | }; | ||
36 | struct { | ||
37 | u64 dir_idx_start; | ||
38 | int dir_idx_offset; | ||
39 | int dir_idx_cnt; | ||
40 | int parent; | ||
41 | }; | ||
42 | }; | ||
43 | struct inode vfs_inode; | ||
44 | }; | ||
45 | #endif | ||
diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h new file mode 100644 index 000000000000..c8c65614dd1c --- /dev/null +++ b/fs/squashfs/squashfs_fs_sb.h | |||
@@ -0,0 +1,76 @@ | |||
1 | #ifndef SQUASHFS_FS_SB | ||
2 | #define SQUASHFS_FS_SB | ||
3 | /* | ||
4 | * Squashfs | ||
5 | * | ||
6 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | ||
7 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version 2, | ||
12 | * or (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
22 | * | ||
23 | * squashfs_fs_sb.h | ||
24 | */ | ||
25 | |||
26 | #include "squashfs_fs.h" | ||
27 | |||
28 | struct squashfs_cache { | ||
29 | char *name; | ||
30 | int entries; | ||
31 | int next_blk; | ||
32 | int num_waiters; | ||
33 | int unused; | ||
34 | int block_size; | ||
35 | int pages; | ||
36 | spinlock_t lock; | ||
37 | wait_queue_head_t wait_queue; | ||
38 | struct squashfs_cache_entry *entry; | ||
39 | }; | ||
40 | |||
41 | struct squashfs_cache_entry { | ||
42 | u64 block; | ||
43 | int length; | ||
44 | int refcount; | ||
45 | u64 next_index; | ||
46 | int pending; | ||
47 | int error; | ||
48 | int num_waiters; | ||
49 | wait_queue_head_t wait_queue; | ||
50 | struct squashfs_cache *cache; | ||
51 | void **data; | ||
52 | }; | ||
53 | |||
54 | struct squashfs_sb_info { | ||
55 | int devblksize; | ||
56 | int devblksize_log2; | ||
57 | struct squashfs_cache *block_cache; | ||
58 | struct squashfs_cache *fragment_cache; | ||
59 | struct squashfs_cache *read_page; | ||
60 | int next_meta_index; | ||
61 | __le64 *id_table; | ||
62 | __le64 *fragment_index; | ||
63 | unsigned int *fragment_index_2; | ||
64 | struct mutex read_data_mutex; | ||
65 | struct mutex meta_index_mutex; | ||
66 | struct meta_index *meta_index; | ||
67 | z_stream stream; | ||
68 | __le64 *inode_lookup_table; | ||
69 | u64 inode_table; | ||
70 | u64 directory_table; | ||
71 | unsigned int block_size; | ||
72 | unsigned short block_log; | ||
73 | long long bytes_used; | ||
74 | unsigned int inodes; | ||
75 | }; | ||
76 | #endif | ||
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c new file mode 100644 index 000000000000..a0466d7467b2 --- /dev/null +++ b/fs/squashfs/super.c | |||
@@ -0,0 +1,440 @@ | |||
1 | /* | ||
2 | * Squashfs - a compressed read only filesystem for Linux | ||
3 | * | ||
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | ||
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2, | ||
10 | * or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | * | ||
21 | * super.c | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * This file implements code to read the superblock, read and initialise | ||
26 | * in-memory structures at mount time, and all the VFS glue code to register | ||
27 | * the filesystem. | ||
28 | */ | ||
29 | |||
30 | #include <linux/fs.h> | ||
31 | #include <linux/vfs.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/mutex.h> | ||
34 | #include <linux/pagemap.h> | ||
35 | #include <linux/init.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/zlib.h> | ||
38 | |||
39 | #include "squashfs_fs.h" | ||
40 | #include "squashfs_fs_sb.h" | ||
41 | #include "squashfs_fs_i.h" | ||
42 | #include "squashfs.h" | ||
43 | |||
44 | static struct file_system_type squashfs_fs_type; | ||
45 | static struct super_operations squashfs_super_ops; | ||
46 | |||
47 | static int supported_squashfs_filesystem(short major, short minor, short comp) | ||
48 | { | ||
49 | if (major < SQUASHFS_MAJOR) { | ||
50 | ERROR("Major/Minor mismatch, older Squashfs %d.%d " | ||
51 | "filesystems are unsupported\n", major, minor); | ||
52 | return -EINVAL; | ||
53 | } else if (major > SQUASHFS_MAJOR || minor > SQUASHFS_MINOR) { | ||
54 | ERROR("Major/Minor mismatch, trying to mount newer " | ||
55 | "%d.%d filesystem\n", major, minor); | ||
56 | ERROR("Please update your kernel\n"); | ||
57 | return -EINVAL; | ||
58 | } | ||
59 | |||
60 | if (comp != ZLIB_COMPRESSION) | ||
61 | return -EINVAL; | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | |||
67 | static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | ||
68 | { | ||
69 | struct squashfs_sb_info *msblk; | ||
70 | struct squashfs_super_block *sblk = NULL; | ||
71 | char b[BDEVNAME_SIZE]; | ||
72 | struct inode *root; | ||
73 | long long root_inode; | ||
74 | unsigned short flags; | ||
75 | unsigned int fragments; | ||
76 | u64 lookup_table_start; | ||
77 | int err; | ||
78 | |||
79 | TRACE("Entered squashfs_fill_superblock\n"); | ||
80 | |||
81 | sb->s_fs_info = kzalloc(sizeof(*msblk), GFP_KERNEL); | ||
82 | if (sb->s_fs_info == NULL) { | ||
83 | ERROR("Failed to allocate squashfs_sb_info\n"); | ||
84 | return -ENOMEM; | ||
85 | } | ||
86 | msblk = sb->s_fs_info; | ||
87 | |||
88 | msblk->stream.workspace = kmalloc(zlib_inflate_workspacesize(), | ||
89 | GFP_KERNEL); | ||
90 | if (msblk->stream.workspace == NULL) { | ||
91 | ERROR("Failed to allocate zlib workspace\n"); | ||
92 | goto failure; | ||
93 | } | ||
94 | |||
95 | sblk = kzalloc(sizeof(*sblk), GFP_KERNEL); | ||
96 | if (sblk == NULL) { | ||
97 | ERROR("Failed to allocate squashfs_super_block\n"); | ||
98 | goto failure; | ||
99 | } | ||
100 | |||
101 | msblk->devblksize = sb_min_blocksize(sb, BLOCK_SIZE); | ||
102 | msblk->devblksize_log2 = ffz(~msblk->devblksize); | ||
103 | |||
104 | mutex_init(&msblk->read_data_mutex); | ||
105 | mutex_init(&msblk->meta_index_mutex); | ||
106 | |||
107 | /* | ||
108 | * msblk->bytes_used is checked in squashfs_read_table to ensure reads | ||
109 | * are not beyond filesystem end. But as we're using | ||
110 | * squashfs_read_table here to read the superblock (including the value | ||
111 | * of bytes_used) we need to set it to an initial sensible dummy value | ||
112 | */ | ||
113 | msblk->bytes_used = sizeof(*sblk); | ||
114 | err = squashfs_read_table(sb, sblk, SQUASHFS_START, sizeof(*sblk)); | ||
115 | |||
116 | if (err < 0) { | ||
117 | ERROR("unable to read squashfs_super_block\n"); | ||
118 | goto failed_mount; | ||
119 | } | ||
120 | |||
121 | /* Check it is a SQUASHFS superblock */ | ||
122 | sb->s_magic = le32_to_cpu(sblk->s_magic); | ||
123 | if (sb->s_magic != SQUASHFS_MAGIC) { | ||
124 | if (!silent) | ||
125 | ERROR("Can't find a SQUASHFS superblock on %s\n", | ||
126 | bdevname(sb->s_bdev, b)); | ||
127 | err = -EINVAL; | ||
128 | goto failed_mount; | ||
129 | } | ||
130 | |||
131 | /* Check the MAJOR & MINOR versions and compression type */ | ||
132 | err = supported_squashfs_filesystem(le16_to_cpu(sblk->s_major), | ||
133 | le16_to_cpu(sblk->s_minor), | ||
134 | le16_to_cpu(sblk->compression)); | ||
135 | if (err < 0) | ||
136 | goto failed_mount; | ||
137 | |||
138 | err = -EINVAL; | ||
139 | |||
140 | /* | ||
141 | * Check if there's xattrs in the filesystem. These are not | ||
142 | * supported in this version, so warn that they will be ignored. | ||
143 | */ | ||
144 | if (le64_to_cpu(sblk->xattr_table_start) != SQUASHFS_INVALID_BLK) | ||
145 | ERROR("Xattrs in filesystem, these will be ignored\n"); | ||
146 | |||
147 | /* Check the filesystem does not extend beyond the end of the | ||
148 | block device */ | ||
149 | msblk->bytes_used = le64_to_cpu(sblk->bytes_used); | ||
150 | if (msblk->bytes_used < 0 || msblk->bytes_used > | ||
151 | i_size_read(sb->s_bdev->bd_inode)) | ||
152 | goto failed_mount; | ||
153 | |||
154 | /* Check block size for sanity */ | ||
155 | msblk->block_size = le32_to_cpu(sblk->block_size); | ||
156 | if (msblk->block_size > SQUASHFS_FILE_MAX_SIZE) | ||
157 | goto failed_mount; | ||
158 | |||
159 | msblk->block_log = le16_to_cpu(sblk->block_log); | ||
160 | if (msblk->block_log > SQUASHFS_FILE_MAX_LOG) | ||
161 | goto failed_mount; | ||
162 | |||
163 | /* Check the root inode for sanity */ | ||
164 | root_inode = le64_to_cpu(sblk->root_inode); | ||
165 | if (SQUASHFS_INODE_OFFSET(root_inode) > SQUASHFS_METADATA_SIZE) | ||
166 | goto failed_mount; | ||
167 | |||
168 | msblk->inode_table = le64_to_cpu(sblk->inode_table_start); | ||
169 | msblk->directory_table = le64_to_cpu(sblk->directory_table_start); | ||
170 | msblk->inodes = le32_to_cpu(sblk->inodes); | ||
171 | flags = le16_to_cpu(sblk->flags); | ||
172 | |||
173 | TRACE("Found valid superblock on %s\n", bdevname(sb->s_bdev, b)); | ||
174 | TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(flags) | ||
175 | ? "un" : ""); | ||
176 | TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(flags) | ||
177 | ? "un" : ""); | ||
178 | TRACE("Filesystem size %lld bytes\n", msblk->bytes_used); | ||
179 | TRACE("Block size %d\n", msblk->block_size); | ||
180 | TRACE("Number of inodes %d\n", msblk->inodes); | ||
181 | TRACE("Number of fragments %d\n", le32_to_cpu(sblk->fragments)); | ||
182 | TRACE("Number of ids %d\n", le16_to_cpu(sblk->no_ids)); | ||
183 | TRACE("sblk->inode_table_start %llx\n", msblk->inode_table); | ||
184 | TRACE("sblk->directory_table_start %llx\n", msblk->directory_table); | ||
185 | TRACE("sblk->fragment_table_start %llx\n", | ||
186 | (u64) le64_to_cpu(sblk->fragment_table_start)); | ||
187 | TRACE("sblk->id_table_start %llx\n", | ||
188 | (u64) le64_to_cpu(sblk->id_table_start)); | ||
189 | |||
190 | sb->s_maxbytes = MAX_LFS_FILESIZE; | ||
191 | sb->s_flags |= MS_RDONLY; | ||
192 | sb->s_op = &squashfs_super_ops; | ||
193 | |||
194 | err = -ENOMEM; | ||
195 | |||
196 | msblk->block_cache = squashfs_cache_init("metadata", | ||
197 | SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE); | ||
198 | if (msblk->block_cache == NULL) | ||
199 | goto failed_mount; | ||
200 | |||
201 | /* Allocate read_page block */ | ||
202 | msblk->read_page = squashfs_cache_init("data", 1, msblk->block_size); | ||
203 | if (msblk->read_page == NULL) { | ||
204 | ERROR("Failed to allocate read_page block\n"); | ||
205 | goto failed_mount; | ||
206 | } | ||
207 | |||
208 | /* Allocate and read id index table */ | ||
209 | msblk->id_table = squashfs_read_id_index_table(sb, | ||
210 | le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids)); | ||
211 | if (IS_ERR(msblk->id_table)) { | ||
212 | err = PTR_ERR(msblk->id_table); | ||
213 | msblk->id_table = NULL; | ||
214 | goto failed_mount; | ||
215 | } | ||
216 | |||
217 | fragments = le32_to_cpu(sblk->fragments); | ||
218 | if (fragments == 0) | ||
219 | goto allocate_lookup_table; | ||
220 | |||
221 | msblk->fragment_cache = squashfs_cache_init("fragment", | ||
222 | SQUASHFS_CACHED_FRAGMENTS, msblk->block_size); | ||
223 | if (msblk->fragment_cache == NULL) { | ||
224 | err = -ENOMEM; | ||
225 | goto failed_mount; | ||
226 | } | ||
227 | |||
228 | /* Allocate and read fragment index table */ | ||
229 | msblk->fragment_index = squashfs_read_fragment_index_table(sb, | ||
230 | le64_to_cpu(sblk->fragment_table_start), fragments); | ||
231 | if (IS_ERR(msblk->fragment_index)) { | ||
232 | err = PTR_ERR(msblk->fragment_index); | ||
233 | msblk->fragment_index = NULL; | ||
234 | goto failed_mount; | ||
235 | } | ||
236 | |||
237 | allocate_lookup_table: | ||
238 | lookup_table_start = le64_to_cpu(sblk->lookup_table_start); | ||
239 | if (lookup_table_start == SQUASHFS_INVALID_BLK) | ||
240 | goto allocate_root; | ||
241 | |||
242 | /* Allocate and read inode lookup table */ | ||
243 | msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb, | ||
244 | lookup_table_start, msblk->inodes); | ||
245 | if (IS_ERR(msblk->inode_lookup_table)) { | ||
246 | err = PTR_ERR(msblk->inode_lookup_table); | ||
247 | msblk->inode_lookup_table = NULL; | ||
248 | goto failed_mount; | ||
249 | } | ||
250 | |||
251 | sb->s_export_op = &squashfs_export_ops; | ||
252 | |||
253 | allocate_root: | ||
254 | root = new_inode(sb); | ||
255 | if (!root) { | ||
256 | err = -ENOMEM; | ||
257 | goto failed_mount; | ||
258 | } | ||
259 | |||
260 | err = squashfs_read_inode(root, root_inode); | ||
261 | if (err) { | ||
262 | iget_failed(root); | ||
263 | goto failed_mount; | ||
264 | } | ||
265 | insert_inode_hash(root); | ||
266 | |||
267 | sb->s_root = d_alloc_root(root); | ||
268 | if (sb->s_root == NULL) { | ||
269 | ERROR("Root inode create failed\n"); | ||
270 | err = -ENOMEM; | ||
271 | iput(root); | ||
272 | goto failed_mount; | ||
273 | } | ||
274 | |||
275 | TRACE("Leaving squashfs_fill_super\n"); | ||
276 | kfree(sblk); | ||
277 | return 0; | ||
278 | |||
279 | failed_mount: | ||
280 | squashfs_cache_delete(msblk->block_cache); | ||
281 | squashfs_cache_delete(msblk->fragment_cache); | ||
282 | squashfs_cache_delete(msblk->read_page); | ||
283 | kfree(msblk->inode_lookup_table); | ||
284 | kfree(msblk->fragment_index); | ||
285 | kfree(msblk->id_table); | ||
286 | kfree(msblk->stream.workspace); | ||
287 | kfree(sb->s_fs_info); | ||
288 | sb->s_fs_info = NULL; | ||
289 | kfree(sblk); | ||
290 | return err; | ||
291 | |||
292 | failure: | ||
293 | kfree(msblk->stream.workspace); | ||
294 | kfree(sb->s_fs_info); | ||
295 | sb->s_fs_info = NULL; | ||
296 | return -ENOMEM; | ||
297 | } | ||
298 | |||
299 | |||
300 | static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) | ||
301 | { | ||
302 | struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info; | ||
303 | |||
304 | TRACE("Entered squashfs_statfs\n"); | ||
305 | |||
306 | buf->f_type = SQUASHFS_MAGIC; | ||
307 | buf->f_bsize = msblk->block_size; | ||
308 | buf->f_blocks = ((msblk->bytes_used - 1) >> msblk->block_log) + 1; | ||
309 | buf->f_bfree = buf->f_bavail = 0; | ||
310 | buf->f_files = msblk->inodes; | ||
311 | buf->f_ffree = 0; | ||
312 | buf->f_namelen = SQUASHFS_NAME_LEN; | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | |||
318 | static int squashfs_remount(struct super_block *sb, int *flags, char *data) | ||
319 | { | ||
320 | *flags |= MS_RDONLY; | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | |||
325 | static void squashfs_put_super(struct super_block *sb) | ||
326 | { | ||
327 | if (sb->s_fs_info) { | ||
328 | struct squashfs_sb_info *sbi = sb->s_fs_info; | ||
329 | squashfs_cache_delete(sbi->block_cache); | ||
330 | squashfs_cache_delete(sbi->fragment_cache); | ||
331 | squashfs_cache_delete(sbi->read_page); | ||
332 | kfree(sbi->id_table); | ||
333 | kfree(sbi->fragment_index); | ||
334 | kfree(sbi->meta_index); | ||
335 | kfree(sbi->stream.workspace); | ||
336 | kfree(sb->s_fs_info); | ||
337 | sb->s_fs_info = NULL; | ||
338 | } | ||
339 | } | ||
340 | |||
341 | |||
342 | static int squashfs_get_sb(struct file_system_type *fs_type, int flags, | ||
343 | const char *dev_name, void *data, | ||
344 | struct vfsmount *mnt) | ||
345 | { | ||
346 | return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super, | ||
347 | mnt); | ||
348 | } | ||
349 | |||
350 | |||
351 | static struct kmem_cache *squashfs_inode_cachep; | ||
352 | |||
353 | |||
354 | static void init_once(void *foo) | ||
355 | { | ||
356 | struct squashfs_inode_info *ei = foo; | ||
357 | |||
358 | inode_init_once(&ei->vfs_inode); | ||
359 | } | ||
360 | |||
361 | |||
362 | static int __init init_inodecache(void) | ||
363 | { | ||
364 | squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache", | ||
365 | sizeof(struct squashfs_inode_info), 0, | ||
366 | SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, init_once); | ||
367 | |||
368 | return squashfs_inode_cachep ? 0 : -ENOMEM; | ||
369 | } | ||
370 | |||
371 | |||
372 | static void destroy_inodecache(void) | ||
373 | { | ||
374 | kmem_cache_destroy(squashfs_inode_cachep); | ||
375 | } | ||
376 | |||
377 | |||
378 | static int __init init_squashfs_fs(void) | ||
379 | { | ||
380 | int err = init_inodecache(); | ||
381 | |||
382 | if (err) | ||
383 | return err; | ||
384 | |||
385 | err = register_filesystem(&squashfs_fs_type); | ||
386 | if (err) { | ||
387 | destroy_inodecache(); | ||
388 | return err; | ||
389 | } | ||
390 | |||
391 | printk(KERN_INFO "squashfs: version 4.0 (2009/01/03) " | ||
392 | "Phillip Lougher\n"); | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | |||
398 | static void __exit exit_squashfs_fs(void) | ||
399 | { | ||
400 | unregister_filesystem(&squashfs_fs_type); | ||
401 | destroy_inodecache(); | ||
402 | } | ||
403 | |||
404 | |||
405 | static struct inode *squashfs_alloc_inode(struct super_block *sb) | ||
406 | { | ||
407 | struct squashfs_inode_info *ei = | ||
408 | kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL); | ||
409 | |||
410 | return ei ? &ei->vfs_inode : NULL; | ||
411 | } | ||
412 | |||
413 | |||
414 | static void squashfs_destroy_inode(struct inode *inode) | ||
415 | { | ||
416 | kmem_cache_free(squashfs_inode_cachep, squashfs_i(inode)); | ||
417 | } | ||
418 | |||
419 | |||
420 | static struct file_system_type squashfs_fs_type = { | ||
421 | .owner = THIS_MODULE, | ||
422 | .name = "squashfs", | ||
423 | .get_sb = squashfs_get_sb, | ||
424 | .kill_sb = kill_block_super, | ||
425 | .fs_flags = FS_REQUIRES_DEV | ||
426 | }; | ||
427 | |||
428 | static struct super_operations squashfs_super_ops = { | ||
429 | .alloc_inode = squashfs_alloc_inode, | ||
430 | .destroy_inode = squashfs_destroy_inode, | ||
431 | .statfs = squashfs_statfs, | ||
432 | .put_super = squashfs_put_super, | ||
433 | .remount_fs = squashfs_remount | ||
434 | }; | ||
435 | |||
436 | module_init(init_squashfs_fs); | ||
437 | module_exit(exit_squashfs_fs); | ||
438 | MODULE_DESCRIPTION("squashfs 4.0, a compressed read-only filesystem"); | ||
439 | MODULE_AUTHOR("Phillip Lougher <phillip@lougher.demon.co.uk>"); | ||
440 | MODULE_LICENSE("GPL"); | ||
diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c new file mode 100644 index 000000000000..83d87880aac8 --- /dev/null +++ b/fs/squashfs/symlink.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | * Squashfs - a compressed read only filesystem for Linux | ||
3 | * | ||
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | ||
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version 2, | ||
10 | * or (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | * | ||
21 | * symlink.c | ||
22 | */ | ||
23 | |||
24 | /* | ||
25 | * This file implements code to handle symbolic links. | ||
26 | * | ||
27 | * The data contents of symbolic links are stored inside the symbolic | ||
28 | * link inode within the inode table. This allows the normally small symbolic | ||
29 | * link to be compressed as part of the inode table, achieving much greater | ||
30 | * compression than if the symbolic link was compressed individually. | ||
31 | */ | ||
32 | |||
33 | #include <linux/fs.h> | ||
34 | #include <linux/vfs.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/string.h> | ||
38 | #include <linux/pagemap.h> | ||
39 | #include <linux/zlib.h> | ||
40 | |||
41 | #include "squashfs_fs.h" | ||
42 | #include "squashfs_fs_sb.h" | ||
43 | #include "squashfs_fs_i.h" | ||
44 | #include "squashfs.h" | ||
45 | |||
46 | static int squashfs_symlink_readpage(struct file *file, struct page *page) | ||
47 | { | ||
48 | struct inode *inode = page->mapping->host; | ||
49 | struct super_block *sb = inode->i_sb; | ||
50 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
51 | int index = page->index << PAGE_CACHE_SHIFT; | ||
52 | u64 block = squashfs_i(inode)->start; | ||
53 | int offset = squashfs_i(inode)->offset; | ||
54 | int length = min_t(int, i_size_read(inode) - index, PAGE_CACHE_SIZE); | ||
55 | int bytes, copied; | ||
56 | void *pageaddr; | ||
57 | struct squashfs_cache_entry *entry; | ||
58 | |||
59 | TRACE("Entered squashfs_symlink_readpage, page index %ld, start block " | ||
60 | "%llx, offset %x\n", page->index, block, offset); | ||
61 | |||
62 | /* | ||
63 | * Skip index bytes into symlink metadata. | ||
64 | */ | ||
65 | if (index) { | ||
66 | bytes = squashfs_read_metadata(sb, NULL, &block, &offset, | ||
67 | index); | ||
68 | if (bytes < 0) { | ||
69 | ERROR("Unable to read symlink [%llx:%x]\n", | ||
70 | squashfs_i(inode)->start, | ||
71 | squashfs_i(inode)->offset); | ||
72 | goto error_out; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | /* | ||
77 | * Read length bytes from symlink metadata. Squashfs_read_metadata | ||
78 | * is not used here because it can sleep and we want to use | ||
79 | * kmap_atomic to map the page. Instead call the underlying | ||
80 | * squashfs_cache_get routine. As length bytes may overlap metadata | ||
81 | * blocks, we may need to call squashfs_cache_get multiple times. | ||
82 | */ | ||
83 | for (bytes = 0; bytes < length; offset = 0, bytes += copied) { | ||
84 | entry = squashfs_cache_get(sb, msblk->block_cache, block, 0); | ||
85 | if (entry->error) { | ||
86 | ERROR("Unable to read symlink [%llx:%x]\n", | ||
87 | squashfs_i(inode)->start, | ||
88 | squashfs_i(inode)->offset); | ||
89 | squashfs_cache_put(entry); | ||
90 | goto error_out; | ||
91 | } | ||
92 | |||
93 | pageaddr = kmap_atomic(page, KM_USER0); | ||
94 | copied = squashfs_copy_data(pageaddr + bytes, entry, offset, | ||
95 | length - bytes); | ||
96 | if (copied == length - bytes) | ||
97 | memset(pageaddr + length, 0, PAGE_CACHE_SIZE - length); | ||
98 | else | ||
99 | block = entry->next_index; | ||
100 | kunmap_atomic(pageaddr, KM_USER0); | ||
101 | squashfs_cache_put(entry); | ||
102 | } | ||
103 | |||
104 | flush_dcache_page(page); | ||
105 | SetPageUptodate(page); | ||
106 | unlock_page(page); | ||
107 | return 0; | ||
108 | |||
109 | error_out: | ||
110 | SetPageError(page); | ||
111 | unlock_page(page); | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | |||
116 | const struct address_space_operations squashfs_symlink_aops = { | ||
117 | .readpage = squashfs_symlink_readpage | ||
118 | }; | ||