Lines Matching +full:file +full:- +full:entry +full:- +full:cache
2 * Squashfs - a compressed read only filesystem for Linux
19 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * cache.c
28 * This file implements a generic cache implementation used for both caches,
29 * plus functions layered ontop of the generic cache implementation to
32 * To avoid out of memory and fragmentation isssues with vmalloc the cache
35 * It should be noted that the cache is not used for file datablocks, these
36 * are decompressed and cached in the page-cache in the normal way. The
37 * cache is only used to temporarily cache fragment and metadata blocks
42 * have been packed with it, these because of locality-of-reference may be read
63 * Look-up block in cache, and increment usage count. If not in cache, read
67 struct squashfs_cache *cache, u64 block, int length) in squashfs_cache_get() argument
70 struct squashfs_cache_entry *entry; in squashfs_cache_get() local
72 spin_lock(&cache->lock); in squashfs_cache_get()
75 for (i = 0; i < cache->entries; i++) in squashfs_cache_get()
76 if (cache->entry[i].block == block) in squashfs_cache_get()
79 if (i == cache->entries) { in squashfs_cache_get()
81 * Block not in cache, if all cache entries are used in squashfs_cache_get()
84 if (cache->unused == 0) { in squashfs_cache_get()
85 cache->num_waiters++; in squashfs_cache_get()
86 spin_unlock(&cache->lock); in squashfs_cache_get()
87 wait_event(cache->wait_queue, cache->unused); in squashfs_cache_get()
88 spin_lock(&cache->lock); in squashfs_cache_get()
89 cache->num_waiters--; in squashfs_cache_get()
94 * At least one unused cache entry. A simple in squashfs_cache_get()
95 * round-robin strategy is used to choose the entry to in squashfs_cache_get()
96 * be evicted from the cache. in squashfs_cache_get()
98 i = cache->next_blk; in squashfs_cache_get()
99 for (n = 0; n < cache->entries; n++) { in squashfs_cache_get()
100 if (cache->entry[i].refcount == 0) in squashfs_cache_get()
102 i = (i + 1) % cache->entries; in squashfs_cache_get()
105 cache->next_blk = (i + 1) % cache->entries; in squashfs_cache_get()
106 entry = &cache->entry[i]; in squashfs_cache_get()
109 * Initialise choosen cache entry, and fill it in from in squashfs_cache_get()
112 cache->unused--; in squashfs_cache_get()
113 entry->block = block; in squashfs_cache_get()
114 entry->refcount = 1; in squashfs_cache_get()
115 entry->pending = 1; in squashfs_cache_get()
116 entry->num_waiters = 0; in squashfs_cache_get()
117 entry->error = 0; in squashfs_cache_get()
118 spin_unlock(&cache->lock); in squashfs_cache_get()
120 entry->length = squashfs_read_data(sb, entry->data, in squashfs_cache_get()
121 block, length, &entry->next_index, in squashfs_cache_get()
122 cache->block_size); in squashfs_cache_get()
124 spin_lock(&cache->lock); in squashfs_cache_get()
126 if (entry->length < 0) in squashfs_cache_get()
127 entry->error = entry->length; in squashfs_cache_get()
129 entry->pending = 0; in squashfs_cache_get()
132 * While filling this entry one or more other processes in squashfs_cache_get()
133 * have looked it up in the cache, and have slept in squashfs_cache_get()
136 if (entry->num_waiters) { in squashfs_cache_get()
137 spin_unlock(&cache->lock); in squashfs_cache_get()
138 wake_up_all(&entry->wait_queue); in squashfs_cache_get()
140 spin_unlock(&cache->lock); in squashfs_cache_get()
146 * Block already in cache. Increment refcount so it doesn't in squashfs_cache_get()
148 * previously unused there's one less cache entry available in squashfs_cache_get()
151 entry = &cache->entry[i]; in squashfs_cache_get()
152 if (entry->refcount == 0) in squashfs_cache_get()
153 cache->unused--; in squashfs_cache_get()
154 entry->refcount++; in squashfs_cache_get()
157 * If the entry is currently being filled in by another process in squashfs_cache_get()
160 if (entry->pending) { in squashfs_cache_get()
161 entry->num_waiters++; in squashfs_cache_get()
162 spin_unlock(&cache->lock); in squashfs_cache_get()
163 wait_event(entry->wait_queue, !entry->pending); in squashfs_cache_get()
165 spin_unlock(&cache->lock); in squashfs_cache_get()
172 cache->name, i, entry->block, entry->refcount, entry->error); in squashfs_cache_get()
174 if (entry->error) in squashfs_cache_get()
175 ERROR("Unable to read %s cache entry [%llx]\n", cache->name, in squashfs_cache_get()
177 return entry; in squashfs_cache_get()
182 * Release cache entry, once usage count is zero it can be reused.
184 void squashfs_cache_put(struct squashfs_cache_entry *entry) in squashfs_cache_put() argument
186 struct squashfs_cache *cache = entry->cache; in squashfs_cache_put() local
188 spin_lock(&cache->lock); in squashfs_cache_put()
189 entry->refcount--; in squashfs_cache_put()
190 if (entry->refcount == 0) { in squashfs_cache_put()
191 cache->unused++; in squashfs_cache_put()
196 if (cache->num_waiters) { in squashfs_cache_put()
197 spin_unlock(&cache->lock); in squashfs_cache_put()
198 wake_up(&cache->wait_queue); in squashfs_cache_put()
202 spin_unlock(&cache->lock); in squashfs_cache_put()
206 * Delete cache reclaiming all kmalloced buffers.
208 void squashfs_cache_delete(struct squashfs_cache *cache) in squashfs_cache_delete() argument
212 if (cache == NULL) in squashfs_cache_delete()
215 for (i = 0; i < cache->entries; i++) { in squashfs_cache_delete()
216 if (cache->entry[i].data) { in squashfs_cache_delete()
217 for (j = 0; j < cache->pages; j++) in squashfs_cache_delete()
218 kfree(cache->entry[i].data[j]); in squashfs_cache_delete()
219 kfree(cache->entry[i].data); in squashfs_cache_delete()
223 kfree(cache->entry); in squashfs_cache_delete()
224 kfree(cache); in squashfs_cache_delete()
229 * Initialise cache allocating the specified number of entries, each of
230 * size block_size. To avoid vmalloc fragmentation issues each entry
237 struct squashfs_cache *cache = kzalloc(sizeof(*cache), GFP_KERNEL); in squashfs_cache_init() local
239 if (cache == NULL) { in squashfs_cache_init()
240 ERROR("Failed to allocate %s cache\n", name); in squashfs_cache_init()
244 cache->entry = kcalloc(entries, sizeof(*(cache->entry)), GFP_KERNEL); in squashfs_cache_init()
245 if (cache->entry == NULL) { in squashfs_cache_init()
246 ERROR("Failed to allocate %s cache\n", name); in squashfs_cache_init()
250 cache->next_blk = 0; in squashfs_cache_init()
251 cache->unused = entries; in squashfs_cache_init()
252 cache->entries = entries; in squashfs_cache_init()
253 cache->block_size = block_size; in squashfs_cache_init()
254 cache->pages = block_size >> PAGE_CACHE_SHIFT; in squashfs_cache_init()
255 cache->name = name; in squashfs_cache_init()
256 cache->num_waiters = 0; in squashfs_cache_init()
257 spin_lock_init(&cache->lock); in squashfs_cache_init()
258 init_waitqueue_head(&cache->wait_queue); in squashfs_cache_init()
261 struct squashfs_cache_entry *entry = &cache->entry[i]; in squashfs_cache_init() local
263 init_waitqueue_head(&cache->entry[i].wait_queue); in squashfs_cache_init()
264 entry->cache = cache; in squashfs_cache_init()
265 entry->block = SQUASHFS_INVALID_BLK; in squashfs_cache_init()
266 entry->data = kcalloc(cache->pages, sizeof(void *), GFP_KERNEL); in squashfs_cache_init()
267 if (entry->data == NULL) { in squashfs_cache_init()
268 ERROR("Failed to allocate %s cache entry\n", name); in squashfs_cache_init()
272 for (j = 0; j < cache->pages; j++) { in squashfs_cache_init()
273 entry->data[j] = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); in squashfs_cache_init()
274 if (entry->data[j] == NULL) { in squashfs_cache_init()
281 return cache; in squashfs_cache_init()
284 squashfs_cache_delete(cache); in squashfs_cache_init()
290 * Copy upto length bytes from cache entry to buffer starting at offset bytes
291 * into the cache entry. If there's not length bytes then copy the number of
294 int squashfs_copy_data(void *buffer, struct squashfs_cache_entry *entry, in squashfs_copy_data() argument
302 return min(length, entry->length - offset); in squashfs_copy_data()
304 while (offset < entry->length) { in squashfs_copy_data()
305 void *buff = entry->data[offset / PAGE_CACHE_SIZE] in squashfs_copy_data()
307 int bytes = min_t(int, entry->length - offset, in squashfs_copy_data()
308 PAGE_CACHE_SIZE - (offset % PAGE_CACHE_SIZE)); in squashfs_copy_data()
318 remaining -= bytes; in squashfs_copy_data()
322 return length - remaining; in squashfs_copy_data()
335 struct squashfs_sb_info *msblk = sb->s_fs_info; in squashfs_read_metadata()
337 struct squashfs_cache_entry *entry; in squashfs_read_metadata() local
342 entry = squashfs_cache_get(sb, msblk->block_cache, *block, 0); in squashfs_read_metadata()
343 if (entry->error) in squashfs_read_metadata()
344 return entry->error; in squashfs_read_metadata()
345 else if (*offset >= entry->length) in squashfs_read_metadata()
346 return -EIO; in squashfs_read_metadata()
348 bytes = squashfs_copy_data(buffer, entry, *offset, length); in squashfs_read_metadata()
351 length -= bytes; in squashfs_read_metadata()
354 if (*offset == entry->length) { in squashfs_read_metadata()
355 *block = entry->next_index; in squashfs_read_metadata()
359 squashfs_cache_put(entry); in squashfs_read_metadata()
367 * Look-up in the fragmment cache the fragment located at <start_block> in the
373 struct squashfs_sb_info *msblk = sb->s_fs_info; in squashfs_get_fragment()
375 return squashfs_cache_get(sb, msblk->fragment_cache, start_block, in squashfs_get_fragment()
382 * filesystem. The cache is used here to avoid duplicating locking and
388 struct squashfs_sb_info *msblk = sb->s_fs_info; in squashfs_get_datablock()
390 return squashfs_cache_get(sb, msblk->read_page, start_block, length); in squashfs_get_datablock()
400 int pages = (length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; in squashfs_read_table()
404 return -ENOMEM; in squashfs_read_table()