LCOV - code coverage report
Current view: top level - fs/isofs - compress.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 3 194 1.5 %
Date: 2022-03-28 13:20:08 Functions: 1 5 20.0 %
Branches: 1 122 0.8 %

           Branch data     Line data    Source code
       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                 :          0 : 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         [ #  # ]:          0 :         unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
      46                 :          0 :         unsigned int bufsize = ISOFS_BUFFER_SIZE(inode);
      47                 :          0 :         unsigned int bufshift = ISOFS_BUFFER_BITS(inode);
      48                 :          0 :         unsigned int bufmask = bufsize - 1;
      49                 :          0 :         int i, block_size = block_end - block_start;
      50                 :          0 :         z_stream stream = { .total_out = 0,
      51                 :            :                             .avail_in = 0,
      52                 :            :                             .avail_out = 0, };
      53                 :          0 :         int zerr;
      54                 :          0 :         int needblocks = (block_size + (block_start & bufmask) + bufmask)
      55                 :          0 :                                 >> bufshift;
      56                 :          0 :         int haveblocks;
      57                 :          0 :         blkcnt_t blocknum;
      58                 :          0 :         struct buffer_head **bhs;
      59                 :          0 :         int curbh, curpage;
      60                 :            : 
      61         [ #  # ]:          0 :         if (block_size > deflateBound(1UL << zisofs_block_shift)) {
      62                 :          0 :                 *errp = -EIO;
      63                 :          0 :                 return 0;
      64                 :            :         }
      65                 :            :         /* Empty block? */
      66         [ #  # ]:          0 :         if (block_size == 0) {
      67         [ #  # ]:          0 :                 for ( i = 0 ; i < pcount ; i++ ) {
      68         [ #  # ]:          0 :                         if (!pages[i])
      69                 :          0 :                                 continue;
      70                 :          0 :                         memset(page_address(pages[i]), 0, PAGE_SIZE);
      71                 :          0 :                         flush_dcache_page(pages[i]);
      72                 :          0 :                         SetPageUptodate(pages[i]);
      73                 :            :                 }
      74                 :          0 :                 return ((loff_t)pcount) << PAGE_SHIFT;
      75                 :            :         }
      76                 :            : 
      77                 :            :         /* Because zlib is not thread-safe, do all the I/O at the top. */
      78                 :          0 :         blocknum = block_start >> bufshift;
      79                 :          0 :         bhs = kcalloc(needblocks + 1, sizeof(*bhs), GFP_KERNEL);
      80         [ #  # ]:          0 :         if (!bhs) {
      81                 :          0 :                 *errp = -ENOMEM;
      82                 :          0 :                 return 0;
      83                 :            :         }
      84                 :          0 :         haveblocks = isofs_get_blocks(inode, blocknum, bhs, needblocks);
      85                 :          0 :         ll_rw_block(REQ_OP_READ, 0, haveblocks, bhs);
      86                 :            : 
      87                 :          0 :         curbh = 0;
      88                 :          0 :         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         [ #  # ]:          0 :         if (!bhs[0])
      97                 :          0 :                 goto b_eio;
      98                 :            : 
      99                 :          0 :         wait_on_buffer(bhs[0]);
     100         [ #  # ]:          0 :         if (!buffer_uptodate(bhs[0])) {
     101                 :          0 :                 *errp = -EIO;
     102                 :          0 :                 goto b_eio;
     103                 :            :         }
     104                 :            : 
     105                 :          0 :         stream.workspace = zisofs_zlib_workspace;
     106                 :          0 :         mutex_lock(&zisofs_zlib_lock);
     107                 :            :                 
     108                 :          0 :         zerr = zlib_inflateInit(&stream);
     109         [ #  # ]:          0 :         if (zerr != Z_OK) {
     110         [ #  # ]:          0 :                 if (zerr == Z_MEM_ERROR)
     111                 :          0 :                         *errp = -ENOMEM;
     112                 :            :                 else
     113                 :          0 :                         *errp = -EIO;
     114                 :          0 :                 printk(KERN_DEBUG "zisofs: zisofs_inflateInit returned %d\n",
     115                 :            :                                zerr);
     116                 :          0 :                 goto z_eio;
     117                 :            :         }
     118                 :            : 
     119   [ #  #  #  # ]:          0 :         while (curpage < pcount && curbh < haveblocks &&
     120                 :            :                zerr != Z_STREAM_END) {
     121         [ #  # ]:          0 :                 if (!stream.avail_out) {
     122         [ #  # ]:          0 :                         if (pages[curpage]) {
     123                 :          0 :                                 stream.next_out = page_address(pages[curpage])
     124                 :          0 :                                                 + poffset;
     125                 :          0 :                                 stream.avail_out = PAGE_SIZE - poffset;
     126                 :          0 :                                 poffset = 0;
     127                 :            :                         } else {
     128                 :          0 :                                 stream.next_out = (void *)&zisofs_sink_page;
     129                 :          0 :                                 stream.avail_out = PAGE_SIZE;
     130                 :            :                         }
     131                 :            :                 }
     132         [ #  # ]:          0 :                 if (!stream.avail_in) {
     133                 :          0 :                         wait_on_buffer(bhs[curbh]);
     134         [ #  # ]:          0 :                         if (!buffer_uptodate(bhs[curbh])) {
     135                 :          0 :                                 *errp = -EIO;
     136                 :          0 :                                 break;
     137                 :            :                         }
     138                 :          0 :                         stream.next_in  = bhs[curbh]->b_data +
     139                 :          0 :                                                 (block_start & bufmask);
     140                 :          0 :                         stream.avail_in = min_t(unsigned, bufsize -
     141                 :            :                                                 (block_start & bufmask),
     142                 :            :                                                 block_size);
     143                 :          0 :                         block_size -= stream.avail_in;
     144                 :          0 :                         block_start = 0;
     145                 :            :                 }
     146                 :            : 
     147   [ #  #  #  # ]:          0 :                 while (stream.avail_out && stream.avail_in) {
     148                 :          0 :                         zerr = zlib_inflate(&stream, Z_SYNC_FLUSH);
     149   [ #  #  #  # ]:          0 :                         if (zerr == Z_BUF_ERROR && stream.avail_in == 0)
     150                 :            :                                 break;
     151         [ #  # ]:          0 :                         if (zerr == Z_STREAM_END)
     152                 :            :                                 break;
     153         [ #  # ]:          0 :                         if (zerr != Z_OK) {
     154                 :            :                                 /* EOF, error, or trying to read beyond end of input */
     155         [ #  # ]:          0 :                                 if (zerr == Z_MEM_ERROR)
     156                 :          0 :                                         *errp = -ENOMEM;
     157                 :            :                                 else {
     158                 :          0 :                                         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                 :          0 :                                         *errp = -EIO;
     168                 :            :                                 }
     169                 :          0 :                                 goto inflate_out;
     170                 :            :                         }
     171                 :            :                 }
     172                 :            : 
     173         [ #  # ]:          0 :                 if (!stream.avail_out) {
     174                 :            :                         /* This page completed */
     175         [ #  # ]:          0 :                         if (pages[curpage]) {
     176                 :          0 :                                 flush_dcache_page(pages[curpage]);
     177                 :          0 :                                 SetPageUptodate(pages[curpage]);
     178                 :            :                         }
     179                 :          0 :                         curpage++;
     180                 :            :                 }
     181         [ #  # ]:          0 :                 if (!stream.avail_in)
     182                 :          0 :                         curbh++;
     183                 :            :         }
     184                 :          0 : inflate_out:
     185                 :          0 :         zlib_inflateEnd(&stream);
     186                 :            : 
     187                 :          0 : z_eio:
     188                 :          0 :         mutex_unlock(&zisofs_zlib_lock);
     189                 :            : 
     190                 :            : b_eio:
     191         [ #  # ]:          0 :         for (i = 0; i < haveblocks; i++)
     192         [ #  # ]:          0 :                 brelse(bhs[i]);
     193                 :          0 :         kfree(bhs);
     194                 :          0 :         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                 :          0 : static int zisofs_fill_pages(struct inode *inode, int full_page, int pcount,
     202                 :            :                              struct page **pages)
     203                 :            : {
     204                 :          0 :         loff_t start_off, end_off;
     205                 :          0 :         loff_t block_start, block_end;
     206         [ #  # ]:          0 :         unsigned int header_size = ISOFS_I(inode)->i_format_parm[0];
     207                 :          0 :         unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
     208                 :          0 :         unsigned int blockptr;
     209                 :          0 :         loff_t poffset = 0;
     210                 :          0 :         blkcnt_t cstart_block, cend_block;
     211                 :          0 :         struct buffer_head *bh;
     212                 :          0 :         unsigned int blkbits = ISOFS_BUFFER_BITS(inode);
     213                 :          0 :         unsigned int blksize = 1 << blkbits;
     214                 :          0 :         int err;
     215                 :          0 :         loff_t ret;
     216                 :            : 
     217         [ #  # ]:          0 :         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         [ #  # ]:          0 :         start_off = page_offset(pages[full_page]);
     225                 :          0 :         end_off = min_t(loff_t, start_off + PAGE_SIZE, inode->i_size);
     226                 :            : 
     227                 :          0 :         cstart_block = start_off >> zisofs_block_shift;
     228                 :          0 :         cend_block = (end_off + (1 << zisofs_block_shift) - 1)
     229                 :          0 :                         >> zisofs_block_shift;
     230                 :            : 
     231         [ #  # ]:          0 :         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                 :          0 :         blockptr = (header_size + cstart_block) << 2;
     238                 :          0 :         bh = isofs_bread(inode, blockptr >> blkbits);
     239         [ #  # ]:          0 :         if (!bh)
     240                 :            :                 return -EIO;
     241                 :          0 :         block_start = le32_to_cpu(*(__le32 *)
     242                 :            :                                 (bh->b_data + (blockptr & (blksize - 1))));
     243                 :            : 
     244         [ #  # ]:          0 :         while (cstart_block < cend_block && pcount > 0) {
     245                 :            :                 /* Load end of the compressed block in the file */
     246                 :          0 :                 blockptr += 4;
     247                 :            :                 /* Traversed to next block? */
     248         [ #  # ]:          0 :                 if (!(blockptr & (blksize - 1))) {
     249         [ #  # ]:          0 :                         brelse(bh);
     250                 :            : 
     251                 :          0 :                         bh = isofs_bread(inode, blockptr >> blkbits);
     252         [ #  # ]:          0 :                         if (!bh)
     253                 :            :                                 return -EIO;
     254                 :            :                 }
     255                 :          0 :                 block_end = le32_to_cpu(*(__le32 *)
     256                 :            :                                 (bh->b_data + (blockptr & (blksize - 1))));
     257         [ #  # ]:          0 :                 if (block_start > block_end) {
     258         [ #  # ]:          0 :                         brelse(bh);
     259                 :          0 :                         return -EIO;
     260                 :            :                 }
     261                 :          0 :                 err = 0;
     262                 :          0 :                 ret = zisofs_uncompress_block(inode, block_start, block_end,
     263                 :            :                                               pcount, pages, poffset, &err);
     264                 :          0 :                 poffset += ret;
     265                 :          0 :                 pages += poffset >> PAGE_SHIFT;
     266                 :          0 :                 pcount -= poffset >> PAGE_SHIFT;
     267                 :          0 :                 full_page -= poffset >> PAGE_SHIFT;
     268                 :          0 :                 poffset &= ~PAGE_MASK;
     269                 :            : 
     270         [ #  # ]:          0 :                 if (err) {
     271         [ #  # ]:          0 :                         brelse(bh);
     272                 :            :                         /*
     273                 :            :                          * Did we finish reading the page we really wanted
     274                 :            :                          * to read?
     275                 :            :                          */
     276         [ #  # ]:          0 :                         if (full_page < 0)
     277                 :            :                                 return 0;
     278                 :          0 :                         return err;
     279                 :            :                 }
     280                 :            : 
     281                 :          0 :                 block_start = block_end;
     282                 :          0 :                 cstart_block++;
     283                 :            :         }
     284                 :            : 
     285   [ #  #  #  # ]:          0 :         if (poffset && *pages) {
     286                 :          0 :                 memset(page_address(*pages) + poffset, 0,
     287                 :          0 :                        PAGE_SIZE - poffset);
     288                 :          0 :                 flush_dcache_page(*pages);
     289                 :          0 :                 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                 :          0 : static int zisofs_readpage(struct file *file, struct page *page)
     300                 :            : {
     301         [ #  # ]:          0 :         struct inode *inode = file_inode(file);
     302                 :          0 :         struct address_space *mapping = inode->i_mapping;
     303                 :          0 :         int err;
     304                 :          0 :         int i, pcount, full_page;
     305         [ #  # ]:          0 :         unsigned int zisofs_block_shift = ISOFS_I(inode)->i_format_parm[1];
     306                 :          0 :         unsigned int zisofs_pages_per_cblock =
     307                 :            :                 PAGE_SHIFT <= zisofs_block_shift ?
     308         [ #  # ]:          0 :                 (1 << (zisofs_block_shift - PAGE_SHIFT)) : 0;
     309                 :          0 :         struct page **pages;
     310                 :          0 :         pgoff_t index = page->index, end_index;
     311                 :            : 
     312                 :          0 :         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         [ #  # ]:          0 :         if (index >= end_index) {
     318                 :          0 :                 SetPageUptodate(page);
     319                 :          0 :                 unlock_page(page);
     320                 :          0 :                 return 0;
     321                 :            :         }
     322                 :            : 
     323         [ #  # ]:          0 :         if (PAGE_SHIFT <= zisofs_block_shift) {
     324                 :            :                 /* We have already been given one page, this is the one
     325                 :            :                    we must do. */
     326                 :          0 :                 full_page = index & (zisofs_pages_per_cblock - 1);
     327                 :          0 :                 pcount = min_t(int, zisofs_pages_per_cblock,
     328                 :            :                         end_index - (index & ~(zisofs_pages_per_cblock - 1)));
     329                 :          0 :                 index -= full_page;
     330                 :            :         } else {
     331                 :            :                 full_page = 0;
     332                 :            :                 pcount = 1;
     333                 :            :         }
     334                 :          0 :         pages = kcalloc(max_t(unsigned int, zisofs_pages_per_cblock, 1),
     335                 :            :                                         sizeof(*pages), GFP_KERNEL);
     336         [ #  # ]:          0 :         if (!pages) {
     337                 :          0 :                 unlock_page(page);
     338                 :          0 :                 return -ENOMEM;
     339                 :            :         }
     340                 :          0 :         pages[full_page] = page;
     341                 :            : 
     342         [ #  # ]:          0 :         for (i = 0; i < pcount; i++, index++) {
     343         [ #  # ]:          0 :                 if (i != full_page)
     344                 :          0 :                         pages[i] = grab_cache_page_nowait(mapping, index);
     345         [ #  # ]:          0 :                 if (pages[i]) {
     346         [ #  # ]:          0 :                         ClearPageError(pages[i]);
     347                 :          0 :                         kmap(pages[i]);
     348                 :            :                 }
     349                 :            :         }
     350                 :            : 
     351                 :          0 :         err = zisofs_fill_pages(inode, full_page, pcount, pages);
     352                 :            : 
     353                 :            :         /* Release any residual pages, do not SetPageUptodate */
     354         [ #  # ]:          0 :         for (i = 0; i < pcount; i++) {
     355         [ #  # ]:          0 :                 if (pages[i]) {
     356         [ #  # ]:          0 :                         flush_dcache_page(pages[i]);
     357         [ #  # ]:          0 :                         if (i == full_page && err)
     358         [ #  # ]:          0 :                                 SetPageError(pages[i]);
     359                 :          0 :                         kunmap(pages[i]);
     360                 :          0 :                         unlock_page(pages[i]);
     361         [ #  # ]:          0 :                         if (i != full_page)
     362                 :          0 :                                 put_page(pages[i]);
     363                 :            :                 }
     364                 :            :         }                       
     365                 :            : 
     366                 :            :         /* At this point, err contains 0 or -EIO depending on the "critical" page */
     367                 :          0 :         kfree(pages);
     368                 :          0 :         return err;
     369                 :            : }
     370                 :            : 
     371                 :            : const struct address_space_operations zisofs_aops = {
     372                 :            :         .readpage = zisofs_readpage,
     373                 :            :         /* No bmap operation supported */
     374                 :            : };
     375                 :            : 
     376                 :         30 : int __init zisofs_init(void)
     377                 :            : {
     378                 :         30 :         zisofs_zlib_workspace = vmalloc(zlib_inflate_workspacesize());
     379         [ -  + ]:         30 :         if ( !zisofs_zlib_workspace )
     380                 :          0 :                 return -ENOMEM;
     381                 :            : 
     382                 :            :         return 0;
     383                 :            : }
     384                 :            : 
     385                 :          0 : void zisofs_cleanup(void)
     386                 :            : {
     387                 :          0 :         vfree(zisofs_zlib_workspace);
     388                 :          0 : }

Generated by: LCOV version 1.14