Commit 82de647e1f81fd89afc48608d889dd3b33cb8983
1 parent
117a91e0f2
Exists in
master
and in
7 other branches
Squashfs: move table allocation into squashfs_read_table()
This eliminates a lot of duplicate code. Signed-off-by: Phillip Lougher <phillip@lougher.demon.co.uk>
Showing 7 changed files with 44 additions and 98 deletions Inline Diff
fs/squashfs/cache.c
1 | /* | 1 | /* |
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@lougher.demon.co.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
9 | * as published by the Free Software Foundation; either version 2, | 9 | * as published by the Free Software Foundation; either version 2, |
10 | * or (at your option) any later version. | 10 | * or (at your option) any later version. |
11 | * | 11 | * |
12 | * This program is distributed in the hope that it will be useful, | 12 | * This program is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
16 | * | 16 | * |
17 | * You should have received a copy of the GNU General Public License | 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 | 18 | * along with this program; if not, write to the Free Software |
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
20 | * | 20 | * |
21 | * cache.c | 21 | * cache.c |
22 | */ | 22 | */ |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * Blocks in Squashfs are compressed. To avoid repeatedly decompressing | 25 | * Blocks in Squashfs are compressed. To avoid repeatedly decompressing |
26 | * recently accessed data Squashfs uses two small metadata and fragment caches. | 26 | * recently accessed data Squashfs uses two small metadata and fragment caches. |
27 | * | 27 | * |
28 | * This file implements a generic cache implementation used for both caches, | 28 | * This file implements a generic cache implementation used for both caches, |
29 | * plus functions layered ontop of the generic cache implementation to | 29 | * plus functions layered ontop of the generic cache implementation to |
30 | * access the metadata and fragment caches. | 30 | * access the metadata and fragment caches. |
31 | * | 31 | * |
32 | * To avoid out of memory and fragmentation isssues with vmalloc the cache | 32 | * To avoid out of memory and fragmentation isssues with vmalloc the cache |
33 | * uses sequences of kmalloced PAGE_CACHE_SIZE buffers. | 33 | * uses sequences of kmalloced PAGE_CACHE_SIZE buffers. |
34 | * | 34 | * |
35 | * It should be noted that the cache is not used for file datablocks, these | 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 | 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 | 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 | 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 | 39 | * directory) or fragment access. Because metadata and fragments are packed |
40 | * together into blocks (to gain greater compression) the read of a particular | 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 | 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 | 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 | 43 | * in the near future. Temporarily caching them ensures they are available for |
44 | * near future access without requiring an additional read and decompress. | 44 | * near future access without requiring an additional read and decompress. |
45 | */ | 45 | */ |
46 | 46 | ||
47 | #include <linux/fs.h> | 47 | #include <linux/fs.h> |
48 | #include <linux/vfs.h> | 48 | #include <linux/vfs.h> |
49 | #include <linux/slab.h> | 49 | #include <linux/slab.h> |
50 | #include <linux/vmalloc.h> | 50 | #include <linux/vmalloc.h> |
51 | #include <linux/sched.h> | 51 | #include <linux/sched.h> |
52 | #include <linux/spinlock.h> | 52 | #include <linux/spinlock.h> |
53 | #include <linux/wait.h> | 53 | #include <linux/wait.h> |
54 | #include <linux/pagemap.h> | 54 | #include <linux/pagemap.h> |
55 | 55 | ||
56 | #include "squashfs_fs.h" | 56 | #include "squashfs_fs.h" |
57 | #include "squashfs_fs_sb.h" | 57 | #include "squashfs_fs_sb.h" |
58 | #include "squashfs.h" | 58 | #include "squashfs.h" |
59 | 59 | ||
60 | /* | 60 | /* |
61 | * Look-up block in cache, and increment usage count. If not in cache, read | 61 | * Look-up block in cache, and increment usage count. If not in cache, read |
62 | * and decompress it from disk. | 62 | * and decompress it from disk. |
63 | */ | 63 | */ |
64 | struct squashfs_cache_entry *squashfs_cache_get(struct super_block *sb, | 64 | struct squashfs_cache_entry *squashfs_cache_get(struct super_block *sb, |
65 | struct squashfs_cache *cache, u64 block, int length) | 65 | struct squashfs_cache *cache, u64 block, int length) |
66 | { | 66 | { |
67 | int i, n; | 67 | int i, n; |
68 | struct squashfs_cache_entry *entry; | 68 | struct squashfs_cache_entry *entry; |
69 | 69 | ||
70 | spin_lock(&cache->lock); | 70 | spin_lock(&cache->lock); |
71 | 71 | ||
72 | while (1) { | 72 | while (1) { |
73 | for (i = 0; i < cache->entries; i++) | 73 | for (i = 0; i < cache->entries; i++) |
74 | if (cache->entry[i].block == block) | 74 | if (cache->entry[i].block == block) |
75 | break; | 75 | break; |
76 | 76 | ||
77 | if (i == cache->entries) { | 77 | if (i == cache->entries) { |
78 | /* | 78 | /* |
79 | * Block not in cache, if all cache entries are used | 79 | * Block not in cache, if all cache entries are used |
80 | * go to sleep waiting for one to become available. | 80 | * go to sleep waiting for one to become available. |
81 | */ | 81 | */ |
82 | if (cache->unused == 0) { | 82 | if (cache->unused == 0) { |
83 | cache->num_waiters++; | 83 | cache->num_waiters++; |
84 | spin_unlock(&cache->lock); | 84 | spin_unlock(&cache->lock); |
85 | wait_event(cache->wait_queue, cache->unused); | 85 | wait_event(cache->wait_queue, cache->unused); |
86 | spin_lock(&cache->lock); | 86 | spin_lock(&cache->lock); |
87 | cache->num_waiters--; | 87 | cache->num_waiters--; |
88 | continue; | 88 | continue; |
89 | } | 89 | } |
90 | 90 | ||
91 | /* | 91 | /* |
92 | * At least one unused cache entry. A simple | 92 | * At least one unused cache entry. A simple |
93 | * round-robin strategy is used to choose the entry to | 93 | * round-robin strategy is used to choose the entry to |
94 | * be evicted from the cache. | 94 | * be evicted from the cache. |
95 | */ | 95 | */ |
96 | i = cache->next_blk; | 96 | i = cache->next_blk; |
97 | for (n = 0; n < cache->entries; n++) { | 97 | for (n = 0; n < cache->entries; n++) { |
98 | if (cache->entry[i].refcount == 0) | 98 | if (cache->entry[i].refcount == 0) |
99 | break; | 99 | break; |
100 | i = (i + 1) % cache->entries; | 100 | i = (i + 1) % cache->entries; |
101 | } | 101 | } |
102 | 102 | ||
103 | cache->next_blk = (i + 1) % cache->entries; | 103 | cache->next_blk = (i + 1) % cache->entries; |
104 | entry = &cache->entry[i]; | 104 | entry = &cache->entry[i]; |
105 | 105 | ||
106 | /* | 106 | /* |
107 | * Initialise choosen cache entry, and fill it in from | 107 | * Initialise choosen cache entry, and fill it in from |
108 | * disk. | 108 | * disk. |
109 | */ | 109 | */ |
110 | cache->unused--; | 110 | cache->unused--; |
111 | entry->block = block; | 111 | entry->block = block; |
112 | entry->refcount = 1; | 112 | entry->refcount = 1; |
113 | entry->pending = 1; | 113 | entry->pending = 1; |
114 | entry->num_waiters = 0; | 114 | entry->num_waiters = 0; |
115 | entry->error = 0; | 115 | entry->error = 0; |
116 | spin_unlock(&cache->lock); | 116 | spin_unlock(&cache->lock); |
117 | 117 | ||
118 | entry->length = squashfs_read_data(sb, entry->data, | 118 | entry->length = squashfs_read_data(sb, entry->data, |
119 | block, length, &entry->next_index, | 119 | block, length, &entry->next_index, |
120 | cache->block_size, cache->pages); | 120 | cache->block_size, cache->pages); |
121 | 121 | ||
122 | spin_lock(&cache->lock); | 122 | spin_lock(&cache->lock); |
123 | 123 | ||
124 | if (entry->length < 0) | 124 | if (entry->length < 0) |
125 | entry->error = entry->length; | 125 | entry->error = entry->length; |
126 | 126 | ||
127 | entry->pending = 0; | 127 | entry->pending = 0; |
128 | 128 | ||
129 | /* | 129 | /* |
130 | * While filling this entry one or more other processes | 130 | * While filling this entry one or more other processes |
131 | * have looked it up in the cache, and have slept | 131 | * have looked it up in the cache, and have slept |
132 | * waiting for it to become available. | 132 | * waiting for it to become available. |
133 | */ | 133 | */ |
134 | if (entry->num_waiters) { | 134 | if (entry->num_waiters) { |
135 | spin_unlock(&cache->lock); | 135 | spin_unlock(&cache->lock); |
136 | wake_up_all(&entry->wait_queue); | 136 | wake_up_all(&entry->wait_queue); |
137 | } else | 137 | } else |
138 | spin_unlock(&cache->lock); | 138 | spin_unlock(&cache->lock); |
139 | 139 | ||
140 | goto out; | 140 | goto out; |
141 | } | 141 | } |
142 | 142 | ||
143 | /* | 143 | /* |
144 | * Block already in cache. Increment refcount so it doesn't | 144 | * Block already in cache. Increment refcount so it doesn't |
145 | * get reused until we're finished with it, if it was | 145 | * get reused until we're finished with it, if it was |
146 | * previously unused there's one less cache entry available | 146 | * previously unused there's one less cache entry available |
147 | * for reuse. | 147 | * for reuse. |
148 | */ | 148 | */ |
149 | entry = &cache->entry[i]; | 149 | entry = &cache->entry[i]; |
150 | if (entry->refcount == 0) | 150 | if (entry->refcount == 0) |
151 | cache->unused--; | 151 | cache->unused--; |
152 | entry->refcount++; | 152 | entry->refcount++; |
153 | 153 | ||
154 | /* | 154 | /* |
155 | * If the entry is currently being filled in by another process | 155 | * If the entry is currently being filled in by another process |
156 | * go to sleep waiting for it to become available. | 156 | * go to sleep waiting for it to become available. |
157 | */ | 157 | */ |
158 | if (entry->pending) { | 158 | if (entry->pending) { |
159 | entry->num_waiters++; | 159 | entry->num_waiters++; |
160 | spin_unlock(&cache->lock); | 160 | spin_unlock(&cache->lock); |
161 | wait_event(entry->wait_queue, !entry->pending); | 161 | wait_event(entry->wait_queue, !entry->pending); |
162 | } else | 162 | } else |
163 | spin_unlock(&cache->lock); | 163 | spin_unlock(&cache->lock); |
164 | 164 | ||
165 | goto out; | 165 | goto out; |
166 | } | 166 | } |
167 | 167 | ||
168 | out: | 168 | out: |
169 | TRACE("Got %s %d, start block %lld, refcount %d, error %d\n", | 169 | TRACE("Got %s %d, start block %lld, refcount %d, error %d\n", |
170 | cache->name, i, entry->block, entry->refcount, entry->error); | 170 | cache->name, i, entry->block, entry->refcount, entry->error); |
171 | 171 | ||
172 | if (entry->error) | 172 | if (entry->error) |
173 | ERROR("Unable to read %s cache entry [%llx]\n", cache->name, | 173 | ERROR("Unable to read %s cache entry [%llx]\n", cache->name, |
174 | block); | 174 | block); |
175 | return entry; | 175 | return entry; |
176 | } | 176 | } |
177 | 177 | ||
178 | 178 | ||
179 | /* | 179 | /* |
180 | * Release cache entry, once usage count is zero it can be reused. | 180 | * Release cache entry, once usage count is zero it can be reused. |
181 | */ | 181 | */ |
182 | void squashfs_cache_put(struct squashfs_cache_entry *entry) | 182 | void squashfs_cache_put(struct squashfs_cache_entry *entry) |
183 | { | 183 | { |
184 | struct squashfs_cache *cache = entry->cache; | 184 | struct squashfs_cache *cache = entry->cache; |
185 | 185 | ||
186 | spin_lock(&cache->lock); | 186 | spin_lock(&cache->lock); |
187 | entry->refcount--; | 187 | entry->refcount--; |
188 | if (entry->refcount == 0) { | 188 | if (entry->refcount == 0) { |
189 | cache->unused++; | 189 | cache->unused++; |
190 | /* | 190 | /* |
191 | * If there's any processes waiting for a block to become | 191 | * If there's any processes waiting for a block to become |
192 | * available, wake one up. | 192 | * available, wake one up. |
193 | */ | 193 | */ |
194 | if (cache->num_waiters) { | 194 | if (cache->num_waiters) { |
195 | spin_unlock(&cache->lock); | 195 | spin_unlock(&cache->lock); |
196 | wake_up(&cache->wait_queue); | 196 | wake_up(&cache->wait_queue); |
197 | return; | 197 | return; |
198 | } | 198 | } |
199 | } | 199 | } |
200 | spin_unlock(&cache->lock); | 200 | spin_unlock(&cache->lock); |
201 | } | 201 | } |
202 | 202 | ||
203 | /* | 203 | /* |
204 | * Delete cache reclaiming all kmalloced buffers. | 204 | * Delete cache reclaiming all kmalloced buffers. |
205 | */ | 205 | */ |
206 | void squashfs_cache_delete(struct squashfs_cache *cache) | 206 | void squashfs_cache_delete(struct squashfs_cache *cache) |
207 | { | 207 | { |
208 | int i, j; | 208 | int i, j; |
209 | 209 | ||
210 | if (cache == NULL) | 210 | if (cache == NULL) |
211 | return; | 211 | return; |
212 | 212 | ||
213 | for (i = 0; i < cache->entries; i++) { | 213 | for (i = 0; i < cache->entries; i++) { |
214 | if (cache->entry[i].data) { | 214 | if (cache->entry[i].data) { |
215 | for (j = 0; j < cache->pages; j++) | 215 | for (j = 0; j < cache->pages; j++) |
216 | kfree(cache->entry[i].data[j]); | 216 | kfree(cache->entry[i].data[j]); |
217 | kfree(cache->entry[i].data); | 217 | kfree(cache->entry[i].data); |
218 | } | 218 | } |
219 | } | 219 | } |
220 | 220 | ||
221 | kfree(cache->entry); | 221 | kfree(cache->entry); |
222 | kfree(cache); | 222 | kfree(cache); |
223 | } | 223 | } |
224 | 224 | ||
225 | 225 | ||
226 | /* | 226 | /* |
227 | * Initialise cache allocating the specified number of entries, each of | 227 | * Initialise cache allocating the specified number of entries, each of |
228 | * size block_size. To avoid vmalloc fragmentation issues each entry | 228 | * size block_size. To avoid vmalloc fragmentation issues each entry |
229 | * is allocated as a sequence of kmalloced PAGE_CACHE_SIZE buffers. | 229 | * is allocated as a sequence of kmalloced PAGE_CACHE_SIZE buffers. |
230 | */ | 230 | */ |
231 | struct squashfs_cache *squashfs_cache_init(char *name, int entries, | 231 | struct squashfs_cache *squashfs_cache_init(char *name, int entries, |
232 | int block_size) | 232 | int block_size) |
233 | { | 233 | { |
234 | int i, j; | 234 | int i, j; |
235 | struct squashfs_cache *cache = kzalloc(sizeof(*cache), GFP_KERNEL); | 235 | struct squashfs_cache *cache = kzalloc(sizeof(*cache), GFP_KERNEL); |
236 | 236 | ||
237 | if (cache == NULL) { | 237 | if (cache == NULL) { |
238 | ERROR("Failed to allocate %s cache\n", name); | 238 | ERROR("Failed to allocate %s cache\n", name); |
239 | return NULL; | 239 | return NULL; |
240 | } | 240 | } |
241 | 241 | ||
242 | cache->entry = kcalloc(entries, sizeof(*(cache->entry)), GFP_KERNEL); | 242 | cache->entry = kcalloc(entries, sizeof(*(cache->entry)), GFP_KERNEL); |
243 | if (cache->entry == NULL) { | 243 | if (cache->entry == NULL) { |
244 | ERROR("Failed to allocate %s cache\n", name); | 244 | ERROR("Failed to allocate %s cache\n", name); |
245 | goto cleanup; | 245 | goto cleanup; |
246 | } | 246 | } |
247 | 247 | ||
248 | cache->next_blk = 0; | 248 | cache->next_blk = 0; |
249 | cache->unused = entries; | 249 | cache->unused = entries; |
250 | cache->entries = entries; | 250 | cache->entries = entries; |
251 | cache->block_size = block_size; | 251 | cache->block_size = block_size; |
252 | cache->pages = block_size >> PAGE_CACHE_SHIFT; | 252 | cache->pages = block_size >> PAGE_CACHE_SHIFT; |
253 | cache->pages = cache->pages ? cache->pages : 1; | 253 | cache->pages = cache->pages ? cache->pages : 1; |
254 | cache->name = name; | 254 | cache->name = name; |
255 | cache->num_waiters = 0; | 255 | cache->num_waiters = 0; |
256 | spin_lock_init(&cache->lock); | 256 | spin_lock_init(&cache->lock); |
257 | init_waitqueue_head(&cache->wait_queue); | 257 | init_waitqueue_head(&cache->wait_queue); |
258 | 258 | ||
259 | for (i = 0; i < entries; i++) { | 259 | for (i = 0; i < entries; i++) { |
260 | struct squashfs_cache_entry *entry = &cache->entry[i]; | 260 | struct squashfs_cache_entry *entry = &cache->entry[i]; |
261 | 261 | ||
262 | init_waitqueue_head(&cache->entry[i].wait_queue); | 262 | init_waitqueue_head(&cache->entry[i].wait_queue); |
263 | entry->cache = cache; | 263 | entry->cache = cache; |
264 | entry->block = SQUASHFS_INVALID_BLK; | 264 | entry->block = SQUASHFS_INVALID_BLK; |
265 | entry->data = kcalloc(cache->pages, sizeof(void *), GFP_KERNEL); | 265 | entry->data = kcalloc(cache->pages, sizeof(void *), GFP_KERNEL); |
266 | if (entry->data == NULL) { | 266 | if (entry->data == NULL) { |
267 | ERROR("Failed to allocate %s cache entry\n", name); | 267 | ERROR("Failed to allocate %s cache entry\n", name); |
268 | goto cleanup; | 268 | goto cleanup; |
269 | } | 269 | } |
270 | 270 | ||
271 | for (j = 0; j < cache->pages; j++) { | 271 | for (j = 0; j < cache->pages; j++) { |
272 | entry->data[j] = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); | 272 | entry->data[j] = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); |
273 | if (entry->data[j] == NULL) { | 273 | if (entry->data[j] == NULL) { |
274 | ERROR("Failed to allocate %s buffer\n", name); | 274 | ERROR("Failed to allocate %s buffer\n", name); |
275 | goto cleanup; | 275 | goto cleanup; |
276 | } | 276 | } |
277 | } | 277 | } |
278 | } | 278 | } |
279 | 279 | ||
280 | return cache; | 280 | return cache; |
281 | 281 | ||
282 | cleanup: | 282 | cleanup: |
283 | squashfs_cache_delete(cache); | 283 | squashfs_cache_delete(cache); |
284 | return NULL; | 284 | return NULL; |
285 | } | 285 | } |
286 | 286 | ||
287 | 287 | ||
288 | /* | 288 | /* |
289 | * Copy upto length bytes from cache entry to buffer starting at offset bytes | 289 | * Copy upto length bytes from cache entry to buffer starting at offset bytes |
290 | * into the cache entry. If there's not length bytes then copy the number of | 290 | * into the cache entry. If there's not length bytes then copy the number of |
291 | * bytes available. In all cases return the number of bytes copied. | 291 | * bytes available. In all cases return the number of bytes copied. |
292 | */ | 292 | */ |
293 | int squashfs_copy_data(void *buffer, struct squashfs_cache_entry *entry, | 293 | int squashfs_copy_data(void *buffer, struct squashfs_cache_entry *entry, |
294 | int offset, int length) | 294 | int offset, int length) |
295 | { | 295 | { |
296 | int remaining = length; | 296 | int remaining = length; |
297 | 297 | ||
298 | if (length == 0) | 298 | if (length == 0) |
299 | return 0; | 299 | return 0; |
300 | else if (buffer == NULL) | 300 | else if (buffer == NULL) |
301 | return min(length, entry->length - offset); | 301 | return min(length, entry->length - offset); |
302 | 302 | ||
303 | while (offset < entry->length) { | 303 | while (offset < entry->length) { |
304 | void *buff = entry->data[offset / PAGE_CACHE_SIZE] | 304 | void *buff = entry->data[offset / PAGE_CACHE_SIZE] |
305 | + (offset % PAGE_CACHE_SIZE); | 305 | + (offset % PAGE_CACHE_SIZE); |
306 | int bytes = min_t(int, entry->length - offset, | 306 | int bytes = min_t(int, entry->length - offset, |
307 | PAGE_CACHE_SIZE - (offset % PAGE_CACHE_SIZE)); | 307 | PAGE_CACHE_SIZE - (offset % PAGE_CACHE_SIZE)); |
308 | 308 | ||
309 | if (bytes >= remaining) { | 309 | if (bytes >= remaining) { |
310 | memcpy(buffer, buff, remaining); | 310 | memcpy(buffer, buff, remaining); |
311 | remaining = 0; | 311 | remaining = 0; |
312 | break; | 312 | break; |
313 | } | 313 | } |
314 | 314 | ||
315 | memcpy(buffer, buff, bytes); | 315 | memcpy(buffer, buff, bytes); |
316 | buffer += bytes; | 316 | buffer += bytes; |
317 | remaining -= bytes; | 317 | remaining -= bytes; |
318 | offset += bytes; | 318 | offset += bytes; |
319 | } | 319 | } |
320 | 320 | ||
321 | return length - remaining; | 321 | return length - remaining; |
322 | } | 322 | } |
323 | 323 | ||
324 | 324 | ||
325 | /* | 325 | /* |
326 | * Read length bytes from metadata position <block, offset> (block is the | 326 | * Read length bytes from metadata position <block, offset> (block is the |
327 | * start of the compressed block on disk, and offset is the offset into | 327 | * start of the compressed block on disk, and offset is the offset into |
328 | * the block once decompressed). Data is packed into consecutive blocks, | 328 | * the block once decompressed). Data is packed into consecutive blocks, |
329 | * and length bytes may require reading more than one block. | 329 | * and length bytes may require reading more than one block. |
330 | */ | 330 | */ |
331 | int squashfs_read_metadata(struct super_block *sb, void *buffer, | 331 | int squashfs_read_metadata(struct super_block *sb, void *buffer, |
332 | u64 *block, int *offset, int length) | 332 | u64 *block, int *offset, int length) |
333 | { | 333 | { |
334 | struct squashfs_sb_info *msblk = sb->s_fs_info; | 334 | struct squashfs_sb_info *msblk = sb->s_fs_info; |
335 | int bytes, copied = length; | 335 | int bytes, copied = length; |
336 | struct squashfs_cache_entry *entry; | 336 | struct squashfs_cache_entry *entry; |
337 | 337 | ||
338 | TRACE("Entered squashfs_read_metadata [%llx:%x]\n", *block, *offset); | 338 | TRACE("Entered squashfs_read_metadata [%llx:%x]\n", *block, *offset); |
339 | 339 | ||
340 | while (length) { | 340 | while (length) { |
341 | entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0); | 341 | entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0); |
342 | if (entry->error) | 342 | if (entry->error) |
343 | return entry->error; | 343 | return entry->error; |
344 | else if (*offset >= entry->length) | 344 | else if (*offset >= entry->length) |
345 | return -EIO; | 345 | return -EIO; |
346 | 346 | ||
347 | bytes = squashfs_copy_data(buffer, entry, *offset, length); | 347 | bytes = squashfs_copy_data(buffer, entry, *offset, length); |
348 | if (buffer) | 348 | if (buffer) |
349 | buffer += bytes; | 349 | buffer += bytes; |
350 | length -= bytes; | 350 | length -= bytes; |
351 | *offset += bytes; | 351 | *offset += bytes; |
352 | 352 | ||
353 | if (*offset == entry->length) { | 353 | if (*offset == entry->length) { |
354 | *block = entry->next_index; | 354 | *block = entry->next_index; |
355 | *offset = 0; | 355 | *offset = 0; |
356 | } | 356 | } |
357 | 357 | ||
358 | squashfs_cache_put(entry); | 358 | squashfs_cache_put(entry); |
359 | } | 359 | } |
360 | 360 | ||
361 | return copied; | 361 | return copied; |
362 | } | 362 | } |
363 | 363 | ||
364 | 364 | ||
365 | /* | 365 | /* |
366 | * Look-up in the fragmment cache the fragment located at <start_block> in the | 366 | * Look-up in the fragmment cache the fragment located at <start_block> in the |
367 | * filesystem. If necessary read and decompress it from disk. | 367 | * filesystem. If necessary read and decompress it from disk. |
368 | */ | 368 | */ |
369 | struct squashfs_cache_entry *squashfs_get_fragment(struct super_block *sb, | 369 | struct squashfs_cache_entry *squashfs_get_fragment(struct super_block *sb, |
370 | u64 start_block, int length) | 370 | u64 start_block, int length) |
371 | { | 371 | { |
372 | struct squashfs_sb_info *msblk = sb->s_fs_info; | 372 | struct squashfs_sb_info *msblk = sb->s_fs_info; |
373 | 373 | ||
374 | return squashfs_cache_get(sb, msblk->fragment_cache, start_block, | 374 | return squashfs_cache_get(sb, msblk->fragment_cache, start_block, |
375 | length); | 375 | length); |
376 | } | 376 | } |
377 | 377 | ||
378 | 378 | ||
379 | /* | 379 | /* |
380 | * Read and decompress the datablock located at <start_block> in the | 380 | * Read and decompress the datablock located at <start_block> in the |
381 | * filesystem. The cache is used here to avoid duplicating locking and | 381 | * filesystem. The cache is used here to avoid duplicating locking and |
382 | * read/decompress code. | 382 | * read/decompress code. |
383 | */ | 383 | */ |
384 | struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *sb, | 384 | struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *sb, |
385 | u64 start_block, int length) | 385 | u64 start_block, int length) |
386 | { | 386 | { |
387 | struct squashfs_sb_info *msblk = sb->s_fs_info; | 387 | struct squashfs_sb_info *msblk = sb->s_fs_info; |
388 | 388 | ||
389 | return squashfs_cache_get(sb, msblk->read_page, start_block, length); | 389 | return squashfs_cache_get(sb, msblk->read_page, start_block, length); |
390 | } | 390 | } |
391 | 391 | ||
392 | 392 | ||
393 | /* | 393 | /* |
394 | * Read a filesystem table (uncompressed sequence of bytes) from disk | 394 | * Read a filesystem table (uncompressed sequence of bytes) from disk |
395 | */ | 395 | */ |
396 | int squashfs_read_table(struct super_block *sb, void *buffer, u64 block, | 396 | void *squashfs_read_table(struct super_block *sb, u64 block, int length) |
397 | int length) | ||
398 | { | 397 | { |
399 | int pages = (length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 398 | int pages = (length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
400 | int i, res; | 399 | int i, res; |
401 | void **data = kcalloc(pages, sizeof(void *), GFP_KERNEL); | 400 | void *table, *buffer, **data; |
402 | if (data == NULL) | ||
403 | return -ENOMEM; | ||
404 | 401 | ||
402 | table = buffer = kmalloc(length, GFP_KERNEL); | ||
403 | if (table == NULL) | ||
404 | return ERR_PTR(-ENOMEM); | ||
405 | |||
406 | data = kcalloc(pages, sizeof(void *), GFP_KERNEL); | ||
407 | if (data == NULL) { | ||
408 | res = -ENOMEM; | ||
409 | goto failed; | ||
410 | } | ||
411 | |||
405 | for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE) | 412 | for (i = 0; i < pages; i++, buffer += PAGE_CACHE_SIZE) |
406 | data[i] = buffer; | 413 | data[i] = buffer; |
414 | |||
407 | res = squashfs_read_data(sb, data, block, length | | 415 | res = squashfs_read_data(sb, data, block, length | |
408 | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length, pages); | 416 | SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, length, pages); |
417 | |||
409 | kfree(data); | 418 | kfree(data); |
410 | return res; | 419 | |
420 | if (res < 0) | ||
421 | goto failed; | ||
422 | |||
423 | return table; | ||
424 | |||
425 | failed: | ||
426 | kfree(table); |
fs/squashfs/export.c
1 | /* | 1 | /* |
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@lougher.demon.co.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
9 | * as published by the Free Software Foundation; either version 2, | 9 | * as published by the Free Software Foundation; either version 2, |
10 | * or (at your option) any later version. | 10 | * or (at your option) any later version. |
11 | * | 11 | * |
12 | * This program is distributed in the hope that it will be useful, | 12 | * This program is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
16 | * | 16 | * |
17 | * You should have received a copy of the GNU General Public License | 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 | 18 | * along with this program; if not, write to the Free Software |
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
20 | * | 20 | * |
21 | * export.c | 21 | * export.c |
22 | */ | 22 | */ |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * This file implements code to make Squashfs filesystems exportable (NFS etc.) | 25 | * This file implements code to make Squashfs filesystems exportable (NFS etc.) |
26 | * | 26 | * |
27 | * The export code uses an inode lookup table to map inode numbers passed in | 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 | 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 | 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 | 30 | * second index table for speed of access (and because it is small) is read at |
31 | * mount time and cached in memory. | 31 | * mount time and cached in memory. |
32 | * | 32 | * |
33 | * The inode lookup table is used only by the export code, inode disk | 33 | * The inode lookup table is used only by the export code, inode disk |
34 | * locations are directly encoded in directories, enabling direct access | 34 | * locations are directly encoded in directories, enabling direct access |
35 | * without an intermediate lookup for all operations except the export ops. | 35 | * without an intermediate lookup for all operations except the export ops. |
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include <linux/fs.h> | 38 | #include <linux/fs.h> |
39 | #include <linux/vfs.h> | 39 | #include <linux/vfs.h> |
40 | #include <linux/dcache.h> | 40 | #include <linux/dcache.h> |
41 | #include <linux/exportfs.h> | 41 | #include <linux/exportfs.h> |
42 | #include <linux/slab.h> | 42 | #include <linux/slab.h> |
43 | 43 | ||
44 | #include "squashfs_fs.h" | 44 | #include "squashfs_fs.h" |
45 | #include "squashfs_fs_sb.h" | 45 | #include "squashfs_fs_sb.h" |
46 | #include "squashfs_fs_i.h" | 46 | #include "squashfs_fs_i.h" |
47 | #include "squashfs.h" | 47 | #include "squashfs.h" |
48 | 48 | ||
49 | /* | 49 | /* |
50 | * Look-up inode number (ino) in table, returning the inode location. | 50 | * Look-up inode number (ino) in table, returning the inode location. |
51 | */ | 51 | */ |
52 | static long long squashfs_inode_lookup(struct super_block *sb, int ino_num) | 52 | static long long squashfs_inode_lookup(struct super_block *sb, int ino_num) |
53 | { | 53 | { |
54 | struct squashfs_sb_info *msblk = sb->s_fs_info; | 54 | struct squashfs_sb_info *msblk = sb->s_fs_info; |
55 | int blk = SQUASHFS_LOOKUP_BLOCK(ino_num - 1); | 55 | int blk = SQUASHFS_LOOKUP_BLOCK(ino_num - 1); |
56 | int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino_num - 1); | 56 | int offset = SQUASHFS_LOOKUP_BLOCK_OFFSET(ino_num - 1); |
57 | u64 start = le64_to_cpu(msblk->inode_lookup_table[blk]); | 57 | u64 start = le64_to_cpu(msblk->inode_lookup_table[blk]); |
58 | __le64 ino; | 58 | __le64 ino; |
59 | int err; | 59 | int err; |
60 | 60 | ||
61 | TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino_num); | 61 | TRACE("Entered squashfs_inode_lookup, inode_number = %d\n", ino_num); |
62 | 62 | ||
63 | err = squashfs_read_metadata(sb, &ino, &start, &offset, sizeof(ino)); | 63 | err = squashfs_read_metadata(sb, &ino, &start, &offset, sizeof(ino)); |
64 | if (err < 0) | 64 | if (err < 0) |
65 | return err; | 65 | return err; |
66 | 66 | ||
67 | TRACE("squashfs_inode_lookup, inode = 0x%llx\n", | 67 | TRACE("squashfs_inode_lookup, inode = 0x%llx\n", |
68 | (u64) le64_to_cpu(ino)); | 68 | (u64) le64_to_cpu(ino)); |
69 | 69 | ||
70 | return le64_to_cpu(ino); | 70 | return le64_to_cpu(ino); |
71 | } | 71 | } |
72 | 72 | ||
73 | 73 | ||
74 | static struct dentry *squashfs_export_iget(struct super_block *sb, | 74 | static struct dentry *squashfs_export_iget(struct super_block *sb, |
75 | unsigned int ino_num) | 75 | unsigned int ino_num) |
76 | { | 76 | { |
77 | long long ino; | 77 | long long ino; |
78 | struct dentry *dentry = ERR_PTR(-ENOENT); | 78 | struct dentry *dentry = ERR_PTR(-ENOENT); |
79 | 79 | ||
80 | TRACE("Entered squashfs_export_iget\n"); | 80 | TRACE("Entered squashfs_export_iget\n"); |
81 | 81 | ||
82 | ino = squashfs_inode_lookup(sb, ino_num); | 82 | ino = squashfs_inode_lookup(sb, ino_num); |
83 | if (ino >= 0) | 83 | if (ino >= 0) |
84 | dentry = d_obtain_alias(squashfs_iget(sb, ino, ino_num)); | 84 | dentry = d_obtain_alias(squashfs_iget(sb, ino, ino_num)); |
85 | 85 | ||
86 | return dentry; | 86 | return dentry; |
87 | } | 87 | } |
88 | 88 | ||
89 | 89 | ||
90 | static struct dentry *squashfs_fh_to_dentry(struct super_block *sb, | 90 | static struct dentry *squashfs_fh_to_dentry(struct super_block *sb, |
91 | struct fid *fid, int fh_len, int fh_type) | 91 | struct fid *fid, int fh_len, int fh_type) |
92 | { | 92 | { |
93 | if ((fh_type != FILEID_INO32_GEN && fh_type != FILEID_INO32_GEN_PARENT) | 93 | if ((fh_type != FILEID_INO32_GEN && fh_type != FILEID_INO32_GEN_PARENT) |
94 | || fh_len < 2) | 94 | || fh_len < 2) |
95 | return NULL; | 95 | return NULL; |
96 | 96 | ||
97 | return squashfs_export_iget(sb, fid->i32.ino); | 97 | return squashfs_export_iget(sb, fid->i32.ino); |
98 | } | 98 | } |
99 | 99 | ||
100 | 100 | ||
101 | static struct dentry *squashfs_fh_to_parent(struct super_block *sb, | 101 | static struct dentry *squashfs_fh_to_parent(struct super_block *sb, |
102 | struct fid *fid, int fh_len, int fh_type) | 102 | struct fid *fid, int fh_len, int fh_type) |
103 | { | 103 | { |
104 | if (fh_type != FILEID_INO32_GEN_PARENT || fh_len < 4) | 104 | if (fh_type != FILEID_INO32_GEN_PARENT || fh_len < 4) |
105 | return NULL; | 105 | return NULL; |
106 | 106 | ||
107 | return squashfs_export_iget(sb, fid->i32.parent_ino); | 107 | return squashfs_export_iget(sb, fid->i32.parent_ino); |
108 | } | 108 | } |
109 | 109 | ||
110 | 110 | ||
111 | static struct dentry *squashfs_get_parent(struct dentry *child) | 111 | static struct dentry *squashfs_get_parent(struct dentry *child) |
112 | { | 112 | { |
113 | struct inode *inode = child->d_inode; | 113 | struct inode *inode = child->d_inode; |
114 | unsigned int parent_ino = squashfs_i(inode)->parent; | 114 | unsigned int parent_ino = squashfs_i(inode)->parent; |
115 | 115 | ||
116 | return squashfs_export_iget(inode->i_sb, parent_ino); | 116 | return squashfs_export_iget(inode->i_sb, parent_ino); |
117 | } | 117 | } |
118 | 118 | ||
119 | 119 | ||
120 | /* | 120 | /* |
121 | * Read uncompressed inode lookup table indexes off disk into memory | 121 | * Read uncompressed inode lookup table indexes off disk into memory |
122 | */ | 122 | */ |
123 | __le64 *squashfs_read_inode_lookup_table(struct super_block *sb, | 123 | __le64 *squashfs_read_inode_lookup_table(struct super_block *sb, |
124 | u64 lookup_table_start, unsigned int inodes) | 124 | u64 lookup_table_start, unsigned int inodes) |
125 | { | 125 | { |
126 | unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(inodes); | 126 | unsigned int length = SQUASHFS_LOOKUP_BLOCK_BYTES(inodes); |
127 | __le64 *inode_lookup_table; | ||
128 | int err; | ||
129 | 127 | ||
130 | TRACE("In read_inode_lookup_table, length %d\n", length); | 128 | TRACE("In read_inode_lookup_table, length %d\n", length); |
131 | 129 | ||
132 | /* Allocate inode lookup table indexes */ | 130 | return squashfs_read_table(sb, lookup_table_start, length); |
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 | } | 131 | } |
149 | 132 | ||
150 | 133 | ||
151 | const struct export_operations squashfs_export_ops = { | 134 | const struct export_operations squashfs_export_ops = { |
152 | .fh_to_dentry = squashfs_fh_to_dentry, | 135 | .fh_to_dentry = squashfs_fh_to_dentry, |
153 | .fh_to_parent = squashfs_fh_to_parent, | 136 | .fh_to_parent = squashfs_fh_to_parent, |
154 | .get_parent = squashfs_get_parent | 137 | .get_parent = squashfs_get_parent |
155 | }; | 138 | }; |
156 | 139 |
fs/squashfs/fragment.c
1 | /* | 1 | /* |
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@lougher.demon.co.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
9 | * as published by the Free Software Foundation; either version 2, | 9 | * as published by the Free Software Foundation; either version 2, |
10 | * or (at your option) any later version. | 10 | * or (at your option) any later version. |
11 | * | 11 | * |
12 | * This program is distributed in the hope that it will be useful, | 12 | * This program is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
16 | * | 16 | * |
17 | * You should have received a copy of the GNU General Public License | 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 | 18 | * along with this program; if not, write to the Free Software |
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
20 | * | 20 | * |
21 | * fragment.c | 21 | * fragment.c |
22 | */ | 22 | */ |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * This file implements code to handle compressed fragments (tail-end packed | 25 | * This file implements code to handle compressed fragments (tail-end packed |
26 | * datablocks). | 26 | * datablocks). |
27 | * | 27 | * |
28 | * Regular files contain a fragment index which is mapped to a fragment | 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. | 29 | * location on disk and compressed size using a fragment lookup table. |
30 | * Like everything in Squashfs this fragment lookup table is itself stored | 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 | 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 | 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. | 33 | * is small) is read at mount time and cached in memory. |
34 | */ | 34 | */ |
35 | 35 | ||
36 | #include <linux/fs.h> | 36 | #include <linux/fs.h> |
37 | #include <linux/vfs.h> | 37 | #include <linux/vfs.h> |
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | 39 | ||
40 | #include "squashfs_fs.h" | 40 | #include "squashfs_fs.h" |
41 | #include "squashfs_fs_sb.h" | 41 | #include "squashfs_fs_sb.h" |
42 | #include "squashfs.h" | 42 | #include "squashfs.h" |
43 | 43 | ||
44 | /* | 44 | /* |
45 | * Look-up fragment using the fragment index table. Return the on disk | 45 | * Look-up fragment using the fragment index table. Return the on disk |
46 | * location of the fragment and its compressed size | 46 | * location of the fragment and its compressed size |
47 | */ | 47 | */ |
48 | int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment, | 48 | int squashfs_frag_lookup(struct super_block *sb, unsigned int fragment, |
49 | u64 *fragment_block) | 49 | u64 *fragment_block) |
50 | { | 50 | { |
51 | struct squashfs_sb_info *msblk = sb->s_fs_info; | 51 | struct squashfs_sb_info *msblk = sb->s_fs_info; |
52 | int block = SQUASHFS_FRAGMENT_INDEX(fragment); | 52 | int block = SQUASHFS_FRAGMENT_INDEX(fragment); |
53 | int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); | 53 | int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment); |
54 | u64 start_block = le64_to_cpu(msblk->fragment_index[block]); | 54 | u64 start_block = le64_to_cpu(msblk->fragment_index[block]); |
55 | struct squashfs_fragment_entry fragment_entry; | 55 | struct squashfs_fragment_entry fragment_entry; |
56 | int size; | 56 | int size; |
57 | 57 | ||
58 | size = squashfs_read_metadata(sb, &fragment_entry, &start_block, | 58 | size = squashfs_read_metadata(sb, &fragment_entry, &start_block, |
59 | &offset, sizeof(fragment_entry)); | 59 | &offset, sizeof(fragment_entry)); |
60 | if (size < 0) | 60 | if (size < 0) |
61 | return size; | 61 | return size; |
62 | 62 | ||
63 | *fragment_block = le64_to_cpu(fragment_entry.start_block); | 63 | *fragment_block = le64_to_cpu(fragment_entry.start_block); |
64 | size = le32_to_cpu(fragment_entry.size); | 64 | size = le32_to_cpu(fragment_entry.size); |
65 | 65 | ||
66 | return size; | 66 | return size; |
67 | } | 67 | } |
68 | 68 | ||
69 | 69 | ||
70 | /* | 70 | /* |
71 | * Read the uncompressed fragment lookup table indexes off disk into memory | 71 | * Read the uncompressed fragment lookup table indexes off disk into memory |
72 | */ | 72 | */ |
73 | __le64 *squashfs_read_fragment_index_table(struct super_block *sb, | 73 | __le64 *squashfs_read_fragment_index_table(struct super_block *sb, |
74 | u64 fragment_table_start, unsigned int fragments) | 74 | u64 fragment_table_start, unsigned int fragments) |
75 | { | 75 | { |
76 | unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(fragments); | 76 | unsigned int length = SQUASHFS_FRAGMENT_INDEX_BYTES(fragments); |
77 | __le64 *fragment_index; | ||
78 | int err; | ||
79 | 77 | ||
80 | /* Allocate fragment lookup table indexes */ | 78 | return squashfs_read_table(sb, fragment_table_start, length); |
81 | fragment_index = kmalloc(length, GFP_KERNEL); | ||
82 | if (fragment_index == NULL) { | ||
83 | ERROR("Failed to allocate fragment index table\n"); | ||
84 | return ERR_PTR(-ENOMEM); | ||
85 | } | ||
86 | |||
87 | err = squashfs_read_table(sb, fragment_index, fragment_table_start, | ||
88 | length); | ||
89 | if (err < 0) { | ||
90 | ERROR("unable to read fragment index table\n"); | ||
91 | kfree(fragment_index); | ||
92 | return ERR_PTR(err); | ||
93 | } | ||
94 | |||
95 | return fragment_index; | ||
96 | } | 79 | } |
97 | 80 |
fs/squashfs/id.c
1 | /* | 1 | /* |
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@lougher.demon.co.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
9 | * as published by the Free Software Foundation; either version 2, | 9 | * as published by the Free Software Foundation; either version 2, |
10 | * or (at your option) any later version. | 10 | * or (at your option) any later version. |
11 | * | 11 | * |
12 | * This program is distributed in the hope that it will be useful, | 12 | * This program is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
16 | * | 16 | * |
17 | * You should have received a copy of the GNU General Public License | 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 | 18 | * along with this program; if not, write to the Free Software |
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
20 | * | 20 | * |
21 | * id.c | 21 | * id.c |
22 | */ | 22 | */ |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * This file implements code to handle uids and gids. | 25 | * This file implements code to handle uids and gids. |
26 | * | 26 | * |
27 | * For space efficiency regular files store uid and gid indexes, which are | 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 | 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 | 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 | 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. | 31 | * is small) is read at mount time and cached in memory. |
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <linux/fs.h> | 34 | #include <linux/fs.h> |
35 | #include <linux/vfs.h> | 35 | #include <linux/vfs.h> |
36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
37 | 37 | ||
38 | #include "squashfs_fs.h" | 38 | #include "squashfs_fs.h" |
39 | #include "squashfs_fs_sb.h" | 39 | #include "squashfs_fs_sb.h" |
40 | #include "squashfs.h" | 40 | #include "squashfs.h" |
41 | 41 | ||
42 | /* | 42 | /* |
43 | * Map uid/gid index into real 32-bit uid/gid using the id look up table | 43 | * Map uid/gid index into real 32-bit uid/gid using the id look up table |
44 | */ | 44 | */ |
45 | int squashfs_get_id(struct super_block *sb, unsigned int index, | 45 | int squashfs_get_id(struct super_block *sb, unsigned int index, |
46 | unsigned int *id) | 46 | unsigned int *id) |
47 | { | 47 | { |
48 | struct squashfs_sb_info *msblk = sb->s_fs_info; | 48 | struct squashfs_sb_info *msblk = sb->s_fs_info; |
49 | int block = SQUASHFS_ID_BLOCK(index); | 49 | int block = SQUASHFS_ID_BLOCK(index); |
50 | int offset = SQUASHFS_ID_BLOCK_OFFSET(index); | 50 | int offset = SQUASHFS_ID_BLOCK_OFFSET(index); |
51 | u64 start_block = le64_to_cpu(msblk->id_table[block]); | 51 | u64 start_block = le64_to_cpu(msblk->id_table[block]); |
52 | __le32 disk_id; | 52 | __le32 disk_id; |
53 | int err; | 53 | int err; |
54 | 54 | ||
55 | err = squashfs_read_metadata(sb, &disk_id, &start_block, &offset, | 55 | err = squashfs_read_metadata(sb, &disk_id, &start_block, &offset, |
56 | sizeof(disk_id)); | 56 | sizeof(disk_id)); |
57 | if (err < 0) | 57 | if (err < 0) |
58 | return err; | 58 | return err; |
59 | 59 | ||
60 | *id = le32_to_cpu(disk_id); | 60 | *id = le32_to_cpu(disk_id); |
61 | return 0; | 61 | return 0; |
62 | } | 62 | } |
63 | 63 | ||
64 | 64 | ||
65 | /* | 65 | /* |
66 | * Read uncompressed id lookup table indexes from disk into memory | 66 | * Read uncompressed id lookup table indexes from disk into memory |
67 | */ | 67 | */ |
68 | __le64 *squashfs_read_id_index_table(struct super_block *sb, | 68 | __le64 *squashfs_read_id_index_table(struct super_block *sb, |
69 | u64 id_table_start, unsigned short no_ids) | 69 | u64 id_table_start, unsigned short no_ids) |
70 | { | 70 | { |
71 | unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids); | 71 | unsigned int length = SQUASHFS_ID_BLOCK_BYTES(no_ids); |
72 | __le64 *id_table; | ||
73 | int err; | ||
74 | 72 | ||
75 | TRACE("In read_id_index_table, length %d\n", length); | 73 | TRACE("In read_id_index_table, length %d\n", length); |
76 | 74 | ||
77 | /* Allocate id lookup table indexes */ | 75 | return squashfs_read_table(sb, id_table_start, length); |
78 | id_table = kmalloc(length, GFP_KERNEL); | ||
79 | if (id_table == NULL) { | ||
80 | ERROR("Failed to allocate id index table\n"); | ||
81 | return ERR_PTR(-ENOMEM); | ||
82 | } | ||
83 | |||
84 | err = squashfs_read_table(sb, id_table, id_table_start, length); | ||
85 | if (err < 0) { | ||
86 | ERROR("unable to read id index table\n"); | ||
87 | kfree(id_table); | ||
88 | return ERR_PTR(err); | ||
89 | } | ||
90 | |||
91 | return id_table; | ||
92 | } | 76 | } |
93 | 77 |
fs/squashfs/squashfs.h
1 | /* | 1 | /* |
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@lougher.demon.co.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
9 | * as published by the Free Software Foundation; either version 2, | 9 | * as published by the Free Software Foundation; either version 2, |
10 | * or (at your option) any later version. | 10 | * or (at your option) any later version. |
11 | * | 11 | * |
12 | * This program is distributed in the hope that it will be useful, | 12 | * This program is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
16 | * | 16 | * |
17 | * You should have received a copy of the GNU General Public License | 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 | 18 | * along with this program; if not, write to the Free Software |
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
20 | * | 20 | * |
21 | * squashfs.h | 21 | * squashfs.h |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #define TRACE(s, args...) pr_debug("SQUASHFS: "s, ## args) | 24 | #define TRACE(s, args...) pr_debug("SQUASHFS: "s, ## args) |
25 | 25 | ||
26 | #define ERROR(s, args...) pr_err("SQUASHFS error: "s, ## args) | 26 | #define ERROR(s, args...) pr_err("SQUASHFS error: "s, ## args) |
27 | 27 | ||
28 | #define WARNING(s, args...) pr_warning("SQUASHFS: "s, ## args) | 28 | #define WARNING(s, args...) pr_warning("SQUASHFS: "s, ## args) |
29 | 29 | ||
30 | /* block.c */ | 30 | /* block.c */ |
31 | extern int squashfs_read_data(struct super_block *, void **, u64, int, u64 *, | 31 | extern int squashfs_read_data(struct super_block *, void **, u64, int, u64 *, |
32 | int, int); | 32 | int, int); |
33 | 33 | ||
34 | /* cache.c */ | 34 | /* cache.c */ |
35 | extern struct squashfs_cache *squashfs_cache_init(char *, int, int); | 35 | extern struct squashfs_cache *squashfs_cache_init(char *, int, int); |
36 | extern void squashfs_cache_delete(struct squashfs_cache *); | 36 | extern void squashfs_cache_delete(struct squashfs_cache *); |
37 | extern struct squashfs_cache_entry *squashfs_cache_get(struct super_block *, | 37 | extern struct squashfs_cache_entry *squashfs_cache_get(struct super_block *, |
38 | struct squashfs_cache *, u64, int); | 38 | struct squashfs_cache *, u64, int); |
39 | extern void squashfs_cache_put(struct squashfs_cache_entry *); | 39 | extern void squashfs_cache_put(struct squashfs_cache_entry *); |
40 | extern int squashfs_copy_data(void *, struct squashfs_cache_entry *, int, int); | 40 | extern int squashfs_copy_data(void *, struct squashfs_cache_entry *, int, int); |
41 | extern int squashfs_read_metadata(struct super_block *, void *, u64 *, | 41 | extern int squashfs_read_metadata(struct super_block *, void *, u64 *, |
42 | int *, int); | 42 | int *, int); |
43 | extern struct squashfs_cache_entry *squashfs_get_fragment(struct super_block *, | 43 | extern struct squashfs_cache_entry *squashfs_get_fragment(struct super_block *, |
44 | u64, int); | 44 | u64, int); |
45 | extern struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *, | 45 | extern struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *, |
46 | u64, int); | 46 | u64, int); |
47 | extern int squashfs_read_table(struct super_block *, void *, u64, int); | 47 | extern void *squashfs_read_table(struct super_block *, u64, int); |
48 | 48 | ||
49 | /* decompressor.c */ | 49 | /* decompressor.c */ |
50 | extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int); | 50 | extern const struct squashfs_decompressor *squashfs_lookup_decompressor(int); |
51 | extern void *squashfs_decompressor_init(struct super_block *, unsigned short); | 51 | extern void *squashfs_decompressor_init(struct super_block *, unsigned short); |
52 | 52 | ||
53 | /* export.c */ | 53 | /* export.c */ |
54 | extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, | 54 | extern __le64 *squashfs_read_inode_lookup_table(struct super_block *, u64, |
55 | unsigned int); | 55 | unsigned int); |
56 | 56 | ||
57 | /* fragment.c */ | 57 | /* fragment.c */ |
58 | extern int squashfs_frag_lookup(struct super_block *, unsigned int, u64 *); | 58 | extern int squashfs_frag_lookup(struct super_block *, unsigned int, u64 *); |
59 | extern __le64 *squashfs_read_fragment_index_table(struct super_block *, | 59 | extern __le64 *squashfs_read_fragment_index_table(struct super_block *, |
60 | u64, unsigned int); | 60 | u64, unsigned int); |
61 | 61 | ||
62 | /* id.c */ | 62 | /* id.c */ |
63 | extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); | 63 | extern int squashfs_get_id(struct super_block *, unsigned int, unsigned int *); |
64 | extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, | 64 | extern __le64 *squashfs_read_id_index_table(struct super_block *, u64, |
65 | unsigned short); | 65 | unsigned short); |
66 | 66 | ||
67 | /* inode.c */ | 67 | /* inode.c */ |
68 | extern struct inode *squashfs_iget(struct super_block *, long long, | 68 | extern struct inode *squashfs_iget(struct super_block *, long long, |
69 | unsigned int); | 69 | unsigned int); |
70 | extern int squashfs_read_inode(struct inode *, long long); | 70 | extern int squashfs_read_inode(struct inode *, long long); |
71 | 71 | ||
72 | /* xattr.c */ | 72 | /* xattr.c */ |
73 | extern ssize_t squashfs_listxattr(struct dentry *, char *, size_t); | 73 | extern ssize_t squashfs_listxattr(struct dentry *, char *, size_t); |
74 | 74 | ||
75 | /* | 75 | /* |
76 | * Inodes, files, decompressor and xattr operations | 76 | * Inodes, files, decompressor and xattr operations |
77 | */ | 77 | */ |
78 | 78 | ||
79 | /* dir.c */ | 79 | /* dir.c */ |
80 | extern const struct file_operations squashfs_dir_ops; | 80 | extern const struct file_operations squashfs_dir_ops; |
81 | 81 | ||
82 | /* export.c */ | 82 | /* export.c */ |
83 | extern const struct export_operations squashfs_export_ops; | 83 | extern const struct export_operations squashfs_export_ops; |
84 | 84 | ||
85 | /* file.c */ | 85 | /* file.c */ |
86 | extern const struct address_space_operations squashfs_aops; | 86 | extern const struct address_space_operations squashfs_aops; |
87 | 87 | ||
88 | /* inode.c */ | 88 | /* inode.c */ |
89 | extern const struct inode_operations squashfs_inode_ops; | 89 | extern const struct inode_operations squashfs_inode_ops; |
90 | 90 | ||
91 | /* namei.c */ | 91 | /* namei.c */ |
92 | extern const struct inode_operations squashfs_dir_inode_ops; | 92 | extern const struct inode_operations squashfs_dir_inode_ops; |
93 | 93 | ||
94 | /* symlink.c */ | 94 | /* symlink.c */ |
95 | extern const struct address_space_operations squashfs_symlink_aops; | 95 | extern const struct address_space_operations squashfs_symlink_aops; |
96 | extern const struct inode_operations squashfs_symlink_inode_ops; | 96 | extern const struct inode_operations squashfs_symlink_inode_ops; |
97 | 97 | ||
98 | /* xattr.c */ | 98 | /* xattr.c */ |
99 | extern const struct xattr_handler *squashfs_xattr_handlers[]; | 99 | extern const struct xattr_handler *squashfs_xattr_handlers[]; |
100 | 100 | ||
101 | /* zlib_wrapper.c */ | 101 | /* zlib_wrapper.c */ |
102 | extern const struct squashfs_decompressor squashfs_zlib_comp_ops; | 102 | extern const struct squashfs_decompressor squashfs_zlib_comp_ops; |
103 | 103 |
fs/squashfs/super.c
1 | /* | 1 | /* |
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 | 4 | * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@lougher.demon.co.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
9 | * as published by the Free Software Foundation; either version 2, | 9 | * as published by the Free Software Foundation; either version 2, |
10 | * or (at your option) any later version. | 10 | * or (at your option) any later version. |
11 | * | 11 | * |
12 | * This program is distributed in the hope that it will be useful, | 12 | * This program is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
16 | * | 16 | * |
17 | * You should have received a copy of the GNU General Public License | 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 | 18 | * along with this program; if not, write to the Free Software |
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
20 | * | 20 | * |
21 | * super.c | 21 | * super.c |
22 | */ | 22 | */ |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * This file implements code to read the superblock, read and initialise | 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 | 26 | * in-memory structures at mount time, and all the VFS glue code to register |
27 | * the filesystem. | 27 | * the filesystem. |
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <linux/fs.h> | 30 | #include <linux/fs.h> |
31 | #include <linux/vfs.h> | 31 | #include <linux/vfs.h> |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
34 | #include <linux/pagemap.h> | 34 | #include <linux/pagemap.h> |
35 | #include <linux/init.h> | 35 | #include <linux/init.h> |
36 | #include <linux/module.h> | 36 | #include <linux/module.h> |
37 | #include <linux/magic.h> | 37 | #include <linux/magic.h> |
38 | #include <linux/xattr.h> | 38 | #include <linux/xattr.h> |
39 | 39 | ||
40 | #include "squashfs_fs.h" | 40 | #include "squashfs_fs.h" |
41 | #include "squashfs_fs_sb.h" | 41 | #include "squashfs_fs_sb.h" |
42 | #include "squashfs_fs_i.h" | 42 | #include "squashfs_fs_i.h" |
43 | #include "squashfs.h" | 43 | #include "squashfs.h" |
44 | #include "decompressor.h" | 44 | #include "decompressor.h" |
45 | #include "xattr.h" | 45 | #include "xattr.h" |
46 | 46 | ||
47 | static struct file_system_type squashfs_fs_type; | 47 | static struct file_system_type squashfs_fs_type; |
48 | static const struct super_operations squashfs_super_ops; | 48 | static const struct super_operations squashfs_super_ops; |
49 | 49 | ||
50 | static const struct squashfs_decompressor *supported_squashfs_filesystem(short | 50 | static const struct squashfs_decompressor *supported_squashfs_filesystem(short |
51 | major, short minor, short id) | 51 | major, short minor, short id) |
52 | { | 52 | { |
53 | const struct squashfs_decompressor *decompressor; | 53 | const struct squashfs_decompressor *decompressor; |
54 | 54 | ||
55 | if (major < SQUASHFS_MAJOR) { | 55 | if (major < SQUASHFS_MAJOR) { |
56 | ERROR("Major/Minor mismatch, older Squashfs %d.%d " | 56 | ERROR("Major/Minor mismatch, older Squashfs %d.%d " |
57 | "filesystems are unsupported\n", major, minor); | 57 | "filesystems are unsupported\n", major, minor); |
58 | return NULL; | 58 | return NULL; |
59 | } else if (major > SQUASHFS_MAJOR || minor > SQUASHFS_MINOR) { | 59 | } else if (major > SQUASHFS_MAJOR || minor > SQUASHFS_MINOR) { |
60 | ERROR("Major/Minor mismatch, trying to mount newer " | 60 | ERROR("Major/Minor mismatch, trying to mount newer " |
61 | "%d.%d filesystem\n", major, minor); | 61 | "%d.%d filesystem\n", major, minor); |
62 | ERROR("Please update your kernel\n"); | 62 | ERROR("Please update your kernel\n"); |
63 | return NULL; | 63 | return NULL; |
64 | } | 64 | } |
65 | 65 | ||
66 | decompressor = squashfs_lookup_decompressor(id); | 66 | decompressor = squashfs_lookup_decompressor(id); |
67 | if (!decompressor->supported) { | 67 | if (!decompressor->supported) { |
68 | ERROR("Filesystem uses \"%s\" compression. This is not " | 68 | ERROR("Filesystem uses \"%s\" compression. This is not " |
69 | "supported\n", decompressor->name); | 69 | "supported\n", decompressor->name); |
70 | return NULL; | 70 | return NULL; |
71 | } | 71 | } |
72 | 72 | ||
73 | return decompressor; | 73 | return decompressor; |
74 | } | 74 | } |
75 | 75 | ||
76 | 76 | ||
77 | static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | 77 | static int squashfs_fill_super(struct super_block *sb, void *data, int silent) |
78 | { | 78 | { |
79 | struct squashfs_sb_info *msblk; | 79 | struct squashfs_sb_info *msblk; |
80 | struct squashfs_super_block *sblk = NULL; | 80 | struct squashfs_super_block *sblk = NULL; |
81 | char b[BDEVNAME_SIZE]; | 81 | char b[BDEVNAME_SIZE]; |
82 | struct inode *root; | 82 | struct inode *root; |
83 | long long root_inode; | 83 | long long root_inode; |
84 | unsigned short flags; | 84 | unsigned short flags; |
85 | unsigned int fragments; | 85 | unsigned int fragments; |
86 | u64 lookup_table_start, xattr_id_table_start; | 86 | u64 lookup_table_start, xattr_id_table_start; |
87 | int err; | 87 | int err; |
88 | 88 | ||
89 | TRACE("Entered squashfs_fill_superblock\n"); | 89 | TRACE("Entered squashfs_fill_superblock\n"); |
90 | 90 | ||
91 | sb->s_fs_info = kzalloc(sizeof(*msblk), GFP_KERNEL); | 91 | sb->s_fs_info = kzalloc(sizeof(*msblk), GFP_KERNEL); |
92 | if (sb->s_fs_info == NULL) { | 92 | if (sb->s_fs_info == NULL) { |
93 | ERROR("Failed to allocate squashfs_sb_info\n"); | 93 | ERROR("Failed to allocate squashfs_sb_info\n"); |
94 | return -ENOMEM; | 94 | return -ENOMEM; |
95 | } | 95 | } |
96 | msblk = sb->s_fs_info; | 96 | msblk = sb->s_fs_info; |
97 | 97 | ||
98 | sblk = kzalloc(sizeof(*sblk), GFP_KERNEL); | ||
99 | if (sblk == NULL) { | ||
100 | ERROR("Failed to allocate squashfs_super_block\n"); | ||
101 | goto failure; | ||
102 | } | ||
103 | |||
104 | msblk->devblksize = sb_min_blocksize(sb, BLOCK_SIZE); | 98 | msblk->devblksize = sb_min_blocksize(sb, BLOCK_SIZE); |
105 | msblk->devblksize_log2 = ffz(~msblk->devblksize); | 99 | msblk->devblksize_log2 = ffz(~msblk->devblksize); |
106 | 100 | ||
107 | mutex_init(&msblk->read_data_mutex); | 101 | mutex_init(&msblk->read_data_mutex); |
108 | mutex_init(&msblk->meta_index_mutex); | 102 | mutex_init(&msblk->meta_index_mutex); |
109 | 103 | ||
110 | /* | 104 | /* |
111 | * msblk->bytes_used is checked in squashfs_read_table to ensure reads | 105 | * msblk->bytes_used is checked in squashfs_read_table to ensure reads |
112 | * are not beyond filesystem end. But as we're using | 106 | * are not beyond filesystem end. But as we're using |
113 | * squashfs_read_table here to read the superblock (including the value | 107 | * squashfs_read_table here to read the superblock (including the value |
114 | * of bytes_used) we need to set it to an initial sensible dummy value | 108 | * of bytes_used) we need to set it to an initial sensible dummy value |
115 | */ | 109 | */ |
116 | msblk->bytes_used = sizeof(*sblk); | 110 | msblk->bytes_used = sizeof(*sblk); |
117 | err = squashfs_read_table(sb, sblk, SQUASHFS_START, sizeof(*sblk)); | 111 | sblk = squashfs_read_table(sb, SQUASHFS_START, sizeof(*sblk)); |
118 | 112 | ||
119 | if (err < 0) { | 113 | if (IS_ERR(sblk)) { |
120 | ERROR("unable to read squashfs_super_block\n"); | 114 | ERROR("unable to read squashfs_super_block\n"); |
115 | err = PTR_ERR(sblk); | ||
116 | sblk = NULL; | ||
121 | goto failed_mount; | 117 | goto failed_mount; |
122 | } | 118 | } |
123 | 119 | ||
124 | err = -EINVAL; | 120 | err = -EINVAL; |
125 | 121 | ||
126 | /* Check it is a SQUASHFS superblock */ | 122 | /* Check it is a SQUASHFS superblock */ |
127 | sb->s_magic = le32_to_cpu(sblk->s_magic); | 123 | sb->s_magic = le32_to_cpu(sblk->s_magic); |
128 | if (sb->s_magic != SQUASHFS_MAGIC) { | 124 | if (sb->s_magic != SQUASHFS_MAGIC) { |
129 | if (!silent) | 125 | if (!silent) |
130 | ERROR("Can't find a SQUASHFS superblock on %s\n", | 126 | ERROR("Can't find a SQUASHFS superblock on %s\n", |
131 | bdevname(sb->s_bdev, b)); | 127 | bdevname(sb->s_bdev, b)); |
132 | goto failed_mount; | 128 | goto failed_mount; |
133 | } | 129 | } |
134 | 130 | ||
135 | /* Check the MAJOR & MINOR versions and lookup compression type */ | 131 | /* Check the MAJOR & MINOR versions and lookup compression type */ |
136 | msblk->decompressor = supported_squashfs_filesystem( | 132 | msblk->decompressor = supported_squashfs_filesystem( |
137 | le16_to_cpu(sblk->s_major), | 133 | le16_to_cpu(sblk->s_major), |
138 | le16_to_cpu(sblk->s_minor), | 134 | le16_to_cpu(sblk->s_minor), |
139 | le16_to_cpu(sblk->compression)); | 135 | le16_to_cpu(sblk->compression)); |
140 | if (msblk->decompressor == NULL) | 136 | if (msblk->decompressor == NULL) |
141 | goto failed_mount; | 137 | goto failed_mount; |
142 | 138 | ||
143 | /* Check the filesystem does not extend beyond the end of the | 139 | /* Check the filesystem does not extend beyond the end of the |
144 | block device */ | 140 | block device */ |
145 | msblk->bytes_used = le64_to_cpu(sblk->bytes_used); | 141 | msblk->bytes_used = le64_to_cpu(sblk->bytes_used); |
146 | if (msblk->bytes_used < 0 || msblk->bytes_used > | 142 | if (msblk->bytes_used < 0 || msblk->bytes_used > |
147 | i_size_read(sb->s_bdev->bd_inode)) | 143 | i_size_read(sb->s_bdev->bd_inode)) |
148 | goto failed_mount; | 144 | goto failed_mount; |
149 | 145 | ||
150 | /* Check block size for sanity */ | 146 | /* Check block size for sanity */ |
151 | msblk->block_size = le32_to_cpu(sblk->block_size); | 147 | msblk->block_size = le32_to_cpu(sblk->block_size); |
152 | if (msblk->block_size > SQUASHFS_FILE_MAX_SIZE) | 148 | if (msblk->block_size > SQUASHFS_FILE_MAX_SIZE) |
153 | goto failed_mount; | 149 | goto failed_mount; |
154 | 150 | ||
155 | /* | 151 | /* |
156 | * Check the system page size is not larger than the filesystem | 152 | * Check the system page size is not larger than the filesystem |
157 | * block size (by default 128K). This is currently not supported. | 153 | * block size (by default 128K). This is currently not supported. |
158 | */ | 154 | */ |
159 | if (PAGE_CACHE_SIZE > msblk->block_size) { | 155 | if (PAGE_CACHE_SIZE > msblk->block_size) { |
160 | ERROR("Page size > filesystem block size (%d). This is " | 156 | ERROR("Page size > filesystem block size (%d). This is " |
161 | "currently not supported!\n", msblk->block_size); | 157 | "currently not supported!\n", msblk->block_size); |
162 | goto failed_mount; | 158 | goto failed_mount; |
163 | } | 159 | } |
164 | 160 | ||
165 | msblk->block_log = le16_to_cpu(sblk->block_log); | 161 | msblk->block_log = le16_to_cpu(sblk->block_log); |
166 | if (msblk->block_log > SQUASHFS_FILE_MAX_LOG) | 162 | if (msblk->block_log > SQUASHFS_FILE_MAX_LOG) |
167 | goto failed_mount; | 163 | goto failed_mount; |
168 | 164 | ||
169 | /* Check the root inode for sanity */ | 165 | /* Check the root inode for sanity */ |
170 | root_inode = le64_to_cpu(sblk->root_inode); | 166 | root_inode = le64_to_cpu(sblk->root_inode); |
171 | if (SQUASHFS_INODE_OFFSET(root_inode) > SQUASHFS_METADATA_SIZE) | 167 | if (SQUASHFS_INODE_OFFSET(root_inode) > SQUASHFS_METADATA_SIZE) |
172 | goto failed_mount; | 168 | goto failed_mount; |
173 | 169 | ||
174 | msblk->inode_table = le64_to_cpu(sblk->inode_table_start); | 170 | msblk->inode_table = le64_to_cpu(sblk->inode_table_start); |
175 | msblk->directory_table = le64_to_cpu(sblk->directory_table_start); | 171 | msblk->directory_table = le64_to_cpu(sblk->directory_table_start); |
176 | msblk->inodes = le32_to_cpu(sblk->inodes); | 172 | msblk->inodes = le32_to_cpu(sblk->inodes); |
177 | flags = le16_to_cpu(sblk->flags); | 173 | flags = le16_to_cpu(sblk->flags); |
178 | 174 | ||
179 | TRACE("Found valid superblock on %s\n", bdevname(sb->s_bdev, b)); | 175 | TRACE("Found valid superblock on %s\n", bdevname(sb->s_bdev, b)); |
180 | TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(flags) | 176 | TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(flags) |
181 | ? "un" : ""); | 177 | ? "un" : ""); |
182 | TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(flags) | 178 | TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(flags) |
183 | ? "un" : ""); | 179 | ? "un" : ""); |
184 | TRACE("Filesystem size %lld bytes\n", msblk->bytes_used); | 180 | TRACE("Filesystem size %lld bytes\n", msblk->bytes_used); |
185 | TRACE("Block size %d\n", msblk->block_size); | 181 | TRACE("Block size %d\n", msblk->block_size); |
186 | TRACE("Number of inodes %d\n", msblk->inodes); | 182 | TRACE("Number of inodes %d\n", msblk->inodes); |
187 | TRACE("Number of fragments %d\n", le32_to_cpu(sblk->fragments)); | 183 | TRACE("Number of fragments %d\n", le32_to_cpu(sblk->fragments)); |
188 | TRACE("Number of ids %d\n", le16_to_cpu(sblk->no_ids)); | 184 | TRACE("Number of ids %d\n", le16_to_cpu(sblk->no_ids)); |
189 | TRACE("sblk->inode_table_start %llx\n", msblk->inode_table); | 185 | TRACE("sblk->inode_table_start %llx\n", msblk->inode_table); |
190 | TRACE("sblk->directory_table_start %llx\n", msblk->directory_table); | 186 | TRACE("sblk->directory_table_start %llx\n", msblk->directory_table); |
191 | TRACE("sblk->fragment_table_start %llx\n", | 187 | TRACE("sblk->fragment_table_start %llx\n", |
192 | (u64) le64_to_cpu(sblk->fragment_table_start)); | 188 | (u64) le64_to_cpu(sblk->fragment_table_start)); |
193 | TRACE("sblk->id_table_start %llx\n", | 189 | TRACE("sblk->id_table_start %llx\n", |
194 | (u64) le64_to_cpu(sblk->id_table_start)); | 190 | (u64) le64_to_cpu(sblk->id_table_start)); |
195 | 191 | ||
196 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 192 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
197 | sb->s_flags |= MS_RDONLY; | 193 | sb->s_flags |= MS_RDONLY; |
198 | sb->s_op = &squashfs_super_ops; | 194 | sb->s_op = &squashfs_super_ops; |
199 | 195 | ||
200 | err = -ENOMEM; | 196 | err = -ENOMEM; |
201 | 197 | ||
202 | msblk->block_cache = squashfs_cache_init("metadata", | 198 | msblk->block_cache = squashfs_cache_init("metadata", |
203 | SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE); | 199 | SQUASHFS_CACHED_BLKS, SQUASHFS_METADATA_SIZE); |
204 | if (msblk->block_cache == NULL) | 200 | if (msblk->block_cache == NULL) |
205 | goto failed_mount; | 201 | goto failed_mount; |
206 | 202 | ||
207 | /* Allocate read_page block */ | 203 | /* Allocate read_page block */ |
208 | msblk->read_page = squashfs_cache_init("data", 1, msblk->block_size); | 204 | msblk->read_page = squashfs_cache_init("data", 1, msblk->block_size); |
209 | if (msblk->read_page == NULL) { | 205 | if (msblk->read_page == NULL) { |
210 | ERROR("Failed to allocate read_page block\n"); | 206 | ERROR("Failed to allocate read_page block\n"); |
211 | goto failed_mount; | 207 | goto failed_mount; |
212 | } | 208 | } |
213 | 209 | ||
214 | msblk->stream = squashfs_decompressor_init(sb, flags); | 210 | msblk->stream = squashfs_decompressor_init(sb, flags); |
215 | if (IS_ERR(msblk->stream)) { | 211 | if (IS_ERR(msblk->stream)) { |
216 | err = PTR_ERR(msblk->stream); | 212 | err = PTR_ERR(msblk->stream); |
217 | msblk->stream = NULL; | 213 | msblk->stream = NULL; |
218 | goto failed_mount; | 214 | goto failed_mount; |
219 | } | 215 | } |
220 | 216 | ||
221 | /* Allocate and read id index table */ | 217 | /* Allocate and read id index table */ |
222 | msblk->id_table = squashfs_read_id_index_table(sb, | 218 | msblk->id_table = squashfs_read_id_index_table(sb, |
223 | le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids)); | 219 | le64_to_cpu(sblk->id_table_start), le16_to_cpu(sblk->no_ids)); |
224 | if (IS_ERR(msblk->id_table)) { | 220 | if (IS_ERR(msblk->id_table)) { |
221 | ERROR("unable to read id index table\n"); | ||
225 | err = PTR_ERR(msblk->id_table); | 222 | err = PTR_ERR(msblk->id_table); |
226 | msblk->id_table = NULL; | 223 | msblk->id_table = NULL; |
227 | goto failed_mount; | 224 | goto failed_mount; |
228 | } | 225 | } |
229 | 226 | ||
230 | fragments = le32_to_cpu(sblk->fragments); | 227 | fragments = le32_to_cpu(sblk->fragments); |
231 | if (fragments == 0) | 228 | if (fragments == 0) |
232 | goto allocate_lookup_table; | 229 | goto allocate_lookup_table; |
233 | 230 | ||
234 | msblk->fragment_cache = squashfs_cache_init("fragment", | 231 | msblk->fragment_cache = squashfs_cache_init("fragment", |
235 | SQUASHFS_CACHED_FRAGMENTS, msblk->block_size); | 232 | SQUASHFS_CACHED_FRAGMENTS, msblk->block_size); |
236 | if (msblk->fragment_cache == NULL) { | 233 | if (msblk->fragment_cache == NULL) { |
237 | err = -ENOMEM; | 234 | err = -ENOMEM; |
238 | goto failed_mount; | 235 | goto failed_mount; |
239 | } | 236 | } |
240 | 237 | ||
241 | /* Allocate and read fragment index table */ | 238 | /* Allocate and read fragment index table */ |
242 | msblk->fragment_index = squashfs_read_fragment_index_table(sb, | 239 | msblk->fragment_index = squashfs_read_fragment_index_table(sb, |
243 | le64_to_cpu(sblk->fragment_table_start), fragments); | 240 | le64_to_cpu(sblk->fragment_table_start), fragments); |
244 | if (IS_ERR(msblk->fragment_index)) { | 241 | if (IS_ERR(msblk->fragment_index)) { |
242 | ERROR("unable to read fragment index table\n"); | ||
245 | err = PTR_ERR(msblk->fragment_index); | 243 | err = PTR_ERR(msblk->fragment_index); |
246 | msblk->fragment_index = NULL; | 244 | msblk->fragment_index = NULL; |
247 | goto failed_mount; | 245 | goto failed_mount; |
248 | } | 246 | } |
249 | 247 | ||
250 | allocate_lookup_table: | 248 | allocate_lookup_table: |
251 | lookup_table_start = le64_to_cpu(sblk->lookup_table_start); | 249 | lookup_table_start = le64_to_cpu(sblk->lookup_table_start); |
252 | if (lookup_table_start == SQUASHFS_INVALID_BLK) | 250 | if (lookup_table_start == SQUASHFS_INVALID_BLK) |
253 | goto allocate_xattr_table; | 251 | goto allocate_xattr_table; |
254 | 252 | ||
255 | /* Allocate and read inode lookup table */ | 253 | /* Allocate and read inode lookup table */ |
256 | msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb, | 254 | msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb, |
257 | lookup_table_start, msblk->inodes); | 255 | lookup_table_start, msblk->inodes); |
258 | if (IS_ERR(msblk->inode_lookup_table)) { | 256 | if (IS_ERR(msblk->inode_lookup_table)) { |
257 | ERROR("unable to read inode lookup table\n"); | ||
259 | err = PTR_ERR(msblk->inode_lookup_table); | 258 | err = PTR_ERR(msblk->inode_lookup_table); |
260 | msblk->inode_lookup_table = NULL; | 259 | msblk->inode_lookup_table = NULL; |
261 | goto failed_mount; | 260 | goto failed_mount; |
262 | } | 261 | } |
263 | 262 | ||
264 | sb->s_export_op = &squashfs_export_ops; | 263 | sb->s_export_op = &squashfs_export_ops; |
265 | 264 | ||
266 | allocate_xattr_table: | 265 | allocate_xattr_table: |
267 | sb->s_xattr = squashfs_xattr_handlers; | 266 | sb->s_xattr = squashfs_xattr_handlers; |
268 | xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start); | 267 | xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start); |
269 | if (xattr_id_table_start == SQUASHFS_INVALID_BLK) | 268 | if (xattr_id_table_start == SQUASHFS_INVALID_BLK) |
270 | goto allocate_root; | 269 | goto allocate_root; |
271 | 270 | ||
272 | /* Allocate and read xattr id lookup table */ | 271 | /* Allocate and read xattr id lookup table */ |
273 | msblk->xattr_id_table = squashfs_read_xattr_id_table(sb, | 272 | msblk->xattr_id_table = squashfs_read_xattr_id_table(sb, |
274 | xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids); | 273 | xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids); |
275 | if (IS_ERR(msblk->xattr_id_table)) { | 274 | if (IS_ERR(msblk->xattr_id_table)) { |
275 | ERROR("unable to read xattr id index table\n"); | ||
276 | err = PTR_ERR(msblk->xattr_id_table); | 276 | err = PTR_ERR(msblk->xattr_id_table); |
277 | msblk->xattr_id_table = NULL; | 277 | msblk->xattr_id_table = NULL; |
278 | if (err != -ENOTSUPP) | 278 | if (err != -ENOTSUPP) |
279 | goto failed_mount; | 279 | goto failed_mount; |
280 | } | 280 | } |
281 | allocate_root: | 281 | allocate_root: |
282 | root = new_inode(sb); | 282 | root = new_inode(sb); |
283 | if (!root) { | 283 | if (!root) { |
284 | err = -ENOMEM; | 284 | err = -ENOMEM; |
285 | goto failed_mount; | 285 | goto failed_mount; |
286 | } | 286 | } |
287 | 287 | ||
288 | err = squashfs_read_inode(root, root_inode); | 288 | err = squashfs_read_inode(root, root_inode); |
289 | if (err) { | 289 | if (err) { |
290 | make_bad_inode(root); | 290 | make_bad_inode(root); |
291 | iput(root); | 291 | iput(root); |
292 | goto failed_mount; | 292 | goto failed_mount; |
293 | } | 293 | } |
294 | insert_inode_hash(root); | 294 | insert_inode_hash(root); |
295 | 295 | ||
296 | sb->s_root = d_alloc_root(root); | 296 | sb->s_root = d_alloc_root(root); |
297 | if (sb->s_root == NULL) { | 297 | if (sb->s_root == NULL) { |
298 | ERROR("Root inode create failed\n"); | 298 | ERROR("Root inode create failed\n"); |
299 | err = -ENOMEM; | 299 | err = -ENOMEM; |
300 | iput(root); | 300 | iput(root); |
301 | goto failed_mount; | 301 | goto failed_mount; |
302 | } | 302 | } |
303 | 303 | ||
304 | TRACE("Leaving squashfs_fill_super\n"); | 304 | TRACE("Leaving squashfs_fill_super\n"); |
305 | kfree(sblk); | 305 | kfree(sblk); |
306 | return 0; | 306 | return 0; |
307 | 307 | ||
308 | failed_mount: | 308 | failed_mount: |
309 | squashfs_cache_delete(msblk->block_cache); | 309 | squashfs_cache_delete(msblk->block_cache); |
310 | squashfs_cache_delete(msblk->fragment_cache); | 310 | squashfs_cache_delete(msblk->fragment_cache); |
311 | squashfs_cache_delete(msblk->read_page); | 311 | squashfs_cache_delete(msblk->read_page); |
312 | squashfs_decompressor_free(msblk, msblk->stream); | 312 | squashfs_decompressor_free(msblk, msblk->stream); |
313 | kfree(msblk->inode_lookup_table); | 313 | kfree(msblk->inode_lookup_table); |
314 | kfree(msblk->fragment_index); | 314 | kfree(msblk->fragment_index); |
315 | kfree(msblk->id_table); | 315 | kfree(msblk->id_table); |
316 | kfree(msblk->xattr_id_table); | 316 | kfree(msblk->xattr_id_table); |
317 | kfree(sb->s_fs_info); | 317 | kfree(sb->s_fs_info); |
318 | sb->s_fs_info = NULL; | 318 | sb->s_fs_info = NULL; |
319 | kfree(sblk); | 319 | kfree(sblk); |
320 | return err; | 320 | return err; |
321 | |||
322 | failure: | ||
323 | kfree(sb->s_fs_info); | ||
324 | sb->s_fs_info = NULL; | ||
325 | return -ENOMEM; | ||
326 | } | 321 | } |
327 | 322 | ||
328 | 323 | ||
329 | static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 324 | static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf) |
330 | { | 325 | { |
331 | struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info; | 326 | struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info; |
332 | u64 id = huge_encode_dev(dentry->d_sb->s_bdev->bd_dev); | 327 | u64 id = huge_encode_dev(dentry->d_sb->s_bdev->bd_dev); |
333 | 328 | ||
334 | TRACE("Entered squashfs_statfs\n"); | 329 | TRACE("Entered squashfs_statfs\n"); |
335 | 330 | ||
336 | buf->f_type = SQUASHFS_MAGIC; | 331 | buf->f_type = SQUASHFS_MAGIC; |
337 | buf->f_bsize = msblk->block_size; | 332 | buf->f_bsize = msblk->block_size; |
338 | buf->f_blocks = ((msblk->bytes_used - 1) >> msblk->block_log) + 1; | 333 | buf->f_blocks = ((msblk->bytes_used - 1) >> msblk->block_log) + 1; |
339 | buf->f_bfree = buf->f_bavail = 0; | 334 | buf->f_bfree = buf->f_bavail = 0; |
340 | buf->f_files = msblk->inodes; | 335 | buf->f_files = msblk->inodes; |
341 | buf->f_ffree = 0; | 336 | buf->f_ffree = 0; |
342 | buf->f_namelen = SQUASHFS_NAME_LEN; | 337 | buf->f_namelen = SQUASHFS_NAME_LEN; |
343 | buf->f_fsid.val[0] = (u32)id; | 338 | buf->f_fsid.val[0] = (u32)id; |
344 | buf->f_fsid.val[1] = (u32)(id >> 32); | 339 | buf->f_fsid.val[1] = (u32)(id >> 32); |
345 | 340 | ||
346 | return 0; | 341 | return 0; |
347 | } | 342 | } |
348 | 343 | ||
349 | 344 | ||
350 | static int squashfs_remount(struct super_block *sb, int *flags, char *data) | 345 | static int squashfs_remount(struct super_block *sb, int *flags, char *data) |
351 | { | 346 | { |
352 | *flags |= MS_RDONLY; | 347 | *flags |= MS_RDONLY; |
353 | return 0; | 348 | return 0; |
354 | } | 349 | } |
355 | 350 | ||
356 | 351 | ||
357 | static void squashfs_put_super(struct super_block *sb) | 352 | static void squashfs_put_super(struct super_block *sb) |
358 | { | 353 | { |
359 | if (sb->s_fs_info) { | 354 | if (sb->s_fs_info) { |
360 | struct squashfs_sb_info *sbi = sb->s_fs_info; | 355 | struct squashfs_sb_info *sbi = sb->s_fs_info; |
361 | squashfs_cache_delete(sbi->block_cache); | 356 | squashfs_cache_delete(sbi->block_cache); |
362 | squashfs_cache_delete(sbi->fragment_cache); | 357 | squashfs_cache_delete(sbi->fragment_cache); |
363 | squashfs_cache_delete(sbi->read_page); | 358 | squashfs_cache_delete(sbi->read_page); |
364 | squashfs_decompressor_free(sbi, sbi->stream); | 359 | squashfs_decompressor_free(sbi, sbi->stream); |
365 | kfree(sbi->id_table); | 360 | kfree(sbi->id_table); |
366 | kfree(sbi->fragment_index); | 361 | kfree(sbi->fragment_index); |
367 | kfree(sbi->meta_index); | 362 | kfree(sbi->meta_index); |
368 | kfree(sbi->inode_lookup_table); | 363 | kfree(sbi->inode_lookup_table); |
369 | kfree(sbi->xattr_id_table); | 364 | kfree(sbi->xattr_id_table); |
370 | kfree(sb->s_fs_info); | 365 | kfree(sb->s_fs_info); |
371 | sb->s_fs_info = NULL; | 366 | sb->s_fs_info = NULL; |
372 | } | 367 | } |
373 | } | 368 | } |
374 | 369 | ||
375 | 370 | ||
376 | static struct dentry *squashfs_mount(struct file_system_type *fs_type, | 371 | static struct dentry *squashfs_mount(struct file_system_type *fs_type, |
377 | int flags, const char *dev_name, void *data) | 372 | int flags, const char *dev_name, void *data) |
378 | { | 373 | { |
379 | return mount_bdev(fs_type, flags, dev_name, data, squashfs_fill_super); | 374 | return mount_bdev(fs_type, flags, dev_name, data, squashfs_fill_super); |
380 | } | 375 | } |
381 | 376 | ||
382 | 377 | ||
383 | static struct kmem_cache *squashfs_inode_cachep; | 378 | static struct kmem_cache *squashfs_inode_cachep; |
384 | 379 | ||
385 | 380 | ||
386 | static void init_once(void *foo) | 381 | static void init_once(void *foo) |
387 | { | 382 | { |
388 | struct squashfs_inode_info *ei = foo; | 383 | struct squashfs_inode_info *ei = foo; |
389 | 384 | ||
390 | inode_init_once(&ei->vfs_inode); | 385 | inode_init_once(&ei->vfs_inode); |
391 | } | 386 | } |
392 | 387 | ||
393 | 388 | ||
394 | static int __init init_inodecache(void) | 389 | static int __init init_inodecache(void) |
395 | { | 390 | { |
396 | squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache", | 391 | squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache", |
397 | sizeof(struct squashfs_inode_info), 0, | 392 | sizeof(struct squashfs_inode_info), 0, |
398 | SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, init_once); | 393 | SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, init_once); |
399 | 394 | ||
400 | return squashfs_inode_cachep ? 0 : -ENOMEM; | 395 | return squashfs_inode_cachep ? 0 : -ENOMEM; |
401 | } | 396 | } |
402 | 397 | ||
403 | 398 | ||
404 | static void destroy_inodecache(void) | 399 | static void destroy_inodecache(void) |
405 | { | 400 | { |
406 | kmem_cache_destroy(squashfs_inode_cachep); | 401 | kmem_cache_destroy(squashfs_inode_cachep); |
407 | } | 402 | } |
408 | 403 | ||
409 | 404 | ||
410 | static int __init init_squashfs_fs(void) | 405 | static int __init init_squashfs_fs(void) |
411 | { | 406 | { |
412 | int err = init_inodecache(); | 407 | int err = init_inodecache(); |
413 | 408 | ||
414 | if (err) | 409 | if (err) |
415 | return err; | 410 | return err; |
416 | 411 | ||
417 | err = register_filesystem(&squashfs_fs_type); | 412 | err = register_filesystem(&squashfs_fs_type); |
418 | if (err) { | 413 | if (err) { |
419 | destroy_inodecache(); | 414 | destroy_inodecache(); |
420 | return err; | 415 | return err; |
421 | } | 416 | } |
422 | 417 | ||
423 | printk(KERN_INFO "squashfs: version 4.0 (2009/01/31) " | 418 | printk(KERN_INFO "squashfs: version 4.0 (2009/01/31) " |
424 | "Phillip Lougher\n"); | 419 | "Phillip Lougher\n"); |
425 | 420 | ||
426 | return 0; | 421 | return 0; |
427 | } | 422 | } |
428 | 423 | ||
429 | 424 | ||
430 | static void __exit exit_squashfs_fs(void) | 425 | static void __exit exit_squashfs_fs(void) |
431 | { | 426 | { |
432 | unregister_filesystem(&squashfs_fs_type); | 427 | unregister_filesystem(&squashfs_fs_type); |
433 | destroy_inodecache(); | 428 | destroy_inodecache(); |
434 | } | 429 | } |
435 | 430 | ||
436 | 431 | ||
437 | static struct inode *squashfs_alloc_inode(struct super_block *sb) | 432 | static struct inode *squashfs_alloc_inode(struct super_block *sb) |
438 | { | 433 | { |
439 | struct squashfs_inode_info *ei = | 434 | struct squashfs_inode_info *ei = |
440 | kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL); | 435 | kmem_cache_alloc(squashfs_inode_cachep, GFP_KERNEL); |
441 | 436 | ||
442 | return ei ? &ei->vfs_inode : NULL; | 437 | return ei ? &ei->vfs_inode : NULL; |
443 | } | 438 | } |
444 | 439 | ||
445 | 440 | ||
446 | static void squashfs_i_callback(struct rcu_head *head) | 441 | static void squashfs_i_callback(struct rcu_head *head) |
447 | { | 442 | { |
448 | struct inode *inode = container_of(head, struct inode, i_rcu); | 443 | struct inode *inode = container_of(head, struct inode, i_rcu); |
449 | INIT_LIST_HEAD(&inode->i_dentry); | 444 | INIT_LIST_HEAD(&inode->i_dentry); |
450 | kmem_cache_free(squashfs_inode_cachep, squashfs_i(inode)); | 445 | kmem_cache_free(squashfs_inode_cachep, squashfs_i(inode)); |
451 | } | 446 | } |
452 | 447 | ||
453 | static void squashfs_destroy_inode(struct inode *inode) | 448 | static void squashfs_destroy_inode(struct inode *inode) |
454 | { | 449 | { |
455 | call_rcu(&inode->i_rcu, squashfs_i_callback); | 450 | call_rcu(&inode->i_rcu, squashfs_i_callback); |
456 | } | 451 | } |
457 | 452 | ||
458 | 453 | ||
459 | static struct file_system_type squashfs_fs_type = { | 454 | static struct file_system_type squashfs_fs_type = { |
460 | .owner = THIS_MODULE, | 455 | .owner = THIS_MODULE, |
461 | .name = "squashfs", | 456 | .name = "squashfs", |
462 | .mount = squashfs_mount, | 457 | .mount = squashfs_mount, |
463 | .kill_sb = kill_block_super, | 458 | .kill_sb = kill_block_super, |
464 | .fs_flags = FS_REQUIRES_DEV | 459 | .fs_flags = FS_REQUIRES_DEV |
465 | }; | 460 | }; |
466 | 461 | ||
467 | static const struct super_operations squashfs_super_ops = { | 462 | static const struct super_operations squashfs_super_ops = { |
468 | .alloc_inode = squashfs_alloc_inode, | 463 | .alloc_inode = squashfs_alloc_inode, |
469 | .destroy_inode = squashfs_destroy_inode, | 464 | .destroy_inode = squashfs_destroy_inode, |
470 | .statfs = squashfs_statfs, | 465 | .statfs = squashfs_statfs, |
471 | .put_super = squashfs_put_super, | 466 | .put_super = squashfs_put_super, |
472 | .remount_fs = squashfs_remount | 467 | .remount_fs = squashfs_remount |
473 | }; | 468 | }; |
474 | 469 |
fs/squashfs/xattr_id.c
1 | /* | 1 | /* |
2 | * Squashfs - a compressed read only filesystem for Linux | 2 | * Squashfs - a compressed read only filesystem for Linux |
3 | * | 3 | * |
4 | * Copyright (c) 2010 | 4 | * Copyright (c) 2010 |
5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | 5 | * Phillip Lougher <phillip@lougher.demon.co.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License | 8 | * modify it under the terms of the GNU General Public License |
9 | * as published by the Free Software Foundation; either version 2, | 9 | * as published by the Free Software Foundation; either version 2, |
10 | * or (at your option) any later version. | 10 | * or (at your option) any later version. |
11 | * | 11 | * |
12 | * This program is distributed in the hope that it will be useful, | 12 | * This program is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
16 | * | 16 | * |
17 | * You should have received a copy of the GNU General Public License | 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 | 18 | * along with this program; if not, write to the Free Software |
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
20 | * | 20 | * |
21 | * xattr_id.c | 21 | * xattr_id.c |
22 | */ | 22 | */ |
23 | 23 | ||
24 | /* | 24 | /* |
25 | * This file implements code to map the 32-bit xattr id stored in the inode | 25 | * This file implements code to map the 32-bit xattr id stored in the inode |
26 | * into the on disk location of the xattr data. | 26 | * into the on disk location of the xattr data. |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/fs.h> | 29 | #include <linux/fs.h> |
30 | #include <linux/vfs.h> | 30 | #include <linux/vfs.h> |
31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
32 | 32 | ||
33 | #include "squashfs_fs.h" | 33 | #include "squashfs_fs.h" |
34 | #include "squashfs_fs_sb.h" | 34 | #include "squashfs_fs_sb.h" |
35 | #include "squashfs.h" | 35 | #include "squashfs.h" |
36 | #include "xattr.h" | 36 | #include "xattr.h" |
37 | 37 | ||
38 | /* | 38 | /* |
39 | * Map xattr id using the xattr id look up table | 39 | * Map xattr id using the xattr id look up table |
40 | */ | 40 | */ |
41 | int squashfs_xattr_lookup(struct super_block *sb, unsigned int index, | 41 | int squashfs_xattr_lookup(struct super_block *sb, unsigned int index, |
42 | int *count, unsigned int *size, unsigned long long *xattr) | 42 | int *count, unsigned int *size, unsigned long long *xattr) |
43 | { | 43 | { |
44 | struct squashfs_sb_info *msblk = sb->s_fs_info; | 44 | struct squashfs_sb_info *msblk = sb->s_fs_info; |
45 | int block = SQUASHFS_XATTR_BLOCK(index); | 45 | int block = SQUASHFS_XATTR_BLOCK(index); |
46 | int offset = SQUASHFS_XATTR_BLOCK_OFFSET(index); | 46 | int offset = SQUASHFS_XATTR_BLOCK_OFFSET(index); |
47 | u64 start_block = le64_to_cpu(msblk->xattr_id_table[block]); | 47 | u64 start_block = le64_to_cpu(msblk->xattr_id_table[block]); |
48 | struct squashfs_xattr_id id; | 48 | struct squashfs_xattr_id id; |
49 | int err; | 49 | int err; |
50 | 50 | ||
51 | err = squashfs_read_metadata(sb, &id, &start_block, &offset, | 51 | err = squashfs_read_metadata(sb, &id, &start_block, &offset, |
52 | sizeof(id)); | 52 | sizeof(id)); |
53 | if (err < 0) | 53 | if (err < 0) |
54 | return err; | 54 | return err; |
55 | 55 | ||
56 | *xattr = le64_to_cpu(id.xattr); | 56 | *xattr = le64_to_cpu(id.xattr); |
57 | *size = le32_to_cpu(id.size); | 57 | *size = le32_to_cpu(id.size); |
58 | *count = le32_to_cpu(id.count); | 58 | *count = le32_to_cpu(id.count); |
59 | return 0; | 59 | return 0; |
60 | } | 60 | } |
61 | 61 | ||
62 | 62 | ||
63 | /* | 63 | /* |
64 | * Read uncompressed xattr id lookup table indexes from disk into memory | 64 | * Read uncompressed xattr id lookup table indexes from disk into memory |
65 | */ | 65 | */ |
66 | __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start, | 66 | __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start, |
67 | u64 *xattr_table_start, int *xattr_ids) | 67 | u64 *xattr_table_start, int *xattr_ids) |
68 | { | 68 | { |
69 | unsigned int len; | 69 | unsigned int len; |
70 | __le64 *xid_table; | 70 | struct squashfs_xattr_id_table *id_table; |
71 | struct squashfs_xattr_id_table id_table; | ||
72 | int err; | ||
73 | 71 | ||
74 | err = squashfs_read_table(sb, &id_table, start, sizeof(id_table)); | 72 | id_table = squashfs_read_table(sb, start, sizeof(*id_table)); |
75 | if (err < 0) { | 73 | if (IS_ERR(id_table)) |
76 | ERROR("unable to read xattr id table\n"); | 74 | return (__le64 *) id_table; |
77 | return ERR_PTR(err); | 75 | |
78 | } | 76 | *xattr_table_start = le64_to_cpu(id_table->xattr_table_start); |
79 | *xattr_table_start = le64_to_cpu(id_table.xattr_table_start); | 77 | *xattr_ids = le32_to_cpu(id_table->xattr_ids); |
80 | *xattr_ids = le32_to_cpu(id_table.xattr_ids); | 78 | kfree(id_table); |
81 | len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids); | 79 | len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids); |
82 | 80 | ||
83 | TRACE("In read_xattr_index_table, length %d\n", len); | 81 | TRACE("In read_xattr_index_table, length %d\n", len); |
84 | 82 | ||
85 | /* Allocate xattr id lookup table indexes */ | 83 | return squashfs_read_table(sb, start + sizeof(*id_table), len); |
86 | xid_table = kmalloc(len, GFP_KERNEL); | ||
87 | if (xid_table == NULL) { | ||
88 | ERROR("Failed to allocate xattr id index table\n"); | ||
89 | return ERR_PTR(-ENOMEM); | ||
90 | } | ||
91 | |||
92 | err = squashfs_read_table(sb, xid_table, start + sizeof(id_table), len); | ||
93 | if (err < 0) { | ||
94 | ERROR("unable to read xattr id index table\n"); | ||
95 | kfree(xid_table); | ||
96 | return ERR_PTR(err); | ||
97 | } | ||
98 | |||
99 | return xid_table; | ||
100 | } | 84 | } |
101 | 85 |