Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Squashfs - a compressed read only filesystem for Linux
0004  *
0005  * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008
0006  * Phillip Lougher <phillip@squashfs.org.uk>
0007  *
0008  * cache.c
0009  */
0010 
0011 /*
0012  * Blocks in Squashfs are compressed.  To avoid repeatedly decompressing
0013  * recently accessed data Squashfs uses two small metadata and fragment caches.
0014  *
0015  * This file implements a generic cache implementation used for both caches,
0016  * plus functions layered ontop of the generic cache implementation to
0017  * access the metadata and fragment caches.
0018  *
0019  * To avoid out of memory and fragmentation issues with vmalloc the cache
0020  * uses sequences of kmalloced PAGE_SIZE buffers.
0021  *
0022  * It should be noted that the cache is not used for file datablocks, these
0023  * are decompressed and cached in the page-cache in the normal way.  The
0024  * cache is only used to temporarily cache fragment and metadata blocks
0025  * which have been read as as a result of a metadata (i.e. inode or
0026  * directory) or fragment access.  Because metadata and fragments are packed
0027  * together into blocks (to gain greater compression) the read of a particular
0028  * piece of metadata or fragment will retrieve other metadata/fragments which
0029  * have been packed with it, these because of locality-of-reference may be read
0030  * in the near future. Temporarily caching them ensures they are available for
0031  * near future access without requiring an additional read and decompress.
0032  */
0033 
0034 #include <linux/fs.h>
0035 #include <linux/vfs.h>
0036 #include <linux/slab.h>
0037 #include <linux/vmalloc.h>
0038 #include <linux/sched.h>
0039 #include <linux/spinlock.h>
0040 #include <linux/wait.h>
0041 #include <linux/pagemap.h>
0042 
0043 #include "squashfs_fs.h"
0044 #include "squashfs_fs_sb.h"
0045 #include "squashfs.h"
0046 #include "page_actor.h"
0047 
0048 /*
0049  * Look-up block in cache, and increment usage count.  If not in cache, read
0050  * and decompress it from disk.
0051  */
0052 struct squashfs_cache_entry *squashfs_cache_get(struct super_block *sb,
0053     struct squashfs_cache *cache, u64 block, int length)
0054 {
0055     int i, n;
0056     struct squashfs_cache_entry *entry;
0057 
0058     spin_lock(&cache->lock);
0059 
0060     while (1) {
0061         for (i = cache->curr_blk, n = 0; n < cache->entries; n++) {
0062             if (cache->entry[i].block == block) {
0063                 cache->curr_blk = i;
0064                 break;
0065             }
0066             i = (i + 1) % cache->entries;
0067         }
0068 
0069         if (n == cache->entries) {
0070             /*
0071              * Block not in cache, if all cache entries are used
0072              * go to sleep waiting for one to become available.
0073              */
0074             if (cache->unused == 0) {
0075                 cache->num_waiters++;
0076                 spin_unlock(&cache->lock);
0077                 wait_event(cache->wait_queue, cache->unused);
0078                 spin_lock(&cache->lock);
0079                 cache->num_waiters--;
0080                 continue;
0081             }
0082 
0083             /*
0084              * At least one unused cache entry.  A simple
0085              * round-robin strategy is used to choose the entry to
0086              * be evicted from the cache.
0087              */
0088             i = cache->next_blk;
0089             for (n = 0; n < cache->entries; n++) {
0090                 if (cache->entry[i].refcount == 0)
0091                     break;
0092                 i = (i + 1) % cache->entries;
0093             }
0094 
0095             cache->next_blk = (i + 1) % cache->entries;
0096             entry = &cache->entry[i];
0097 
0098             /*
0099              * Initialise chosen cache entry, and fill it in from
0100              * disk.
0101              */
0102             cache->unused--;
0103             entry->block = block;
0104             entry->refcount = 1;
0105             entry->pending = 1;
0106             entry->num_waiters = 0;
0107             entry->error = 0;
0108             spin_unlock(&cache->lock);
0109 
0110             entry->length = squashfs_read_data(sb, block, length,
0111                 &entry->next_index, entry->actor);
0112 
0113             spin_lock(&cache->lock);
0114 
0115             if (entry->length < 0)
0116                 entry->error = entry->length;
0117 
0118             entry->pending = 0;
0119 
0120             /*
0121              * While filling this entry one or more other processes
0122              * have looked it up in the cache, and have slept
0123              * waiting for it to become available.
0124              */
0125             if (entry->num_waiters) {
0126                 spin_unlock(&cache->lock);
0127                 wake_up_all(&entry->wait_queue);
0128             } else
0129                 spin_unlock(&cache->lock);
0130 
0131             goto out;
0132         }
0133 
0134         /*
0135          * Block already in cache.  Increment refcount so it doesn't
0136          * get reused until we're finished with it, if it was
0137          * previously unused there's one less cache entry available
0138          * for reuse.
0139          */
0140         entry = &cache->entry[i];
0141         if (entry->refcount == 0)
0142             cache->unused--;
0143         entry->refcount++;
0144 
0145         /*
0146          * If the entry is currently being filled in by another process
0147          * go to sleep waiting for it to become available.
0148          */
0149         if (entry->pending) {
0150             entry->num_waiters++;
0151             spin_unlock(&cache->lock);
0152             wait_event(entry->wait_queue, !entry->pending);
0153         } else
0154             spin_unlock(&cache->lock);
0155 
0156         goto out;
0157     }
0158 
0159 out:
0160     TRACE("Got %s %d, start block %lld, refcount %d, error %d\n",
0161         cache->name, i, entry->block, entry->refcount, entry->error);
0162 
0163     if (entry->error)
0164         ERROR("Unable to read %s cache entry [%llx]\n", cache->name,
0165                             block);
0166     return entry;
0167 }
0168 
0169 
0170 /*
0171  * Release cache entry, once usage count is zero it can be reused.
0172  */
0173 void squashfs_cache_put(struct squashfs_cache_entry *entry)
0174 {
0175     struct squashfs_cache *cache = entry->cache;
0176 
0177     spin_lock(&cache->lock);
0178     entry->refcount--;
0179     if (entry->refcount == 0) {
0180         cache->unused++;
0181         /*
0182          * If there's any processes waiting for a block to become
0183          * available, wake one up.
0184          */
0185         if (cache->num_waiters) {
0186             spin_unlock(&cache->lock);
0187             wake_up(&cache->wait_queue);
0188             return;
0189         }
0190     }
0191     spin_unlock(&cache->lock);
0192 }
0193 
0194 /*
0195  * Delete cache reclaiming all kmalloced buffers.
0196  */
0197 void squashfs_cache_delete(struct squashfs_cache *cache)
0198 {
0199     int i, j;
0200 
0201     if (cache == NULL)
0202         return;
0203 
0204     for (i = 0; i < cache->entries; i++) {
0205         if (cache->entry[i].data) {
0206             for (j = 0; j < cache->pages; j++)
0207                 kfree(cache->entry[i].data[j]);
0208             kfree(cache->entry[i].data);
0209         }
0210         kfree(cache->entry[i].actor);
0211     }
0212 
0213     kfree(cache->entry);
0214     kfree(cache);
0215 }
0216 
0217 
0218 /*
0219  * Initialise cache allocating the specified number of entries, each of
0220  * size block_size.  To avoid vmalloc fragmentation issues each entry
0221  * is allocated as a sequence of kmalloced PAGE_SIZE buffers.
0222  */
0223 struct squashfs_cache *squashfs_cache_init(char *name, int entries,
0224     int block_size)
0225 {
0226     int i, j;
0227     struct squashfs_cache *cache = kzalloc(sizeof(*cache), GFP_KERNEL);
0228 
0229     if (cache == NULL) {
0230         ERROR("Failed to allocate %s cache\n", name);
0231         return NULL;
0232     }
0233 
0234     cache->entry = kcalloc(entries, sizeof(*(cache->entry)), GFP_KERNEL);
0235     if (cache->entry == NULL) {
0236         ERROR("Failed to allocate %s cache\n", name);
0237         goto cleanup;
0238     }
0239 
0240     cache->curr_blk = 0;
0241     cache->next_blk = 0;
0242     cache->unused = entries;
0243     cache->entries = entries;
0244     cache->block_size = block_size;
0245     cache->pages = block_size >> PAGE_SHIFT;
0246     cache->pages = cache->pages ? cache->pages : 1;
0247     cache->name = name;
0248     cache->num_waiters = 0;
0249     spin_lock_init(&cache->lock);
0250     init_waitqueue_head(&cache->wait_queue);
0251 
0252     for (i = 0; i < entries; i++) {
0253         struct squashfs_cache_entry *entry = &cache->entry[i];
0254 
0255         init_waitqueue_head(&cache->entry[i].wait_queue);
0256         entry->cache = cache;
0257         entry->block = SQUASHFS_INVALID_BLK;
0258         entry->data = kcalloc(cache->pages, sizeof(void *), GFP_KERNEL);
0259         if (entry->data == NULL) {
0260             ERROR("Failed to allocate %s cache entry\n", name);
0261             goto cleanup;
0262         }
0263 
0264         for (j = 0; j < cache->pages; j++) {
0265             entry->data[j] = kmalloc(PAGE_SIZE, GFP_KERNEL);
0266             if (entry->data[j] == NULL) {
0267                 ERROR("Failed to allocate %s buffer\n", name);
0268                 goto cleanup;
0269             }
0270         }
0271 
0272         entry->actor = squashfs_page_actor_init(entry->data,
0273                         cache->pages, 0);
0274         if (entry->actor == NULL) {
0275             ERROR("Failed to allocate %s cache entry\n", name);
0276             goto cleanup;
0277         }
0278     }
0279 
0280     return cache;
0281 
0282 cleanup:
0283     squashfs_cache_delete(cache);
0284     return NULL;
0285 }
0286 
0287 
0288 /*
0289  * Copy up to length bytes from cache entry to buffer starting at offset bytes
0290  * into the cache entry.  If there's not length bytes then copy the number of
0291  * bytes available.  In all cases return the number of bytes copied.
0292  */
0293 int squashfs_copy_data(void *buffer, struct squashfs_cache_entry *entry,
0294         int offset, int length)
0295 {
0296     int remaining = length;
0297 
0298     if (length == 0)
0299         return 0;
0300     else if (buffer == NULL)
0301         return min(length, entry->length - offset);
0302 
0303     while (offset < entry->length) {
0304         void *buff = entry->data[offset / PAGE_SIZE]
0305                 + (offset % PAGE_SIZE);
0306         int bytes = min_t(int, entry->length - offset,
0307                 PAGE_SIZE - (offset % PAGE_SIZE));
0308 
0309         if (bytes >= remaining) {
0310             memcpy(buffer, buff, remaining);
0311             remaining = 0;
0312             break;
0313         }
0314 
0315         memcpy(buffer, buff, bytes);
0316         buffer += bytes;
0317         remaining -= bytes;
0318         offset += bytes;
0319     }
0320 
0321     return length - remaining;
0322 }
0323 
0324 
0325 /*
0326  * Read length bytes from metadata position <block, offset> (block is the
0327  * start of the compressed block on disk, and offset is the offset into
0328  * the block once decompressed).  Data is packed into consecutive blocks,
0329  * and length bytes may require reading more than one block.
0330  */
0331 int squashfs_read_metadata(struct super_block *sb, void *buffer,
0332         u64 *block, int *offset, int length)
0333 {
0334     struct squashfs_sb_info *msblk = sb->s_fs_info;
0335     int bytes, res = length;
0336     struct squashfs_cache_entry *entry;
0337 
0338     TRACE("Entered squashfs_read_metadata [%llx:%x]\n", *block, *offset);
0339 
0340     if (unlikely(length < 0))
0341         return -EIO;
0342 
0343     while (length) {
0344         entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0);
0345         if (entry->error) {
0346             res = entry->error;
0347             goto error;
0348         } else if (*offset >= entry->length) {
0349             res = -EIO;
0350             goto error;
0351         }
0352 
0353         bytes = squashfs_copy_data(buffer, entry, *offset, length);
0354         if (buffer)
0355             buffer += bytes;
0356         length -= bytes;
0357         *offset += bytes;
0358 
0359         if (*offset == entry->length) {
0360             *block = entry->next_index;
0361             *offset = 0;
0362         }
0363 
0364         squashfs_cache_put(entry);
0365     }
0366 
0367     return res;
0368 
0369 error:
0370     squashfs_cache_put(entry);
0371     return res;
0372 }
0373 
0374 
0375 /*
0376  * Look-up in the fragmment cache the fragment located at <start_block> in the
0377  * filesystem.  If necessary read and decompress it from disk.
0378  */
0379 struct squashfs_cache_entry *squashfs_get_fragment(struct super_block *sb,
0380                 u64 start_block, int length)
0381 {
0382     struct squashfs_sb_info *msblk = sb->s_fs_info;
0383 
0384     return squashfs_cache_get(sb, msblk->fragment_cache, start_block,
0385         length);
0386 }
0387 
0388 
0389 /*
0390  * Read and decompress the datablock located at <start_block> in the
0391  * filesystem.  The cache is used here to avoid duplicating locking and
0392  * read/decompress code.
0393  */
0394 struct squashfs_cache_entry *squashfs_get_datablock(struct super_block *sb,
0395                 u64 start_block, int length)
0396 {
0397     struct squashfs_sb_info *msblk = sb->s_fs_info;
0398 
0399     return squashfs_cache_get(sb, msblk->read_page, start_block, length);
0400 }
0401 
0402 
0403 /*
0404  * Read a filesystem table (uncompressed sequence of bytes) from disk
0405  */
0406 void *squashfs_read_table(struct super_block *sb, u64 block, int length)
0407 {
0408     int pages = (length + PAGE_SIZE - 1) >> PAGE_SHIFT;
0409     int i, res;
0410     void *table, *buffer, **data;
0411     struct squashfs_page_actor *actor;
0412 
0413     table = buffer = kmalloc(length, GFP_KERNEL);
0414     if (table == NULL)
0415         return ERR_PTR(-ENOMEM);
0416 
0417     data = kcalloc(pages, sizeof(void *), GFP_KERNEL);
0418     if (data == NULL) {
0419         res = -ENOMEM;
0420         goto failed;
0421     }
0422 
0423     actor = squashfs_page_actor_init(data, pages, length);
0424     if (actor == NULL) {
0425         res = -ENOMEM;
0426         goto failed2;
0427     }
0428 
0429     for (i = 0; i < pages; i++, buffer += PAGE_SIZE)
0430         data[i] = buffer;
0431 
0432     res = squashfs_read_data(sb, block, length |
0433         SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, actor);
0434 
0435     kfree(data);
0436     kfree(actor);
0437 
0438     if (res < 0)
0439         goto failed;
0440 
0441     return table;
0442 
0443 failed2:
0444     kfree(data);
0445 failed:
0446     kfree(table);
0447     return ERR_PTR(res);
0448 }