6db4831e98
Android 14
164 lines
4.6 KiB
C
164 lines
4.6 KiB
C
/*
|
|
* PROCA task descriptors table
|
|
*
|
|
* Copyright (C) 2018 Samsung Electronics, Inc.
|
|
* Hryhorii Tur, <hryhorii.tur@partner.samsung.com>
|
|
*
|
|
* This software is licensed under the terms of the GNU General Public
|
|
* License version 2, as published by the Free Software Foundation, and
|
|
* may be copied, distributed, and modified under those terms.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include "proca_table.h"
|
|
|
|
#include <linux/hashtable.h>
|
|
#include <linux/string.h>
|
|
|
|
void proca_table_init(struct proca_table *table)
|
|
{
|
|
BUG_ON(!table);
|
|
|
|
memset(table, 0, sizeof(*table));
|
|
|
|
spin_lock_init(&table->pid_map_lock);
|
|
hash_init(table->pid_map);
|
|
|
|
spin_lock_init(&table->app_name_map_lock);
|
|
hash_init(table->app_name_map);
|
|
|
|
table->hash_tables_shift = PROCA_TASKS_TABLE_SHIFT;
|
|
}
|
|
|
|
/*
|
|
* Following hash functions and constants were taken from 4.9.59 kernel
|
|
* in order to simplify porting to new devices.
|
|
*/
|
|
|
|
#define GOLDEN_RATIO_32 0x61C88647
|
|
|
|
static inline u32 proca_hash_32(u32 val)
|
|
{
|
|
return val * GOLDEN_RATIO_32;
|
|
}
|
|
|
|
/* Hash courtesy of the R5 hash in reiserfs modulo sign bits */
|
|
#define proca_init_name_hash(salt) (unsigned long)(salt)
|
|
|
|
/* partial hash update function. Assume roughly 4 bits per character */
|
|
static inline unsigned long
|
|
proca_partial_name_hash(unsigned long c, unsigned long prevhash)
|
|
{
|
|
return (prevhash + (c << 4) + (c >> 4)) * 11;
|
|
}
|
|
|
|
/*
|
|
* Finally: cut down the number of bits to a int value (and try to avoid
|
|
* losing bits). This also has the property (wanted by the dcache)
|
|
* that the msbits make a good hash table index.
|
|
*/
|
|
static inline unsigned long proca_end_name_hash(unsigned long hash)
|
|
{
|
|
return proca_hash_32((unsigned int)hash);
|
|
}
|
|
|
|
static unsigned long calculate_app_name_hash(struct proca_table *table,
|
|
const char *app_name,
|
|
size_t app_name_size)
|
|
{
|
|
size_t i;
|
|
unsigned long hash = proca_init_name_hash(0);
|
|
|
|
if (!app_name)
|
|
return proca_end_name_hash(hash);
|
|
|
|
for (i = 0; i < app_name_size; ++i)
|
|
hash = proca_partial_name_hash(app_name[i], hash);
|
|
return proca_end_name_hash(hash) % (1 << table->hash_tables_shift);
|
|
}
|
|
|
|
static unsigned long calculate_pid_hash(struct proca_table *table, pid_t pid)
|
|
{
|
|
return proca_hash_32(pid) >> (32 - table->hash_tables_shift);
|
|
}
|
|
|
|
void proca_table_add_task_descr(struct proca_table *table,
|
|
struct proca_task_descr *descr)
|
|
{
|
|
unsigned long hash_key;
|
|
unsigned long irqsave_flags;
|
|
|
|
hash_key = calculate_pid_hash(table, descr->task->pid);
|
|
spin_lock_irqsave(&table->pid_map_lock, irqsave_flags);
|
|
hlist_add_head(&descr->pid_map_node,
|
|
&table->pid_map[hash_key]);
|
|
spin_unlock_irqrestore(&table->pid_map_lock, irqsave_flags);
|
|
|
|
if (descr->proca_identity.certificate) {
|
|
hash_key = calculate_app_name_hash(table,
|
|
descr->proca_identity.parsed_cert.app_name,
|
|
descr->proca_identity.parsed_cert.app_name_size);
|
|
spin_lock_irqsave(&table->app_name_map_lock, irqsave_flags);
|
|
hlist_add_head(&descr->app_name_map_node,
|
|
&table->app_name_map[hash_key]);
|
|
spin_unlock_irqrestore(
|
|
&table->app_name_map_lock, irqsave_flags);
|
|
}
|
|
}
|
|
|
|
void proca_table_remove_task_descr(struct proca_table *table,
|
|
struct proca_task_descr *descr)
|
|
{
|
|
unsigned long irqsave_flags;
|
|
|
|
if (!descr)
|
|
return;
|
|
|
|
spin_lock_irqsave(&table->pid_map_lock, irqsave_flags);
|
|
hash_del(&descr->pid_map_node);
|
|
spin_unlock_irqrestore(&table->pid_map_lock, irqsave_flags);
|
|
|
|
spin_lock_irqsave(&table->app_name_map_lock, irqsave_flags);
|
|
hash_del(&descr->app_name_map_node);
|
|
spin_unlock_irqrestore(&table->app_name_map_lock, irqsave_flags);
|
|
}
|
|
|
|
struct proca_task_descr *proca_table_get_by_task(
|
|
struct proca_table *table,
|
|
const struct task_struct *task)
|
|
{
|
|
struct proca_task_descr *descr;
|
|
struct proca_task_descr *target_task_descr = NULL;
|
|
unsigned long hash_key;
|
|
unsigned long irqsave_flags;
|
|
|
|
hash_key = calculate_pid_hash(table, task->pid);
|
|
|
|
spin_lock_irqsave(&table->pid_map_lock, irqsave_flags);
|
|
hlist_for_each_entry(descr, &table->pid_map[hash_key], pid_map_node) {
|
|
if (task == descr->task) {
|
|
target_task_descr = descr;
|
|
break;
|
|
}
|
|
}
|
|
spin_unlock_irqrestore(&table->pid_map_lock, irqsave_flags);
|
|
|
|
return target_task_descr;
|
|
}
|
|
|
|
struct proca_task_descr *proca_table_remove_by_task(
|
|
struct proca_table *table,
|
|
const struct task_struct *task)
|
|
{
|
|
struct proca_task_descr *target_task_descr = NULL;
|
|
|
|
target_task_descr = proca_table_get_by_task(table, task);
|
|
proca_table_remove_task_descr(table, target_task_descr);
|
|
|
|
return target_task_descr;
|
|
}
|