diff options
author | Miloslav Trmač <mitr@redhat.com> | 2010-07-28 00:17:24 +0200 |
---|---|---|
committer | Miloslav Trmač <mitr@redhat.com> | 2010-07-28 01:29:08 +0200 |
commit | 16a6c980b405924a26fec8508bb6181897402bec (patch) | |
tree | 6d594e04c8519de5319296d39239133abc1012d6 /ncr-key.c | |
parent | df4c072acb675a4c89882e3c92442978cf94eedd (diff) | |
download | cryptodev-linux-16a6c980b405924a26fec8508bb6181897402bec.tar.gz cryptodev-linux-16a6c980b405924a26fec8508bb6181897402bec.tar.xz cryptodev-linux-16a6c980b405924a26fec8508bb6181897402bec.zip |
Use <linux/idr.h> for key ID allocation and lookup
Diffstat (limited to 'ncr-key.c')
-rw-r--r-- | ncr-key.c | 188 |
1 files changed, 82 insertions, 106 deletions
@@ -33,75 +33,54 @@ static void ncr_key_clear(struct key_item_st* item); -/* must be called with data semaphore down */ -static void _ncr_key_unlink_item(struct key_item_st *item) +static int key_list_deinit_fn(int id, void *item, void *unused) { - list_del(&item->list); - _ncr_key_item_put( item); /* decrement ref count */ + (void)unused; + _ncr_key_item_put(item); + return 0; } -void ncr_key_list_deinit(struct ncr_lists *lst_) +void ncr_key_list_deinit(struct ncr_lists *lst) { - struct list_sem_st *lst; - struct key_item_st * item, *tmp; - - lst = &lst_->key; - down(&lst->sem); - - list_for_each_entry_safe(item, tmp, &lst->list, list) { - _ncr_key_unlink_item(item); - } - up(&lst->sem); -} - -/* must be called with data semaphore down - */ -static ncr_key_t _ncr_key_get_new_desc( struct list_sem_st* lst) -{ -struct key_item_st* item; -int mx = 1; - - list_for_each_entry(item, &lst->list, list) { - mx = max(mx, item->desc); - } - mx++; - - return mx; + /* The mutex is not necessary, but doesn't hurt and makes it easier to + verify locking correctness. */ + mutex_lock(&lst->key_idr_mutex); + idr_for_each(&lst->key_idr, key_list_deinit_fn, NULL); + idr_remove_all(&lst->key_idr); + idr_destroy(&lst->key_idr); + mutex_unlock(&lst->key_idr_mutex); } /* returns the data item corresponding to desc */ -int ncr_key_item_get_read(struct key_item_st**st, struct ncr_lists *lst_, +int ncr_key_item_get_read(struct key_item_st**st, struct ncr_lists *lst, ncr_key_t desc) { -struct list_sem_st *lst; struct key_item_st* item; int ret; - lst = &lst_->key; *st = NULL; - down(&lst->sem); - list_for_each_entry(item, &lst->list, list) { - if (item->desc == desc) { - atomic_inc(&item->refcnt); - - if (atomic_read(&item->writer) != 0) { - /* writer in place busy */ - atomic_dec(&item->refcnt); - ret = -EBUSY; - goto exit; - } - - *st = item; - ret = 0; - goto exit; - } + mutex_lock(&lst->key_idr_mutex); + item = idr_find(&lst->key_idr, desc); + if (item == NULL) { + err(); + ret = -EINVAL; + goto exit; + } + atomic_inc(&item->refcnt); + + if (atomic_read(&item->writer) != 0) { + /* writer in place busy */ + atomic_dec(&item->refcnt); + ret = -EBUSY; + goto exit; } - err(); - ret = -EINVAL; + *st = item; + ret = 0; + exit: - up(&lst->sem); + mutex_unlock(&lst->key_idr_mutex); return ret; } @@ -109,44 +88,40 @@ exit: * is in use. */ int ncr_key_item_get_write( struct key_item_st** st, - struct ncr_lists *lst_, ncr_key_t desc) + struct ncr_lists *lst, ncr_key_t desc) { -struct list_sem_st *lst; struct key_item_st* item; int ret; - lst = &lst_->key; *st = NULL; - down(&lst->sem); - list_for_each_entry(item, &lst->list, list) { - if (item->desc == desc) { - /* do not return items that are in use already */ + mutex_lock(&lst->key_idr_mutex); + item = idr_find(&lst->key_idr, desc); + if (item == NULL) { + err(); + ret = -EINVAL; + goto exit; + } + /* do not return items that are in use already */ - if (atomic_add_unless(&item->writer, 1, 1)==0) { - /* another writer so busy */ - ret = -EBUSY; - goto exit; - } - - if (atomic_add_unless(&item->refcnt, 1, 2)==0) { - /* some reader is active so busy */ - atomic_dec(&item->writer); - ret = -EBUSY; - goto exit; - } + if (atomic_add_unless(&item->writer, 1, 1)==0) { + /* another writer so busy */ + ret = -EBUSY; + goto exit; + } - *st = item; - ret = 0; - goto exit; - } + if (atomic_add_unless(&item->refcnt, 1, 2)==0) { + /* some reader is active so busy */ + atomic_dec(&item->writer); + ret = -EBUSY; + goto exit; } - err(); - ret = -EINVAL; + *st = item; + ret = 0; exit: - up(&lst->sem); + mutex_unlock(&lst->key_idr_mutex); return ret; } @@ -161,14 +136,26 @@ void _ncr_key_item_put( struct key_item_st* item) } } -int ncr_key_init(struct ncr_lists *lst_, void __user* arg) +static void _ncr_key_remove(struct ncr_lists *lst, ncr_key_t desc) +{ + struct key_item_st * item; + + mutex_lock(&lst->key_idr_mutex); + item = idr_find(&lst->key_idr, desc); + if (item != NULL) + idr_remove(&lst->key_idr, desc); /* Steal the reference */ + mutex_unlock(&lst->key_idr_mutex); + + if (item != NULL) + _ncr_key_item_put(item); +} + +int ncr_key_init(struct ncr_lists *lst, void __user* arg) { - struct list_sem_st *lst; ncr_key_t desc; struct key_item_st* key; int ret; - lst = &lst_->key; ret = ncr_limits_add_and_check(current_euid(), task_pid_nr(current), LIMIT_TYPE_KEY); if (ret < 0) { err(); @@ -186,23 +173,25 @@ int ncr_key_init(struct ncr_lists *lst_, void __user* arg) atomic_set(&key->refcnt, 1); atomic_set(&key->writer, 0); - - down(&lst->sem); - - key->desc = _ncr_key_get_new_desc(lst); key->uid = current_euid(); key->pid = task_pid_nr(current); - list_add(&key->list, &lst->list); - - up(&lst->sem); + mutex_lock(&lst->key_idr_mutex); + /* idr_pre_get() should preallocate enough, and, due to key_idr_mutex, + nobody else can use the preallocated data. Therefore the loop + recommended in idr_get_new() documentation is not necessary. */ + if (idr_pre_get(&lst->key_idr, GFP_KERNEL) == 0 || + idr_get_new(&lst->key_idr, key, &key->desc) != 0) { + mutex_unlock(&lst->key_idr_mutex); + _ncr_key_item_put(key); + return -ENOMEM; + } + mutex_unlock(&lst->key_idr_mutex); desc = key->desc; ret = copy_to_user(arg, &desc, sizeof(desc)); if (unlikely(ret)) { - down(&lst->sem); - _ncr_key_unlink_item(key); - up(&lst->sem); + _ncr_key_remove(lst, desc); return -EFAULT; } return ret; @@ -212,29 +201,16 @@ err_limits: return ret; } - -int ncr_key_deinit(struct ncr_lists *lst_, void __user* arg) +int ncr_key_deinit(struct ncr_lists *lst, void __user* arg) { - struct list_sem_st *lst; ncr_key_t desc; - struct key_item_st * item, *tmp; - lst = &lst_->key; if (unlikely(copy_from_user(&desc, arg, sizeof(desc)))) { err(); return -EFAULT; } - down(&lst->sem); - - list_for_each_entry_safe(item, tmp, &lst->list, list) { - if(item->desc == desc) { - _ncr_key_unlink_item(item); - break; - } - } - - up(&lst->sem); + _ncr_key_remove(lst, desc); return 0; } |