hashtable
authorMateusz Majewski <m.majewski2@samsung.com>
Tue, 23 Aug 2022 12:05:16 +0000 (14:05 +0200)
committerMateusz Majewski <m.majewski2@samsung.com>
Wed, 24 Aug 2022 08:09:06 +0000 (10:09 +0200)
Change-Id: I859bd4954ec9243cab3417c0b50f1309d05941c3

kernel/vlogger/vlogger.c

index 8dd4901e36b0ecf540ef720eaaae7852932c759e..536bcae1768e918683debe0bb9e566580672082c 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/time.h>
 #include <linux/completion.h>
 #include <linux/version.h>
+#include <linux/hashtable.h>
 #include <uapi/linux/vlogger.h>
 
 #define MB (1 << 20)
@@ -46,8 +47,6 @@
 #define V_BLOCK_SIZE (2 * KB)
 #define BLOCK_COUNT (BUFFER_SIZE / V_BLOCK_SIZE)
 #define DATA_MAX (V_BLOCK_SIZE - sizeof(struct head_t))
-// TODO: We do not want to have a MAX_THREAD limitation. Remove this.
-#define MAX_THREAD (0x8000)
 #define MS_PER_SEC (1000)
 #define NS_PER_SEC (1000000000UL)
 
@@ -93,6 +92,16 @@ struct queue_t {
        uint16_t *values;
 };
 
+struct thread_table_field {
+       pid_t tid;
+       uint16_t blk;
+       struct hlist_node next;
+};
+
+struct thread_table {
+       DECLARE_HASHTABLE(data, 16);
+};
+
 // taken from dlog.h
 typedef enum {
        DLOG_UNKNOWN = 0, /**< Keep this always at the start */
@@ -125,12 +134,8 @@ static struct miscdevice vlogger_device;
 
 static int g_init;
 static char *g_shm_ptr[DEVICE_COUNT];
-// TODO: Having an array indexed by TIDs is unnacceptable.
-static struct thread_t *g_threads;
+static struct thread_table *g_thread_table;
 
-// TODO: g_block_mutex is basically smoke and mirrors,
-// since the protected array is basically world-writable
-// and can change at any time.
 static struct mutex g_block_mutex;
 static struct mutex g_task_mutex;
 
@@ -158,6 +163,44 @@ static inline u64 ktime_get_ns(void)
 }
 #endif
 
