????
| Current Path : /var/lib/dkms/file_protector/1.1-1578/source/ |
| Current File : //var/lib/dkms/file_protector/1.1-1578/source/file_contexts_priv.h |
/**
@file file_contexts_priv.h
@brief Store the opened file contexts(inode + pid), private struct definitions
@details Copyright (c) 2024 Acronis International GmbH
@author Bruce Wang (bruce.wang@acronis.com)
@since $Id: $
*/
#include <linux/list.h>
#include <linux/rcupdate.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/version.h>
#include <linux/rbtree.h>
#include "file_contexts.h"
#include "hashtable_compat.h"
#include "transport.h"
#define FILE_CONTEXT_SMALL_TABLE_SIZE_BITS 6 // 64
#define FILE_CONTEXT_SMALL_TABLE_MAX_SIZE (1 << (FILE_CONTEXT_SMALL_TABLE_SIZE_BITS - 1)) // 32
#define FILE_CONTEXT_SMALL_TABLE_LRU_CLEAN_SIZE (10)
#define FILE_CONTEXT_BIG_TABLE_SIZE_BITS 15 // 32768
#define FILE_CONTEXT_BIG_TBALE_SIZE (1 << (FILE_CONTEXT_BIG_TABLE_SIZE_BITS - 1)) // 16384
#define FILE_CONTEXT_BIG_TABLE_LRU_CLEAN_SIZE (100)
#define FILE_CONTEXT_EXPIRE_TIME_MS (180 * 1000)
#define FILE_CONTEXT_CHUNK_SIZE 4096
#define FILE_CONTEXT_CHUNK_LOWER_BOUND(N) ((uint64_t)(N / FILE_CONTEXT_CHUNK_SIZE) * FILE_CONTEXT_CHUNK_SIZE)
#define FILE_CONTEXT_CHUNK_UPPER_BOUND(N) ((uint64_t)((N + FILE_CONTEXT_CHUNK_SIZE - 1) / FILE_CONTEXT_CHUNK_SIZE) * FILE_CONTEXT_CHUNK_SIZE)
#define FILE_CONTEXT_MAX_FILE_SIZE (100 * 1024 * 1024)
/*
size of file_context_tables_t: 786576 Bytes => 0.75MB
size of interval_node_t: 72 Bytes
size of file_context_rw_node_t: 192 Bytes
size of file_context_open_file_node_t: 720 Bytes
size of file_context_open_process_node_t: 104 Bytes
In the scenario that all tables are full:
2 *32768 * (sizeof(file_context_rw_node_t) + 32(estimated) * sizeof(interval_node_t)) +
32768 * (sizeof(file_context_open_file_node_t) + 32 * sizeof(file_context_open_process_node_t)) +
sizeof(file_context_tables_t)
= 283 MB
*/
// Node in file_context_common_table_t
// this struct should always be the first in the assembled struct
typedef struct
{
// node in file_context_common_table_t->hashtable
struct hlist_node hash_node;
uint64_t key;
// node in file_context_common_table_t->lru_list
bool lru_list_node_inserted;
struct list_head lru_list_node;
// node in temporary delete list
struct list_head del_list_node;
unsigned long last_access_time;
atomic_t ref_count;
struct kmem_cache *kmem;
struct rcu_head rcu;
void (*pre_free_func)(void *);
} file_context_common_node_t;
// Abstruction of tables
typedef struct
{
struct hlist_head *hashtable;
struct list_head lru_list;
unsigned int size;
uint8_t hashbits;
unsigned int max_size;
unsigned short clean_count;
spinlock_t spinlock;
} file_context_common_table_t;
// A small hashtable struct to store file_context_open_process_node_t, the key is pid
typedef struct
{
DECLARE_HASHTABLE(hashtable, FILE_CONTEXT_SMALL_TABLE_SIZE_BITS);
file_context_common_table_t common_table;
} file_context_small_table_t;
// A big hashtable struct to store file_context_open_file_node_t, file_context_rw_node_t, the key is inode ptr
typedef struct
{
DECLARE_HASHTABLE(hashtable, FILE_CONTEXT_BIG_TABLE_SIZE_BITS);
file_context_common_table_t common_table;
} file_context_big_table_t;
// Node in process_table
typedef struct
{
file_context_common_node_t common_node;
file_context_open_process_t data;
} file_context_open_process_node_t;
// Node in open_table
typedef struct
{
file_context_common_node_t common_node;
// Key: pid, Value: flags
file_context_small_table_t process_table;
file_context_key_t key;
file_context_open_file_t data;
} file_context_open_file_node_t;
typedef struct
{
uint64_t low;
uint64_t high;
struct rb_node rb;
// node in temporary delete list
struct list_head del_list_node;
struct list_head stack_node;
} interval_node_t;
// Node in read_table/write_table
typedef struct
{
file_context_common_node_t common_node;
// data fields
file_context_key_t key;
file_context_rw_t data;
} file_context_rw_node_t;
typedef struct
{
file_context_common_node_t common_node;
file_context_process_t data;
} file_context_process_node_t;
typedef struct
{
file_context_common_node_t common_node;
// data fields
file_context_key_t key;
file_context_small_table_t process_table;
} file_context_file_modify_node_t;
typedef struct
{
uint64_t transport_id;
// TODO: ref_count is excessive, it is going to be used very rarely in a normal run
// A better idea would be using rcu to acquire the file_context_tables_t pointer
// and avoid using reference counts altogether
atomic_t ref_count;
// Key: inode.ptr, Value: processes
file_context_big_table_t open_table;
// Key: inode.ptr, Value: intervals
file_context_big_table_t read_table;
// Key: inode.ptr, Value: intervals
file_context_big_table_t write_table;
struct rcu_head rcu;
} file_context_tables_t;
#define MAX_TRANSPORT_EXTENDED_SIZE MAX_TRANSPORT_SIZE + 1
typedef struct
{
spinlock_t writer_lock;
// file_context_tables_t is memory costly, malloc it only when new transport is opened
// file_context_tables_t pointer is RCU protected
// this is a quick fix, tables[MAX_TRANSPORT_SIZE] is used for file modified flag cache.
// TODO: reorganize the tables
file_context_tables_t *tables[MAX_TRANSPORT_EXTENDED_SIZE];
} file_context_manager_t;