root/fs/isofs/compress.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zisofs_uncompress_block
  2. zisofs_fill_pages
  3. zisofs_readpage
  4. zisofs_init
  5. zisofs_cleanup

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /* -*- linux-c -*- ------------------------------------------------------- *
   3  *   
   4  *   Copyright 2001 H. Peter Anvin - All Rights Reserved
   5  *
   6  * ----------------------------------------------------------------------- */
   7 
   8 /*
   9  * linux/fs/isofs/compress.c
  10  *
  11  * Transparent decompression of files on an iso9660 filesystem
  12  */
  13 
  14 #include <linux/module.h>
  15 #include <linux/init.h>
  16 #include <linux/bio.h>
  17 
  18 #include <linux/slab.h>
  19 #include <linux/vmalloc.h>
  20 #include <linux/zlib.h>
  21 
  22 #include "isofs.h"
  23 #include "zisofs.h"
  24 
  25 /* This should probably be global. */
  26 static char zisofs_sink_page[PAGE_SIZE];
  27 
  28 /*
  29  * This contains the zlib memory allocation and the mutex for the
  30  * allocation; this avoids failures at block-decompression time.
  31  */
  32 static void *zisofs_zlib_workspace;
  33 static DEFINE_MUTEX(zisofs_zlib_lock);
  34 
  35 /*
  36  * Read data of @inode from @block_start to @block_end and uncompress
  37  * to one zisofs block. Store the data in the @pages array with @pcount
  38  * entries. Start storing at offset @poffset of the first page.
  39  */
  40 static loff_t zisofs_uncompress_block(struct inode *inode, loff_t block_start,
  41                                       loff_t block_end, int pcount,
  42                                       struct page **pages, unsigned poffset,
  43                                       int *errp)
  44 {
  45         unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
  46         unsigned int bufsize = ISOFS_BUFFER_SIZE(inode);
  47         unsigned int bufshift = ISOFS_BUFFER_BITS(inode);
  48         unsigned int bufmask = bufsize - 1;
  49         int i, block_size = block_end - block_start;
  50         z_stream stream = { .total_out = 0,
  51                             .avail_in = 0,
  52                             .avail_out = 0, };
  53         int zerr;
  54         int needblocks = (block_size + (block_start & bufmask) + bufmask)
  55                                 >> bufshift;
  56         int haveblocks;
  57         blkcnt_t blocknum;
  58         struct buffer_head **bhs;
  59         int curbh, curpage;
  60 
  61         if (block_size > deflateBound(1UL << zisofs_block_shift)) {
  62                 *errp = -EIO;
  63                 return 0;
  64         }
  65         /* Empty block? */
  66         if (block_size == 0) {
  67                 for ( i = 0 ; i < pcount ; i++ ) {
  68                         if (!pages[i])
  69                                 continue;
  70                         memset(page_address(pages[i]), 0, PAGE_SIZE);
  71                         flush_dcache_page(pages[i]);
  72                         SetPageUptodate(pages[i]);
  73                 }
  74                 return ((loff_t)pcount) << PAGE_SHIFT;
  75         }
  76 
  77         /* Because zlib is not thread-safe, do all the I/O at the top. */
  78         blocknum = block_start >> bufshift;
  79         bhs = kcalloc(needblocks + 1, sizeof(*bhs), GFP_KERNEL);
  80         if (!bhs) {
  81                 *errp = -ENOMEM;
  82                 return 0;
  83         }
  84         haveblocks = isofs_get_blocks(inode, blocknum, bhs, needblocks);
  85         ll_rw_block(REQ_OP_READ, 0, haveblocks, bhs);
  86 
  87         curbh = 0;
  88         curpage = 0;
  89         /*
  90          * First block is special since it may be fractional.  We also wait for
  91          * it before grabbing the zlib mutex; odds are that the subsequent
  92          * blocks are going to come in in short order so we don't hold the zlib
  93          * mutex longer than necessary.
  94          */
  95 
  96         if (!bhs[0])
  97                 goto b_eio;
  98 
  99         wait_on_buffer(bhs[0]);
 100         if (!buffer_uptodate(bhs[0])) {
 101                 *errp = -EIO;
 102                 goto b_eio;
 103         }
 104 
 105         stream.workspace = zisofs_zlib_workspace;
 106         mutex_lock(&zisofs_zlib_lock);
 107                 
 108         zerr = zlib_inflateInit(&stream);
 109         if (zerr != Z_OK) {
 110                 if (zerr == Z_MEM_ERROR)
 111                         *errp = -ENOMEM;
 112                 else
 113                         *errp = -EIO;
 114                 printk(KERN_DEBUG "zisofs: zisofs_inflateInit returned %d\n",
 115                                zerr);
 116                 goto z_eio;
 117         }
 118 
 119         while (curpage < pcount && curbh < haveblocks &&
 120                zerr != Z_STREAM_END) {
 121                 if (!stream.avail_out) {
 122                         if (pages[curpage]) {
 123                                 stream.next_out = page_address(pages[curpage])
 124                                                 + poffset;
 125                                 stream.avail_out = PAGE_SIZE - poffset;
 126                                 poffset = 0;
 127                         } else {
 128                                 stream.next_out = (void *)&zisofs_sink_page;
 129                                 stream.avail_out = PAGE_SIZE;
 130                         }
 131                 }
 132                 if (!stream.avail_in) {
 133                         wait_on_buffer(bhs[curbh]);
 134                         if (!buffer_uptodate(bhs[curbh])) {
 135                                 *errp = -EIO;
 136                                 break;
 137                         }
 138                         stream.next_in  = bhs[curbh]->b_data +
 139                                                 (block_start & bufmask);
 140                         stream.avail_in = min_t(unsigned, bufsize -
 141                                                 (block_start & bufmask),
 142                                                 block_size);
 143                         block_size -= stream.avail_in;
 144                         block_start = 0;
 145                 }
 146 
 147                 while (stream.avail_out && stream.avail_in) {
 148                         zerr = zlib_inflate(&stream, Z_SYNC_FLUSH);
 149                         if (zerr == Z_BUF_ERROR && stream.avail_in == 0)
 150                                 break;
 151                         if (zerr == Z_STREAM_END)
 152                                 break;
 153                         if (zerr != Z_OK) {
 154                                 /* EOF, error, or trying to read beyond end of input */
 155                                 if (zerr == Z_MEM_ERROR)
 156                                         *errp = -ENOMEM;
 157                                 else {
 158                                         printk(KERN_DEBUG
 159                                                "zisofs: zisofs_inflate returned"
 160                                                " %d, inode = %lu,"
 161                                                " page idx = %d, bh idx = %d,"
 162                                                " avail_in = %ld,"
 163                                                " avail_out = %ld\n",
 164                                                zerr, inode->i_ino, curpage,
 165                                                curbh, stream.avail_in,
 166                                                stream.avail_out);
 167                                         *errp = -EIO;
 168                                 }
 169                                 goto inflate_out;
 170                         }
 171                 }
 172 
 173                 if (!stream.avail_out) {
 174                         /* This page completed */
 175                         if (pages[curpage]) {
 176                                 flush_dcache_page(pages[curpage]);
 177                                 SetPageUptodate(pages[curpage]);
 178                         }
 179                         curpage++;
 180                 }
 181                 if (!stream.avail_in)
 182                         curbh++;
 183         }
 184 inflate_out:
 185         zlib_inflateEnd(&stream);
 186 
 187 z_eio:
 188         mutex_unlock(&zisofs_zlib_lock);
 189 
 190 b_eio:
 191         for (i = 0; i < haveblocks; i++)
 192                 brelse(bhs[i]);
 193         kfree(bhs);
 194         return stream.total_out;
 195 }
 196 
 197 /*
 198  * Uncompress data so that pages[full_page] is fully uptodate and possibly
 199  * fills in other pages if we have data for them.
 200  */
 201 static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
 202                              struct page **pages)
 203 {
 204         loff_t start_off, end_off;
 205         loff_t block_start, block_end;
 206         unsigned int header_size = ISOFS_I(inode)->i_format_parm[0];
 207         unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
 208         unsigned int blockptr;
 209         loff_t poffset = 0;
 210         blkcnt_t cstart_block, cend_block;
 211         struct buffer_head *bh;
 212         unsigned int blkbits = ISOFS_BUFFER_BITS(inode);
 213         unsigned int blksize = 1 << blkbits;
 214         int err;
 215         loff_t ret;
 216 
 217         BUG_ON(!pages[full_page]);
 218 
 219         /*
 220          * We want to read at least 'full_page' page. Because we have to
 221          * uncompress the whole compression block anyway, fill the surrounding
 222          * pages with the data we have anyway...
 223          */
 224         start_off = page_offset(pages[full_page]);
 225         end_off = min_t(loff_t, start_off + PAGE_SIZE, inode->i_size);
 226 
 227         cstart_block = start_off >> zisofs_block_shift;
 228         cend_block = (end_off + (1 << zisofs_block_shift) - 1)
 229                         >> zisofs_block_shift;
 230 
 231         WARN_ON(start_off - (full_page << PAGE_SHIFT) !=
 232                 ((cstart_block << zisofs_block_shift) & PAGE_MASK));
 233 
 234         /* Find the pointer to this specific chunk */
 235         /* Note: we're not using isonum_731() here because the data is known aligned */
 236         /* Note: header_size is in 32-bit words (4 bytes) */
 237         blockptr = (header_size + cstart_block) << 2;
 238         bh = isofs_bread(inode, blockptr >> blkbits);
 239         if (!bh)
 240                 return -EIO;
 241         block_start = le32_to_cpu(*(__le32 *)
 242                                 (bh->b_data + (blockptr & (blksize - 1))));
 243 
 244         while (cstart_block < cend_block && pcount > 0) {
 245                 /* Load end of the compressed block in the file */
 246                 blockptr += 4;
 247                 /* Traversed to next block? */
 248                 if (!(blockptr & (blksize - 1))) {
 249                         brelse(bh);
 250 
 251                         bh = isofs_bread(inode, blockptr >> blkbits);
 252                         if (!bh)
 253                                 return -EIO;
 254                 }
 255                 block_end = le32_to_cpu(*(__le32 *)
 256                                 (bh->b_data + (blockptr & (blksize - 1))));
 257                 if (block_start > block_end) {
 258                         brelse(bh);
 259                         return -EIO;
 260                 }
 261                 err = 0;
 262                 ret = zisofs_uncompress_block(inode, block_start, block_end,
 263                                               pcount, pages, poffset, &err);
 264                 poffset += ret;
 265                 pages += poffset >> PAGE_SHIFT;
 266                 pcount -= poffset >> PAGE_SHIFT;
 267                 full_page -= poffset >> PAGE_SHIFT;
 268                 poffset &= ~PAGE_MASK;
 269 
 270                 if (err) {
 271                         brelse(bh);
 272                         /*
 273                          * Did we finish reading the page we really wanted
 274                          * to read?
 275                          */
 276                         if (full_page < 0)
 277                                 return 0;
 278                         return err;
 279                 }
 280 
 281                 block_start = block_end;
 282                 cstart_block++;
 283         }
 284 
 285         if (poffset && *pages) {
 286                 memset(page_address(*pages) + poffset, 0,
 287                        PAGE_SIZE - poffset);
 288                 flush_dcache_page(*pages);
 289                 SetPageUptodate(*pages);
 290         }
 291         return 0;
 292 }
 293 
 294 /*
 295  * When decompressing, we typically obtain more than one page
 296  * per reference.  We inject the additional pages into the page
 297  * cache as a form of readahead.
 298  */
 299 static int zisofs_readpage(struct file *file, struct page *page)
 300 {
 301         struct inode *inode = file_inode(file);
 302         struct address_space *mapping = inode->i_mapping;
 303         int err;
 304         int i, pcount, full_page;
 305         unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
 306         unsigned int zisofs_pages_per_cblock =
 307                 PAGE_SHIFT <= zisofs_block_shift ?
 308                 (1 << (zisofs_block_shift - PAGE_SHIFT)) : 0;
 309         struct page **pages;
 310         pgoff_t index = page->index, end_index;
 311 
 312         end_index = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 313         /*
 314          * If this page is wholly outside i_size we just return zero;
 315          * do_generic_file_read() will handle this for us
 316          */
 317         if (index >= end_index) {
 318                 SetPageUptodate(page);
 319                 unlock_page(page);
 320                 return 0;
 321         }
 322 
 323         if (PAGE_SHIFT <= zisofs_block_shift) {
 324                 /* We have already been given one page, this is the one
 325                    we must do. */
 326                 full_page = index & (zisofs_pages_per_cblock - 1);
 327                 pcount = min_t(int, zisofs_pages_per_cblock,
 328                         end_index - (index & ~(zisofs_pages_per_cblock - 1)));
 329                 index -= full_page;
 330         } else {
 331                 full_page = 0;
 332                 pcount = 1;
 333         }
 334         pages = kcalloc(max_t(unsigned int, zisofs_pages_per_cblock, 1),
 335                                         sizeof(*pages), GFP_KERNEL);
 336         if (!pages) {
 337                 unlock_page(page);
 338                 return -ENOMEM;
 339         }
 340         pages[full_page] = page;
 341 
 342         for (i = 0; i < pcount; i++, index++) {
 343                 if (i != full_page)
 344                         pages[i] = grab_cache_page_nowait(mapping, index);
 345                 if (pages[i]) {
 346                         ClearPageError(pages[i]);
 347                         kmap(pages[i]);
 348                 }
 349         }
 350 
 351         err = zisofs_fill_pages(inode, full_page, pcount, pages);
 352 
 353         /* Release any residual pages, do not SetPageUptodate */
 354         for (i = 0; i < pcount; i++) {
 355                 if (pages[i]) {
 356                         flush_dcache_page(pages[i]);
 357                         if (i == full_page && err)
 358                                 SetPageError(pages[i]);
 359                         kunmap(pages[i]);
 360                         unlock_page(pages[i]);
 361                         if (i != full_page)
 362                                 put_page(pages[i]);
 363                 }
 364         }                       
 365 
 366         /* At this point, err contains 0 or -EIO depending on the "critical" page */
 367         kfree(pages);
 368         return err;
 369 }
 370 
 371 const struct address_space_operations zisofs_aops = {
 372         .readpage = zisofs_readpage,
 373         /* No bmap operation supported */
 374 };
 375 
 376 int __init zisofs_init(void)
 377 {
 378         zisofs_zlib_workspace = vmalloc(zlib_inflate_workspacesize());
 379         if ( !zisofs_zlib_workspace )
 380                 return -ENOMEM;
 381 
 382         return 0;
 383 }
 384 
 385 void zisofs_cleanup(void)
 386 {
 387         vfree(zisofs_zlib_workspace);
 388 }

/* [<][>][^][v][top][bottom][index][help] */