+static uint16_t get_thread_table(pid_t tid)
+{
+       struct thread_table_field *ptr = NULL;
+
+       // TODO: Is this needed?
+       if (g_thread_table == NULL)
+               return 0;
+
+       hash_for_each_possible(g_thread_table->data, ptr, next, tid) {
+               if (ptr->tid == tid) {
+                       return ptr->blk;
+               }
+       }
+
+       return 0;
+}
+
+static void set_thread_table(pid_t tid, uint16_t blk)
+{
+       struct thread_table_field *ptr = NULL;
+
+       // TODO: Is this needed?
+       if (g_thread_table == NULL)
+               return;
+
+       hash_for_each_possible(g_thread_table->data, ptr, next, tid) {
+               if (ptr->tid == tid) {
+                       ptr->blk = blk;
+                       return;
+               }
+       }
+
+       ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
+       ptr->tid = tid;
+       ptr->blk = blk;
+       hash_add(g_thread_table->data, &ptr->next, tid);
+}
+
 static inline char *get_shared_memory(int dev_index)
 {
        if (dev_index < 0 || dev_index >= DEVICE_COUNT) {
@@ -241,14 +284,15 @@ static int vlog_task(void *user_data)
        uint16_t blk;
 
        do {
+               // TODO: Consider hash_for_each_safe
                for (i = 1; i <= g_max_thread_id; i++) {
-                       blk = g_threads[i].block;
+                       blk = get_thread_table(i);
                        // TODO: g_start_time should be under some kind of mutex.
                        if (blk && get_block(blk)->head.ts < g_start_time) {
                                mutex_lock(&g_block_mutex);
                                get_block(blk)->head.tid = 0;
                                queue_push(&g_free_q, blk);
-                               g_threads[i].block = 0;
+                               set_thread_table(i, 0);
                                // TODO: The userspace might very well be using this block right now.
                                mutex_unlock(&g_block_mutex);
                                g_free_count++;
@@ -296,20 +340,15 @@ static long alloc_block_for_thread(void)
        uint16_t blk;
        struct block_t *block;
 
-       if (tid >= MAX_THREAD) {
-               pr_err("Invalid tid: %d", tid);
-               return -EINVAL;
-       }
-
        if (g_max_thread_id < tid)
                g_max_thread_id = tid;
 
        mutex_lock(&g_block_mutex);
-       blk = g_threads[tid].block;
+       blk = get_thread_table(tid);
        if (blk)
                queue_push(&g_free_q, blk);
        blk = queue_pop(&g_free_q);
-       g_threads[tid].block = blk;
+       set_thread_table(tid, blk);
 
        if (!blk) {
                if ((g_err_count++ % 10000) < 3)
@@ -338,10 +377,7 @@ static inline struct block_t *get_valid_block(int tid, size_t len)
        uint16_t blk = 0;
        long r;
 
-       if (g_threads == NULL)
-               return NULL;
-
-       blk = g_threads[tid].block;
+       blk = get_thread_table(tid);
 
        if (blk != 0) {
                struct block_t *block = get_block(blk);
@@ -620,18 +656,19 @@ static const struct file_operations vlogger_fops = {
 static ssize_t status_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       int thread_count = 0;
-       int i;
-
-       for (i = 0; i < MAX_THREAD; i++) {
-               if (g_threads[i].block > 0)
-                       thread_count ++;
-       }
-
-       return snprintf(buf, PAGE_SIZE,
-                       "free(%d%%):%d/%d task_on:%d gc_free:%u error:%u tid_max:%d\n",
-                       BLOCK_RATIO(g_free_q.count), g_free_q.count, (g_free_q.count + thread_count),
-                       g_task_on, g_free_count, g_err_count, g_max_thread_id);
+       // int thread_count = 0;
+       // int i;
+
+       // for (i = 0; i < MAX_THREAD; i++) {
+       //      if (g_threads[i].block > 0)
+       //              thread_count ++;
+       // }
+
+       // return snprintf(buf, PAGE_SIZE,
+       //              "free(%d%%):%d/%d task_on:%d gc_free:%u error:%u tid_max:%d\n",
+       //              BLOCK_RATIO(g_free_q.count), g_free_q.count, (g_free_q.count + thread_count),
+       //              g_task_on, g_free_count, g_err_count, g_max_thread_id);
+       return -ENOTSUPP; // TODO
 }
 
 static DEVICE_ATTR_RO(status);
@@ -702,7 +739,8 @@ static ssize_t thread_store(struct device *dev,
 static ssize_t thread_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       return snprintf(buf, PAGE_SIZE, "[%d] block:%u\n", g_thread, g_threads[g_thread].block);
+       // return snprintf(buf, PAGE_SIZE, "[%d] block:%u\n", g_thread, g_threads[g_thread].block);
+       return -ENOTSUPP; // TODO
 }
 
 static DEVICE_ATTR_RW(thread);
@@ -749,15 +787,16 @@ int __init vlogger_init(void)
                return r;
        }
 
-       g_threads = kzalloc(sizeof(struct thread_t) * MAX_THREAD, GFP_KERNEL);
-       if (g_threads == NULL)
+       g_thread_table = kzalloc(sizeof(struct thread_table), GFP_KERNEL);
+       if (g_thread_table == NULL)
                return -ENOMEM;
+       hash_init(g_thread_table->data);
 
        for (g_shm_ptr_i = 0; g_shm_ptr_i < DEVICE_COUNT; g_shm_ptr_i++) {
                g_shm_ptr[g_shm_ptr_i] = kzalloc(MAP_SIZE, GFP_KERNEL);
                if (g_shm_ptr[g_shm_ptr_i] == NULL) {
                        r = -ENOMEM;
-                       goto out_free_g_threads_g_shm_ptr;
+                       goto out_free_g_thread_table_g_shm_ptr;
                }
        }
 
@@ -780,10 +819,10 @@ int __init vlogger_init(void)
 
        return 0;
 
-out_free_g_threads_g_shm_ptr:
+out_free_g_thread_table_g_shm_ptr:
        for (i = 0; i < g_shm_ptr_i; ++i)
                kfree(g_shm_ptr[i]);
-       kfree(g_threads);
+       kfree(g_thread_table);
        return r;
 }
 
@@ -794,7 +833,7 @@ static void __exit vlogger_exit(void)
        // TODO: What about the task that is running in the background?
 
        queue_deinit(&g_free_q);
-       kfree(g_threads);
+       kfree(g_thread_table); // TODO: Free innards
        for (i = 0; i < DEVICE_COUNT; i++)
                kfree(g_shm_ptr[i]);