OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [isofs/] [compress.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* -*- linux-c -*- ------------------------------------------------------- *
2
 *
3
 *   Copyright 2001 H. Peter Anvin - All Rights Reserved
4
 *
5
 *   This program is free software; you can redistribute it and/or modify
6
 *   it under the terms of the GNU General Public License as published by
7
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
8
 *   USA; either version 2 of the License, or (at your option) any later
9
 *   version; incorporated herein by reference.
10
 *
11
 * ----------------------------------------------------------------------- */
12
 
13
/*
14
 * linux/fs/isofs/compress.c
15
 *
16
 * Transparent decompression of files on an iso9660 filesystem
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
/* This should probably be global. */
48
static char zisofs_sink_page[PAGE_CACHE_SIZE];
49
 
50
/*
51
 * This contains the zlib memory allocation and the mutex for the
52
 * allocation; this avoids failures at block-decompression time.
53
 */
54
static void *zisofs_zlib_workspace;
55
static struct semaphore zisofs_zlib_semaphore;
56
 
57
/*
58
 * When decompressing, we typically obtain more than one page
59
 * per reference.  We inject the additional pages into the page
60
 * cache as a form of readahead.
61
 */
62
static 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
        /* unsigned long zisofs_block_size = 1UL << zisofs_block_shift; */
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
        /* We have already been given one page, this is the one
86
           we must do. */
87
        xpage = index & zisofs_block_page_mask;
88
        pages[xpage] = page;
89
 
90
        /* The remaining pages need to be allocated and inserted */
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
        /* This is the last page filled, plus one; used in case of abort. */
108
        fpage = 0;
109
 
110
        /* Find the pointer to this specific chunk */
111
        /* Note: we're not using isonum_731() here because the data is known aligned */
112
        /* Note: header_size is in 32-bit words (4 bytes) */
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
                /* We just crossed a block boundary.  Switch to the next block */
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
        /* Now page[] contains an array of pages, any of which can be NULL,
153
           and the locks on which we hold.  We should now read the data and
154
           release the pages.  If the pages are NULL the decompressed data
155
           for that particular page should be discarded. */
156
 
157
        if ( csize == 0 ) {
158
                /* This data block is empty. */
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; /* The critical page */
170
                                else
171
                                        page_cache_release(page);
172
                        }
173
                }
174
        } else {
175
                /* This data block is compressed. */
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
                /* Because zlib is not thread-safe, do all the I/O at the top. */
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
                /* First block is special since it may be fractional.
195
                   We also wait for it before grabbing the zlib
196
                   semaphore; odds are that the subsequent blocks are
197
                   going to come in in short order so we don't hold
198
                   the zlib semaphore longer than necessary. */
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
                                                        /* Reached an EIO */
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
                                        /* EOF, error, or trying to read beyond end of input */
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
                                /* Fractional page written before EOF.  This may
274
                                   be the last page in the file. */
275
                                memset(stream.next_out, 0, stream.avail_out);
276
                                stream.avail_out = 0;
277
                        }
278
 
279
                        if ( !stream.avail_out ) {
280
                                /* This page completed */
281
                                if ( page ) {
282
                                        flush_dcache_page(page);
283
                                        SetPageUptodate(page);
284
                                        kunmap(page);
285
                                        UnlockPage(page);
286
                                        if ( fpage == xpage )
287
                                                err = 0; /* The critical page */
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
 
306
eio:
307
 
308
        /* Release any residual pages, do not SetPageUptodate */
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
        /* At this point, err contains 0 or -EIO depending on the "critical" page */
324
        return err;
325
}
326
 
327
struct address_space_operations zisofs_aops = {
328
        readpage: zisofs_readpage,
329
        /* No sync_page operation supported? */
330
        /* No bmap operation supported */
331
};
332
 
333
static int initialized = 0;
334
 
335
int __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
 
351
void __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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.