1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <linux/config.h>
20#include <linux/module.h>
21
22#include <linux/stat.h>
23#include <linux/sched.h>
24#include <linux/iso_fs.h>
25#include <linux/kernel.h>
26#include <linux/major.h>
27#include <linux/mm.h>
28#include <linux/string.h>
29#include <linux/locks.h>
30#include <linux/slab.h>
31#include <linux/errno.h>
32#include <linux/cdrom.h>
33#include <linux/init.h>
34#include <linux/nls.h>
35#include <linux/ctype.h>
36#include <linux/smp_lock.h>
37#include <linux/blkdev.h>
38#include <linux/vmalloc.h>
39#include <linux/zlib.h>
40
41#include <asm/system.h>
42#include <asm/uaccess.h>
43#include <asm/semaphore.h>
44
45#include "zisofs.h"
46
47
48static char zisofs_sink_page[PAGE_CACHE_SIZE];
49
50
51
52
53
54static void *zisofs_zlib_workspace;
55static struct semaphore zisofs_zlib_semaphore;
56
57
58
59
60
61
62static int zisofs_readpage(struct file *file, struct page *page)
63{
64 struct inode *inode = file->f_dentry->d_inode;
65 struct address_space *mapping = inode->i_mapping;
66 unsigned int maxpage, xpage, fpage, blockindex;
67 unsigned long offset;
68 unsigned long blockptr, blockendptr, cstart, cend, csize;
69 struct buffer_head *bh, *ptrbh[2];
70 unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
71 unsigned int bufshift = ISOFS_BUFFER_BITS(inode);
72 unsigned long bufmask = bufsize - 1;
73 int err = -EIO;
74 int i;
75 unsigned int header_size = inode->u.isofs_i.i_format_parm[0];
76 unsigned int zisofs_block_shift = inode->u.isofs_i.i_format_parm[1];
77
78 unsigned int zisofs_block_page_shift = zisofs_block_shift-PAGE_CACHE_SHIFT;
79 unsigned long zisofs_block_pages = 1UL << zisofs_block_page_shift;
80 unsigned long zisofs_block_page_mask = zisofs_block_pages-1;
81 struct page *pages[zisofs_block_pages];
82 unsigned long index = page->index;
83 int indexblocks;
84
85
86
87 xpage = index & zisofs_block_page_mask;
88 pages[xpage] = page;
89
90
91 offset = index & ~zisofs_block_page_mask;
92 blockindex = offset >> zisofs_block_page_shift;
93 maxpage = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
94 maxpage = min(zisofs_block_pages, maxpage-offset);
95
96 for ( i = 0 ; i < maxpage ; i++, offset++ ) {
97 if ( i != xpage ) {
98 pages[i] = grab_cache_page_nowait(mapping, offset);
99 }
100 page = pages[i];
101 if ( page ) {
102 ClearPageError(page);
103 kmap(page);
104 }
105 }
106
107
108 fpage = 0;
109
110
111
112
113 blockptr = (header_size + blockindex) << 2;
114 blockendptr = blockptr + 4;
115
116 indexblocks = ((blockptr^blockendptr) >> bufshift) ? 2 : 1;
117 ptrbh[0] = ptrbh[1] = 0;
118
119 if ( isofs_get_blocks(inode, blockptr >> bufshift, ptrbh, indexblocks) != indexblocks ) {
120 if ( ptrbh[0] ) brelse(ptrbh[0]);
121 printk(KERN_DEBUG "zisofs: Null buffer on reading block table, inode = %lu, block = %lu\n",
122 inode->i_ino, blockptr >> bufshift);
123 goto eio;
124 }
125 ll_rw_block(READ, indexblocks, ptrbh);
126
127 bh = ptrbh[0];
128 if ( !bh || (wait_on_buffer(bh), !buffer_uptodate(bh)) ) {
129 printk(KERN_DEBUG "zisofs: Failed to read block table, inode = %lu, block = %lu\n",
130 inode->i_ino, blockptr >> bufshift);
131 if ( ptrbh[1] )
132 brelse(ptrbh[1]);
133 goto eio;
134 }
135 cstart = le32_to_cpu(*(u32 *)(bh->b_data + (blockptr & bufmask)));
136
137 if ( indexblocks == 2 ) {
138
139 brelse(bh);
140 bh = ptrbh[1];
141 if ( !bh || (wait_on_buffer(bh), !buffer_uptodate(bh)) ) {
142 printk(KERN_DEBUG "zisofs: Failed to read block table, inode = %lu, block = %lu\n",
143 inode->i_ino, blockendptr >> bufshift);
144 goto eio;
145 }
146 }
147 cend = le32_to_cpu(*(u32 *)(bh->b_data + (blockendptr & bufmask)));
148 brelse(bh);
149
150 csize = cend-cstart;
151
152
153
154
155
156
157 if ( csize == 0 ) {
158
159
160 for ( fpage = 0 ; fpage < maxpage ; fpage++ ) {
161 if ( (page = pages[fpage]) != NULL ) {
162 memset(page_address(page), 0, PAGE_CACHE_SIZE);
163
164 flush_dcache_page(page);
165 SetPageUptodate(page);
166 kunmap(page);
167 UnlockPage(page);
168 if ( fpage == xpage )
169 err = 0;
170 else
171 page_cache_release(page);
172 }
173 }
174 } else {
175
176 z_stream stream;
177 int bail = 0, left_out = -1;
178 int zerr;
179 int needblocks = (csize + (cstart & bufmask) + bufmask) >> bufshift;
180 int haveblocks;
181 struct buffer_head *bhs[needblocks+1];
182 struct buffer_head **bhptr;
183
184
185
186 blockptr = cstart >> bufshift;
187 memset(bhs, 0, (needblocks+1)*sizeof(struct buffer_head *));
188 haveblocks = isofs_get_blocks(inode, blockptr, bhs, needblocks);
189 ll_rw_block(READ, haveblocks, bhs);
190
191 bhptr = &bhs[0];
192 bh = *bhptr++;
193
194
195
196
197
198
199
200 if ( !bh || (wait_on_buffer(bh), !buffer_uptodate(bh)) ) {
201 printk(KERN_DEBUG "zisofs: Hit null buffer, fpage = %d, xpage = %d, csize = %ld\n",
202 fpage, xpage, csize);
203 goto b_eio;
204 }
205 stream.next_in = bh->b_data + (cstart & bufmask);
206 stream.avail_in = min(bufsize-(cstart & bufmask), csize);
207 csize -= stream.avail_in;
208
209 stream.workspace = zisofs_zlib_workspace;
210 down(&zisofs_zlib_semaphore);
211
212 zerr = zlib_inflateInit(&stream);
213 if ( zerr != Z_OK ) {
214 if ( err && zerr == Z_MEM_ERROR )
215 err = -ENOMEM;
216 printk(KERN_DEBUG "zisofs: zisofs_inflateInit returned %d\n",
217 zerr);
218 goto z_eio;
219 }
220
221 while ( !bail && fpage < maxpage ) {
222 page = pages[fpage];
223 if ( page )
224 stream.next_out = page_address(page);
225 else
226 stream.next_out = (void *)&zisofs_sink_page;
227 stream.avail_out = PAGE_CACHE_SIZE;
228
229 while ( stream.avail_out ) {
230 int ao, ai;
231 if ( stream.avail_in == 0 && left_out ) {
232 if ( !csize ) {
233 printk(KERN_WARNING "zisofs: ZF read beyond end of input\n");
234 bail = 1;
235 break;
236 } else {
237 bh = *bhptr++;
238 if ( !bh ||
239 (wait_on_buffer(bh), !buffer_uptodate(bh)) ) {
240
241 printk(KERN_DEBUG "zisofs: Hit null buffer, fpage = %d, xpage = %d, csize = %ld\n",
242 fpage, xpage, csize);
243
244 bail = 1;
245 break;
246 }
247 stream.next_in = bh->b_data;
248 stream.avail_in = min(csize,bufsize);
249 csize -= stream.avail_in;
250 }
251 }
252 ao = stream.avail_out; ai = stream.avail_in;
253 zerr = zlib_inflate(&stream, Z_SYNC_FLUSH);
254 left_out = stream.avail_out;
255 if ( zerr == Z_BUF_ERROR && stream.avail_in == 0 )
256 continue;
257 if ( zerr != Z_OK ) {
258
259 if ( err && zerr == Z_MEM_ERROR )
260 err = -ENOMEM;
261 if ( zerr != Z_STREAM_END )
262 printk(KERN_DEBUG "zisofs: zisofs_inflate returned %d, inode = %lu, index = %lu, fpage = %d, xpage = %d, avail_in = %d, avail_out = %d, ai = %d, ao = %d\n",
263 zerr, inode->i_ino, index,
264 fpage, xpage,
265 stream.avail_in, stream.avail_out,
266 ai, ao);
267 bail = 1;
268 break;
269 }
270 }
271
272 if ( stream.avail_out && zerr == Z_STREAM_END ) {
273
274
275 memset(stream.next_out, 0, stream.avail_out);
276 stream.avail_out = 0;
277 }
278
279 if ( !stream.avail_out ) {
280
281 if ( page ) {
282 flush_dcache_page(page);
283 SetPageUptodate(page);
284 kunmap(page);
285 UnlockPage(page);
286 if ( fpage == xpage )
287 err = 0;
288 else
289 page_cache_release(page);
290 }
291 fpage++;
292 }
293 }
294 zlib_inflateEnd(&stream);
295
296 z_eio:
297 up(&zisofs_zlib_semaphore);
298
299 b_eio:
300 for ( i = 0 ; i < haveblocks ; i++ ) {
301 if ( bhs[i] )
302 brelse(bhs[i]);
303 }
304 }
305
306eio:
307
308
309 while ( fpage < maxpage ) {
310 page = pages[fpage];
311 if ( page ) {
312 flush_dcache_page(page);
313 if ( fpage == xpage )
314 SetPageError(page);
315 kunmap(page);
316 UnlockPage(page);
317 if ( fpage != xpage )
318 page_cache_release(page);
319 }
320 fpage++;
321 }
322
323
324 return err;
325}
326
327struct address_space_operations zisofs_aops = {
328 readpage: zisofs_readpage,
329
330
331};
332
333static int initialized = 0;
334
335int __init zisofs_init(void)
336{
337 if ( initialized ) {
338 printk("zisofs_init: called more than once\n");
339 return 0;
340 }
341
342 zisofs_zlib_workspace = vmalloc(zlib_inflate_workspacesize());
343 if ( !zisofs_zlib_workspace )
344 return -ENOMEM;
345 init_MUTEX(&zisofs_zlib_semaphore);
346
347 initialized = 1;
348 return 0;
349}
350
351void __exit zisofs_cleanup(void)
352{
353 if ( !initialized ) {
354 printk("zisofs_cleanup: called without initialization\n");
355 return;
356 }
357
358 vfree(zisofs_zlib_workspace);
359 initialized = 0;
360}
361