Home | History | Annotate | Download | only in fio
      1 /*
      2  * Really simple exclusive file locking based on filename.
      3  * No hash indexing, just a list, so only works well for < 100 files or
      4  * so. But that's more than what fio needs, so should be fine.
      5  */
      6 #include <inttypes.h>
      7 #include <string.h>
      8 #include <assert.h>
      9 
     10 #include "flist.h"
     11 #include "filelock.h"
     12 #include "smalloc.h"
     13 #include "mutex.h"
     14 #include "hash.h"
     15 #include "log.h"
     16 
     17 struct fio_filelock {
     18 	uint32_t hash;
     19 	struct fio_mutex lock;
     20 	struct flist_head list;
     21 	unsigned int references;
     22 };
     23 
     24 static struct flist_head *filelock_list;
     25 static struct fio_mutex *filelock_lock;
     26 
     27 int fio_filelock_init(void)
     28 {
     29 	filelock_list = smalloc(sizeof(*filelock_list));
     30 	if (!filelock_list)
     31 		return 1;
     32 
     33 	INIT_FLIST_HEAD(filelock_list);
     34 	filelock_lock = fio_mutex_init(FIO_MUTEX_UNLOCKED);
     35 	if (!filelock_lock) {
     36 		sfree(filelock_list);
     37 		return 1;
     38 	}
     39 
     40 	return 0;
     41 }
     42 
     43 void fio_filelock_exit(void)
     44 {
     45 	if (!filelock_list)
     46 		return;
     47 
     48 	assert(flist_empty(filelock_list));
     49 	sfree(filelock_list);
     50 	filelock_list = NULL;
     51 	fio_mutex_remove(filelock_lock);
     52 	filelock_lock = NULL;
     53 }
     54 
     55 static struct fio_filelock *fio_hash_find(uint32_t hash)
     56 {
     57 	struct flist_head *entry;
     58 	struct fio_filelock *ff;
     59 
     60 	flist_for_each(entry, filelock_list) {
     61 		ff = flist_entry(entry, struct fio_filelock, list);
     62 		if (ff->hash == hash)
     63 			return ff;
     64 	}
     65 
     66 	return NULL;
     67 }
     68 
     69 static struct fio_filelock *fio_hash_get(uint32_t hash)
     70 {
     71 	struct fio_filelock *ff;
     72 
     73 	ff = fio_hash_find(hash);
     74 	if (!ff) {
     75 		ff = smalloc(sizeof(*ff));
     76 		ff->hash = hash;
     77 		__fio_mutex_init(&ff->lock, FIO_MUTEX_UNLOCKED);
     78 		ff->references = 0;
     79 		flist_add(&ff->list, filelock_list);
     80 	}
     81 
     82 	return ff;
     83 }
     84 
     85 int fio_trylock_file(const char *fname)
     86 {
     87 	struct fio_filelock *ff;
     88 	uint32_t hash;
     89 
     90 	hash = jhash(fname, strlen(fname), 0);
     91 
     92 	fio_mutex_down(filelock_lock);
     93 	ff = fio_hash_get(hash);
     94 	ff->references++;
     95 	fio_mutex_up(filelock_lock);
     96 
     97 	if (!fio_mutex_down_trylock(&ff->lock))
     98 		return 0;
     99 
    100 	fio_mutex_down(filelock_lock);
    101 
    102 	/*
    103 	 * If we raced and the only reference to the lock is us, we can
    104 	 * grab it
    105 	 */
    106 	if (ff->references != 1) {
    107 		ff->references--;
    108 		ff = NULL;
    109 	}
    110 
    111 	fio_mutex_up(filelock_lock);
    112 
    113 	if (ff) {
    114 		fio_mutex_down(&ff->lock);
    115 		return 0;
    116 	}
    117 
    118 	return 1;
    119 }
    120 
    121 void fio_lock_file(const char *fname)
    122 {
    123 	struct fio_filelock *ff;
    124 	uint32_t hash;
    125 
    126 	hash = jhash(fname, strlen(fname), 0);
    127 
    128 	fio_mutex_down(filelock_lock);
    129 	ff = fio_hash_get(hash);
    130 	ff->references++;
    131 	fio_mutex_up(filelock_lock);
    132 
    133 	fio_mutex_down(&ff->lock);
    134 }
    135 
    136 void fio_unlock_file(const char *fname)
    137 {
    138 	struct fio_filelock *ff;
    139 	uint32_t hash;
    140 
    141 	hash = jhash(fname, strlen(fname), 0);
    142 
    143 	fio_mutex_down(filelock_lock);
    144 
    145 	ff = fio_hash_find(hash);
    146 	if (ff) {
    147 		ff->references--;
    148 		fio_mutex_up(&ff->lock);
    149 		if (!ff->references) {
    150 			flist_del(&ff->list);
    151 			sfree(ff);
    152 		}
    153 	} else
    154 		log_err("fio: file not found for unlocking\n");
    155 
    156 	fio_mutex_up(filelock_lock);
    157 }
    158