Home | History | Annotate | Download | only in squashfs-tools
      1 /*
      2  * Create a squashfs filesystem.  This is a highly compressed read only
      3  * filesystem.
      4  *
      5  * Copyright (c) 2013, 2014
      6  * Phillip Lougher <phillip (at) squashfs.org.uk>
      7  *
      8  * This program is free software; you can redistribute it and/or
      9  * modify it under the terms of the GNU General Public License
     10  * as published by the Free Software Foundation; either version 2,
     11  * or (at your option) any later version.
     12  *
     13  * This program is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  * GNU General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU General Public License
     19  * along with this program; if not, write to the Free Software
     20  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     21  *
     22  * caches-queues-lists.c
     23  */
     24 
     25 #include <pthread.h>
     26 #include <stdlib.h>
     27 #include <string.h>
     28 #include <stdio.h>
     29 
     30 #include "error.h"
     31 #include "caches-queues-lists.h"
     32 
     33 extern int add_overflow(int, int);
     34 extern int multiply_overflow(int, int);
     35 
     36 #define TRUE 1
     37 #define FALSE 0
     38 
     39 struct queue *queue_init(int size)
     40 {
     41 	struct queue *queue = malloc(sizeof(struct queue));
     42 
     43 	if(queue == NULL)
     44 		MEM_ERROR();
     45 
     46 	if(add_overflow(size, 1) ||
     47 				multiply_overflow(size + 1, sizeof(void *)))
     48 		BAD_ERROR("Size too large in queue_init\n");
     49 
     50 	queue->data = malloc(sizeof(void *) * (size + 1));
     51 	if(queue->data == NULL)
     52 		MEM_ERROR();
     53 
     54 	queue->size = size + 1;
     55 	queue->readp = queue->writep = 0;
     56 	pthread_mutex_init(&queue->mutex, NULL);
     57 	pthread_cond_init(&queue->empty, NULL);
     58 	pthread_cond_init(&queue->full, NULL);
     59 
     60 	return queue;
     61 }
     62 
     63 
     64 void queue_put(struct queue *queue, void *data)
     65 {
     66 	int nextp;
     67 
     68 	pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
     69 	pthread_mutex_lock(&queue->mutex);
     70 
     71 	while((nextp = (queue->writep + 1) % queue->size) == queue->readp)
     72 		pthread_cond_wait(&queue->full, &queue->mutex);
     73 
     74 	queue->data[queue->writep] = data;
     75 	queue->writep = nextp;
     76 	pthread_cond_signal(&queue->empty);
     77 	pthread_cleanup_pop(1);
     78 }
     79 
     80 
     81 void *queue_get(struct queue *queue)
     82 {
     83 	void *data;
     84 
     85 	pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
     86 	pthread_mutex_lock(&queue->mutex);
     87 
     88 	while(queue->readp == queue->writep)
     89 		pthread_cond_wait(&queue->empty, &queue->mutex);
     90 
     91 	data = queue->data[queue->readp];
     92 	queue->readp = (queue->readp + 1) % queue->size;
     93 	pthread_cond_signal(&queue->full);
     94 	pthread_cleanup_pop(1);
     95 
     96 	return data;
     97 }
     98 
     99 
    100 int queue_empty(struct queue *queue)
    101 {
    102 	int empty;
    103 
    104 	pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
    105 	pthread_mutex_lock(&queue->mutex);
    106 
    107 	empty = queue->readp == queue->writep;
    108 
    109 	pthread_cleanup_pop(1);
    110 
    111 	return empty;
    112 }
    113 
    114 
    115 void queue_flush(struct queue *queue)
    116 {
    117 	pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
    118 	pthread_mutex_lock(&queue->mutex);
    119 
    120 	queue->readp = queue->writep;
    121 
    122 	pthread_cleanup_pop(1);
    123 }
    124 
    125 
    126 void dump_queue(struct queue *queue)
    127 {
    128 	pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
    129 	pthread_mutex_lock(&queue->mutex);
    130 
    131 	printf("\tMax size %d, size %d%s\n", queue->size - 1,
    132 		queue->readp <= queue->writep ? queue->writep - queue->readp :
    133 			queue->size - queue->readp + queue->writep,
    134 		queue->readp == queue->writep ? " (EMPTY)" :
    135 			((queue->writep + 1) % queue->size) == queue->readp ?
    136 			" (FULL)" : "");
    137 
    138 	pthread_cleanup_pop(1);
    139 }
    140 
    141 
    142 /* define seq queue hash tables */
    143 #define CALCULATE_SEQ_HASH(N) CALCULATE_HASH(N)
    144 
    145 /* Called with the seq queue mutex held */
    146 INSERT_HASH_TABLE(seq, struct seq_queue, CALCULATE_SEQ_HASH, sequence, seq)
    147 
    148 /* Called with the cache mutex held */
    149 REMOVE_HASH_TABLE(seq, struct seq_queue, CALCULATE_SEQ_HASH, sequence, seq);
    150 
    151 static unsigned int sequence = 0;
    152 
    153 
    154 struct seq_queue *seq_queue_init()
    155 {
    156 	struct seq_queue *queue = malloc(sizeof(struct seq_queue));
    157 	if(queue == NULL)
    158 		MEM_ERROR();
    159 
    160 	memset(queue, 0, sizeof(struct seq_queue));
    161 
    162 	pthread_mutex_init(&queue->mutex, NULL);
    163 	pthread_cond_init(&queue->wait, NULL);
    164 
    165 	return queue;
    166 }
    167 
    168 
    169 void seq_queue_put(struct seq_queue *queue, struct file_buffer *entry)
    170 {
    171 	pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
    172 	pthread_mutex_lock(&queue->mutex);
    173 
    174 	insert_seq_hash_table(queue, entry);
    175 
    176 	if(entry->fragment)
    177 		queue->fragment_count ++;
    178 	else
    179 		queue->block_count ++;
    180 
    181 	if(entry->sequence == sequence)
    182 		pthread_cond_signal(&queue->wait);
    183 
    184 	pthread_cleanup_pop(1);
    185 }
    186 
    187 
    188 struct file_buffer *seq_queue_get(struct seq_queue *queue)
    189 {
    190 	/*
    191 	 * Look-up buffer matching sequence in the queue, if found return
    192 	 * it, otherwise wait until it arrives
    193 	 */
    194 	int hash = CALCULATE_SEQ_HASH(sequence);
    195 	struct file_buffer *entry;
    196 
    197 	pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
    198 	pthread_mutex_lock(&queue->mutex);
    199 
    200 	while(1) {
    201 		for(entry = queue->hash_table[hash]; entry;
    202 						entry = entry->seq_next)
    203 			if(entry->sequence == sequence)
    204 				break;
    205 
    206 		if(entry) {
    207 			/*
    208 			 * found the buffer in the queue, decrement the
    209 			 * appropriate count, and remove from hash list
    210 			 */
    211 			if(entry->fragment)
    212 				queue->fragment_count --;
    213 			else
    214 				queue->block_count --;
    215 
    216 			remove_seq_hash_table(queue, entry);
    217 
    218 			sequence ++;
    219 
    220 			break;
    221 		}
    222 
    223 		/* entry not found, wait for it to arrive */
    224 		pthread_cond_wait(&queue->wait, &queue->mutex);
    225 	}
    226 
    227 	pthread_cleanup_pop(1);
    228 
    229 	return entry;
    230 }
    231 
    232 
    233 void seq_queue_flush(struct seq_queue *queue)
    234 {
    235 	int i;
    236 
    237 	pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
    238 	pthread_mutex_lock(&queue->mutex);
    239 
    240 	for(i = 0; i < HASH_SIZE; i++)
    241 		queue->hash_table[i] = NULL;
    242 
    243 	queue->fragment_count = queue->block_count = 0;
    244 
    245 	pthread_cleanup_pop(1);
    246 }
    247 
    248 
    249 void dump_seq_queue(struct seq_queue *queue, int fragment_queue)
    250 {
    251 	int size;
    252 
    253 	pthread_cleanup_push((void *) pthread_mutex_unlock, &queue->mutex);
    254 	pthread_mutex_lock(&queue->mutex);
    255 
    256 	size = fragment_queue ? queue->fragment_count : queue->block_count;
    257 
    258 	printf("\tMax size unlimited, size %d%s\n", size,
    259 						size == 0 ? " (EMPTY)" : "");
    260 
    261 	pthread_cleanup_pop(1);
    262 }
    263 
    264 
    265 /* define cache hash tables */
    266 #define CALCULATE_CACHE_HASH(N) CALCULATE_HASH(llabs(N))
    267 
    268 /* Called with the cache mutex held */
    269 INSERT_HASH_TABLE(cache, struct cache, CALCULATE_CACHE_HASH, index, hash)
    270 
    271 /* Called with the cache mutex held */
    272 REMOVE_HASH_TABLE(cache, struct cache, CALCULATE_CACHE_HASH, index, hash);
    273 
    274 /* define cache free list */
    275 
    276 /* Called with the cache mutex held */
    277 INSERT_LIST(free, struct file_buffer)
    278 
    279 /* Called with the cache mutex held */
    280 REMOVE_LIST(free, struct file_buffer)
    281 
    282 
    283 struct cache *cache_init(int buffer_size, int max_buffers, int noshrink_lookup,
    284 	int first_freelist)
    285 {
    286 	struct cache *cache = malloc(sizeof(struct cache));
    287 
    288 	if(cache == NULL)
    289 		MEM_ERROR();
    290 
    291 	cache->max_buffers = max_buffers;
    292 	cache->buffer_size = buffer_size;
    293 	cache->count = 0;
    294 	cache->used = 0;
    295 	cache->free_list = NULL;
    296 
    297 	/*
    298 	 * The cache will grow up to max_buffers in size in response to
    299 	 * an increase in readhead/number of buffers in flight.  But
    300 	 * once the outstanding buffers gets returned, we can either elect
    301 	 * to shrink the cache, or to put the freed blocks onto a free list.
    302 	 *
    303 	 * For the caches where we want to do lookup (fragment/writer),
    304 	 * a don't shrink policy is best, for the reader cache it
    305 	 * makes no sense to keep buffers around longer than necessary as
    306 	 * we don't do any lookup on those blocks.
    307 	 */
    308 	cache->noshrink_lookup = noshrink_lookup;
    309 
    310 	/*
    311 	 * The default use freelist before growing cache policy behaves
    312 	 * poorly with appending - with many duplicates the caches
    313 	 * do not grow due to the fact that large queues of outstanding
    314 	 * fragments/writer blocks do not occur, leading to small caches
    315 	 * and un-uncessary performance loss to frequent cache
    316 	 * replacement in the small caches.  Therefore with appending
    317 	 * change the policy to grow the caches before reusing blocks
    318 	 * from the freelist
    319 	 */
    320 	cache->first_freelist = first_freelist;
    321 
    322 	memset(cache->hash_table, 0, sizeof(struct file_buffer *) * 65536);
    323 	pthread_mutex_init(&cache->mutex, NULL);
    324 	pthread_cond_init(&cache->wait_for_free, NULL);
    325 	pthread_cond_init(&cache->wait_for_unlock, NULL);
    326 
    327 	return cache;
    328 }
    329 
    330 
    331 struct file_buffer *cache_lookup(struct cache *cache, long long index)
    332 {
    333 	/* Lookup block in the cache, if found return with usage count
    334  	 * incremented, if not found return NULL */
    335 	int hash = CALCULATE_CACHE_HASH(index);
    336 	struct file_buffer *entry;
    337 
    338 	pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
    339 	pthread_mutex_lock(&cache->mutex);
    340 
    341 	for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
    342 		if(entry->index == index)
    343 			break;
    344 
    345 	if(entry) {
    346 		/* found the block in the cache, increment used count and
    347  		 * if necessary remove from free list so it won't disappear
    348  		 */
    349 		if(entry->used == 0) {
    350 			remove_free_list(&cache->free_list, entry);
    351 			cache->used ++;
    352 		}
    353 		entry->used ++;
    354 	}
    355 
    356 	pthread_cleanup_pop(1);
    357 
    358 	return entry;
    359 }
    360 
    361 
    362 static struct file_buffer *cache_freelist(struct cache *cache)
    363 {
    364 	struct file_buffer *entry = cache->free_list;
    365 
    366 	remove_free_list(&cache->free_list, entry);
    367 
    368 	/* a block on the free_list is hashed */
    369 	remove_cache_hash_table(cache, entry);
    370 
    371 	cache->used ++;
    372 	return entry;
    373 }
    374 
    375 
    376 static struct file_buffer *cache_alloc(struct cache *cache)
    377 {
    378 	struct file_buffer *entry = malloc(sizeof(struct file_buffer) +
    379 							cache->buffer_size);
    380 	if(entry == NULL)
    381 			MEM_ERROR();
    382 
    383 	entry->cache = cache;
    384 	entry->free_prev = entry->free_next = NULL;
    385 	cache->count ++;
    386 	return entry;
    387 }
    388 
    389 
    390 static struct file_buffer *_cache_get(struct cache *cache, long long index,
    391 	int hash)
    392 {
    393 	/* Get a free block out of the cache indexed on index. */
    394 	struct file_buffer *entry = NULL;
    395 
    396 	pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
    397 	pthread_mutex_lock(&cache->mutex);
    398 
    399 	while(1) {
    400 		if(cache->noshrink_lookup) {
    401 			/* first try to get a block from the free list */
    402 			if(cache->first_freelist && cache->free_list)
    403 				entry = cache_freelist(cache);
    404 			else if(cache->count < cache->max_buffers) {
    405 				entry = cache_alloc(cache);
    406 				cache->used ++;
    407 			} else if(!cache->first_freelist && cache->free_list)
    408 				entry = cache_freelist(cache);
    409 		} else { /* shrinking non-lookup cache */
    410 			if(cache->count < cache->max_buffers) {
    411 				entry = cache_alloc(cache);
    412 				if(cache->count > cache->max_count)
    413 					cache->max_count = cache->count;
    414 			}
    415 		}
    416 
    417 		if(entry)
    418 			break;
    419 
    420 		/* wait for a block */
    421 		pthread_cond_wait(&cache->wait_for_free, &cache->mutex);
    422 	}
    423 
    424 	/* initialise block and if hash is set insert into the hash table */
    425 	entry->used = 1;
    426 	entry->locked = FALSE;
    427 	entry->wait_on_unlock = FALSE;
    428 	entry->error = FALSE;
    429 	if(hash) {
    430 		entry->index = index;
    431 		insert_cache_hash_table(cache, entry);
    432 	}
    433 
    434 	pthread_cleanup_pop(1);
    435 
    436 	return entry;
    437 }
    438 
    439 
    440 struct file_buffer *cache_get(struct cache *cache, long long index)
    441 {
    442 	return _cache_get(cache, index, 1);
    443 }
    444 
    445 
    446 struct file_buffer *cache_get_nohash(struct cache *cache)
    447 {
    448 	return _cache_get(cache, 0, 0);
    449 }
    450 
    451 
    452 void cache_hash(struct file_buffer *entry, long long index)
    453 {
    454 	struct cache *cache = entry->cache;
    455 
    456 	pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
    457 	pthread_mutex_lock(&cache->mutex);
    458 
    459 	entry->index = index;
    460 	insert_cache_hash_table(cache, entry);
    461 
    462 	pthread_cleanup_pop(1);
    463 }
    464 
    465 
    466 void cache_block_put(struct file_buffer *entry)
    467 {
    468 	struct cache *cache;
    469 
    470 	/*
    471 	 * Finished with this cache entry, once the usage count reaches zero it
    472  	 * can be reused.
    473 	 *
    474 	 * If noshrink_lookup is set, put the block onto the free list.
    475  	 * As blocks remain accessible via the hash table they can be found
    476  	 * getting a new lease of life before they are reused.
    477 	 *
    478 	 * if noshrink_lookup is not set then shrink the cache.
    479 	 */
    480 
    481 	if(entry == NULL)
    482 		return;
    483 
    484 	cache = entry->cache;
    485 
    486 	pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
    487 	pthread_mutex_lock(&cache->mutex);
    488 
    489 	entry->used --;
    490 	if(entry->used == 0) {
    491 		if(cache->noshrink_lookup) {
    492 			insert_free_list(&cache->free_list, entry);
    493 			cache->used --;
    494 		} else {
    495 			free(entry);
    496 			cache->count --;
    497 		}
    498 
    499 		/* One or more threads may be waiting on this block */
    500 		pthread_cond_signal(&cache->wait_for_free);
    501 	}
    502 
    503 	pthread_cleanup_pop(1);
    504 }
    505 
    506 
    507 void dump_cache(struct cache *cache)
    508 {
    509 	pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
    510 	pthread_mutex_lock(&cache->mutex);
    511 
    512 	if(cache->noshrink_lookup)
    513 		printf("\tMax buffers %d, Current size %d, Used %d,  %s\n",
    514 			cache->max_buffers, cache->count, cache->used,
    515 			cache->free_list ?  "Free buffers" : "No free buffers");
    516 	else
    517 		printf("\tMax buffers %d, Current size %d, Maximum historical "
    518 			"size %d\n", cache->max_buffers, cache->count,
    519 			cache->max_count);
    520 
    521 	pthread_cleanup_pop(1);
    522 }
    523 
    524 
    525 struct file_buffer *cache_get_nowait(struct cache *cache, long long index)
    526 {
    527 	struct file_buffer *entry = NULL;
    528 	/*
    529 	 * block doesn't exist, create it, but return it with the
    530 	 * locked flag set, so nothing tries to use it while it doesn't
    531 	 * contain data.
    532 	 *
    533 	 * If there's no space in the cache then return NULL.
    534 	 */
    535 
    536 	pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
    537 	pthread_mutex_lock(&cache->mutex);
    538 
    539 	/* first try to get a block from the free list */
    540 	if(cache->first_freelist && cache->free_list)
    541 		entry = cache_freelist(cache);
    542 	else if(cache->count < cache->max_buffers) {
    543 		entry = cache_alloc(cache);
    544 		cache->used ++;
    545 	} else if(!cache->first_freelist && cache->free_list)
    546 		entry = cache_freelist(cache);
    547 
    548 	if(entry) {
    549 		/* initialise block and insert into the hash table */
    550 		entry->used = 1;
    551 		entry->locked = TRUE;
    552 		entry->wait_on_unlock = FALSE;
    553 		entry->error = FALSE;
    554 		entry->index = index;
    555 		insert_cache_hash_table(cache, entry);
    556 	}
    557 
    558 	pthread_cleanup_pop(1);
    559 
    560 	return entry;
    561 }
    562 
    563 
    564 struct file_buffer *cache_lookup_nowait(struct cache *cache, long long index,
    565 	char *locked)
    566 {
    567 	/*
    568 	 * Lookup block in the cache, if found return it with the locked flag
    569 	 * indicating whether it is currently locked.  In both cases increment
    570 	 * the used count.
    571 	 *
    572 	 * If it doesn't exist in the cache return NULL;
    573 	 */
    574 	int hash = CALCULATE_CACHE_HASH(index);
    575 	struct file_buffer *entry;
    576 
    577 	pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
    578 	pthread_mutex_lock(&cache->mutex);
    579 
    580 	/* first check if the entry already exists */
    581 	for(entry = cache->hash_table[hash]; entry; entry = entry->hash_next)
    582 		if(entry->index == index)
    583 			break;
    584 
    585 	if(entry) {
    586 		if(entry->used == 0) {
    587 			remove_free_list(&cache->free_list, entry);
    588 			cache->used ++;
    589 		}
    590 		entry->used ++;
    591 		*locked = entry->locked;
    592 	}
    593 
    594 	pthread_cleanup_pop(1);
    595 
    596 	return entry;
    597 }
    598 
    599 
    600 void cache_wait_unlock(struct file_buffer *buffer)
    601 {
    602 	struct cache *cache = buffer->cache;
    603 
    604 	pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
    605 	pthread_mutex_lock(&cache->mutex);
    606 
    607 	while(buffer->locked) {
    608 		/*
    609 		 * another thread is filling this in, wait until it
    610 		 * becomes unlocked.  Used has been incremented to ensure it
    611 		 * doesn't get reused.  By definition a block can't be
    612 		 * locked and unused, and so we don't need to worry
    613 		 * about it being on the freelist now, but, it may
    614 		 * become unused when unlocked unless used is
    615 		 * incremented
    616 		 */
    617 		buffer->wait_on_unlock = TRUE;
    618 		pthread_cond_wait(&cache->wait_for_unlock, &cache->mutex);
    619 	}
    620 
    621 	pthread_cleanup_pop(1);
    622 }
    623 
    624 
    625 void cache_unlock(struct file_buffer *entry)
    626 {
    627 	struct cache *cache = entry->cache;
    628 
    629 	/*
    630 	 * Unlock this locked cache entry.  If anything is waiting for this
    631 	 * to become unlocked, wake it up.
    632 	 */
    633 	pthread_cleanup_push((void *) pthread_mutex_unlock, &cache->mutex);
    634 	pthread_mutex_lock(&cache->mutex);
    635 
    636 	entry->locked = FALSE;
    637 
    638 	if(entry->wait_on_unlock) {
    639 		entry->wait_on_unlock = FALSE;
    640 		pthread_cond_broadcast(&cache->wait_for_unlock);
    641 	}
    642 
    643 	pthread_cleanup_pop(1);
    644 }
    645